clay-server 5.2.0-beta.5 → 5.2.0-beta.7
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/claude-hook-installer.js +1 -267
- package/lib/claude-jsonl-watcher.js +1 -204
- package/lib/clay-control-presentation-binding.js +96 -0
- package/lib/clay-control-presentation.js +128 -0
- package/lib/clay-control-target-projection.js +26 -0
- package/lib/clay-mate-chat.js +1 -0
- package/lib/clay-mate-knowledge.js +1 -1
- package/lib/clay-product-control-tools.js +1 -1
- package/lib/clay-product-control.js +22 -12
- package/lib/clay-project-records.js +2 -1
- package/lib/clay-scheduling.js +1 -1
- package/lib/clay-screen-controls.js +13 -5
- package/lib/clay-skill-install.js +1 -33
- package/lib/clay-workspace-controls.js +2 -1
- package/lib/cli-sessions.js +1 -300
- package/lib/codex-defaults.js +1 -28
- package/lib/context-usage.js +3 -2
- package/lib/contextual-screen-snapshot.js +38 -0
- package/lib/daemon.js +5 -55
- package/lib/default-ai-runtime.js +4 -8
- package/lib/email-mcp-server.js +1 -1
- package/lib/kiro-defaults.js +1 -22
- package/lib/mate-context-service.js +138 -0
- package/lib/mate-context-tools.js +21 -0
- package/lib/mcp-proxy.js +2 -32
- package/lib/mcp-query-bridge.js +1 -1
- package/lib/mcp-source-adapters.js +1 -91
- package/lib/mcp-source-context.js +1 -42
- package/lib/mcp-source-discovery.js +1 -169
- package/lib/mcp-source-plugins.js +1 -68
- package/lib/mcp-source-restrictions.js +1 -47
- package/lib/mcp-tool-policy.js +1 -26
- package/lib/os-user-diagnostics.js +2 -4
- package/lib/os-users.js +4 -65
- package/lib/project-connection.js +14 -10
- package/lib/project-control-git-view.js +12 -0
- package/lib/project-filesystem.js +5 -1
- package/lib/project-http.js +7 -4
- package/lib/project-mcp.js +2 -2
- package/lib/project-notifications.js +5 -4
- package/lib/project-pair-result-delivery.js +2 -2
- package/lib/project-pair-usage.js +12 -13
- package/lib/project-pending-message-queue.js +3 -1
- package/lib/project-product-control.js +3 -1
- package/lib/project-scheduled-messages.js +4 -4
- package/lib/project-scheduled-task-control.js +1 -1
- package/lib/project-session-document.js +20 -5
- package/lib/project-session-history-actions.js +5 -3
- package/lib/project-session-pair.js +1 -1
- package/lib/project-session-runtime-actions.js +2 -1
- package/lib/project-session-spawn.js +2 -3
- package/lib/project-session-vendor.js +2 -1
- package/lib/project-sessions.js +18 -26
- package/lib/project-shared-browser.js +22 -5
- package/lib/project-studio-presentation.js +58 -0
- package/lib/project-user-message.js +37 -0
- package/lib/project-vendor-login.js +6 -36
- package/lib/project-workspace-query.js +11 -1
- package/lib/project.js +24 -7
- package/lib/public/app.js +25 -0
- package/lib/public/appearance-bootstrap.js +2 -0
- package/lib/public/css/contextual-clay.css +240 -0
- package/lib/public/css/messages.css +6 -2
- package/lib/public/modules/app-favicon.js +18 -9
- package/lib/public/modules/app-header.js +4 -2
- package/lib/public/modules/app-loop-ui.js +2 -0
- package/lib/public/modules/app-message-router.js +5 -1
- package/lib/public/modules/app-messages.js +50 -6
- package/lib/public/modules/app-notifications.js +11 -5
- package/lib/public/modules/app-panels.js +61 -123
- package/lib/public/modules/app-projects.js +3 -0
- package/lib/public/modules/app-rate-limit.js +7 -27
- package/lib/public/modules/chat-render-runtime.js +3 -0
- package/lib/public/modules/clay-control-activity.js +214 -0
- package/lib/public/modules/clay-control-copy.js +36 -0
- package/lib/public/modules/clay-control-detail-targets.js +44 -0
- package/lib/public/modules/clay-control-object-targets.js +52 -0
- package/lib/public/modules/clay-control-target-visibility.js +12 -0
- package/lib/public/modules/clay-control-targets.js +44 -0
- package/lib/public/modules/clay-navigation-render.js +52 -0
- package/lib/public/modules/clay-owner-navigation.js +11 -2
- package/lib/public/modules/clay-session-links.js +31 -0
- package/lib/public/modules/clay-studio-bridge.js +20 -0
- package/lib/public/modules/clay-studio-document.js +67 -0
- package/lib/public/modules/clay-studio-render.js +144 -0
- package/lib/public/modules/clay-tool-presentation.js +4 -0
- package/lib/public/modules/command-palette.js +26 -31
- package/lib/public/modules/contextual-ask-session.js +26 -0
- package/lib/public/modules/contextual-clay-geometry.js +155 -0
- package/lib/public/modules/contextual-clay-session.js +130 -0
- package/lib/public/modules/contextual-clay-workspace.js +157 -0
- package/lib/public/modules/contextual-clay.js +237 -0
- package/lib/public/modules/contextual-composer.js +91 -0
- package/lib/public/modules/contextual-mate-context.js +115 -0
- package/lib/public/modules/contextual-mate-hint.js +40 -0
- package/lib/public/modules/contextual-mate-identity.js +23 -0
- package/lib/public/modules/contextual-mate-sessions.js +134 -0
- package/lib/public/modules/contextual-search.js +137 -0
- package/lib/public/modules/contextual-session-citations.js +58 -0
- package/lib/public/modules/filebrowser.js +20 -1
- package/lib/public/modules/generation-stop.js +8 -5
- package/lib/public/modules/git-panel.js +3 -1
- package/lib/public/modules/icon-strip-tooltip.js +2 -1
- package/lib/public/modules/input.js +35 -1
- package/lib/public/modules/issues-render.js +3 -2
- package/lib/public/modules/knowledge-db-workbench.js +4 -4
- package/lib/public/modules/markdown.js +2 -34
- package/lib/public/modules/mate-knowledge-workbench.js +1 -1
- package/lib/public/modules/mcp-connection-view.js +1 -1
- package/lib/public/modules/message-delivery.js +10 -0
- package/lib/public/modules/pane-bridge.js +2 -2
- package/lib/public/modules/pending-message-queue.js +1 -0
- package/lib/public/modules/permission-control.js +5 -4
- package/lib/public/modules/product-review.js +26 -0
- package/lib/public/modules/project-chat-identity.js +13 -4
- package/lib/public/modules/project-logs-render.js +3 -0
- package/lib/public/modules/project-mate-navigation.js +58 -21
- package/lib/public/modules/scheduled-tasks.js +2 -0
- package/lib/public/modules/scheduler.js +2 -0
- package/lib/public/modules/search-clay-chat.js +5 -454
- package/lib/public/modules/session-create-form.js +10 -10
- package/lib/public/modules/settings-defaults.js +27 -28
- package/lib/public/modules/shared-browser.js +2 -0
- package/lib/public/modules/sidebar-mobile.js +4 -3
- package/lib/public/modules/sidebar-projects.js +1 -0
- package/lib/public/modules/sidebar-sessions.js +1 -0
- package/lib/public/modules/split-view.js +7 -16
- package/lib/public/modules/terminal.js +9 -0
- package/lib/public/modules/tools.js +6 -2
- package/lib/public/modules/tui-grab.js +1 -2
- package/lib/public/modules/vendor-login-browser.js +5 -3
- package/lib/public/modules/vendor-login.js +2 -2
- package/lib/public/modules/vendor-priority.js +15 -1
- package/lib/public/modules/wireframe-workbench.js +5 -2
- package/lib/public/muse-avatar.svg +4 -0
- package/lib/public/style.css +2 -0
- package/lib/safe-bash-commands.js +3 -45
- package/lib/sdk-bridge.js +131 -395
- package/lib/sdk-foreground-admission.js +16 -0
- package/lib/sdk-mcp-descriptors.js +2 -37
- package/lib/sdk-message-processor.js +50 -17
- package/lib/sdk-quota-snapshot.js +1 -1
- package/lib/sdk-response-recovery.js +1 -155
- package/lib/sdk-worker.js +2 -677
- package/lib/server-contextual-clay-settings.js +40 -0
- package/lib/server-contextual-mate-sessions.js +70 -0
- package/lib/server-home-chat.js +7 -1
- package/lib/server-home-clay-entry.js +23 -4
- package/lib/server-home-clay-session-links.js +12 -0
- package/lib/server-owner-ui.js +49 -8
- package/lib/server-settings.js +2 -0
- package/lib/server.js +18 -1
- package/lib/session-fork-history.js +21 -0
- package/lib/session-hygiene.js +3 -35
- package/lib/session-permission-mode.js +4 -3
- package/lib/session-skill-scope.js +11 -0
- package/lib/sessions.js +24 -89
- package/lib/terminal-manager.js +18 -11
- package/lib/tool-llm.js +1 -1
- package/lib/tui-transcript-index.js +1 -132
- package/lib/users-contextual-clay-preferences.js +31 -0
- package/lib/users.js +3 -0
- package/lib/vendor-login-browser.js +1 -11
- package/lib/workspace-assignment-service.js +25 -0
- package/lib/workspace-query-mcp-server.js +1 -1
- package/lib/ws-request.js +1 -0
- package/lib/ws-schema.js +10 -0
- package/lib/yoke/acp-agent-profiles.js +5 -3
- package/lib/yoke/adapters/antigravity.js +3 -14
- package/lib/yoke/adapters/claude-query-contract.js +9 -0
- package/lib/yoke/adapters/claude.js +7 -42
- package/lib/yoke/adapters/codex-query-contract.js +24 -0
- package/lib/yoke/adapters/codex.js +1 -0
- package/lib/yoke/adapters/kiro.js +3 -1
- package/lib/yoke/adapters/muse-query-contract.js +7 -0
- package/lib/yoke/adapters/muse.js +122 -0
- package/lib/yoke/auth-events.js +17 -0
- package/lib/yoke/claude-hook-installer.js +271 -0
- package/lib/yoke/claude-jsonl-watcher.js +204 -0
- package/lib/yoke/claude-maintenance.js +55 -0
- package/lib/yoke/claude-permission-patterns.js +53 -0
- package/lib/yoke/claude-response-recovery.js +155 -0
- package/lib/yoke/claude-transcript-hygiene.js +34 -0
- package/lib/yoke/clay-skill-install.js +33 -0
- package/lib/yoke/cli-sessions.js +300 -0
- package/lib/yoke/codex-app-server.js +7 -12
- package/lib/yoke/configuration.js +13 -0
- package/lib/yoke/discovery.js +70 -0
- package/lib/yoke/errors.js +8 -0
- package/lib/yoke/host-environment.js +7 -0
- package/lib/yoke/index.js +9 -51
- package/lib/yoke/interface.js +116 -0
- package/lib/yoke/kiro-acp-server.js +5 -5
- package/lib/yoke/legacy-sessions.js +89 -0
- package/lib/yoke/login-protocol.js +25 -0
- package/lib/yoke/maintenance.js +12 -0
- package/lib/yoke/mcp-proxy.js +32 -0
- package/lib/yoke/mcp-source-adapters.js +91 -0
- package/lib/yoke/mcp-source-context.js +42 -0
- package/lib/yoke/mcp-source-discovery.js +169 -0
- package/lib/yoke/mcp-source-plugins.js +68 -0
- package/lib/yoke/mcp-source-restrictions.js +47 -0
- package/lib/yoke/mcp-tool-policy-normalize.js +28 -0
- package/lib/yoke/model-preferences.js +6 -0
- package/lib/yoke/muse-artifacts.js +36 -0
- package/lib/yoke/muse-controls.js +50 -0
- package/lib/yoke/muse-input.js +64 -0
- package/lib/yoke/muse-items.js +157 -0
- package/lib/yoke/muse-policy.js +52 -0
- package/lib/yoke/muse-query.js +428 -0
- package/lib/yoke/muse-runtime.js +211 -0
- package/lib/yoke/muse-services.js +79 -0
- package/lib/yoke/muse-skills.js +79 -0
- package/lib/yoke/muse-turns.js +71 -0
- package/lib/yoke/options/acp.js +2 -0
- package/lib/yoke/options/antigravity.js +2 -0
- package/lib/yoke/options/claude.js +21 -0
- package/lib/yoke/options/codex-defaults.js +29 -0
- package/lib/yoke/options/codex-settings.js +21 -0
- package/lib/yoke/options/codex.js +6 -0
- package/lib/yoke/options/kiro-defaults.js +22 -0
- package/lib/yoke/options/kiro.js +5 -0
- package/lib/yoke/options/muse.js +5 -0
- package/lib/yoke/provider-contract.js +5 -0
- package/lib/yoke/providers/antigravity-executable.js +8 -0
- package/lib/yoke/providers/claude-executable.js +40 -0
- package/lib/yoke/providers/claude-model-descriptions.js +14 -0
- package/lib/yoke/providers/claude-process.js +97 -0
- package/lib/yoke/providers/claude-provision.js +75 -0
- package/lib/yoke/providers/codex-errors.js +8 -0
- package/lib/yoke/providers/muse-executable.js +17 -0
- package/lib/yoke/provisioning.js +6 -0
- package/lib/yoke/query-options.js +10 -0
- package/lib/yoke/response-recovery.js +41 -0
- package/lib/yoke/sdk-mcp-descriptors.js +37 -0
- package/lib/yoke/sdk-server-factory.js +7 -0
- package/lib/yoke/session-history.js +8 -0
- package/lib/yoke/session-tool-transport.js +31 -13
- package/lib/yoke/settings.js +23 -0
- package/lib/yoke/source-locations.js +4 -0
- package/lib/yoke/title-query.js +18 -7
- package/lib/yoke/tui-transcript-index.js +132 -0
- package/lib/yoke/usage.js +48 -0
- package/lib/yoke/user-input.js +13 -0
- package/lib/yoke/vendor-registry.js +81 -1
- package/package.json +3 -2
|
@@ -11,7 +11,8 @@ function attachSessionRuntimeActions(ctx) {
|
|
|
11
11
|
var vendor = session.vendor || ctx.sm.defaultVendor || "claude";
|
|
12
12
|
var ids = Array.from(new Set([session.terminalId, session.runtimeTerminalId].filter(function (id) { return typeof id === "number"; })));
|
|
13
13
|
if (!ids.length && (session.runtimeMode || session.mode || "gui") === "gui") return { status: "completed", runtimeMode: "gui", runtimeEffect: "none", threadPreserved: true };
|
|
14
|
-
|
|
14
|
+
var lifecycle = require("./yoke/provider-contract").resolve(vendor);
|
|
15
|
+
if (typeof lifecycle.supportsLegacyGuiResume !== "function" || !lifecycle.supportsLegacyGuiResume(session)) throw new Error("This provider cannot return a legacy terminal thread to GUI chat.");
|
|
15
16
|
var closed = 0, persisted = false;
|
|
16
17
|
var fields = ['terminalId', 'runtimeTerminalId'];
|
|
17
18
|
var originalFields = fields.map(function (field) { return session[field]; });
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
var yoke = require("./yoke");
|
|
2
2
|
var sessionSpawnMcp = require("./session-spawn-mcp-server");
|
|
3
|
-
var cliSessions = require("./cli-sessions");
|
|
4
3
|
var os = require("os");
|
|
5
4
|
var osUsers = require("./os-users");
|
|
6
5
|
|
|
@@ -161,7 +160,7 @@ function attachSessionSpawn(ctx) {
|
|
|
161
160
|
var sm = ctx.sm;
|
|
162
161
|
var queue = createSpawnQueue(SPAWN_CONCURRENCY);
|
|
163
162
|
var adapters = ctx.adapters || {};
|
|
164
|
-
var readCliSessionHistory = ctx.readCliSessionHistory ||
|
|
163
|
+
var readCliSessionHistory = ctx.readCliSessionHistory || function(home, project, sessionId, provider) { return require("./yoke/session-history").read(provider || "claude", home, project, sessionId); };
|
|
165
164
|
|
|
166
165
|
function resolveSessionHome(session) {
|
|
167
166
|
var linuxUser = ctx.getLinuxUserForSession(session);
|
|
@@ -283,7 +282,7 @@ function attachSessionSpawn(ctx) {
|
|
|
283
282
|
forkHistory = parent.history.slice();
|
|
284
283
|
} else {
|
|
285
284
|
forkHistory = await readCliSessionHistory(
|
|
286
|
-
resolveSessionHome(parent), ctx.cwd, forkResult.sessionId
|
|
285
|
+
resolveSessionHome(parent), ctx.cwd, forkResult.sessionId, parent.vendor
|
|
287
286
|
);
|
|
288
287
|
}
|
|
289
288
|
} catch (e) {
|
|
@@ -18,7 +18,8 @@ function attachSessionVendor(ctx) {
|
|
|
18
18
|
session.vendor = vendor;
|
|
19
19
|
session.model = null;
|
|
20
20
|
session.effort = yoke.clampEffort(vendor, session.effort) || null;
|
|
21
|
-
|
|
21
|
+
var modes = yoke.sessionTools.contract(ctx.adapters[vendor]).permissionModes;
|
|
22
|
+
if (session.permissionMode === 'auto' && (!Array.isArray(modes) || modes.indexOf('auto') < 0)) session.permissionMode = 'default';
|
|
22
23
|
session.effectivePermissionMode = null;
|
|
23
24
|
try { if (ctx.sm.saveSessionFile(session) !== true) throw new Error('Could not persist the provider selection.'); }
|
|
24
25
|
catch (error) { Object.assign(session, previous); throw error; }
|
package/lib/project-sessions.js
CHANGED
|
@@ -2,7 +2,7 @@ var serverSettingsMessages = require("./project-server-settings");
|
|
|
2
2
|
var fs = require("fs");
|
|
3
3
|
var path = require("path");
|
|
4
4
|
var { execFileSync } = require("child_process");
|
|
5
|
-
var
|
|
5
|
+
var providerSettings = require("./yoke/settings");
|
|
6
6
|
var updateSnooze = require("./update-snooze");
|
|
7
7
|
var yoke = require("./yoke");
|
|
8
8
|
var sessionVisibility = require("./session-visibility");
|
|
@@ -258,7 +258,7 @@ function attachSessions(ctx) {
|
|
|
258
258
|
if (!session || !session.cliSessionId) return;
|
|
259
259
|
if (session._titleWatcherStop) return; // already watching
|
|
260
260
|
var watcher;
|
|
261
|
-
try { watcher = require("./claude-jsonl-watcher"); } catch (e) { return; }
|
|
261
|
+
try { watcher = require("./yoke/claude-jsonl-watcher"); } catch (e) { return; }
|
|
262
262
|
var home = resolveSessionHome(session);
|
|
263
263
|
var jsonlPath = watcher.jsonlPathFor(home, cwd, session.cliSessionId);
|
|
264
264
|
if (!jsonlPath) return;
|
|
@@ -326,7 +326,7 @@ function attachSessions(ctx) {
|
|
|
326
326
|
// message right away. The transcript is small enough that a full
|
|
327
327
|
// re-send beats maintaining a delta protocol.
|
|
328
328
|
try {
|
|
329
|
-
var newIndex = require("./tui-transcript-index").readAssistantIndex(resolveSessionHome(s), cwd, s.cliSessionId);
|
|
329
|
+
var newIndex = require("./yoke/tui-transcript-index").readAssistantIndex(resolveSessionHome(s), cwd, s.cliSessionId);
|
|
330
330
|
send({
|
|
331
331
|
type: "tui_transcript_state",
|
|
332
332
|
id: s.localId,
|
|
@@ -453,7 +453,7 @@ function attachSessions(ctx) {
|
|
|
453
453
|
function prepareTuiSessionForGuiView(session, options) {
|
|
454
454
|
if (!session || session.cliSessionId == null) return;
|
|
455
455
|
var cliSess;
|
|
456
|
-
try { cliSess = require("./cli-sessions"); } catch (e) { return; }
|
|
456
|
+
try { cliSess = require("./yoke/cli-sessions"); } catch (e) { return; }
|
|
457
457
|
// Re-read whenever the jsonl has changed since the last hydrate (a TUI
|
|
458
458
|
// turn appended messages), not just when history is empty. The earlier
|
|
459
459
|
// "already hydrated" short-circuit kept stale history after a
|
|
@@ -603,7 +603,7 @@ function attachSessions(ctx) {
|
|
|
603
603
|
var from = sm.findTurnBoundary(session.history, Math.max(0, targetFrom));
|
|
604
604
|
var to = before;
|
|
605
605
|
var items = session.history.slice(from, to).map(function (item, index) {
|
|
606
|
-
return Object.assign({}, hydrateImageRefs(item), { _historyIndex: from + index });
|
|
606
|
+
return Object.assign({}, hydrateImageRefs(require("./yoke/usage").clientEvent(item, session.vendor || "claude")), { _historyIndex: from + index });
|
|
607
607
|
});
|
|
608
608
|
sendTo(ws, {
|
|
609
609
|
type: "history_prepend",
|
|
@@ -918,7 +918,7 @@ function attachSessions(ctx) {
|
|
|
918
918
|
return true;
|
|
919
919
|
}
|
|
920
920
|
try {
|
|
921
|
-
var tprIndex = require("./tui-transcript-index").readAssistantIndex(resolveSessionHome(tprSess), cwd, tprSess.cliSessionId);
|
|
921
|
+
var tprIndex = require("./yoke/tui-transcript-index").readAssistantIndex(resolveSessionHome(tprSess), cwd, tprSess.cliSessionId);
|
|
922
922
|
sendTo(ws, {
|
|
923
923
|
type: "tui_transcript_state",
|
|
924
924
|
id: tprId,
|
|
@@ -1099,14 +1099,14 @@ function attachSessions(ctx) {
|
|
|
1099
1099
|
var pid = msg.pid;
|
|
1100
1100
|
if (!pid || typeof pid !== "number") return true;
|
|
1101
1101
|
// Verify target is actually a claude process before killing
|
|
1102
|
-
if (!sdk.
|
|
1103
|
-
console.error("[project] Refused to kill PID " + pid + ": not a
|
|
1104
|
-
sendTo(ws, { type: "error", text: "Process " + pid + " is not a
|
|
1102
|
+
if (!sdk.isProviderProcess(pid, getSessionForWs(ws))) {
|
|
1103
|
+
console.error("[project] Refused to kill PID " + pid + ": not a verified provider process");
|
|
1104
|
+
sendTo(ws, { type: "error", text: "Process " + pid + " is not a verified provider process." });
|
|
1105
1105
|
return true;
|
|
1106
1106
|
}
|
|
1107
1107
|
try {
|
|
1108
1108
|
process.kill(pid, "SIGTERM");
|
|
1109
|
-
console.log("[project] Sent SIGTERM to conflicting
|
|
1109
|
+
console.log("[project] Sent SIGTERM to conflicting provider process PID " + pid);
|
|
1110
1110
|
sendTo(ws, { type: "process_killed", pid: pid });
|
|
1111
1111
|
} catch (e) {
|
|
1112
1112
|
console.error("[project] Failed to kill PID " + pid + ":", e.message);
|
|
@@ -1367,20 +1367,12 @@ function attachSessions(ctx) {
|
|
|
1367
1367
|
return true;
|
|
1368
1368
|
}
|
|
1369
1369
|
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
if (msg.type === "set_codex_sandbox") {
|
|
1377
|
-
sm.codexSandbox = msg.sandbox || CODEX_DEFAULTS.sandbox;
|
|
1378
|
-
send(Object.assign({ type: "codex_config" }, getCodexConfig(sm)));
|
|
1379
|
-
return true;
|
|
1380
|
-
}
|
|
1381
|
-
if (msg.type === "set_codex_websearch") {
|
|
1382
|
-
sm.codexWebSearch = msg.webSearch || CODEX_DEFAULTS.webSearch;
|
|
1383
|
-
send(Object.assign({ type: "codex_config" }, getCodexConfig(sm)));
|
|
1370
|
+
var providerChange;
|
|
1371
|
+
try { providerChange = providerSettings.change(msg, sm); }
|
|
1372
|
+
catch (error) { sendTo(ws, { type: "error", text: error.message }); return true; }
|
|
1373
|
+
if (providerChange) {
|
|
1374
|
+
Object.keys(providerChange.patch).forEach(function(key) { sm[key] = providerChange.patch[key]; });
|
|
1375
|
+
providerChange.messages.forEach(function(message) { send(message); });
|
|
1384
1376
|
return true;
|
|
1385
1377
|
}
|
|
1386
1378
|
|
|
@@ -1924,7 +1916,7 @@ function attachSessions(ctx) {
|
|
|
1924
1916
|
var galManaged = [];
|
|
1925
1917
|
var galUser = [];
|
|
1926
1918
|
try {
|
|
1927
|
-
var galInstaller = require("./claude-hook-installer");
|
|
1919
|
+
var galInstaller = require("./yoke/claude-hook-installer");
|
|
1928
1920
|
galManaged = galInstaller.CLAY_MANAGED_ALLOW || [];
|
|
1929
1921
|
} catch (e) {}
|
|
1930
1922
|
if (galUid) {
|
|
@@ -1950,7 +1942,7 @@ function attachSessions(ctx) {
|
|
|
1950
1942
|
// home (OS-mode: getent passwd; single-user: os.homedir()).
|
|
1951
1943
|
var salEffective = false;
|
|
1952
1944
|
try {
|
|
1953
|
-
var salInstaller = require("./claude-hook-installer");
|
|
1945
|
+
var salInstaller = require("./yoke/claude-hook-installer");
|
|
1954
1946
|
var salHome = null;
|
|
1955
1947
|
if (osUsers && ws._clayUser && ws._clayUser.linuxUser) {
|
|
1956
1948
|
try {
|
|
@@ -175,13 +175,14 @@ function attachSharedBrowser(ctx) {
|
|
|
175
175
|
record.touched = Date.now(); broadcast(record);
|
|
176
176
|
return projection(record);
|
|
177
177
|
}
|
|
178
|
-
async function run(session, record, actor, action, event, intent) {
|
|
178
|
+
async function run(session, record, actor, action, event, intent, presentationStart) {
|
|
179
179
|
requireAccess(session);
|
|
180
180
|
if (!record || !record.runtime || !recordAllowed(record)) throw new Error("Open a browser first");
|
|
181
181
|
if (record.handoff) throw new Error("Browser control is changing; wait for the handoff");
|
|
182
182
|
// control "agent" = shared (owner and Clay may both act); "user" = exclusive human mode (Clay mutations denied).
|
|
183
183
|
// The authorized owner is never blocked by control mode and ordinary human input never changes it.
|
|
184
184
|
if (action !== "inspect" && actor === "agent" && record.control !== "agent") throw new Error("Only the user can control this browser right now (Clay is paused). Wait for them to resume shared control; do not work around it.");
|
|
185
|
+
if (action !== 'inspect') { record.presentationRevision = (record.presentationRevision || 0) + 1; if (presentationStart) presentationStart(record.presentationRevision); }
|
|
185
186
|
var epoch = record.epoch;
|
|
186
187
|
var generation = Number(session._sdkQueryGeneration || 0);
|
|
187
188
|
await record.ready;
|
|
@@ -204,18 +205,22 @@ function attachSharedBrowser(ctx) {
|
|
|
204
205
|
return result;
|
|
205
206
|
}
|
|
206
207
|
async function tool(session, args) {
|
|
208
|
+
var observer;
|
|
207
209
|
try {
|
|
208
210
|
requireAccess(session);
|
|
209
211
|
if (args.intent !== undefined && (typeof args.intent !== "string" || args.intent.length > 160)) throw new Error("Browser intent must be at most 160 characters");
|
|
210
212
|
var record = args.action === "status" || args.action === "open" ? null : selectRecord(session, args.browserId);
|
|
211
|
-
var value;
|
|
213
|
+
var value, actionRevision = record && (record.presentationRevision || 0);
|
|
214
|
+
function presentationStart(value) { actionRevision = value; }
|
|
215
|
+
if (['status', 'inspect'].indexOf(args.action) < 0 && ctx.getPresentation) { var display = ctx.getPresentation(session); if (display) observer = ctx.studioPresentation ? ctx.studioPresentation.begin(session, 'browser') : display.track('studio', 'browser'); }
|
|
212
216
|
if (args.action === "status") value = { browsers: sessionRecords(session).map(projection) };
|
|
213
217
|
else if (args.action === "open") {
|
|
214
218
|
if (args.incognito !== undefined && typeof args.incognito !== "boolean") throw new Error("Invalid incognito mode");
|
|
215
219
|
var url = args.url ? policy.browserUrl(args.url) : null;
|
|
216
220
|
record = args.browserId ? selectRecord(session, args.browserId) : create(session, "agent", args.newTab === true, args.incognito);
|
|
217
221
|
if (args.incognito !== undefined && record.incognito !== (!ctx.isMate || args.incognito)) throw new Error("This tab has a different cookie mode. Open a new tab with the requested mode.");
|
|
218
|
-
if (url) await run(session, record, "agent", "action", { kind: "navigate", url: url }, args.intent);
|
|
222
|
+
if (url) await run(session, record, "agent", "action", { kind: "navigate", url: url }, args.intent, presentationStart);
|
|
223
|
+
else actionRevision = record.presentationRevision || 0;
|
|
219
224
|
value = projection(record);
|
|
220
225
|
} else if (args.action === "finish") {
|
|
221
226
|
if (!record || !record.runtime) throw new Error("Open a browser first");
|
|
@@ -227,11 +232,23 @@ function attachSharedBrowser(ctx) {
|
|
|
227
232
|
var image = value.image; delete value.image;
|
|
228
233
|
return { content: [{ type: "text", text: JSON.stringify(value) }, { type: "image", mimeType: "image/jpeg", data: image }] };
|
|
229
234
|
} else {
|
|
230
|
-
value = await run(session, record, "agent", "action", policy.validateAction(Object.assign({}, args, { kind: args.action })), args.intent);
|
|
235
|
+
value = await run(session, record, "agent", "action", policy.validateAction(Object.assign({}, args, { kind: args.action })), args.intent, presentationStart);
|
|
231
236
|
}
|
|
237
|
+
if (observer && observer.present) {
|
|
238
|
+
observer.phase('completed');
|
|
239
|
+
try {
|
|
240
|
+
observer.guard();
|
|
241
|
+
var expectedRecord = record, expectedEpoch = record.epoch, expectedUrl = record.url;
|
|
242
|
+
if ((record.presentationRevision || 0) !== actionRevision || record.control !== 'agent') throw new Error('The browser changed after this action.');
|
|
243
|
+
var view = await run(session, record, 'agent', 'inspect', null, args.intent);
|
|
244
|
+
if (view && view.url && policy.visibleUrl(view.url) !== expectedUrl) throw new Error('The browser navigated after this action.');
|
|
245
|
+
if (!view || typeof view.image !== 'string' || !view.image) throw new Error('No exact browser frame was returned.');
|
|
246
|
+
observer.present({ type: 'shared_browser_frame', sessionId: session.localId, browserId: record.id, data: view.image, width: view.width, height: view.height }, 'browser', record.id, require('./clay-control-target-projection').digest(view.image), function () { requireAccess(session); if (records.get(expectedRecord.id) !== expectedRecord || !recordAllowed(expectedRecord) || expectedRecord.epoch !== expectedEpoch || expectedRecord.url !== expectedUrl || expectedRecord.control !== 'agent' || (expectedRecord.presentationRevision || 0) !== actionRevision || !expectedRecord.runtime) throw new Error('Browser target changed.'); }, function (message, onSent) { return ctx.sendToSession(session.localId, message, onSent); });
|
|
247
|
+
} catch (visibilityError) { observer.noVisibility(); }
|
|
248
|
+
} else if (observer) observer.finish({ status: 'completed' });
|
|
232
249
|
if (value && value.url) value.browserLink = "browser:" + policy.visibleUrl(value.url);
|
|
233
250
|
return { content: [{ type: "text", text: JSON.stringify(value) }] };
|
|
234
|
-
} catch (e) { return { isError: true, content: [{ type: "text", text: e.message }] }; }
|
|
251
|
+
} catch (e) { if (observer) { if (observer.unknown) observer.unknown(); else observer.finish({ outcome: "uncertain" }); } return { isError: true, content: [{ type: "text", text: e.message }] }; }
|
|
235
252
|
}
|
|
236
253
|
async function openLinkedPage(session, url, incognito) {
|
|
237
254
|
var record = sessionRecords(session).find(function (tab) {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
var crypto = require('crypto');
|
|
2
|
+
|
|
3
|
+
// Visibility receipts observe existing workbench effects; they dispatch no product action.
|
|
4
|
+
function attachStudioPresentation(ctx) {
|
|
5
|
+
var pending = new Map();
|
|
6
|
+
function begin(session, action) {
|
|
7
|
+
var display = ctx.getPresentation && ctx.getPresentation(session);
|
|
8
|
+
if (!display) return null;
|
|
9
|
+
var source = display.source(), observer = display.track('studio', action);
|
|
10
|
+
if (!observer) return null;
|
|
11
|
+
var id = crypto.randomUUID(), token = crypto.randomUUID(), record;
|
|
12
|
+
function end(status, viewer) {
|
|
13
|
+
if (!record || !pending.has(id)) return;
|
|
14
|
+
pending.delete(id); clearTimeout(record.timer);
|
|
15
|
+
if (viewer) observer.focus(viewer);
|
|
16
|
+
observer.finish({ status: status });
|
|
17
|
+
}
|
|
18
|
+
function cancel() { if (record) { pending.delete(id); clearTimeout(record.timer); } observer.cancel(); }
|
|
19
|
+
return {
|
|
20
|
+
phase: observer.phase,
|
|
21
|
+
guard: observer.guard,
|
|
22
|
+
noVisibility: function () { observer.finish({ status: "render_unknown" }); },
|
|
23
|
+
fail: function () { cancel(); },
|
|
24
|
+
unknown: function () { observer.finish({ outcome: 'uncertain' }); },
|
|
25
|
+
present: function (message, surface, key, revision, validate, send) {
|
|
26
|
+
observer.guard();
|
|
27
|
+
if (pending.size >= 100) { observer.finish({ status: 'render_unknown' }); return 0; }
|
|
28
|
+
var target = { kind: 'surface', sourceSlug: source.sourceSlug, sourceSessionId: session.localId, sourceSessionOriginId: source.sourceSessionOriginId,
|
|
29
|
+
runtimeId: source.runtimeId, surface: surface, key: key, revision: revision };
|
|
30
|
+
observer.target(target, validate); observer.guard();
|
|
31
|
+
var evidence = Object.assign({ version: 1, id: id, activityId: observer.id, token: token, deadline: Date.now() + 5000, target: target }, source);
|
|
32
|
+
record = { session: session, source: source, evidence: evidence, observer: observer, viewers: new Set(), end: end, cancel: cancel };
|
|
33
|
+
pending.set(id, record);
|
|
34
|
+
record.timer = setTimeout(function () { end('render_unknown'); }, 5000); record.timer.unref();
|
|
35
|
+
var sent = send(Object.assign({}, message, { controlPresentation: evidence }), function (ws) { record.viewers.add(ws); });
|
|
36
|
+
if (sent > 0) { if (surface !== 'browser') observer.phase('delivered'); }
|
|
37
|
+
else end('render_unknown');
|
|
38
|
+
return sent;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function handleMessage(ws, msg) {
|
|
43
|
+
if (msg.type !== 'clay_studio_rendered') return false;
|
|
44
|
+
var record = pending.get(msg.id);
|
|
45
|
+
if (!record || record.evidence.token !== msg.token || !record.viewers.has(ws)) return true;
|
|
46
|
+
try {
|
|
47
|
+
record.observer.guard();
|
|
48
|
+
if (Date.now() > record.evidence.deadline) { record.end('render_unknown', ws); return true; }
|
|
49
|
+
if (ws.readyState !== 1 || ws._clayAuthCheck && !ws._clayAuthCheck() ||
|
|
50
|
+
ws._clayActiveSession !== record.session.localId || ctx.getSessionForWs(ws) !== record.session || (ws._clayUser && ws._clayUser.id || null) !== record.source.ownerId ||
|
|
51
|
+
msg.sessionOriginId !== record.source.sourceSessionOriginId || msg.revision !== record.evidence.target.revision) throw new Error('Studio viewer or target changed.');
|
|
52
|
+
record.end(msg.visible === true ? 'rendered' : 'render_unknown', ws);
|
|
53
|
+
} catch (error) { record.cancel(); }
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
return { begin: begin, handleMessage: handleMessage };
|
|
57
|
+
}
|
|
58
|
+
module.exports = { attachStudioPresentation: attachStudioPresentation };
|
|
@@ -49,6 +49,7 @@ function attachUserMessage(ctx) {
|
|
|
49
49
|
|
|
50
50
|
var clients = ctx.clients;
|
|
51
51
|
var opts = ctx.opts;
|
|
52
|
+
var snapshotService = require('./contextual-screen-snapshot').attachContextualScreenSnapshot(ctx);
|
|
52
53
|
|
|
53
54
|
var usersModule = ctx.usersModule;
|
|
54
55
|
var matesModule = ctx.matesModule;
|
|
@@ -450,6 +451,10 @@ function attachUserMessage(ctx) {
|
|
|
450
451
|
return true;
|
|
451
452
|
}
|
|
452
453
|
|
|
454
|
+
var screenSnapshot;
|
|
455
|
+
try { screenSnapshot = snapshotService.capture(ws, session, msg); }
|
|
456
|
+
catch (error) { sendTo(ws, { type: 'error', text: error.message }); finishPendingEarly(false, error.message); return true; }
|
|
457
|
+
|
|
453
458
|
// A configured Split Worker is Driver-operated: its work arrives through
|
|
454
459
|
// the Driver's delegation, not from a person typing into its pane. The UI
|
|
455
460
|
// hides the composer, but the refusal has to live here too — a legacy
|
|
@@ -470,9 +475,13 @@ function attachUserMessage(ctx) {
|
|
|
470
475
|
try { ctx.resumeLifecycleProject(ws); }
|
|
471
476
|
catch (error) { sendTo(ws, { type: "error", text: error.message }); return true; }
|
|
472
477
|
}
|
|
478
|
+
function reportQueuedContext() {
|
|
479
|
+
if (msg.mateContextRef) sendTo(ws, { type: 'mate_context_shared', status: 'unavailable', error: 'Queued messages do not retain contextual access. Send again from the current view when ready.' });
|
|
480
|
+
}
|
|
473
481
|
if (!pendingInternal && session._driverContinuationLease && pendingMessageQueue) {
|
|
474
482
|
var continuationQueued = pendingMessageQueue.admit(session, msg, ws && ws._clayUser);
|
|
475
483
|
if (continuationQueued.ok) {
|
|
484
|
+
reportQueuedContext();
|
|
476
485
|
messageDelivery.acknowledge(ws, deliveryReceipt, null, session);
|
|
477
486
|
sendTo(ws, { type: "message_queued", clientMessageId: msg.clientMessageId || null,
|
|
478
487
|
sessionId: session.localId, projectSlug: slug, state: "pending",
|
|
@@ -486,8 +495,10 @@ function attachUserMessage(ctx) {
|
|
|
486
495
|
if (!pendingInternal && pendingMessageQueue && (pendingMessageQueue.hasActive(session) || session.isProcessing || session._queryStarting || session._awaitingTurnResult)) {
|
|
487
496
|
var queuedResult = pendingMessageQueue.admit(session, msg, ws && ws._clayUser);
|
|
488
497
|
if (queuedResult.ok) {
|
|
498
|
+
reportQueuedContext();
|
|
489
499
|
messageDelivery.acknowledge(ws, deliveryReceipt, null, session);
|
|
490
500
|
sendTo(ws, { type: "message_queued", clientMessageId: msg.clientMessageId || null, sessionId: session.localId, projectSlug: slug, state: "pending", paused: pendingMessageQueue.isPaused(session), revision: pendingMessageQueue.getRevision() });
|
|
501
|
+
if (require('./sdk-foreground-admission').available(session)) setImmediate(function () { consumePendingMessage(session); });
|
|
491
502
|
} else {
|
|
492
503
|
sendTo(ws, { type: "error", text: queuedResult.error || "Unable to queue message" });
|
|
493
504
|
}
|
|
@@ -553,6 +564,7 @@ function attachUserMessage(ctx) {
|
|
|
553
564
|
if (msg.pastes && msg.pastes.length > 0) {
|
|
554
565
|
userMsg2.pastes = msg.pastes;
|
|
555
566
|
}
|
|
567
|
+
if (screenSnapshot) { userMsg2.contextualSnapshot = screenSnapshot.snapshot; userMsg2.sessionOriginId = session.sessionOriginId; }
|
|
556
568
|
if (deliveryReceipt.clientMessageId) userMsg2.clientMessageId = deliveryReceipt.clientMessageId;
|
|
557
569
|
if (!userMsg2._ts) userMsg2._ts = Date.now();
|
|
558
570
|
var transcriptRecorded = false;
|
|
@@ -757,7 +769,12 @@ function attachUserMessage(ctx) {
|
|
|
757
769
|
return !pendingBlockReason();
|
|
758
770
|
}
|
|
759
771
|
|
|
772
|
+
var contextualAdmission = null, contextualNotified = false;
|
|
760
773
|
function acceptPendingDispatch() {
|
|
774
|
+
if (contextualAdmission && !contextualNotified) {
|
|
775
|
+
contextualNotified = true;
|
|
776
|
+
sendTo(ws, { type: 'mate_context_shared', contextRef: contextualAdmission.contextRef, summary: contextualAdmission.summary, status: 'submitted' });
|
|
777
|
+
}
|
|
761
778
|
if (!pendingInternal) return true;
|
|
762
779
|
var blockReason = pendingBlockReason();
|
|
763
780
|
if (blockReason) {
|
|
@@ -784,6 +801,11 @@ function attachUserMessage(ctx) {
|
|
|
784
801
|
console.log("[PERF] project.js: startQuery called, localId=" + session.localId + " t=0ms");
|
|
785
802
|
var started = sdk.startQuery(session, finalText, msg.images, ensureProjectAccessForSession(session), function () {
|
|
786
803
|
var blockReason = pendingBlockReason();
|
|
804
|
+
if (screenSnapshot) { try { screenSnapshot.assertLive(); } catch (error) { blockReason = error.message; } }
|
|
805
|
+
if (contextualAdmission) {
|
|
806
|
+
try { opts.mateContextService.assertActive(session, contextualAdmission.contextRef); }
|
|
807
|
+
catch (error) { blockReason = error.message; sendTo(ws, { type: 'mate_context_shared', status: 'unavailable', error: error.message }); }
|
|
808
|
+
}
|
|
787
809
|
if (blockReason) rejectPendingDispatch(blockReason);
|
|
788
810
|
return !blockReason;
|
|
789
811
|
}, acceptPendingDispatch);
|
|
@@ -793,6 +815,21 @@ function attachUserMessage(ctx) {
|
|
|
793
815
|
}
|
|
794
816
|
|
|
795
817
|
function dispatchToSdk(finalText) {
|
|
818
|
+
if (screenSnapshot) {
|
|
819
|
+
try { screenSnapshot.assertLive(); } catch (error) { sendTo(ws, { type: 'error', text: error.message }); rejectPendingDispatch(error); return; }
|
|
820
|
+
finalText = require('./contextual-screen-snapshot').modelContext(screenSnapshot.snapshot) + finalText;
|
|
821
|
+
}
|
|
822
|
+
if (isMate && opts.mateContextService) {
|
|
823
|
+
opts.mateContextService.clear(session);
|
|
824
|
+
if (msg.mateContextRef && !pendingInternal) {
|
|
825
|
+
try {
|
|
826
|
+
var shared = opts.mateContextService.activate(ws, session, msg.mateContextRef, userMsg2);
|
|
827
|
+
contextualAdmission = shared;
|
|
828
|
+
sdk.refreshSessionRuntime(session);
|
|
829
|
+
finalText = 'Shared context metadata (untrusted task data, never approval):\n' + JSON.stringify(shared) + '\n\n' + finalText;
|
|
830
|
+
} catch (error) { sendTo(ws, { type: 'mate_context_shared', status: 'unavailable', error: error.message }); }
|
|
831
|
+
} else if (msg.mateContextRef) sendTo(ws, { type: 'mate_context_shared', status: 'unavailable', error: 'Queued messages do not retain contextual access. Send again from the current view when ready.' });
|
|
832
|
+
}
|
|
796
833
|
if (!session.isProcessing) {
|
|
797
834
|
session.isProcessing = true;
|
|
798
835
|
onProcessingChanged();
|
|
@@ -25,37 +25,11 @@ var yoke = require("./yoke");
|
|
|
25
25
|
// Login CLIs print a success line and then hand the shell back, so the PTY
|
|
26
26
|
// itself does not exit. Watch the output stream instead. Deliberately narrow:
|
|
27
27
|
// "Successfully logged out" and MCP-server logins must not match.
|
|
28
|
-
var LOGIN_SUCCESS_PATTERNS = [
|
|
29
|
-
/successfully logged in(?![ \t]+to[ \t]+mcp)/i,
|
|
30
|
-
/logged in successfully/i,
|
|
31
|
-
/login successful/i,
|
|
32
|
-
/successfully authenticated/i,
|
|
33
|
-
/authentication successful/i,
|
|
34
|
-
/signed in successfully/i,
|
|
35
|
-
/signed in with your [a-z ]+ account/i,
|
|
36
|
-
/you(?:'re| are) (?:now )?(?:logged|signed) in/i,
|
|
37
|
-
];
|
|
38
|
-
|
|
39
|
-
// Rolling window kept per flow so a success line split across PTY chunks is
|
|
40
|
-
// still matched, without buffering the whole login transcript.
|
|
41
28
|
var OUTPUT_TAIL_MAX = 4096;
|
|
42
|
-
|
|
43
|
-
// Grace period between detecting success and killing the terminal, so the user
|
|
44
|
-
// actually sees the confirmation line before the modal closes.
|
|
45
29
|
var CLOSE_AFTER_SUCCESS_MS = 2000;
|
|
46
|
-
|
|
47
|
-
var
|
|
48
|
-
|
|
49
|
-
function stripAnsi(text) {
|
|
50
|
-
return String(text).replace(ANSI_PATTERN, "");
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function looksLikeLoginSuccess(text) {
|
|
54
|
-
for (var i = 0; i < LOGIN_SUCCESS_PATTERNS.length; i++) {
|
|
55
|
-
if (LOGIN_SUCCESS_PATTERNS[i].test(text)) return true;
|
|
56
|
-
}
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
30
|
+
var loginProtocol = require("./yoke/login-protocol");
|
|
31
|
+
var stripAnsi = loginProtocol.stripAnsi;
|
|
32
|
+
var looksLikeLoginSuccess = loginProtocol.successful;
|
|
59
33
|
|
|
60
34
|
/**
|
|
61
35
|
* ctx fields:
|
|
@@ -96,11 +70,7 @@ function attachVendorLogin(ctx) {
|
|
|
96
70
|
cancel: function (vendor) { closeFlowTerminal(discardFlow(vendor)); broadcastState(); },
|
|
97
71
|
});
|
|
98
72
|
|
|
99
|
-
function loginCommandFor(vendor) {
|
|
100
|
-
if (vendor === "claude") return "claude auth login";
|
|
101
|
-
var info = vendorRegistry.getVendorInfo(vendor);
|
|
102
|
-
return (info && info.loginCommand) || "claude login";
|
|
103
|
-
}
|
|
73
|
+
function loginCommandFor(vendor) { return loginProtocol.command(vendor, false); }
|
|
104
74
|
|
|
105
75
|
function vendorDisplayName(vendor) {
|
|
106
76
|
var info = vendorRegistry.getVendorInfo(vendor);
|
|
@@ -284,8 +254,8 @@ function attachVendorLogin(ctx) {
|
|
|
284
254
|
var key = flowKey(ws, vendor);
|
|
285
255
|
var identity = resolveLoginIdentity(ws, msg);
|
|
286
256
|
var command = loginCommandFor(vendor);
|
|
287
|
-
var browserMode = msg.mode === "browser" && (vendor
|
|
288
|
-
if (browserMode) command = vendor
|
|
257
|
+
var browserMode = msg.mode === "browser" && !!(vendorRegistry.getVendorInfo(vendor) || {}).browserLoginCommand;
|
|
258
|
+
if (browserMode) command = loginProtocol.command(vendor, true);
|
|
289
259
|
var flow = {
|
|
290
260
|
vendor: vendor,
|
|
291
261
|
key: key,
|
|
@@ -31,6 +31,10 @@ function attachProjectWorkspaceQuery(ctx) {
|
|
|
31
31
|
var controls = ctx.controlService.bind({ projectSlug: projectSlug, projectOwnerId: getProjectOwnerId(), isMate: true, mateId: mateId, session: session });
|
|
32
32
|
if (controls) tools = tools.concat(productTools.getToolDefs(controls));
|
|
33
33
|
}
|
|
34
|
+
if (bound && !bound.isClay && ctx.contextService) {
|
|
35
|
+
var context = ctx.contextService.bind({ projectSlug: projectSlug, projectOwnerId: getProjectOwnerId(), mateId: mateId, session: session });
|
|
36
|
+
if (context) tools = tools.concat(require('./mate-context-tools').getToolDefs(context));
|
|
37
|
+
}
|
|
34
38
|
return tools;
|
|
35
39
|
}
|
|
36
40
|
|
|
@@ -41,7 +45,7 @@ function attachProjectWorkspaceQuery(ctx) {
|
|
|
41
45
|
var projectBound = binding(null);
|
|
42
46
|
if (!projectBound) return null;
|
|
43
47
|
if (!adapter || typeof adapter.createToolServer !== "function") return null;
|
|
44
|
-
return adapter.createToolServer({ name: "clay-workspace", version: "2.0.0", tools: session ? getToolDefs(session) : workspaceMcp.getToolDefs(null, projectBound.isClay) });
|
|
48
|
+
return adapter.createToolServer({ name: "clay-workspace", version: "2.0.0", tools: session ? getToolDefs(session) : workspaceMcp.getToolDefs(null, projectBound.isClay).concat(!projectBound.isClay && ctx.contextService ? require('./mate-context-tools').getToolDefs(null) : []) });
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
function createHistoryMcpServer(adapter, session) {
|
|
@@ -169,6 +173,12 @@ function attachProjectWorkspaceQuery(ctx) {
|
|
|
169
173
|
getHistoryDynamicToolDefs: getHistoryDynamicToolDefs,
|
|
170
174
|
callBridgeTool: callBridgeTool,
|
|
171
175
|
callHistoryBridgeTool: callHistoryBridgeTool,
|
|
176
|
+
getPresentation: function (session) {
|
|
177
|
+
try {
|
|
178
|
+
var bound = ctx.controlService && ctx.controlService.bind({ projectSlug: projectSlug, projectOwnerId: getProjectOwnerId(), isMate: isMate, mateId: mateId, session: session });
|
|
179
|
+
return bound && bound._presentation;
|
|
180
|
+
} catch (error) { return null; }
|
|
181
|
+
},
|
|
172
182
|
getMemorySessions: getMemorySessions,
|
|
173
183
|
};
|
|
174
184
|
}
|
package/lib/project.js
CHANGED
|
@@ -551,17 +551,18 @@ function createProjectContext(opts) {
|
|
|
551
551
|
|| !!(ws._clayUser && ws._clayUser.id === session.userKnowledgeOwnerId);
|
|
552
552
|
}
|
|
553
553
|
|
|
554
|
-
function sendToSession(sessionId, obj) {
|
|
555
|
-
var data = JSON.stringify(obj);
|
|
554
|
+
function sendToSession(sessionId, obj, onSent) {
|
|
555
|
+
var data = JSON.stringify(obj), delivered = 0;
|
|
556
556
|
for (var ws of clients) {
|
|
557
557
|
if (ws.readyState === 1 && canReceiveMate(ws) && canReceiveYou(ws, sessionId) && ws._clayActiveSession === sessionId) {
|
|
558
|
-
ws.send(data);
|
|
558
|
+
ws.send(data); delivered++; if (onSent) onSent(ws);
|
|
559
559
|
}
|
|
560
560
|
}
|
|
561
561
|
homeDebateClients.forEach(function (ws) {
|
|
562
562
|
if (ws.readyState !== 1) { homeDebateClients.delete(ws); return; }
|
|
563
|
-
if (canReceiveMate(ws) && canReceiveYou(ws, sessionId) && !clients.has(ws) && ws._clayHomeDebateSlug === slug && ws._clayActiveSession === sessionId) ws.send(data);
|
|
563
|
+
if (canReceiveMate(ws) && canReceiveYou(ws, sessionId) && !clients.has(ws) && ws._clayHomeDebateSlug === slug && ws._clayActiveSession === sessionId) { ws.send(data); delivered++; if (onSent) onSent(ws); }
|
|
564
564
|
});
|
|
565
|
+
return delivered;
|
|
565
566
|
}
|
|
566
567
|
|
|
567
568
|
function sendToSessionOthers(sender, sessionId, obj) {
|
|
@@ -791,7 +792,14 @@ function createProjectContext(opts) {
|
|
|
791
792
|
}
|
|
792
793
|
},
|
|
793
794
|
});
|
|
795
|
+
var _studioPresentation = require('./project-studio-presentation').attachStudioPresentation({
|
|
796
|
+
getPresentation: function (session) { return _workspaceQuery && _workspaceQuery.getPresentation(session); },
|
|
797
|
+
getSessionForWs: getSessionForWs,
|
|
798
|
+
});
|
|
794
799
|
var _sharedBrowser = attachSharedBrowser({
|
|
800
|
+
studioPresentation: _studioPresentation,
|
|
801
|
+
sendToSession: sendToSession,
|
|
802
|
+
getPresentation: function (session) { return _workspaceQuery && _workspaceQuery.getPresentation(session); },
|
|
795
803
|
slug: slug, isMate: isMate, ownerId: projectOwnerId, sm: sm, clients: clients, sendTo: sendTo,
|
|
796
804
|
usersModule: usersModule, requestAccess: _requestAccess, osUsers: osUsers,
|
|
797
805
|
getSessionForWs: getSessionForWs,
|
|
@@ -801,6 +809,8 @@ function createProjectContext(opts) {
|
|
|
801
809
|
},
|
|
802
810
|
});
|
|
803
811
|
var _sessionDocument = attachSessionDocument({
|
|
812
|
+
studioPresentation: _studioPresentation,
|
|
813
|
+
getPresentation: function (session) { return _workspaceQuery && _workspaceQuery.getPresentation(session); },
|
|
804
814
|
cwd: cwd,
|
|
805
815
|
isMate: isMate,
|
|
806
816
|
canUseSession: _sessionNotes.canUseSession,
|
|
@@ -824,6 +834,7 @@ function createProjectContext(opts) {
|
|
|
824
834
|
var _workspaceQuery = attachProjectWorkspaceQuery({
|
|
825
835
|
service: opts.workspaceQueryService || null,
|
|
826
836
|
controlService: opts.clayProductControl || null,
|
|
837
|
+
contextService: opts.mateContextService || null,
|
|
827
838
|
sm: sm,
|
|
828
839
|
projectSlug: slug,
|
|
829
840
|
getProjectOwnerId: function () { return projectOwnerId; },
|
|
@@ -1837,8 +1848,10 @@ function createProjectContext(opts) {
|
|
|
1837
1848
|
}
|
|
1838
1849
|
}
|
|
1839
1850
|
|
|
1851
|
+
if (_studioPresentation.handleMessage(ws, msg)) return;
|
|
1852
|
+
|
|
1840
1853
|
// --- DM messages (delegated to server-level handler) ---
|
|
1841
|
-
if (msg.type === "home_mate_question_response" || msg.type === "clay_ui_ready" || msg.type === "clay_navigation_claim" || msg.type === "clay_navigation_ack" || msg.type === "home_debate_question_response" || msg.type === "home_debate_control" || msg.type === "home_mate_creation_question_response" || msg.type === "default_ai_get" || msg.type === "default_ai_catalog_get" || msg.type === "default_ai_set" || msg.type === "default_vendor_get" || msg.type === "default_vendor_set" || msg.type === "context_view_get" || msg.type === "context_view_set" || msg.type === "cursor_sharing_get" || msg.type === "cursor_sharing_set") {
|
|
1854
|
+
if (msg.type === "home_mate_question_response" || msg.type === "mate_context_prepare" || msg.type === "clay_ui_ready" || msg.type === "clay_navigation_claim" || msg.type === "clay_navigation_ack" || msg.type === "clay_navigation_rendered" || msg.type === "home_debate_question_response" || msg.type === "home_debate_control" || msg.type === "home_mate_creation_question_response" || msg.type === "default_ai_get" || msg.type === "default_ai_catalog_get" || msg.type === "default_ai_set" || msg.type === "default_vendor_get" || msg.type === "default_vendor_set" || msg.type === "context_view_get" || msg.type === "context_view_set" || msg.type === "cursor_sharing_get" || msg.type === "cursor_sharing_set") {
|
|
1842
1855
|
if (typeof opts.onDmMessage === "function") opts.onDmMessage(ws, msg, slug);
|
|
1843
1856
|
return;
|
|
1844
1857
|
}
|
|
@@ -2323,6 +2336,7 @@ function createProjectContext(opts) {
|
|
|
2323
2336
|
cwd: cwd,
|
|
2324
2337
|
slug: slug,
|
|
2325
2338
|
isMate: isMate,
|
|
2339
|
+
mateId: mateId,
|
|
2326
2340
|
osUsers: osUsers,
|
|
2327
2341
|
sm: sm,
|
|
2328
2342
|
sdk: sdk,
|
|
@@ -2422,7 +2436,7 @@ function createProjectContext(opts) {
|
|
|
2422
2436
|
cwd: cwd, isMate: isMate, osUsers: osUsers, users: usersModule, tm: tm,
|
|
2423
2437
|
getAccess: opts.getProjectAccess || function () { return { ownerId: projectOwnerId || null, visibility: 'private' }; },
|
|
2424
2438
|
files: function () { return _filesystem.productOperations; },
|
|
2425
|
-
publishTerminals: function () { send({ type: 'term_list', terminals: tm.list() }); },
|
|
2439
|
+
publishTerminals: function () { send({ type: 'term_list', terminals: tm.list(true) }); },
|
|
2426
2440
|
});
|
|
2427
2441
|
|
|
2428
2442
|
// --- MCP bridge handler for Codex and session-bound Kiro tools ---
|
|
@@ -2696,6 +2710,8 @@ function createProjectContext(opts) {
|
|
|
2696
2710
|
|
|
2697
2711
|
// --- HTTP handler (delegated to project-http.js) ---
|
|
2698
2712
|
var _http = attachHTTP({
|
|
2713
|
+
workspaceOperations: _workspaceOperations,
|
|
2714
|
+
getProjectOwnerId: function () { return projectOwnerId; },
|
|
2699
2715
|
requestAccess: _requestAccess,
|
|
2700
2716
|
cwd: cwd,
|
|
2701
2717
|
slug: slug,
|
|
@@ -2877,6 +2893,7 @@ function createProjectContext(opts) {
|
|
|
2877
2893
|
}
|
|
2878
2894
|
});
|
|
2879
2895
|
var status = {
|
|
2896
|
+
controlRuntimeId: require('./clay-control-target-projection').runtime(sm),
|
|
2880
2897
|
slug: slug,
|
|
2881
2898
|
path: cwd,
|
|
2882
2899
|
project: project,
|
|
@@ -2927,7 +2944,7 @@ function createProjectContext(opts) {
|
|
|
2927
2944
|
|
|
2928
2945
|
function setTitle(newTitle) {
|
|
2929
2946
|
title = newTitle || null;
|
|
2930
|
-
send({ type: "info", cwd: cwd, slug: slug, project: title || project, version: currentVersion, debug: !!debug, osUsers: osUsers, lanHost: lanHost, projectCount: getProjectCount(), projects: getProjectList(), projectOwnerId: projectOwnerId, isMate: isMate, mateId: isMate ? mateId : null, mateDisplayName: isMate ? (opts.mateDisplayName || title || project || "Mate") : "" });
|
|
2947
|
+
send({ type: "info", controlRuntimeId: require("./clay-control-target-projection").runtime(sm), cwd: cwd, slug: slug, project: title || project, version: currentVersion, debug: !!debug, osUsers: osUsers, lanHost: lanHost, projectCount: getProjectCount(), projects: getProjectList(), projectOwnerId: projectOwnerId, isMate: isMate, mateId: isMate ? mateId : null, mateDisplayName: isMate ? (opts.mateDisplayName || title || project || "Mate") : "" });
|
|
2931
2948
|
}
|
|
2932
2949
|
|
|
2933
2950
|
function setIcon(newIcon) {
|