clay-server 5.2.0-beta.3 → 5.2.0-beta.5
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 +28 -0
- package/lib/clay-mate-chat-receipts.js +26 -0
- package/lib/clay-mate-chat.js +87 -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 +237 -0
- package/lib/clay-project-lifecycle.js +154 -0
- package/lib/clay-project-record-input.js +44 -0
- package/lib/clay-project-records.js +83 -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 +96 -0
- package/lib/clay-workspace-controls.js +83 -0
- package/lib/clay-workspace-input.js +17 -0
- package/lib/clay-workspace-receipts.js +26 -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 +73 -221
- package/lib/issues-service.js +29 -15
- package/lib/knowledge-db-import.js +5 -4
- package/lib/knowledge-db-service.js +9 -6
- 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-creation-mcp-server.js +2 -0
- package/lib/mate-knowledge-canonical-access.js +10 -0
- package/lib/mate-knowledge-service.js +7 -4
- 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-query-bridge.js +30 -0
- package/lib/mcp-remote-connections.js +74 -20
- package/lib/mcp-source-adapters.js +91 -0
- package/lib/mcp-source-context.js +42 -0
- package/lib/mcp-source-discovery.js +169 -0
- package/lib/mcp-source-plugins.js +68 -0
- package/lib/mcp-source-restrictions.js +47 -0
- package/lib/mcp-tool-policy.js +34 -0
- package/lib/notes-checklist.js +50 -0
- package/lib/notes.js +49 -3
- package/lib/os-users.js +20 -5
- package/lib/project-admin-overview.js +51 -0
- package/lib/project-ask-user.js +8 -4
- 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 +13 -87
- package/lib/project-full-access.js +23 -2
- 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 +8 -0
- package/lib/project-mcp.js +54 -16
- package/lib/project-models.js +14 -31
- package/lib/project-notifications.js +74 -16
- package/lib/project-ownership.js +77 -0
- package/lib/project-pair-result-delivery.js +14 -3
- package/lib/project-pending-message-queue.js +1 -0
- package/lib/project-product-control.js +87 -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 +63 -64
- 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 +8 -3
- package/lib/project-session-github.js +63 -19
- package/lib/project-session-history-actions.js +165 -0
- package/lib/project-session-linear.js +14 -6
- package/lib/project-session-notes.js +7 -3
- package/lib/project-session-runtime-actions.js +63 -0
- package/lib/project-session-vendor.js +54 -0
- package/lib/project-sessions.js +68 -241
- package/lib/project-shared-browser.js +56 -12
- package/lib/project-user-message.js +30 -1
- package/lib/project-workspace-operations.js +126 -0
- package/lib/project-workspace-query.js +9 -2
- package/lib/project.js +144 -37
- package/lib/public/app.js +5 -0
- package/lib/public/appearance-bootstrap.js +14 -0
- package/lib/public/css/clay-tool-activity.css +51 -0
- package/lib/public/css/clay-workspace.css +29 -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/mate-avatar-gallery.css +12 -0
- package/lib/public/css/mate-conversation.css +10 -5
- 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 +61 -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 +8 -1
- package/lib/public/modules/app-message-router.js +4 -0
- package/lib/public/modules/app-messages.js +31 -5
- package/lib/public/modules/app-projects.js +5 -0
- package/lib/public/modules/app-rendering.js +1 -1
- package/lib/public/modules/avatar.js +15 -41
- package/lib/public/modules/chat-render-runtime.js +10 -1
- package/lib/public/modules/clay-browser-links.js +47 -0
- package/lib/public/modules/clay-log-links.js +1 -1
- package/lib/public/modules/clay-owner-navigation.js +27 -0
- package/lib/public/modules/clay-tool-activity.js +140 -0
- package/lib/public/modules/clay-tool-presentation.js +338 -0
- package/lib/public/modules/command-palette.js +2 -2
- package/lib/public/modules/debate.js +1 -0
- package/lib/public/modules/default-ai.js +11 -3
- package/lib/public/modules/history-replay-batch.js +5 -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/markdown.js +4 -0
- package/lib/public/modules/mate-avatar-catalog.js +97 -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/pane-browser-bridge.js +20 -0
- package/lib/public/modules/personal-settings-dialog.js +7 -1
- 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-mate-navigation.js +99 -14
- package/lib/public/modules/search-clay-chat.js +16 -2
- 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-work-primary.js +51 -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 +27 -6
- package/lib/public/modules/sidebar-session-folders-ui.js +1 -1
- package/lib/public/modules/split-view.js +2 -0
- 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 +71 -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/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 +36 -7
- 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/style.css +3 -0
- package/lib/public/sw.js +3 -1
- package/lib/scheduled-task-records.js +3 -1
- package/lib/scheduler.js +2 -0
- package/lib/sdk-bridge.js +228 -23
- package/lib/sdk-message-processor.js +2 -0
- package/lib/sdk-response-recovery.js +155 -0
- package/lib/server-admin.js +63 -16
- package/lib/server-appearance-settings.js +13 -1
- 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 +12 -16
- 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 +77 -0
- package/lib/server-path-access.js +38 -0
- package/lib/server-project-removal.js +22 -0
- package/lib/server-settings.js +4 -1
- package/lib/server.js +144 -41
- package/lib/session-config-transition.js +45 -0
- package/lib/session-folders.js +7 -2
- package/lib/session-github.js +9 -2
- package/lib/session-visibility.js +5 -2
- package/lib/session-work-primary.js +50 -0
- package/lib/sessions.js +13 -0
- 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 +52 -0
- package/lib/users-permissions.js +2 -8
- package/lib/users.js +4 -0
- package/lib/workspace-query-access.js +4 -1
- package/lib/ws-schema.js +8 -2
- package/lib/yoke/acp-agent-profiles.js +2 -2
- package/lib/yoke/adapters/claude.js +47 -8
- package/lib/yoke/adapters/codex.js +52 -111
- package/lib/yoke/claude-worker-startup.js +28 -0
- package/lib/yoke/codex-idle-recovery.js +81 -1
- package/lib/yoke/codex-recovery-admission.js +164 -0
- package/lib/yoke/session-tool-transport.js +3 -0
- package/package.json +5 -1
package/lib/project-sessions.js
CHANGED
|
@@ -118,14 +118,20 @@ function attachSessions(ctx) {
|
|
|
118
118
|
var ensureProjectAccessForSession = ctx.ensureProjectAccessForSession;
|
|
119
119
|
var getOsUserInfoForWs = ctx.getOsUserInfoForWs;
|
|
120
120
|
var hydrateSkillCatalog = ctx.hydrateSkillCatalog || function () { return []; };
|
|
121
|
+
var sessionActions = require("./project-session-actions").attachSessionActions(ctx);
|
|
122
|
+
var sessionVendor = require("./project-session-vendor").attachSessionVendor(ctx);
|
|
123
|
+
var sessionRuntime = require("./project-session-runtime-actions").attachSessionRuntimeActions({ sm: sm, tm: tm, prepareGui: prepareTuiSessionForGuiView, isPendingQueuePaused: ctx.isPendingQueuePaused,
|
|
124
|
+
publishGui: function (session) {
|
|
125
|
+
clients.forEach(function (ws) {
|
|
126
|
+
if (ws.readyState !== 1 || ws._clayActiveSession !== session.localId) return;
|
|
127
|
+
if (usersModule.isMultiUser() && (!ws._clayUser || !usersModule.findUserById(ws._clayUser.id) || !usersModule.canAccessProject(ws._clayUser.id, getProjectAccess()) || !usersModule.canAccessSession(ws._clayUser.id, session, getProjectAccess()))) return;
|
|
128
|
+
sm.switchSession(session.localId, ws, ctx.hydrateImageRefs);
|
|
129
|
+
});
|
|
130
|
+
},
|
|
131
|
+
});
|
|
121
132
|
function stopSession(session, actor) {
|
|
122
133
|
if (!session) return false;
|
|
123
|
-
session
|
|
124
|
-
if (typeof ctx.onPendingQueuePause === "function") ctx.onPendingQueuePause(session, actor || null);
|
|
125
|
-
if (!session.isProcessing && !session._queryStarting) return true;
|
|
126
|
-
if (typeof ctx.onHumanPairStop === "function") ctx.onHumanPairStop(session);
|
|
127
|
-
session.taskStopRequested = true;
|
|
128
|
-
if (session.abortController) session.abortController.abort();
|
|
134
|
+
sessionActions.stop(session, actor);
|
|
129
135
|
return true;
|
|
130
136
|
}
|
|
131
137
|
var hydrateImageRefs = ctx.hydrateImageRefs;
|
|
@@ -143,12 +149,16 @@ function attachSessions(ctx) {
|
|
|
143
149
|
return !session.ownerId;
|
|
144
150
|
}
|
|
145
151
|
|
|
146
|
-
function respondToAskUser(session, msg) {
|
|
152
|
+
function respondToAskUser(session, msg, ws) {
|
|
147
153
|
if (!session || !msg || !msg.toolId) return false;
|
|
148
154
|
var toolId = msg.toolId;
|
|
149
155
|
var answers = msg.answers || {};
|
|
150
156
|
var pending = session.pendingAskUser && session.pendingAskUser[toolId];
|
|
151
157
|
if (!pending) return false;
|
|
158
|
+
if (pending.request && ["mcp-import", "product-control"].indexOf(pending.request.source) >= 0 &&
|
|
159
|
+
(typeof pending.request.authorizeResponse !== "function" || !pending.request.authorizeResponse(ws))) return false;
|
|
160
|
+
if (pending.request && ["work-primary", "mate-schedule"].indexOf(pending.request.source) >= 0 && usersModule.isMultiUser() &&
|
|
161
|
+
(!ws || !ws._clayUser || ws._clayUser.id !== session.ownerId)) return false;
|
|
152
162
|
if (pending.mode === "yoke") {
|
|
153
163
|
try { yoke.userInput.normalizeAnswers(pending.request.questions, answers); }
|
|
154
164
|
catch (e) { return false; }
|
|
@@ -209,6 +219,10 @@ function attachSessions(ctx) {
|
|
|
209
219
|
var setLatestVersion = ctx.setLatestVersion;
|
|
210
220
|
var loadContextSources = ctx.loadContextSources;
|
|
211
221
|
|
|
222
|
+
var sessionHistory = require("./project-session-history-actions").attachSessionHistoryActions(Object.assign({}, ctx, {
|
|
223
|
+
resolveSessionHome: resolveSessionHome, cancelPendingAskUser: cancelPendingAskUser,
|
|
224
|
+
}));
|
|
225
|
+
|
|
212
226
|
function canAccessProjectSlug(ws, targetSlug) {
|
|
213
227
|
if (!targetSlug) return false;
|
|
214
228
|
if (!usersModule || typeof usersModule.isMultiUser !== "function" || !usersModule.isMultiUser()) return true;
|
|
@@ -436,7 +450,7 @@ function attachSessions(ctx) {
|
|
|
436
450
|
// Idempotent: if the PTY is already gone and history is populated, this
|
|
437
451
|
// is a no-op (avoids re-reading jsonl and re-writing the session file on
|
|
438
452
|
// every click while the user is reading the session in GUI mode).
|
|
439
|
-
function prepareTuiSessionForGuiView(session) {
|
|
453
|
+
function prepareTuiSessionForGuiView(session, options) {
|
|
440
454
|
if (!session || session.cliSessionId == null) return;
|
|
441
455
|
var cliSess;
|
|
442
456
|
try { cliSess = require("./cli-sessions"); } catch (e) { return; }
|
|
@@ -463,7 +477,7 @@ function attachSessions(ctx) {
|
|
|
463
477
|
try { tm.close(session.terminalId); } catch (e) {}
|
|
464
478
|
}
|
|
465
479
|
session.terminalId = null;
|
|
466
|
-
try { sm.saveSessionFile(session); } catch (e) {}
|
|
480
|
+
if (!options || !options.deferSave) { try { sm.saveSessionFile(session); } catch (e) {} }
|
|
467
481
|
}
|
|
468
482
|
|
|
469
483
|
// Resolve how a session should be presented to a viewer WITHOUT spawning a
|
|
@@ -764,11 +778,10 @@ function attachSessions(ctx) {
|
|
|
764
778
|
sendTo(ws, { type: "error", text: "Cannot transfer ownership of home directory projects." });
|
|
765
779
|
return true;
|
|
766
780
|
}
|
|
767
|
-
var projectOwnerId =
|
|
768
|
-
var isAdmin = ws._clayUser && ws._clayUser.role === "admin";
|
|
781
|
+
var projectOwnerId = getProjectAccess().ownerId;
|
|
769
782
|
var isProjectOwner = ws._clayUser && projectOwnerId && ws._clayUser.id === projectOwnerId;
|
|
770
|
-
if (!ws._clayUser ||
|
|
771
|
-
sendTo(ws, { type: "error", text: "Only project owners
|
|
783
|
+
if (!ws._clayUser || !isProjectOwner) {
|
|
784
|
+
sendTo(ws, { type: "error", text: "Only project owners can transfer ownership." });
|
|
772
785
|
return true;
|
|
773
786
|
}
|
|
774
787
|
var targetUser = msg.userId ? usersModule.findUserById(msg.userId) : null;
|
|
@@ -776,11 +789,11 @@ function attachSessions(ctx) {
|
|
|
776
789
|
sendTo(ws, { type: "error", text: "User not found." });
|
|
777
790
|
return true;
|
|
778
791
|
}
|
|
792
|
+
// Persist before publishing runtime ownership.
|
|
793
|
+
if (!opts.onProjectOwnerChanged) return true;
|
|
794
|
+
var savedOwner = opts.onProjectOwnerChanged(slug, targetUser.id);
|
|
795
|
+
if (savedOwner && savedOwner.error) { sendTo(ws, { type: "error", text: savedOwner.error }); return true; }
|
|
779
796
|
setProjectOwnerId(targetUser.id);
|
|
780
|
-
// Persist via daemon callback
|
|
781
|
-
if (opts.onProjectOwnerChanged) {
|
|
782
|
-
opts.onProjectOwnerChanged(slug, targetUser.id);
|
|
783
|
-
}
|
|
784
797
|
send({ type: "project_owner_changed", ownerId: targetUser.id, ownerName: targetUser.displayName || targetUser.username });
|
|
785
798
|
return true;
|
|
786
799
|
}
|
|
@@ -797,6 +810,7 @@ function attachSessions(ctx) {
|
|
|
797
810
|
// broadcasts session_switched. A live runtime keeps its actual mode
|
|
798
811
|
// for every viewer; idle sessions open in chat. Nothing is spawned here.
|
|
799
812
|
var xmTarget = sm.sessions.get(msg.id);
|
|
813
|
+
if (usersModule.isMultiUser() && (!ws._clayUser || !usersModule.canAccessSession(ws._clayUser.id, xmTarget, getProjectAccess()))) return true;
|
|
800
814
|
if (xmTarget && (!xmTarget.vendor || vendorSupportsTui(xmTarget.vendor))) {
|
|
801
815
|
// Single source of truth: live runtime wins (tui stays tui, gui stays
|
|
802
816
|
// gui); idle legacy sessions hydrate their transcript into chat.
|
|
@@ -935,19 +949,7 @@ function attachSessions(ctx) {
|
|
|
935
949
|
var s = sm.sessions.get(msg.id);
|
|
936
950
|
if (usersModule.isMultiUser() && (!ws._clayUser ||
|
|
937
951
|
!usersModule.canAccessSession(ws._clayUser.id, s, getProjectAccess()))) return true;
|
|
938
|
-
s
|
|
939
|
-
s.titleProvisional = false;
|
|
940
|
-
s.titleAutoGenerated = false;
|
|
941
|
-
s.titleManuallySet = true;
|
|
942
|
-
sm.saveSessionFile(s);
|
|
943
|
-
sm.notifySessionRenamed(s.localId);
|
|
944
|
-
sm.broadcastSessionList();
|
|
945
|
-
// Sync title to SDK session
|
|
946
|
-
if (s.cliSessionId) {
|
|
947
|
-
adapter.renameSession(s.cliSessionId, s.title, { dir: cwd }).catch(function(e) {
|
|
948
|
-
console.error("[project] SDK renameSession failed:", e.message);
|
|
949
|
-
});
|
|
950
|
-
}
|
|
952
|
+
sessionActions.rename(s, String(msg.title).substring(0, 100));
|
|
951
953
|
}
|
|
952
954
|
return true;
|
|
953
955
|
}
|
|
@@ -1082,7 +1084,6 @@ function attachSessions(ctx) {
|
|
|
1082
1084
|
|
|
1083
1085
|
if (msg.type === "stop") {
|
|
1084
1086
|
var session = getSessionForWs(ws);
|
|
1085
|
-
if (autonomousRun && session && session.autonomousRun) autonomousRun.finish(session, "stopped", "Stopped by the user.");
|
|
1086
1087
|
stopSession(session, ws && ws._clayUser);
|
|
1087
1088
|
return true;
|
|
1088
1089
|
}
|
|
@@ -1183,38 +1184,14 @@ function attachSessions(ctx) {
|
|
|
1183
1184
|
|
|
1184
1185
|
if (msg.type === "set_vendor" && msg.vendor) {
|
|
1185
1186
|
var vendorSession = getSessionForWs(ws);
|
|
1186
|
-
if (vendorSession)
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
if (alreadyBound) {
|
|
1193
|
-
console.warn("[project] set_vendor ignored: session " + vendorSession.localId +
|
|
1194
|
-
" is bound to '" + vendorSession.vendor + "', refused rebind to '" + msg.vendor + "'");
|
|
1195
|
-
} else {
|
|
1196
|
-
vendorSession.vendor = msg.vendor;
|
|
1197
|
-
if (vendorSession.permissionMode === "auto" && msg.vendor !== "claude") {
|
|
1198
|
-
vendorSession.permissionMode = "default";
|
|
1199
|
-
vendorSession.effectivePermissionMode = null;
|
|
1200
|
-
}
|
|
1201
|
-
if (vendorSession.vendor !== msg.vendor) vendorSession.model = "";
|
|
1202
|
-
sm.saveSessionFile(vendorSession);
|
|
1203
|
-
sm.broadcastSessionList();
|
|
1204
|
-
}
|
|
1205
|
-
}
|
|
1206
|
-
if (msg.vendor) {
|
|
1207
|
-
var vendorModels = (sm.modelsByVendor && sm.modelsByVendor[msg.vendor]) || [];
|
|
1208
|
-
sendTo(ws, {
|
|
1209
|
-
type: "model_info",
|
|
1210
|
-
model: "",
|
|
1211
|
-
models: vendorModels,
|
|
1212
|
-
vendor: msg.vendor, sessionId: vendorSession ? vendorSession.localId : null,
|
|
1213
|
-
availableVendors: sm.availableVendors || [],
|
|
1214
|
-
installedVendors: sm.installedVendors || [],
|
|
1215
|
-
});
|
|
1216
|
-
send({ type: "config_state", vendor: null, sessionId: null, mode: sm.currentPermissionMode || "default", effort: sm.currentEffort || "medium", betas: sm.currentBetas || [], thinking: sm.currentThinking || "adaptive", thinkingBudget: sm.currentThinkingBudget || 10000 });
|
|
1187
|
+
if (!vendorSession) return true;
|
|
1188
|
+
// Re-selecting the provider of an established thread does not rebind it.
|
|
1189
|
+
if (vendorSession.cliSessionId && vendorSession.vendor === msg.vendor) return true;
|
|
1190
|
+
try {
|
|
1191
|
+
var vendorResult = sessionVendor.setVendor(vendorSession, msg.vendor);
|
|
1192
|
+
if (vendorResult.status === "failed") sendTo(ws, { type: "error", text: vendorResult.error });
|
|
1217
1193
|
}
|
|
1194
|
+
catch (error) { sendTo(ws, { type: "error", text: error.message }); }
|
|
1218
1195
|
return true;
|
|
1219
1196
|
}
|
|
1220
1197
|
|
|
@@ -1282,15 +1259,7 @@ function attachSessions(ctx) {
|
|
|
1282
1259
|
if (!valid.ok) { permissionResult(false, valid.error, true); return true; }
|
|
1283
1260
|
(async function() {
|
|
1284
1261
|
try {
|
|
1285
|
-
|
|
1286
|
-
await autonomousRun.stopForPermissionChange(session);
|
|
1287
|
-
}
|
|
1288
|
-
await fullAccessService.setMode(session, valid.mode);
|
|
1289
|
-
var state = permissionModes.clientState(session, sm.currentPermissionMode, sm.defaultVendor);
|
|
1290
|
-
sm.sendToSession(session, { type: "config_state", sessionId: session.localId, vendor: session.vendor || sm.defaultVendor || "claude", mode: state.requestedPermissionMode,
|
|
1291
|
-
effectivePermissionMode: state.effectivePermissionMode, permissionRequestId: requestId,
|
|
1292
|
-
permissionCapabilities: state.permissionCapabilities, mcpPermissionModeOverrides: state.mcpPermissionModeOverrides,
|
|
1293
|
-
effort: session.effort || sm.currentEffort || "medium", betas: sm.currentBetas || [] });
|
|
1262
|
+
await sessionActions.permission(session, valid.mode, requestId);
|
|
1294
1263
|
permissionResult(true, null, true);
|
|
1295
1264
|
} catch (error) {
|
|
1296
1265
|
permissionResult(false, "Failed to change permission mode: " + (error.message || error), true);
|
|
@@ -1360,10 +1329,9 @@ function attachSessions(ctx) {
|
|
|
1360
1329
|
sendTo(ws, { type: "error", text: "This effort level is not supported by the selected vendor." });
|
|
1361
1330
|
return true;
|
|
1362
1331
|
}
|
|
1363
|
-
|
|
1332
|
+
sessionActions.effort(session, sessionEffort).catch(function (e) {
|
|
1364
1333
|
sendTo(ws, { type: "error", text: "Failed to change reasoning effort: " + (e.message || e) });
|
|
1365
1334
|
});
|
|
1366
|
-
sm.sendToSession(session, { type: "config_state", model: session.model || ((sm.defaultModelByVendor || {})[effortVendor]) || "", vendor: effortVendor, sessionId: session.localId, mode: session.permissionMode || sm.currentPermissionMode || "default", effort: sessionEffort, betas: sm.currentBetas || [], thinking: sm.currentThinking || "adaptive", thinkingBudget: sm.currentThinkingBudget || 10000 });
|
|
1367
1335
|
}
|
|
1368
1336
|
return true;
|
|
1369
1337
|
}
|
|
@@ -1440,92 +1408,9 @@ function attachSessions(ctx) {
|
|
|
1440
1408
|
sendTo(ws, { type: "rewind_error", text: "Rewind already in progress." });
|
|
1441
1409
|
return true;
|
|
1442
1410
|
}
|
|
1443
|
-
session.
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
(async function () {
|
|
1447
|
-
try {
|
|
1448
|
-
// File restoration (delegated to adapter via sdk-bridge)
|
|
1449
|
-
if (mode !== "chat") {
|
|
1450
|
-
await sdk.rewindExecuteFiles(session, msg.uuid);
|
|
1451
|
-
}
|
|
1452
|
-
|
|
1453
|
-
// Conversation rollback (skip for files-only mode)
|
|
1454
|
-
if (mode !== "files") {
|
|
1455
|
-
var targetIdx = -1;
|
|
1456
|
-
for (var i = 0; i < session.messageUUIDs.length; i++) {
|
|
1457
|
-
if (session.messageUUIDs[i].uuid === msg.uuid) {
|
|
1458
|
-
targetIdx = i;
|
|
1459
|
-
break;
|
|
1460
|
-
}
|
|
1461
|
-
}
|
|
1462
|
-
|
|
1463
|
-
// Codex's thread/revert cuts at a turn id, not a count. Read the
|
|
1464
|
-
// target entry's turnId BEFORE trimming local history below.
|
|
1465
|
-
var hasTurnsToRollBack = false;
|
|
1466
|
-
var targetTurnId = null;
|
|
1467
|
-
if (targetIdx >= 0) {
|
|
1468
|
-
targetTurnId = session.messageUUIDs[targetIdx].turnId || null;
|
|
1469
|
-
for (var ri = targetIdx; ri < session.messageUUIDs.length; ri++) {
|
|
1470
|
-
if (session.messageUUIDs[ri].type === "user") { hasTurnsToRollBack = true; break; }
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
|
|
1474
|
-
// Notify adapter of conversation rollback (e.g. Codex thread/revert)
|
|
1475
|
-
// BEFORE trimming local history below. Deliberately not caught
|
|
1476
|
-
// here: a failed or impossible (missing turnId) provider-side
|
|
1477
|
-
// rollback must abort the whole rewind via the outer catch, never
|
|
1478
|
-
// leave local history trimmed ahead of the real provider thread.
|
|
1479
|
-
if (hasTurnsToRollBack) {
|
|
1480
|
-
await sdk.rollbackConversation(session, targetTurnId);
|
|
1481
|
-
}
|
|
1482
|
-
|
|
1483
|
-
if (targetIdx >= 0) {
|
|
1484
|
-
var trimTo = session.messageUUIDs[targetIdx].historyIndex;
|
|
1485
|
-
for (var k = trimTo - 1; k >= 0; k--) {
|
|
1486
|
-
if (session.history[k].type === "user_message") {
|
|
1487
|
-
trimTo = k;
|
|
1488
|
-
break;
|
|
1489
|
-
}
|
|
1490
|
-
}
|
|
1491
|
-
session.history = session.history.slice(0, trimTo);
|
|
1492
|
-
session.messageUUIDs = session.messageUUIDs.slice(0, targetIdx);
|
|
1493
|
-
// Reset digest checkpoint if it points past the trimmed history
|
|
1494
|
-
if (typeof session._dmLastDigestedIndex === "number" && session._dmLastDigestedIndex > trimTo) {
|
|
1495
|
-
session._dmLastDigestedIndex = trimTo;
|
|
1496
|
-
}
|
|
1497
|
-
}
|
|
1498
|
-
|
|
1499
|
-
var kept = session.messageUUIDs;
|
|
1500
|
-
session.lastRewindUuid = kept.length > 0 ? kept[kept.length - 1].uuid : null;
|
|
1501
|
-
}
|
|
1502
|
-
|
|
1503
|
-
if (session.abortController) {
|
|
1504
|
-
try { session.abortController.abort(); } catch (e) {}
|
|
1505
|
-
}
|
|
1506
|
-
if (session.messageQueue) {
|
|
1507
|
-
try { session.messageQueue.end(); } catch (e) {}
|
|
1508
|
-
}
|
|
1509
|
-
session.queryInstance = null;
|
|
1510
|
-
session.messageQueue = null;
|
|
1511
|
-
session.abortController = null;
|
|
1512
|
-
session.blocks = {};
|
|
1513
|
-
session.sentToolResults = {};
|
|
1514
|
-
session.pendingPermissions = {};
|
|
1515
|
-
cancelPendingAskUser(session, "Conversation rewound");
|
|
1516
|
-
session.isProcessing = false;
|
|
1517
|
-
onProcessingChanged();
|
|
1518
|
-
|
|
1519
|
-
sm.saveSessionFile(session);
|
|
1520
|
-
sm.switchSession(session.localId, ws, hydrateImageRefs);
|
|
1521
|
-
sm.sendAndRecord(session, { type: "rewind_complete", mode: mode });
|
|
1522
|
-
sm.broadcastSessionList();
|
|
1523
|
-
} catch (err) {
|
|
1524
|
-
sendTo(ws, { type: "rewind_error", text: "Rewind failed: " + err.message });
|
|
1525
|
-
} finally {
|
|
1526
|
-
session._rewindInProgress = false;
|
|
1527
|
-
}
|
|
1528
|
-
})();
|
|
1411
|
+
sessionHistory.rewind(session, msg.uuid, msg.mode || "both", ws, function () {}).catch(function (error) {
|
|
1412
|
+
sendTo(ws, { type: "rewind_error", text: "Rewind failed: " + error.message });
|
|
1413
|
+
});
|
|
1529
1414
|
return true;
|
|
1530
1415
|
}
|
|
1531
1416
|
|
|
@@ -1535,69 +1420,17 @@ function attachSessions(ctx) {
|
|
|
1535
1420
|
sendTo(ws, { type: "error", text: "Cannot fork: no CLI session" });
|
|
1536
1421
|
return true;
|
|
1537
1422
|
}
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
// Copy local history up to the target UUID
|
|
1543
|
-
var targetIdx = -1;
|
|
1544
|
-
for (var fi = 0; fi < session.messageUUIDs.length; fi++) {
|
|
1545
|
-
if (session.messageUUIDs[fi].uuid === msg.uuid) { targetIdx = fi; break; }
|
|
1546
|
-
}
|
|
1547
|
-
var forkHistory = [];
|
|
1548
|
-
if (targetIdx >= 0) {
|
|
1549
|
-
var trimTo = session.messageUUIDs[targetIdx].historyIndex;
|
|
1550
|
-
forkHistory = session.history.slice(0, trimTo);
|
|
1551
|
-
} else {
|
|
1552
|
-
forkHistory = session.history.slice();
|
|
1553
|
-
}
|
|
1554
|
-
var forked = sm.createSession({
|
|
1555
|
-
vendor: session.vendor,
|
|
1556
|
-
ownerId: session.ownerId || null,
|
|
1557
|
-
userKnowledgeOwnerId: session.userKnowledgeOwnerId || null,
|
|
1558
|
-
sessionVisibility: sessionVisibility.normalize(session.sessionVisibility),
|
|
1559
|
-
}, ws);
|
|
1560
|
-
forked.cliSessionId = result.sessionId;
|
|
1561
|
-
forked.title = forkTitle;
|
|
1562
|
-
forked.history = forkHistory;
|
|
1563
|
-
forked.messageUUIDs = [];
|
|
1564
|
-
for (var hi = 0; hi < forkHistory.length; hi++) {
|
|
1565
|
-
if (forkHistory[hi].type === "message_uuid") {
|
|
1566
|
-
forked.messageUUIDs.push({ uuid: forkHistory[hi].uuid, type: forkHistory[hi].messageType, historyIndex: hi, turnId: forkHistory[hi].turnId || null });
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
sm.saveSessionFile(forked);
|
|
1570
|
-
sm.switchSession(forked.localId, ws, hydrateImageRefs);
|
|
1571
|
-
sendTo(ws, { type: "fork_complete", sessionId: forked.localId });
|
|
1572
|
-
sm.broadcastSessionList();
|
|
1573
|
-
} else {
|
|
1574
|
-
// Read history from CLI session files
|
|
1575
|
-
var cliSess = require("./cli-sessions");
|
|
1576
|
-
return cliSess.readCliSessionHistory(resolveSessionHome(session), cwd, result.sessionId).then(function(history) {
|
|
1577
|
-
var forked = sm.resumeSession(result.sessionId, {
|
|
1578
|
-
history: history,
|
|
1579
|
-
title: forkTitle,
|
|
1580
|
-
vendor: session.vendor,
|
|
1581
|
-
ownerId: session.ownerId || null,
|
|
1582
|
-
userKnowledgeOwnerId: session.userKnowledgeOwnerId || null,
|
|
1583
|
-
sessionVisibility: sessionVisibility.normalize(session.sessionVisibility),
|
|
1584
|
-
sessionVisibilityExplicit: session.sessionVisibilityExplicit === true,
|
|
1585
|
-
}, ws);
|
|
1586
|
-
if (forked) {
|
|
1587
|
-
ws._clayActiveSession = forked.localId;
|
|
1588
|
-
sendTo(ws, { type: "fork_complete", sessionId: forked.localId });
|
|
1589
|
-
}
|
|
1590
|
-
});
|
|
1591
|
-
}
|
|
1592
|
-
}).catch(function(e) {
|
|
1593
|
-
sendTo(ws, { type: "error", text: "Fork failed: " + (e.message || e) });
|
|
1423
|
+
sessionHistory.fork(session, msg.uuid, ws, function () {}).then(function (forked) {
|
|
1424
|
+
if (forked) sendTo(ws, { type: "fork_complete", sessionId: forked.localId });
|
|
1425
|
+
}).catch(function (error) {
|
|
1426
|
+
sendTo(ws, { type: "error", text: "Fork failed: " + error.message });
|
|
1594
1427
|
});
|
|
1595
1428
|
return true;
|
|
1596
1429
|
}
|
|
1597
1430
|
|
|
1598
1431
|
if (msg.type === "ask_user_response") {
|
|
1599
1432
|
var session = getSessionForWs(ws);
|
|
1600
|
-
if (session) respondToAskUser(session, msg);
|
|
1433
|
+
if (session) respondToAskUser(session, msg, ws);
|
|
1601
1434
|
return true;
|
|
1602
1435
|
}
|
|
1603
1436
|
|
|
@@ -1805,14 +1638,6 @@ function attachSessions(ctx) {
|
|
|
1805
1638
|
if (msg.type === "browse_dir") {
|
|
1806
1639
|
var rawPath = (msg.path || "").replace(/^~/, require("./config").REAL_HOME);
|
|
1807
1640
|
var absTarget = path.resolve(rawPath);
|
|
1808
|
-
// Multi-user mode: non-admins can only browse their home directory
|
|
1809
|
-
if (osUsers && osUsers.length > 0 && ws._clayUser && ws._clayUser.role !== "admin") {
|
|
1810
|
-
var browseHome = ws._clayUser.linuxUser ? "/home/" + ws._clayUser.linuxUser : null;
|
|
1811
|
-
if (!browseHome || (absTarget !== browseHome && (absTarget + "/").indexOf(browseHome + "/") !== 0)) {
|
|
1812
|
-
sendTo(ws, { type: "browse_dir_result", path: msg.path, entries: [], error: "Access restricted to your home directory" });
|
|
1813
|
-
return true;
|
|
1814
|
-
}
|
|
1815
|
-
}
|
|
1816
1641
|
var parentDir, prefix;
|
|
1817
1642
|
try {
|
|
1818
1643
|
var stat = fs.statSync(absTarget);
|
|
@@ -1829,12 +1654,17 @@ function attachSessions(ctx) {
|
|
|
1829
1654
|
parentDir = path.dirname(absTarget);
|
|
1830
1655
|
prefix = path.basename(absTarget).toLowerCase();
|
|
1831
1656
|
}
|
|
1657
|
+
if (opts.canUsePath && !opts.canUsePath(ws._clayUser && ws._clayUser.id, parentDir)) {
|
|
1658
|
+
sendTo(ws, { type: "browse_dir_result", entries: [], error: "Directory access is not permitted" });
|
|
1659
|
+
return true;
|
|
1660
|
+
}
|
|
1832
1661
|
try {
|
|
1833
1662
|
var dirItems = fs.readdirSync(parentDir, { withFileTypes: true });
|
|
1834
1663
|
var dirEntries = [];
|
|
1835
1664
|
for (var di = 0; di < dirItems.length; di++) {
|
|
1836
1665
|
var d = dirItems[di];
|
|
1837
1666
|
if (!d.isDirectory()) continue;
|
|
1667
|
+
if (opts.canUsePath && !opts.canUsePath(ws._clayUser && ws._clayUser.id, path.join(parentDir, d.name))) continue;
|
|
1838
1668
|
if (d.name.charAt(0) === ".") continue;
|
|
1839
1669
|
if (IGNORED_DIRS.has(d.name)) continue;
|
|
1840
1670
|
if (prefix && !d.name.toLowerCase().startsWith(prefix)) continue;
|
|
@@ -1852,17 +1682,9 @@ function attachSessions(ctx) {
|
|
|
1852
1682
|
if (msg.type === "add_project") {
|
|
1853
1683
|
var addPath = (msg.path || "").replace(/^~/, require("./config").REAL_HOME);
|
|
1854
1684
|
var addAbs = path.resolve(addPath);
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
sendTo(ws, { type: "add_project_result", ok: false, error: "No Linux user assigned" });
|
|
1859
|
-
return true;
|
|
1860
|
-
}
|
|
1861
|
-
var userHome = "/home/" + ws._clayUser.linuxUser;
|
|
1862
|
-
if (addAbs !== userHome && (addAbs + "/").indexOf(userHome + "/") !== 0) {
|
|
1863
|
-
sendTo(ws, { type: "add_project_result", ok: false, error: "Path not allowed. You can only add directories under " + userHome });
|
|
1864
|
-
return true;
|
|
1865
|
-
}
|
|
1685
|
+
if (opts.canUsePath && !opts.canUsePath(ws._clayUser && ws._clayUser.id, addAbs)) {
|
|
1686
|
+
sendTo(ws, { type: "add_project_result", ok: false, error: "Directory access is not permitted" });
|
|
1687
|
+
return true;
|
|
1866
1688
|
}
|
|
1867
1689
|
try {
|
|
1868
1690
|
var addStat = fs.statSync(addAbs);
|
|
@@ -1876,7 +1698,7 @@ function attachSessions(ctx) {
|
|
|
1876
1698
|
}
|
|
1877
1699
|
if (typeof opts.onAddProject === "function") {
|
|
1878
1700
|
var result = opts.onAddProject(addAbs, ws._clayUser);
|
|
1879
|
-
sendTo(ws, {
|
|
1701
|
+
sendTo(ws, Object.assign({}, result, { type: "add_project_result" }));
|
|
1880
1702
|
} else {
|
|
1881
1703
|
sendTo(ws, { type: "add_project_result", ok: false, error: "Not supported" });
|
|
1882
1704
|
}
|
|
@@ -1901,7 +1723,7 @@ function attachSessions(ctx) {
|
|
|
1901
1723
|
}
|
|
1902
1724
|
if (typeof opts.onCreateProject === "function") {
|
|
1903
1725
|
var createResult = opts.onCreateProject(createName, ws._clayUser);
|
|
1904
|
-
sendTo(ws, {
|
|
1726
|
+
sendTo(ws, Object.assign({}, createResult, { type: "add_project_result" }));
|
|
1905
1727
|
} else {
|
|
1906
1728
|
sendTo(ws, { type: "add_project_result", ok: false, error: "Not supported" });
|
|
1907
1729
|
}
|
|
@@ -1991,10 +1813,10 @@ function attachSessions(ctx) {
|
|
|
1991
1813
|
moveAllSchedulesToProject(removeSlug, msg.moveTasksTo);
|
|
1992
1814
|
}
|
|
1993
1815
|
if (typeof opts.onRemoveProject === "function") {
|
|
1994
|
-
// Send result before removing so the WS is still open
|
|
1995
|
-
sendTo(ws, { type: "remove_project_result", ok: true, slug: removeSlug });
|
|
1996
1816
|
var removeUserId = ws._clayUser ? ws._clayUser.id : null;
|
|
1997
|
-
opts.onRemoveProject(removeSlug, removeUserId);
|
|
1817
|
+
Promise.resolve().then(function () { return opts.onRemoveProject(removeSlug, removeUserId); }).then(function (result) {
|
|
1818
|
+
sendTo(ws, { type: "remove_project_result", ok: !!result && result.ok === true, slug: removeSlug, error: result && result.error });
|
|
1819
|
+
}, function (error) { sendTo(ws, { type: "remove_project_result", ok: false, slug: removeSlug, error: error.message }); });
|
|
1998
1820
|
} else {
|
|
1999
1821
|
sendTo(ws, { type: "remove_project_result", ok: false, error: "Not supported" });
|
|
2000
1822
|
}
|
|
@@ -2040,7 +1862,7 @@ function attachSessions(ctx) {
|
|
|
2040
1862
|
}
|
|
2041
1863
|
if (typeof opts.onSetProjectTitle === "function") {
|
|
2042
1864
|
var titleResult = opts.onSetProjectTitle(msg.slug, msg.title || null);
|
|
2043
|
-
sendTo(ws, { type: "set_project_title_result",
|
|
1865
|
+
sendTo(ws, Object.assign({}, titleResult, { type: "set_project_title_result", slug: msg.slug }));
|
|
2044
1866
|
} else {
|
|
2045
1867
|
sendTo(ws, { type: "set_project_title_result", ok: false, error: "Not supported" });
|
|
2046
1868
|
}
|
|
@@ -2194,6 +2016,11 @@ function attachSessions(ctx) {
|
|
|
2194
2016
|
return handleSessionsMessage(ws, { type: "permission_response", requestId: msg.requestId, decision: msg.decision });
|
|
2195
2017
|
},
|
|
2196
2018
|
stopHomeSession: stopSession,
|
|
2019
|
+
sessionActions: sessionActions,
|
|
2020
|
+
sessionHistoryActions: sessionHistory,
|
|
2021
|
+
sessionVendorActions: sessionVendor,
|
|
2022
|
+
sessionRuntimeActions: sessionRuntime,
|
|
2023
|
+
deleteProductControlPlan: function (plan) { sessionDelete.executeOwnedDeletion(plan); },
|
|
2197
2024
|
};
|
|
2198
2025
|
}
|
|
2199
2026
|
|