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
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// Claude delivery watchdog. Only an unanswered foreground turn is replayable.
|
|
2
|
+
function attachResponseRecovery(ctx) {
|
|
3
|
+
var states = new Map();
|
|
4
|
+
var schedule = ctx.setTimeout || setTimeout;
|
|
5
|
+
var unschedule = ctx.clearTimeout || clearTimeout;
|
|
6
|
+
var waitMs = ctx.waitMs || 180000;
|
|
7
|
+
var stopMs = ctx.stopMs || 10000;
|
|
8
|
+
|
|
9
|
+
function live(session, state) {
|
|
10
|
+
return states.get(session) === state && !session.destroying && !session.taskStopRequested
|
|
11
|
+
&& state.ownerId === session.ownerId && state.vendor === session.vendor
|
|
12
|
+
&& (!ctx.sessions || ctx.sessions.get(session.localId) === session);
|
|
13
|
+
}
|
|
14
|
+
function clearTimer(state) {
|
|
15
|
+
if (state.timer) unschedule(state.timer);
|
|
16
|
+
state.timer = null;
|
|
17
|
+
}
|
|
18
|
+
function cancel(session, expected) {
|
|
19
|
+
var state = states.get(session);
|
|
20
|
+
if (expected && state !== expected) return;
|
|
21
|
+
if (state) clearTimer(state);
|
|
22
|
+
states.delete(session);
|
|
23
|
+
}
|
|
24
|
+
function protectedWait(session) {
|
|
25
|
+
return [session.pendingPermissions, session.pendingAskUser, session.pendingElicitations,
|
|
26
|
+
session.pendingUserDialogs, session.activeTaskToolIds].some(function(map) {
|
|
27
|
+
return map && Object.keys(map).length > 0;
|
|
28
|
+
}) || (session.activeBackgroundTasks && session.activeBackgroundTasks.length > 0);
|
|
29
|
+
}
|
|
30
|
+
function arm(session, state) {
|
|
31
|
+
clearTimer(state);
|
|
32
|
+
if (!state.turns.length || state.turns[0].progress || state.stopping) return;
|
|
33
|
+
state.timer = schedule(function() { expire(session, state); }, waitMs);
|
|
34
|
+
if (state.timer && state.timer.unref) state.timer.unref();
|
|
35
|
+
}
|
|
36
|
+
function snapshot(payload) {
|
|
37
|
+
return Object.assign({}, payload, { images: payload.images ? JSON.parse(JSON.stringify(payload.images)) : payload.images });
|
|
38
|
+
}
|
|
39
|
+
function begin(session, payload, retryState) {
|
|
40
|
+
if (retryState) return retryState;
|
|
41
|
+
cancel(session);
|
|
42
|
+
var state = { turns: [snapshot(payload)], timer: null, stopping: false, retried: false, ownerId: session.ownerId, vendor: session.vendor };
|
|
43
|
+
states.set(session, state);
|
|
44
|
+
arm(session, state);
|
|
45
|
+
return state;
|
|
46
|
+
}
|
|
47
|
+
function enqueue(session, payload) {
|
|
48
|
+
var state = states.get(session);
|
|
49
|
+
if (!state) return begin(session, payload);
|
|
50
|
+
state.turns.push(snapshot(payload));
|
|
51
|
+
return state;
|
|
52
|
+
}
|
|
53
|
+
function progress(session) {
|
|
54
|
+
var state = states.get(session);
|
|
55
|
+
if (!state || state.stopping || !state.turns.length) return;
|
|
56
|
+
state.turns[0].progress = true;
|
|
57
|
+
clearTimer(state);
|
|
58
|
+
}
|
|
59
|
+
function event(session, msg) {
|
|
60
|
+
var state = states.get(session);
|
|
61
|
+
if (!state || state.stopping || !msg) return;
|
|
62
|
+
var type = msg.yokeType;
|
|
63
|
+
if (type === 'error' || type === 'interrupted') { cancel(session); return; }
|
|
64
|
+
if (type === 'result') {
|
|
65
|
+
if (msg.subtype === 'success' && !msg.is_error && msg.numTurns === 0
|
|
66
|
+
&& msg.origin && msg.origin.kind === 'task-notification'
|
|
67
|
+
&& !msg.localCommand && msg.resultText === '') return;
|
|
68
|
+
var remaining = require('./sdk-turn-queue').pendingSends(session, msg);
|
|
69
|
+
state.turns = remaining ? state.turns.slice(-remaining) : [];
|
|
70
|
+
state.retried = false;
|
|
71
|
+
arm(session, state);
|
|
72
|
+
if (!state.turns.length) cancel(session);
|
|
73
|
+
} else if ((type === 'text_delta' || type === 'thinking_delta') && (msg.text || msg.delta)
|
|
74
|
+
|| type === 'tool_start' || type === 'tool_input_delta' || type === 'tool_progress'
|
|
75
|
+
|| type === 'task_started' || type === 'task_progress' || type === 'subagent_message'
|
|
76
|
+
|| type === 'message' && msg.messageRole === 'assistant' && msg.content && msg.content.length) {
|
|
77
|
+
progress(session);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function finish(session, state, text) {
|
|
81
|
+
if (!live(session, state)) { cancel(session, state); return; }
|
|
82
|
+
cancel(session);
|
|
83
|
+
// Fence late output when a transport cannot confirm termination.
|
|
84
|
+
session._sdkQueryGeneration = Number(session._sdkQueryGeneration || 0) + 1;
|
|
85
|
+
session.isProcessing = false;
|
|
86
|
+
session._awaitingTurnResult = false;
|
|
87
|
+
session._queuedTurnCount = 0;
|
|
88
|
+
ctx.changed();
|
|
89
|
+
ctx.record(session, { type: 'thinking_stop' });
|
|
90
|
+
ctx.record(session, { type: 'error', text: text });
|
|
91
|
+
ctx.record(session, { type: 'done', code: 1 });
|
|
92
|
+
ctx.broadcast();
|
|
93
|
+
}
|
|
94
|
+
async function expire(session, state) {
|
|
95
|
+
clearTimer(state);
|
|
96
|
+
if (!live(session, state)) { cancel(session, state); return; }
|
|
97
|
+
// Never stop a known tool or a human decision because prose is absent.
|
|
98
|
+
if (protectedWait(session)) { progress(session); return; }
|
|
99
|
+
state.stopping = true;
|
|
100
|
+
ctx.record(session, { type: 'info', text: 'Claude has not responded for three minutes. Stopping this attempt safely before retrying.' });
|
|
101
|
+
var timeout;
|
|
102
|
+
var stopped = false;
|
|
103
|
+
try {
|
|
104
|
+
var stopAttempt = (async function() {
|
|
105
|
+
var handle = session.queryInstance || state.handle;
|
|
106
|
+
if (!handle && session.abortController) session.abortController.abort();
|
|
107
|
+
if (!handle && state.starting) await state.starting;
|
|
108
|
+
handle = handle || session.queryInstance || state.handle;
|
|
109
|
+
if (handle) {
|
|
110
|
+
if (typeof handle.stopAndWait !== 'function') return false;
|
|
111
|
+
await handle.stopAndWait();
|
|
112
|
+
if (session.streamPromise) await session.streamPromise;
|
|
113
|
+
}
|
|
114
|
+
return true;
|
|
115
|
+
})();
|
|
116
|
+
session._responseRecoveryStopPending = stopAttempt;
|
|
117
|
+
stopAttempt.then(function(confirmed) {
|
|
118
|
+
if (confirmed && session._responseRecoveryStopPending === stopAttempt) session._responseRecoveryStopPending = null;
|
|
119
|
+
}, function() {});
|
|
120
|
+
stopped = await Promise.race([
|
|
121
|
+
stopAttempt,
|
|
122
|
+
new Promise(function(resolve) { timeout = schedule(function() { resolve(false); }, stopMs); }),
|
|
123
|
+
]);
|
|
124
|
+
} catch (e) { stopped = false; }
|
|
125
|
+
if (timeout) unschedule(timeout);
|
|
126
|
+
if (!live(session, state)) { cancel(session, state); return; }
|
|
127
|
+
if (!stopped) {
|
|
128
|
+
finish(session, state, 'Claude could not be confirmed stopped. Automatic retry was cancelled to avoid running your request twice. Check your Claude connection before trying again.');
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (state.retried || state.turns.length !== 1) {
|
|
132
|
+
finish(session, state, state.retried
|
|
133
|
+
? 'Claude still has not responded after one automatic retry. Please send your message again or check your Claude connection.'
|
|
134
|
+
: 'Claude did not respond. Several messages were queued, so automatic replay was cancelled to avoid duplicating work. Please send the unanswered messages again.');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
state.retried = true;
|
|
138
|
+
state.stopping = false;
|
|
139
|
+
session.isProcessing = true;
|
|
140
|
+
ctx.changed();
|
|
141
|
+
ctx.record(session, { type: 'info', text: 'The previous attempt has stopped. Retrying your original message once.' });
|
|
142
|
+
ctx.send(session, { type: 'status', status: 'processing' });
|
|
143
|
+
arm(session, state);
|
|
144
|
+
var payload = state.turns[0];
|
|
145
|
+
await ctx.restart(session, payload, state);
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
begin: begin, enqueue: enqueue, event: event, progress: progress, cancel: cancel,
|
|
149
|
+
current: function(session) { return states.get(session); },
|
|
150
|
+
valid: live,
|
|
151
|
+
stopping: function(session) { var state = states.get(session); return !!(state && state.stopping); },
|
|
152
|
+
dispose: function() { states.forEach(function(state) { clearTimer(state); }); states.clear(); },
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
module.exports = { attachResponseRecovery: attachResponseRecovery };
|
package/lib/server-admin.js
CHANGED
|
@@ -18,6 +18,13 @@ function attachAdmin(ctx) {
|
|
|
18
18
|
var onGetProjectAccess = ctx.onGetProjectAccess;
|
|
19
19
|
var onProjectOwnerChanged = ctx.onProjectOwnerChanged;
|
|
20
20
|
|
|
21
|
+
function verifyCurrentOwner(req, route) {
|
|
22
|
+
if (!route || req.method === "GET" || !users.isMultiUser()) return;
|
|
23
|
+
var actor = getMultiUserFromReq(req);
|
|
24
|
+
var access = onGetProjectAccess && onGetProjectAccess(route[1]);
|
|
25
|
+
if (!actor || !access || access.ownerId !== actor.id || !users.findUserById(access.ownerId)) throw new Error("Project owner access required");
|
|
26
|
+
}
|
|
27
|
+
|
|
21
28
|
function handleRequest(req, res, fullUrl) {
|
|
22
29
|
var mateAccessRoute = /^\/api\/admin\/projects\/([^/]+)\/(visibility|owner|users|access)$/.exec(fullUrl);
|
|
23
30
|
if (mateAccessRoute) {
|
|
@@ -31,6 +38,25 @@ function attachAdmin(ctx) {
|
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
|
|
41
|
+
// Project content authority belongs to the valid owner, never the role.
|
|
42
|
+
if (mateAccessRoute && users.isMultiUser()) {
|
|
43
|
+
var actor = getMultiUserFromReq(req);
|
|
44
|
+
var governing = onGetProjectAccess && onGetProjectAccess(mateAccessRoute[1]);
|
|
45
|
+
var validOwner = governing && governing.ownerId && users.findUserById(governing.ownerId);
|
|
46
|
+
var owns = actor && validOwner && actor.id === validOwner.id;
|
|
47
|
+
if (req.method !== "GET" && !owns) {
|
|
48
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
49
|
+
res.end(JSON.stringify({ error: "Only the valid project owner can change access." }));
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
if (req.method === "GET" && !owns && actor && actor.role === "admin") {
|
|
53
|
+
var overview = require("./project-admin-overview").metadataFor(actor, target && target.getStatus(), governing, users);
|
|
54
|
+
res.writeHead(overview ? 200 : 404, { "Content-Type": "application/json", "Cache-Control": "no-store" });
|
|
55
|
+
res.end(JSON.stringify(overview || { error: "Project not found" }));
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
34
60
|
// --- Admin API endpoints (multi-user mode only) ---
|
|
35
61
|
|
|
36
62
|
// List all users (admin only)
|
|
@@ -83,6 +109,16 @@ function attachAdmin(ctx) {
|
|
|
83
109
|
// Look up the user before deletion to get linuxUser for deactivation
|
|
84
110
|
var targetUser = users.findUserById(targetUserId);
|
|
85
111
|
var targetLinuxUser = targetUser ? targetUser.linuxUser : null;
|
|
112
|
+
var owned = false;
|
|
113
|
+
projects.forEach(function (project, slug) {
|
|
114
|
+
var access = onGetProjectAccess && onGetProjectAccess(slug);
|
|
115
|
+
if (access && !access.isMate && access.ownerId === targetUserId) owned = true;
|
|
116
|
+
});
|
|
117
|
+
if (owned) {
|
|
118
|
+
res.writeHead(409, { "Content-Type": "application/json" });
|
|
119
|
+
res.end(JSON.stringify({ error: "The owner must transfer ordinary projects before account deletion." }));
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
86
122
|
var result = users.removeUser(targetUserId);
|
|
87
123
|
if (result.error) {
|
|
88
124
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
@@ -118,6 +154,7 @@ function attachAdmin(ctx) {
|
|
|
118
154
|
req.on("end", function () {
|
|
119
155
|
try {
|
|
120
156
|
var data = JSON.parse(body);
|
|
157
|
+
verifyCurrentOwner(req, mateAccessRoute);
|
|
121
158
|
if (!data.username || typeof data.username !== "string" || data.username.trim().length < 1) {
|
|
122
159
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
123
160
|
res.end('{"error":"Username is required"}');
|
|
@@ -182,6 +219,11 @@ function attachAdmin(ctx) {
|
|
|
182
219
|
res.end('{"error":"User not found"}');
|
|
183
220
|
return true;
|
|
184
221
|
}
|
|
222
|
+
if (mu.id !== targetUserId) {
|
|
223
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
224
|
+
res.end(JSON.stringify({ error: "Use account-owner credential recovery. Administrators cannot impersonate another account." }));
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
185
227
|
var newPin = users.generatePin();
|
|
186
228
|
var pinResult = users.updateUserPin(targetUserId, newPin);
|
|
187
229
|
if (pinResult.error) {
|
|
@@ -222,15 +264,10 @@ function attachAdmin(ctx) {
|
|
|
222
264
|
req.on("data", function(chunk) { body += chunk; });
|
|
223
265
|
req.on("end", function() {
|
|
224
266
|
try {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
res.end(JSON.stringify({ error: result.error }));
|
|
230
|
-
} else {
|
|
231
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
232
|
-
res.end('{"ok":true}');
|
|
233
|
-
}
|
|
267
|
+
JSON.parse(body);
|
|
268
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
269
|
+
res.end(JSON.stringify({ error: "OS identity mapping requires server-side verified provisioning." }));
|
|
270
|
+
return;
|
|
234
271
|
} catch (e) {
|
|
235
272
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
236
273
|
res.end('{"error":"Invalid request body"}');
|
|
@@ -363,6 +400,7 @@ function attachAdmin(ctx) {
|
|
|
363
400
|
req.on("end", function () {
|
|
364
401
|
try {
|
|
365
402
|
var data = JSON.parse(body);
|
|
403
|
+
verifyCurrentOwner(req, mateAccessRoute);
|
|
366
404
|
if (!data.email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) {
|
|
367
405
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
368
406
|
res.end('{"error":"Valid email is required"}');
|
|
@@ -429,6 +467,7 @@ function attachAdmin(ctx) {
|
|
|
429
467
|
req.on("end", function () {
|
|
430
468
|
try {
|
|
431
469
|
var data = JSON.parse(body);
|
|
470
|
+
verifyCurrentOwner(req, mateAccessRoute);
|
|
432
471
|
// Allow clearing SMTP config by sending empty fields
|
|
433
472
|
if (!data.host && !data.user && !data.pass && !data.from) {
|
|
434
473
|
smtp.saveSmtpConfig(null);
|
|
@@ -484,6 +523,7 @@ function attachAdmin(ctx) {
|
|
|
484
523
|
req.on("end", function () {
|
|
485
524
|
try {
|
|
486
525
|
var data = JSON.parse(body);
|
|
526
|
+
verifyCurrentOwner(req, mateAccessRoute);
|
|
487
527
|
// Use provided config or fall back to saved
|
|
488
528
|
var existingCfg = smtp.getSmtpConfig();
|
|
489
529
|
var pass = data.pass;
|
|
@@ -548,6 +588,7 @@ function attachAdmin(ctx) {
|
|
|
548
588
|
req.on("end", function () {
|
|
549
589
|
try {
|
|
550
590
|
var data = JSON.parse(body);
|
|
591
|
+
verifyCurrentOwner(req, mateAccessRoute);
|
|
551
592
|
if (data.visibility !== "public" && data.visibility !== "private") {
|
|
552
593
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
553
594
|
res.end('{"error":"Visibility must be public or private"}');
|
|
@@ -582,9 +623,10 @@ function attachAdmin(ctx) {
|
|
|
582
623
|
return true;
|
|
583
624
|
}
|
|
584
625
|
var mu = getMultiUserFromReq(req);
|
|
585
|
-
|
|
626
|
+
var ownerAccess = onGetProjectAccess && onGetProjectAccess(fullUrl.split("/")[4]);
|
|
627
|
+
if (!mu || !ownerAccess || mu.id !== ownerAccess.ownerId) {
|
|
586
628
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
587
|
-
res.end('{"error":"
|
|
629
|
+
res.end('{"error":"Project owner access required"}');
|
|
588
630
|
return true;
|
|
589
631
|
}
|
|
590
632
|
var projSlug = fullUrl.split("/")[4];
|
|
@@ -598,17 +640,21 @@ function attachAdmin(ctx) {
|
|
|
598
640
|
req.on("end", function () {
|
|
599
641
|
try {
|
|
600
642
|
var data = JSON.parse(body);
|
|
643
|
+
verifyCurrentOwner(req, mateAccessRoute);
|
|
601
644
|
var targetCtx = projects.get(projSlug);
|
|
602
645
|
if (!targetCtx) {
|
|
603
646
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
604
647
|
res.end('{"error":"Project not found"}');
|
|
605
648
|
return;
|
|
606
649
|
}
|
|
607
|
-
var ownerId = data.userId
|
|
650
|
+
var ownerId = data.userId;
|
|
651
|
+
if (typeof ownerId !== "string" || !users.findUserById(ownerId)) throw new Error("A valid owner is required");
|
|
652
|
+
var currentAccess = onGetProjectAccess && onGetProjectAccess(projSlug);
|
|
653
|
+
if (!currentAccess || currentAccess.ownerId !== mu.id) throw new Error("Project owner access required");
|
|
654
|
+
if (!onProjectOwnerChanged) throw new Error("Ownership persistence is unavailable");
|
|
655
|
+
var saved = onProjectOwnerChanged(projSlug, ownerId);
|
|
656
|
+
if (saved && saved.error) throw new Error(saved.error);
|
|
608
657
|
targetCtx.setProjectOwner(ownerId);
|
|
609
|
-
if (onProjectOwnerChanged) {
|
|
610
|
-
onProjectOwnerChanged(projSlug, ownerId);
|
|
611
|
-
}
|
|
612
658
|
// Broadcast to project clients
|
|
613
659
|
var ownerName = null;
|
|
614
660
|
if (ownerId) {
|
|
@@ -653,7 +699,8 @@ function attachAdmin(ctx) {
|
|
|
653
699
|
req.on("end", function () {
|
|
654
700
|
try {
|
|
655
701
|
var data = JSON.parse(body);
|
|
656
|
-
|
|
702
|
+
verifyCurrentOwner(req, mateAccessRoute);
|
|
703
|
+
if (!Array.isArray(data.allowedUsers) || data.allowedUsers.some(function (id) { return typeof id !== "string" || !users.findUserById(id); })) {
|
|
657
704
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
658
705
|
res.end('{"error":"allowedUsers must be an array"}');
|
|
659
706
|
return;
|
|
@@ -34,6 +34,18 @@ function attachAppearanceSettings(ctx) {
|
|
|
34
34
|
fs.renameSync(defaultPath + '.tmp', defaultPath);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
+
function getInitialAppearance(req) {
|
|
38
|
+
var user = identity(req);
|
|
39
|
+
if (!user) return null;
|
|
40
|
+
var saved = read(user);
|
|
41
|
+
return {
|
|
42
|
+
configured: saved.configured,
|
|
43
|
+
theme: saved.theme,
|
|
44
|
+
mode: saved.mode,
|
|
45
|
+
lightTheme: saved.lightTheme || null,
|
|
46
|
+
darkTheme: saved.darkTheme || null
|
|
47
|
+
};
|
|
48
|
+
}
|
|
37
49
|
function handleRequest(req, res, url) {
|
|
38
50
|
if (url !== '/api/user/appearance') return false;
|
|
39
51
|
var user = identity(req);
|
|
@@ -66,6 +78,6 @@ function attachAppearanceSettings(ctx) {
|
|
|
66
78
|
});
|
|
67
79
|
return true;
|
|
68
80
|
}
|
|
69
|
-
return { handleRequest: handleRequest };
|
|
81
|
+
return { handleRequest: handleRequest, getInitialAppearance: getInitialAppearance };
|
|
70
82
|
}
|
|
71
83
|
module.exports = { attachAppearanceSettings: attachAppearanceSettings };
|
package/lib/server-dm.js
CHANGED
|
@@ -49,7 +49,7 @@ function attachDm(ctx) {
|
|
|
49
49
|
var mateCtx2 = mates.buildMateCtx(userId);
|
|
50
50
|
if (mates.isMate(mateCtx2, msg.targetUserId)) {
|
|
51
51
|
var mate = mates.getMate(mateCtx2, msg.targetUserId);
|
|
52
|
-
if (!mate) return true;
|
|
52
|
+
if (!mate || mate.lifecycleDeletion) return true;
|
|
53
53
|
// Ensure mate project is registered (survives server restarts)
|
|
54
54
|
var mateSlug2 = "mate-" + mate.id;
|
|
55
55
|
if (!projects.has(mateSlug2)) {
|
|
@@ -69,6 +69,7 @@ function attachDm(ctx) {
|
|
|
69
69
|
id: mate.id,
|
|
70
70
|
displayName: mp.displayName || mate.name || "New Mate",
|
|
71
71
|
username: mate.id,
|
|
72
|
+
avatarCatalogId: mp.avatarCatalogId || "",
|
|
72
73
|
avatarStyle: mp.avatarStyle || "imprint",
|
|
73
74
|
avatarSeed: mp.avatarSeed || mate.id,
|
|
74
75
|
avatarColor: mp.avatarColor || "#5857fc",
|
package/lib/server-global-ws.js
CHANGED
|
@@ -63,14 +63,6 @@ function attachGlobalWs(opts) {
|
|
|
63
63
|
if (msg.type === "browse_dir") {
|
|
64
64
|
var rawPath = (msg.path || "").replace(/^~/, config.REAL_HOME);
|
|
65
65
|
var absTarget = path.resolve(rawPath);
|
|
66
|
-
// Multi-user mode: non-admins can only browse their home directory.
|
|
67
|
-
if (osUsers && ws._clayUser && ws._clayUser.role !== "admin") {
|
|
68
|
-
var browseHome = ws._clayUser.linuxUser ? "/home/" + ws._clayUser.linuxUser : null;
|
|
69
|
-
if (!browseHome || (absTarget !== browseHome && (absTarget + "/").indexOf(browseHome + "/") !== 0)) {
|
|
70
|
-
sendTo(ws, { type: "browse_dir_result", path: msg.path, entries: [], error: "Access restricted to your home directory" });
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
66
|
var parentDir, prefix;
|
|
75
67
|
try {
|
|
76
68
|
var stat = fs.statSync(absTarget);
|
|
@@ -87,12 +79,17 @@ function attachGlobalWs(opts) {
|
|
|
87
79
|
parentDir = path.dirname(absTarget);
|
|
88
80
|
prefix = path.basename(absTarget).toLowerCase();
|
|
89
81
|
}
|
|
82
|
+
if (opts.canUsePath && !opts.canUsePath(ws._clayUser && ws._clayUser.id, parentDir)) {
|
|
83
|
+
sendTo(ws, { type: "browse_dir_result", entries: [], error: "Directory access is not permitted" });
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
90
86
|
try {
|
|
91
87
|
var dirItems = fs.readdirSync(parentDir, { withFileTypes: true });
|
|
92
88
|
var dirEntries = [];
|
|
93
89
|
for (var di = 0; di < dirItems.length; di++) {
|
|
94
90
|
var d = dirItems[di];
|
|
95
91
|
if (!d.isDirectory()) continue;
|
|
92
|
+
if (opts.canUsePath && !opts.canUsePath(ws._clayUser && ws._clayUser.id, path.join(parentDir, d.name))) continue;
|
|
96
93
|
if (d.name.charAt(0) === ".") continue;
|
|
97
94
|
if (IGNORED_DIRS.has(d.name)) continue;
|
|
98
95
|
if (prefix && !d.name.toLowerCase().startsWith(prefix)) continue;
|
|
@@ -110,16 +107,9 @@ function attachGlobalWs(opts) {
|
|
|
110
107
|
if (msg.type === "add_project") {
|
|
111
108
|
var addPath = (msg.path || "").replace(/^~/, config.REAL_HOME);
|
|
112
109
|
var addAbs = path.resolve(addPath);
|
|
113
|
-
if (
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
var userHome = "/home/" + ws._clayUser.linuxUser;
|
|
119
|
-
if (addAbs !== userHome && (addAbs + "/").indexOf(userHome + "/") !== 0) {
|
|
120
|
-
sendTo(ws, { type: "add_project_result", ok: false, error: "Path not allowed. You can only add directories under " + userHome });
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
110
|
+
if (opts.canUsePath && !opts.canUsePath(ws._clayUser && ws._clayUser.id, addAbs)) {
|
|
111
|
+
sendTo(ws, { type: "add_project_result", ok: false, error: "Directory access is not permitted" });
|
|
112
|
+
return;
|
|
123
113
|
}
|
|
124
114
|
try {
|
|
125
115
|
var addStat = fs.statSync(addAbs);
|
|
@@ -133,7 +123,7 @@ function attachGlobalWs(opts) {
|
|
|
133
123
|
}
|
|
134
124
|
if (typeof onAddProject === "function") {
|
|
135
125
|
var result = onAddProject(addAbs, ws._clayUser);
|
|
136
|
-
sendTo(ws, {
|
|
126
|
+
sendTo(ws, Object.assign({}, result, { type: "add_project_result" }));
|
|
137
127
|
} else {
|
|
138
128
|
sendTo(ws, { type: "add_project_result", ok: false, error: "Not supported" });
|
|
139
129
|
}
|
|
@@ -159,7 +149,7 @@ function attachGlobalWs(opts) {
|
|
|
159
149
|
}
|
|
160
150
|
if (typeof onCreateProject === "function") {
|
|
161
151
|
var createResult = onCreateProject(createName, ws._clayUser);
|
|
162
|
-
sendTo(ws, {
|
|
152
|
+
sendTo(ws, Object.assign({}, createResult, { type: "add_project_result" }));
|
|
163
153
|
} else {
|
|
164
154
|
sendTo(ws, { type: "add_project_result", ok: false, error: "Not supported" });
|
|
165
155
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
function homeDebateQuestions(input) {
|
|
4
4
|
var source = input && Array.isArray(input.questions) && input.questions[0] ? input.questions[0] : null;
|
|
5
5
|
if (!source) return [];
|
|
6
|
-
var question = { header: source.header || "", question: source.question || "", multiSelect: false, options: [] };
|
|
6
|
+
var question = { header: source.header || "", question: source.question || "", multiSelect: false, allowOther: source.allowOther !== false, options: [] };
|
|
7
7
|
var options = Array.isArray(source.options) ? source.options.slice(0, 6) : [];
|
|
8
8
|
for (var i = 0; i < options.length; i++) question.options.push({ label: options[i].label || "Option", description: options[i].description || "" });
|
|
9
9
|
return [question];
|
|
@@ -36,6 +36,7 @@ function findDebateTurn(messages, event) {
|
|
|
36
36
|
function debateIdentity(source, fallback) {
|
|
37
37
|
var prior = fallback || {};
|
|
38
38
|
return {
|
|
39
|
+
avatarCatalogId: source.avatarCatalogId || prior.avatarCatalogId || "",
|
|
39
40
|
avatarStyle: source.avatarStyle || prior.avatarStyle || "imprint",
|
|
40
41
|
avatarSeed: source.avatarSeed || prior.avatarSeed || source.mateId || "mate",
|
|
41
42
|
avatarColor: source.avatarColor || prior.avatarColor || "",
|
|
@@ -112,7 +113,7 @@ function applyAssignmentHistoryEvent(messages, event) {
|
|
|
112
113
|
messages.push({ role: "assignment", assignment: assignment });
|
|
113
114
|
}
|
|
114
115
|
|
|
115
|
-
function historyToHomeChat(history, debateSetupMode, mateCreationMode) {
|
|
116
|
+
function historyToHomeChat(history, debateSetupMode, mateCreationMode, pendingAskUser) {
|
|
116
117
|
var messages = [];
|
|
117
118
|
var pending = "";
|
|
118
119
|
var interviewMode = debateSetupMode === true || mateCreationMode === true;
|
|
@@ -124,6 +125,12 @@ function historyToHomeChat(history, debateSetupMode, mateCreationMode) {
|
|
|
124
125
|
for (var i = 0; i < history.length; i++) {
|
|
125
126
|
var event = history[i];
|
|
126
127
|
if (!event) continue;
|
|
128
|
+
if (event.type === 'tool_executing' && event.name === 'AskUserQuestion' && ['mcp-import', 'mate-schedule', 'mcp_fallback', 'product-control'].indexOf(event.source) >= 0) {
|
|
129
|
+
flushAssistant();
|
|
130
|
+
var activeConsent = pendingAskUser === undefined || !!(pendingAskUser && pendingAskUser[event.id]);
|
|
131
|
+
messages.push({ role: 'question', flow: event.source === 'mcp-import' ? 'mcp_import' : 'mate_question', toolId: event.id, questions: homeDebateQuestions(event.input), status: activeConsent ? 'pending' : 'expired', error: activeConsent ? '' : 'This question is no longer active. Ask for a new review.' });
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
127
134
|
if (event.type === "project_assignment_proposal" || event.type === "project_assignment_status") {
|
|
128
135
|
flushAssistant();
|
|
129
136
|
applyAssignmentHistoryEvent(messages, event);
|
|
@@ -185,7 +192,7 @@ function historyToHomeChat(history, debateSetupMode, mateCreationMode) {
|
|
|
185
192
|
} else if (interviewMode && event.type === "tool_executing" && event.name === "AskUserQuestion" && event.id && event.input) {
|
|
186
193
|
flushAssistant();
|
|
187
194
|
messages.push({ role: "question", flow: mateCreationMode === true ? "mate_creation" : "debate", toolId: event.id, questions: homeDebateQuestions(event.input), status: "pending", error: "" });
|
|
188
|
-
} else if ((event.type === "ask_user_answered" || event.type === "home_debate_question_expired" || event.type === "home_mate_creation_question_expired") && event.toolId) {
|
|
195
|
+
} else if ((event.type === "ask_user_answered" || event.type === "home_debate_question_expired" || event.type === "home_mate_creation_question_expired" || event.type === "mcp_import_consent_expired" || event.type === "mate_schedule_question_expired") && event.toolId) {
|
|
189
196
|
for (var k = messages.length - 1; k >= 0; k--) {
|
|
190
197
|
if (messages[k].role === "question" && messages[k].toolId === event.toolId) {
|
|
191
198
|
messages[k].status = event.type === "ask_user_answered" ? "answered" : "expired";
|
|
@@ -273,7 +280,7 @@ function transformEvent(event, mateId, session, requestId, stableSessionId) {
|
|
|
273
280
|
}
|
|
274
281
|
if (session && session.homeDebatePlanning === true && HOME_DEBATE_EVENT_TYPES[event.type]) {
|
|
275
282
|
var live = { type: "home_debate_event", eventType: event.type };
|
|
276
|
-
var fields = ["turnId", "decisionId", "decision", "toolName", "command", "commandTruncated", "topic", "format", "moderatorId", "moderatorName", "panelists", "mateName", "role", "round", "activity", "delta", "text", "reason", "action", "avatarStyle", "avatarSeed", "avatarColor", "avatarCustom"];
|
|
283
|
+
var fields = ["turnId", "decisionId", "decision", "toolName", "command", "commandTruncated", "topic", "format", "moderatorId", "moderatorName", "panelists", "mateName", "role", "round", "activity", "delta", "text", "reason", "action", "avatarCatalogId", "avatarStyle", "avatarSeed", "avatarColor", "avatarCustom"];
|
|
277
284
|
for (var fi = 0; fi < fields.length; fi++) if (Object.prototype.hasOwnProperty.call(event, fields[fi])) live[fields[fi]] = event[fields[fi]];
|
|
278
285
|
if (event.mateId) live.speakerMateId = event.mateId;
|
|
279
286
|
return Object.assign(live, metadata);
|
|
@@ -298,6 +305,13 @@ function transformEvent(event, mateId, session, requestId, stableSessionId) {
|
|
|
298
305
|
if (event.type === "debate_proposal_resolved" && event.proposalId) return Object.assign({ type: "home_debate_proposal_resolved", proposalId: event.proposalId, action: event.action || "cancel", error: event.error || "" }, metadata);
|
|
299
306
|
if (session && session.mateCreationMode === true && event.type === "mate_creation_proposal" && event.proposal) return Object.assign({ type: "home_mate_creation_proposal", proposal: event.proposal }, metadata);
|
|
300
307
|
if (session && session.mateCreationMode === true && event.type === "mate_creation_proposal_resolved" && event.proposalId) return Object.assign({ type: "home_mate_creation_proposal_resolved", proposalId: event.proposalId, action: event.action || "cancel", createdMateId: event.mateId || null, mateName: event.mateName || null, error: event.error || "" }, metadata);
|
|
308
|
+
if (!(session && (session.debateSetupMode === true || session.mateCreationMode === true)) && event.type === 'tool_executing' && event.name === 'AskUserQuestion' && ['mate-schedule', 'mcp_fallback', 'product-control'].indexOf(event.source) >= 0) return Object.assign({ type: 'home_mate_question', toolId: event.id, questions: homeDebateQuestions(event.input) }, metadata);
|
|
309
|
+
if (session && session.debateSetupMode !== true && session.mateCreationMode !== true && event.type === 'ask_user_answered' && event.toolId && (session.history || []).some(function (item) { return item.id === event.toolId && ['mate-schedule', 'mcp_fallback', 'product-control'].indexOf(item.source) >= 0; })) return Object.assign({ type: 'home_mate_question_resolved', toolId: event.toolId, status: 'answered', answers: event.answers }, metadata);
|
|
310
|
+
if (event.type === 'tool_executing' && event.name === 'AskUserQuestion' && event.source === 'mcp-import') return Object.assign({ type: 'home_mcp_import_question', toolId: event.id, questions: homeDebateQuestions(event.input) }, metadata);
|
|
311
|
+
if (event.type === 'product_control_question_expired') return Object.assign({ type: 'home_mate_question_resolved', toolId: event.toolId, status: 'expired', error: event.error }, metadata);
|
|
312
|
+
if (event.type === 'mate_schedule_question_expired') return Object.assign({ type: 'home_mate_question_resolved', toolId: event.toolId, status: 'expired', error: event.error }, metadata);
|
|
313
|
+
if (event.type === 'mcp_import_consent_expired') return Object.assign({ type: 'home_mcp_import_question_resolved', toolId: event.toolId, status: 'expired', error: event.error }, metadata);
|
|
314
|
+
if (session && event.type === 'ask_user_answered' && event.toolId && (session.history || []).some(function (item) { return item.id === event.toolId && item.source === 'mcp-import'; })) return Object.assign({ type: 'home_mcp_import_question_resolved', toolId: event.toolId, status: 'answered', answers: event.answers }, metadata);
|
|
301
315
|
if (session && session.debateSetupMode === true && event.type === "tool_executing" && event.name === "AskUserQuestion" && event.id && event.input) {
|
|
302
316
|
return Object.assign({ type: "home_debate_question", toolId: event.id, questions: homeDebateQuestions(event.input) }, metadata);
|
|
303
317
|
}
|
package/lib/server-home-chat.js
CHANGED
|
@@ -31,7 +31,7 @@ function attachHomeChat(deps) {
|
|
|
31
31
|
}
|
|
32
32
|
if (!mateId && allMates[i].builtinKey === "clay") mate = allMates[i];
|
|
33
33
|
}
|
|
34
|
-
if (!mate) return null;
|
|
34
|
+
if (!mate || mate.lifecycleDeletion) return null;
|
|
35
35
|
var slug = "mate-" + mate.id;
|
|
36
36
|
if (!projects.has(slug)) {
|
|
37
37
|
if (!ensureRegistered) return null;
|
|
@@ -184,6 +184,12 @@ function attachHomeChat(deps) {
|
|
|
184
184
|
}
|
|
185
185
|
});
|
|
186
186
|
if (!unsubscribe) return;
|
|
187
|
+
var unregisterConsent = null;
|
|
188
|
+
if (openedSession && typeof found.ctx.registerMcpConsentViewer === 'function') {
|
|
189
|
+
try { unregisterConsent = found.ctx.registerMcpConsentViewer(ws, openedSession); } catch (error) {}
|
|
190
|
+
}
|
|
191
|
+
var unsubscribeEvents = unsubscribe;
|
|
192
|
+
unsubscribe = function () { if (unregisterConsent) unregisterConsent(); unsubscribeEvents(); };
|
|
187
193
|
ws[tapKey] = {
|
|
188
194
|
unsubscribe: unsubscribe,
|
|
189
195
|
sessionId: sessionId,
|
|
@@ -238,7 +244,7 @@ function attachHomeChat(deps) {
|
|
|
238
244
|
requestId: requestId || null,
|
|
239
245
|
model: session.model || null,
|
|
240
246
|
vendor: session.vendor || null,
|
|
241
|
-
messages: historyToHomeChat(session.history || [], session.debateSetupMode === true, session.mateCreationMode === true),
|
|
247
|
+
messages: historyToHomeChat(session.history || [], session.debateSetupMode === true, session.mateCreationMode === true, session.pendingAskUser),
|
|
242
248
|
isProcessing: session.isProcessing === true,
|
|
243
249
|
};
|
|
244
250
|
if (session.homeClayEntryMode === "search") {
|
|
@@ -293,6 +299,7 @@ function attachHomeChat(deps) {
|
|
|
293
299
|
homeModels: homeModels, isActorLive: isActorLive, persistActiveSession: persistActiveSession,
|
|
294
300
|
});
|
|
295
301
|
var homeMateCreation = attachHomeMateCreation({ findMateProject: findMateProject, resolveHomeSession: resolveHomeSession, sessionReference: sessionReference, setupTap: setupTap, sendHistory: sendHistory, sendSessionList: sendSessionList, sendError: sendError, sendModelError: sendModelError, homeModels: homeModels, isActorLive: isActorLive, persistActiveSession: persistActiveSession });
|
|
302
|
+
var homeMcpConsent = require('./server-home-mcp-consent').attachHomeMcpConsent({ findMateProject: findMateProject, resolveHomeSession: resolveHomeSession, messageTap: messageTap, isActorLive: isActorLive, sendError: sendError });
|
|
296
303
|
var homeClayEntry = attachHomeClayEntry({ findMateProject: findMateProject, ownsSession: ownsSession, sessionReference: sessionReference, setupSearchTap: setupSearchTap, sendHistory: sendHistory, sendSessionList: sendSessionList, sendError: sendError, sendModelError: sendModelError, homeModels: homeModels, isActorLive: isActorLive });
|
|
297
304
|
|
|
298
305
|
async function openExactSession(ws, found, userId, selected, msg) {
|
|
@@ -397,20 +404,8 @@ function attachHomeChat(deps) {
|
|
|
397
404
|
historyError.sessionId = sessionReference(activeSession);
|
|
398
405
|
throw historyError;
|
|
399
406
|
}
|
|
400
|
-
sessionManager.sendAndRecord(activeSession, { type: "user_message", text: text });
|
|
401
407
|
try {
|
|
402
|
-
|
|
403
|
-
activeSession.isProcessing = true;
|
|
404
|
-
activeSession.sentToolResults = {};
|
|
405
|
-
if (typeof options.onRecorded === "function") options.onRecorded(activeSession);
|
|
406
|
-
if (!activeSession.queryInstance && (!activeSession.worker || activeSession.messageQueue !== "worker")) {
|
|
407
|
-
sdk.startQuery(activeSession, options.queryText || text, null, null);
|
|
408
|
-
} else {
|
|
409
|
-
sdk.pushMessage(activeSession, options.queryText || text, null);
|
|
410
|
-
}
|
|
411
|
-
} else {
|
|
412
|
-
sdk.pushMessage(activeSession, options.queryText || text, null);
|
|
413
|
-
}
|
|
408
|
+
await require('./mate-message-delivery').deliver({ sm: sessionManager, sdk: sdk }, activeSession, text, options);
|
|
414
409
|
} catch (error) {
|
|
415
410
|
error.sessionId = sessionReference(activeSession);
|
|
416
411
|
throw error;
|
|
@@ -449,7 +444,7 @@ function attachHomeChat(deps) {
|
|
|
449
444
|
}
|
|
450
445
|
return true;
|
|
451
446
|
}
|
|
452
|
-
if (msg.type !== "issue_reference_resolve" && msg.type !== "home_debates_list" && msg.type !== "home_clay_ask" && msg.type !== "home_clay_session_resolve" && msg.type !== "home_clay_log_resolve" && msg.type !== "home_mate_present" && msg.type !== "home_mate_open" && msg.type !== "home_mate_sessions_list" && msg.type !== "home_mate_session_open" && msg.type !== "home_mate_send" && msg.type !== "home_mate_new_session" && msg.type !== "home_mate_debate_plan" && msg.type !== "home_debate_proposal_response" && msg.type !== "home_debate_question_response" && msg.type !== "home_debate_control" && msg.type !== "home_mate_creation_plan" && msg.type !== "home_mate_creation_question_response" && msg.type !== "home_mate_creation_proposal_response" && msg.type !== "home_mate_close" && msg.type !== "home_mate_memory_list" && msg.type !== "home_mate_knowledge_list" && msg.type !== "home_mate_models_get" && msg.type !== "home_mate_model_set") {
|
|
447
|
+
if (msg.type !== "issue_reference_resolve" && msg.type !== "home_debates_list" && msg.type !== "home_clay_ask" && msg.type !== "home_clay_session_resolve" && msg.type !== "home_clay_log_resolve" && msg.type !== "home_mate_present" && msg.type !== "home_mate_open" && msg.type !== "home_mate_sessions_list" && msg.type !== "home_mate_session_open" && msg.type !== "home_mate_send" && msg.type !== "home_mate_new_session" && msg.type !== "home_mate_debate_plan" && msg.type !== "home_debate_proposal_response" && msg.type !== "home_mcp_import_response" && msg.type !== "home_mate_question_response" && msg.type !== "home_debate_question_response" && msg.type !== "home_debate_control" && msg.type !== "home_mate_creation_plan" && msg.type !== "home_mate_creation_question_response" && msg.type !== "home_mate_creation_proposal_response" && msg.type !== "home_mate_close" && msg.type !== "home_mate_memory_list" && msg.type !== "home_mate_knowledge_list" && msg.type !== "home_mate_models_get" && msg.type !== "home_mate_model_set") {
|
|
453
448
|
return false;
|
|
454
449
|
}
|
|
455
450
|
|
|
@@ -474,6 +469,7 @@ function attachHomeChat(deps) {
|
|
|
474
469
|
return true;
|
|
475
470
|
}
|
|
476
471
|
|
|
472
|
+
if (msg.type === "home_mcp_import_response" || msg.type === "home_mate_question_response") { homeMcpConsent.respond(ws, userId, msg); return true; }
|
|
477
473
|
if (msg.type === "issue_reference_resolve") { resolveIssueLink(ws, msg); return true; }
|
|
478
474
|
if (homeDebates.handle(ws, userId, msg)) return true;
|
|
479
475
|
if (msg.type === "home_clay_ask") { homeClayEntry.start(ws, userId, msg); return true; }
|
|
@@ -18,6 +18,7 @@ var INITIATION_PROMPT = [
|
|
|
18
18
|
"Before the user answers again, your first and only action must be the next most useful AskUserQuestion. Before presenting it, do not use Bash, Read, Glob, Grep, workspace history, general knowledge, or any other inspection tool, and do not add a preface.",
|
|
19
19
|
"When that tool returns the user's answer, continue the interview normally. Inspect only bounded context that is directly relevant to what the user supplied, and do not bulk-read knowledge files.",
|
|
20
20
|
"Then explore the working relationship, recurring activities and context, communication preferences, autonomy, boundaries, and escalation behavior. Use grounded choices only when helpful. Every three to five exchanges, briefly summarize what you understand inside the next question and let the user correct it.",
|
|
21
|
+
"If the user explicitly asks the future Mate to send a scheduled message, collect the message and exact local date/time, timezone, and repetition only through one focused structured question at a time. Treat it as optional schedule intent: never create or register a job during this interview; include it only in propose_mate after reviewing it with the user.",
|
|
21
22
|
"Choose the Mate's name last. Do not write files and do not create or update a Mate directly.",
|
|
22
23
|
"When the identity is complete, end only by calling propose_mate with a concise public bio, structured preferences, and a complete first-person identityMarkdown. Do not emit a normal assistant preface or conclusion.",
|
|
23
24
|
].join("\n");
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Home transcript responses retain the project's server-owned consent request.
|
|
2
|
+
function attachHomeMcpConsent(ctx) {
|
|
3
|
+
function respond(ws, userId, msg) {
|
|
4
|
+
var found = ctx.findMateProject(userId, msg.mateId || null, false);
|
|
5
|
+
var session = found && ctx.resolveHomeSession(found, userId, msg.sessionId);
|
|
6
|
+
var tap = ctx.messageTap(ws, msg), pending = session && session.pendingAskUser && session.pendingAskUser[msg.toolId];
|
|
7
|
+
if (!ctx.isActorLive(ws, userId) || !found || !session || !tap || tap.mateSlug !== found.slug || tap.sessionId !== session.localId || (tap.requestId || null) !== (msg.requestId || null) || !pending || !pending.request || ['mcp-import', 'mate-schedule', 'mcp_fallback', 'product-control'].indexOf(pending.request.source) < 0) {
|
|
8
|
+
ctx.sendError(ws, found && found.mate.id, 'This owner question is unavailable or expired.', msg.requestId || null, msg.sessionId || null, 'question_expired', { toolId: msg.toolId }); return;
|
|
9
|
+
}
|
|
10
|
+
if (!found.ctx.handleHomeAskUserResponse({ type: 'ask_user_response', toolId: msg.toolId, answers: msg.answers || {} }, session, ws)) ctx.sendError(ws, found.mate.id, 'This question could not be submitted.', msg.requestId || null, msg.sessionId, 'question_refused', { toolId: msg.toolId });
|
|
11
|
+
}
|
|
12
|
+
return { respond: respond };
|
|
13
|
+
}
|
|
14
|
+
module.exports = { attachHomeMcpConsent: attachHomeMcpConsent };
|