clay-server 3.8.1 → 4.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/ask-user-mcp-server.js +5 -119
- package/lib/background-task-timing.js +105 -0
- package/lib/builtin-mates.js +6 -6
- package/lib/claude-hook-installer.js +15 -0
- package/lib/clay-history-mcp-server.js +62 -297
- package/lib/daemon.js +23 -1
- package/lib/debate-model-selection.js +119 -0
- package/lib/home-debate-tool-policy.js +164 -0
- package/lib/home-response-notifications.js +26 -0
- package/lib/knowledge-import.js +436 -0
- package/lib/knowledge-record-store.js +188 -0
- package/lib/knowledge-search.js +224 -0
- package/lib/mate-creation-mcp-server.js +55 -0
- package/lib/mate-knowledge-mcp-server.js +151 -0
- package/lib/mate-knowledge-migration.js +283 -0
- package/lib/mate-knowledge-service.js +488 -0
- package/lib/mate-knowledge-sync.js +482 -0
- package/lib/mate-ready-creation.js +95 -0
- package/lib/mates.js +2 -0
- package/lib/notes.js +2 -1
- package/lib/project-ask-user.js +64 -0
- package/lib/project-capsule-catalog.js +101 -0
- package/lib/project-connection.js +17 -0
- package/lib/project-debate-proposal.js +133 -17
- package/lib/project-debate.js +214 -110
- package/lib/project-delegated-follow-up.js +84 -0
- package/lib/project-delegated-session.js +53 -0
- package/lib/project-filesystem.js +7 -9
- package/lib/project-knowledge.js +23 -0
- package/lib/project-logs-comments.js +137 -0
- package/lib/project-logs-mcp-server.js +290 -0
- package/lib/project-logs-query.js +167 -0
- package/lib/project-logs-root.js +67 -0
- package/lib/project-logs-schema.js +259 -0
- package/lib/project-logs-service.js +357 -0
- package/lib/project-logs-snapshot.js +202 -0
- package/lib/project-logs-store.js +498 -0
- package/lib/project-logs-versioning.js +128 -0
- package/lib/project-logs.js +347 -0
- package/lib/project-mate-creation-proposal.js +120 -0
- package/lib/project-mate-interaction.js +14 -0
- package/lib/project-mate-knowledge.js +110 -0
- package/lib/project-memory.js +36 -7
- package/lib/project-models.js +157 -32
- package/lib/project-session-notes.js +2 -2
- package/lib/project-session-pair.js +8 -8
- package/lib/project-sessions.js +66 -51
- package/lib/project-vendor-login.js +414 -0
- package/lib/project-worker-proposal.js +25 -25
- package/lib/project-workspace-query.js +144 -0
- package/lib/project.js +433 -102
- package/lib/public/app.js +109 -48
- package/lib/public/css/avatar-imprints.css +0 -1
- package/lib/public/css/base.css +4 -0
- package/lib/public/css/capsule-ui.css +389 -0
- package/lib/public/css/command-palette.css +306 -6
- package/lib/public/css/home-capsule-library.css +243 -0
- package/lib/public/css/home-capsule-source.css +192 -0
- package/lib/public/css/home-debate-live.css +146 -0
- package/lib/public/css/home-debate-planning.css +125 -0
- package/lib/public/css/home-debates-archive.css +281 -0
- package/lib/public/css/home-hub.css +896 -405
- package/lib/public/css/home-mate-creation.css +34 -0
- package/lib/public/css/home-mate-model-picker.css +131 -0
- package/lib/public/css/home-mate-settings.css +344 -0
- package/lib/public/css/home-session-actions.css +265 -0
- package/lib/public/css/home-sidebar.css +667 -0
- package/lib/public/css/icon-strip.css +1 -2
- package/lib/public/css/input.css +79 -25
- package/lib/public/css/mates.css +7 -34
- package/lib/public/css/pane.css +1 -1
- package/lib/public/css/playbook.css +0 -80
- package/lib/public/css/project-logs.css +234 -0
- package/lib/public/css/scheduler.css +1 -1
- package/lib/public/css/sticky-notes.css +53 -117
- package/lib/public/css/tui-attention.css +0 -44
- package/lib/public/css/workspace-assignment.css +45 -0
- package/lib/public/fonts/source-serif-4/LICENSE.md +93 -0
- package/lib/public/fonts/source-serif-4/SourceSerif4Caption-Semibold.ttf.woff2 +0 -0
- package/lib/public/index.html +96 -74
- package/lib/public/modules/app-connection.js +100 -5
- package/lib/public/modules/app-dm.js +43 -160
- package/lib/public/modules/app-home-hub.js +328 -585
- package/lib/public/modules/app-message-cards.js +242 -0
- package/lib/public/modules/app-message-router.js +84 -0
- package/lib/public/modules/app-messages.js +124 -38
- package/lib/public/modules/app-notifications.js +8 -119
- package/lib/public/modules/app-panels.js +43 -2
- package/lib/public/modules/app-projects.js +9 -1
- package/lib/public/modules/app-rendering.js +21 -602
- package/lib/public/modules/avatar-imprint.js +11 -8
- package/lib/public/modules/background-tasks-ui.js +139 -16
- package/lib/public/modules/chat-bubble-renderer.js +152 -0
- package/lib/public/modules/chat-render-runtime.js +198 -0
- package/lib/public/modules/command-palette.js +225 -436
- package/lib/public/modules/dm-render.js +82 -0
- package/lib/public/modules/home-capsule-creation-intent.js +31 -0
- package/lib/public/modules/home-capsule-library.js +146 -0
- package/lib/public/modules/home-capsule-source.js +383 -0
- package/lib/public/modules/home-chat-identity.js +35 -0
- package/lib/public/modules/home-chat-scroll.js +77 -0
- package/lib/public/modules/home-chat-stream-state.js +34 -0
- package/lib/public/modules/home-composer-focus.js +25 -0
- package/lib/public/modules/home-conversations-sheet.js +179 -0
- package/lib/public/modules/home-debate-activity.js +48 -0
- package/lib/public/modules/home-debate-controls.js +295 -0
- package/lib/public/modules/home-debate-launch.js +41 -0
- package/lib/public/modules/home-debate-live.js +284 -0
- package/lib/public/modules/home-debate-models.js +73 -0
- package/lib/public/modules/home-debate-planning.js +335 -0
- package/lib/public/modules/home-debates-archive.js +279 -0
- package/lib/public/modules/home-dock-resize.js +74 -0
- package/lib/public/modules/home-dock.js +446 -0
- package/lib/public/modules/home-mate-chat.js +496 -0
- package/lib/public/modules/home-mate-creation.js +109 -0
- package/lib/public/modules/home-mate-model-picker.js +281 -0
- package/lib/public/modules/home-mate-selection.js +38 -0
- package/lib/public/modules/home-mate-settings-menu.js +131 -0
- package/lib/public/modules/home-mate-settings.js +383 -0
- package/lib/public/modules/home-session-actions.js +373 -0
- package/lib/public/modules/home-session-model-confirmation.js +13 -0
- package/lib/public/modules/home-shell.js +9 -0
- package/lib/public/modules/home-sidebar-chat-list.js +63 -0
- package/lib/public/modules/home-sidebar.js +165 -0
- package/lib/public/modules/home-sub-surface.js +19 -0
- package/lib/public/modules/home-surface-boot.js +68 -0
- package/lib/public/modules/home-surface.js +141 -0
- package/lib/public/modules/home-tools.js +271 -0
- package/lib/public/modules/markdown.js +50 -2
- package/lib/public/modules/mate-management.js +86 -0
- package/lib/public/modules/mate-sidebar.js +0 -8
- package/lib/public/modules/mate-wizard.js +0 -7
- package/lib/public/modules/mention.js +17 -19
- package/lib/public/modules/pane-bridge.js +9 -0
- package/lib/public/modules/profile.js +4 -5
- package/lib/public/modules/project-logs-ambient.js +238 -0
- package/lib/public/modules/project-logs-render.js +359 -0
- package/lib/public/modules/project-logs.js +328 -0
- package/lib/public/modules/project-settings.js +34 -28
- package/lib/public/modules/project-switcher.js +11 -5
- package/lib/public/modules/project-workspace-assignment.js +23 -0
- package/lib/public/modules/scheduler.js +17 -3
- package/lib/public/modules/search-clay-chat.js +402 -0
- package/lib/public/modules/server-settings.js +14 -12
- package/lib/public/modules/session-actions.js +1 -1
- package/lib/public/modules/sidebar-mates.js +56 -552
- package/lib/public/modules/sidebar-mobile.js +12 -73
- package/lib/public/modules/sidebar-presence.js +37 -0
- package/lib/public/modules/sidebar-sessions.js +25 -1
- package/lib/public/modules/split-pair-ui.js +13 -13
- package/lib/public/modules/split-view.js +7 -0
- package/lib/public/modules/sticky-notes.js +106 -53
- package/lib/public/modules/tool-input-composition.js +48 -0
- package/lib/public/modules/tool-llm-status.js +167 -0
- package/lib/public/modules/tool-palette.js +76 -4
- package/lib/public/modules/tool-renderer-advanced.js +285 -0
- package/lib/public/modules/tool-renderer-chart.js +158 -0
- package/lib/public/modules/tool-renderer-semantics.js +35 -0
- package/lib/public/modules/tool-renderer.js +464 -0
- package/lib/public/modules/tool-runtime.js +309 -0
- package/lib/public/modules/tool-ui-evaluator.js +97 -0
- package/lib/public/modules/tool-ui-tree.js +21 -0
- package/lib/public/modules/tui-attention.js +10 -0
- package/lib/public/modules/user-settings.js +16 -23
- package/lib/public/modules/vendor-login.js +287 -0
- package/lib/public/modules/worker-proposal.js +2 -2
- package/lib/public/modules/workspace-assignment-card.js +149 -0
- package/lib/public/modules/workspace-assignment-routing.js +4 -0
- package/lib/public/style.css +14 -2
- package/lib/runtime-env.js +65 -0
- package/lib/sdk-bridge.js +120 -32
- package/lib/sdk-message-processor.js +34 -13
- package/lib/server-home-capsule-creation.js +36 -0
- package/lib/server-home-chat-events.js +287 -0
- package/lib/server-home-chat.js +518 -0
- package/lib/server-home-clay-entry.js +65 -0
- package/lib/server-home-clay-session-links.js +26 -0
- package/lib/server-home-debate-planning.js +214 -0
- package/lib/server-home-debates.js +137 -0
- package/lib/server-home-mate-creation.js +261 -0
- package/lib/server-home-models.js +241 -0
- package/lib/server-home-preferences.js +61 -0
- package/lib/server-mates.js +37 -0
- package/lib/server-tools.js +377 -0
- package/lib/server.js +166 -59
- package/lib/session-pair-mcp-server.js +6 -6
- package/lib/sessions.js +22 -4
- package/lib/tool-capsule-source.js +142 -0
- package/lib/tool-control-mcp-server.js +126 -0
- package/lib/tool-llm.js +48 -0
- package/lib/tool-storage.js +77 -0
- package/lib/tool-ui-spec-advanced.js +82 -0
- package/lib/tool-ui-spec.js +261 -0
- package/lib/tools-registry.js +286 -0
- package/lib/users-home-dock-preferences.js +77 -0
- package/lib/users-home-surface-preferences.js +99 -0
- package/lib/users-preferences.js +4 -7
- package/lib/users.js +12 -0
- package/lib/whats-new-content.js +3 -3
- package/lib/workspace-assignment-service.js +420 -0
- package/lib/workspace-query-mcp-server.js +154 -0
- package/lib/workspace-query-service.js +492 -0
- package/lib/ws-schema.js +107 -12
- package/lib/yoke/adapters/acp.js +2 -1
- package/lib/yoke/adapters/antigravity.js +2 -1
- package/lib/yoke/adapters/claude-worker.js +11 -4
- package/lib/yoke/adapters/claude.js +141 -46
- package/lib/yoke/adapters/codex.js +79 -11
- package/lib/yoke/adapters/kiro.js +2 -1
- package/lib/yoke/claude-user-input.js +38 -0
- package/lib/yoke/codex-app-server.js +20 -2
- package/lib/yoke/codex-background-tasks.js +8 -2
- package/lib/yoke/codex-user-input.js +64 -0
- package/lib/yoke/complete-once.js +164 -0
- package/lib/yoke/index.js +5 -1
- package/lib/yoke/interface.js +19 -0
- package/lib/yoke/mcp-bridge-server.js +2 -6
- package/lib/yoke/user-input.js +254 -0
- package/package.json +4 -3
- package/lib/public/css/home-chat.css +0 -380
- package/lib/public/modules/home-chat.js +0 -438
- package/lib/server-clay-home.js +0 -245
|
@@ -1,313 +1,78 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
// Tools that let the Clay host agent search and read across the user's
|
|
4
|
-
// entire workspace (sessions, project memory, decision history). Scoped
|
|
5
|
-
// strictly to the active user's data via the projectSessions accessor;
|
|
6
|
-
// the Clay session never reads other users' files.
|
|
7
|
-
//
|
|
8
|
-
// Mounted only on host-agent mate projects (def.hostAgent === true), so
|
|
9
|
-
// regular Mates and project sessions never see these tools.
|
|
10
|
-
//
|
|
11
|
-
// Usage:
|
|
12
|
-
// var clayHistoryMcp = require("./clay-history-mcp-server");
|
|
13
|
-
// var tools = clayHistoryMcp.getToolDefs({ getAllProjectsWithSessions: ..., readSessionRange: ... });
|
|
14
|
-
// var mcpConfig = adapter.createToolServer({ name: "clay-history", version: "1.0.0", tools: tools });
|
|
15
|
-
|
|
16
|
-
var fs = require("fs");
|
|
17
|
-
var path = require("path");
|
|
18
|
-
var sessionSearch = require("./session-search");
|
|
1
|
+
// Compatibility MCP surface for existing builtin Clay prompts. All reads
|
|
2
|
+
// delegate to the same exact-owner workspace query binding as clay-workspace.
|
|
19
3
|
|
|
20
4
|
var z;
|
|
21
5
|
try { z = require("zod"); } catch (e) { z = null; }
|
|
22
6
|
|
|
23
|
-
function
|
|
7
|
+
function field(type, description, optional) {
|
|
24
8
|
if (!z) return {};
|
|
25
|
-
var
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
var k = keys[i];
|
|
29
|
-
var p = props[k];
|
|
30
|
-
var field;
|
|
31
|
-
if (p.type === "number") field = z.number();
|
|
32
|
-
else if (p.type === "boolean") field = z.boolean();
|
|
33
|
-
else if (p.enum) field = z.enum(p.enum);
|
|
34
|
-
else field = z.string();
|
|
35
|
-
if (p.description) field = field.describe(p.description);
|
|
36
|
-
if (!required || required.indexOf(k) === -1) field = field.optional();
|
|
37
|
-
shape[k] = field;
|
|
38
|
-
}
|
|
39
|
-
return shape;
|
|
9
|
+
var value = type === "number" ? z.number() : z.string();
|
|
10
|
+
if (description) value = value.describe(description);
|
|
11
|
+
return optional ? value.optional() : value;
|
|
40
12
|
}
|
|
41
13
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
/\bdecided\s+to\b/i,
|
|
46
|
-
/\bdecision\b/i,
|
|
47
|
-
/\bgoing\s+with\b/i,
|
|
48
|
-
/\bsettled\s+on\b/i,
|
|
49
|
-
/\bchose\s+to\b/i,
|
|
50
|
-
/\bwill\s+go\s+with\b/i,
|
|
51
|
-
/\blet'?s\s+go\s+with\b/i,
|
|
52
|
-
/\b결정\b/, // Korean "decision"
|
|
53
|
-
/\b정했\b/, // Korean "settled/chose"
|
|
54
|
-
/\b이걸로\s+가/, // Korean "going with this"
|
|
55
|
-
];
|
|
14
|
+
function result(value) {
|
|
15
|
+
return Promise.resolve({ content: [{ type: "text", text: JSON.stringify(value) }] });
|
|
16
|
+
}
|
|
56
17
|
|
|
57
|
-
function
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
throw new Error("clay-history-mcp-server requires getAllProjectsWithSessions");
|
|
61
|
-
}
|
|
18
|
+
function error(value) {
|
|
19
|
+
return Promise.resolve({ content: [{ type: "text", text: "Error: " + value }], isError: true });
|
|
20
|
+
}
|
|
62
21
|
|
|
63
|
-
|
|
22
|
+
function guarded(workspace, method, mapArgs) {
|
|
23
|
+
return function (args) {
|
|
24
|
+
if (!workspace || workspace.isClay !== true || typeof workspace[method] !== "function") {
|
|
25
|
+
return error("Clay history requires an exact session-bound builtin Clay query.");
|
|
26
|
+
}
|
|
27
|
+
try { return result(workspace[method](mapArgs ? mapArgs(args || {}) : (args || {}))); }
|
|
28
|
+
catch (e) { return error(e && e.message ? e.message : String(e)); }
|
|
29
|
+
};
|
|
30
|
+
}
|
|
64
31
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
handler: function (args) {
|
|
81
|
-
try {
|
|
82
|
-
var query = (args.query || "").trim();
|
|
83
|
-
if (!query) {
|
|
84
|
-
return Promise.resolve({
|
|
85
|
-
content: [{ type: "text", text: "Empty query." }],
|
|
86
|
-
isError: true,
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
var maxResults = Math.min(50, Math.max(1, args.maxResults || 20));
|
|
90
|
-
var projectSessions = getAllProjectsWithSessions();
|
|
91
|
-
if (args.projectSlug) {
|
|
92
|
-
projectSessions = projectSessions.filter(function (p) {
|
|
93
|
-
return p.projectSlug === args.projectSlug;
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
var sinceMs = parseTime(args.since);
|
|
97
|
-
var untilMs = parseTime(args.until);
|
|
98
|
-
if (sinceMs != null || untilMs != null) {
|
|
99
|
-
projectSessions = projectSessions.map(function (p) {
|
|
100
|
-
var filtered = (p.sessions || []).filter(function (s) {
|
|
101
|
-
var t = s.lastActivity || s.createdAt || 0;
|
|
102
|
-
if (sinceMs != null && t < sinceMs) return false;
|
|
103
|
-
if (untilMs != null && t > untilMs) return false;
|
|
104
|
-
return true;
|
|
105
|
-
});
|
|
106
|
-
return Object.assign({}, p, { sessions: filtered });
|
|
107
|
-
}).filter(function (p) { return p.sessions.length > 0; });
|
|
108
|
-
}
|
|
109
|
-
var results = sessionSearch.searchPalette(projectSessions, query, { maxResults: maxResults });
|
|
110
|
-
if (results.length === 0) {
|
|
111
|
-
return Promise.resolve({
|
|
112
|
-
content: [{ type: "text", text: "No matches for: " + query }],
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
var lines = results.map(function (r) {
|
|
116
|
-
var when = r.lastActivity ? new Date(r.lastActivity).toISOString().slice(0, 10) : "";
|
|
117
|
-
var ref = "[" + r.projectSlug + "/" + r.sessionId + " — " + when + "]";
|
|
118
|
-
var head = r.sessionTitle || "(untitled)";
|
|
119
|
-
var body = r.snippet ? r.snippet.replace(/\s+/g, " ").trim() : "";
|
|
120
|
-
if (body.length > 220) body = body.substring(0, 220) + "...";
|
|
121
|
-
return ref + " " + head + (body ? " — " + body : "");
|
|
122
|
-
});
|
|
123
|
-
return Promise.resolve({
|
|
124
|
-
content: [{ type: "text", text: lines.join("\n") }],
|
|
125
|
-
});
|
|
126
|
-
} catch (e) {
|
|
127
|
-
return Promise.resolve({
|
|
128
|
-
content: [{ type: "text", text: "Search failed: " + (e.message || String(e)) }],
|
|
129
|
-
isError: true,
|
|
130
|
-
});
|
|
131
|
-
}
|
|
32
|
+
function getToolDefs(deps) {
|
|
33
|
+
var workspace = deps && deps.workspace;
|
|
34
|
+
return [
|
|
35
|
+
{
|
|
36
|
+
name: "search_clay_history",
|
|
37
|
+
description: "Search canonical user and assistant text across projects owned by the current user. Returns sanitized snippets and opaque session references.",
|
|
38
|
+
inputSchema: z ? {
|
|
39
|
+
query: field("string", "Search query."),
|
|
40
|
+
projectSlug: field("string", "Optional project slug.", true),
|
|
41
|
+
maxResults: field("number", "Maximum results, from 1 to 50.", true),
|
|
42
|
+
} : {},
|
|
43
|
+
handler: guarded(workspace, "searchWorkspaceHistory", function (args) {
|
|
44
|
+
if (args.projectSlug) return { projectSlug: args.projectSlug, query: args.query, limit: args.maxResults };
|
|
45
|
+
return { query: args.query, limit: args.maxResults };
|
|
46
|
+
}),
|
|
132
47
|
},
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}, ["projectSlug", "sessionId"]),
|
|
147
|
-
handler: function (args) {
|
|
148
|
-
try {
|
|
149
|
-
var projectSlug = args.projectSlug;
|
|
150
|
-
var sessionId = args.sessionId;
|
|
151
|
-
var offset = Math.max(0, args.offset || 0);
|
|
152
|
-
var limit = Math.min(100, Math.max(1, args.limit || 30));
|
|
153
|
-
|
|
154
|
-
var projectSessions = getAllProjectsWithSessions();
|
|
155
|
-
var found = null;
|
|
156
|
-
for (var p = 0; p < projectSessions.length; p++) {
|
|
157
|
-
if (projectSessions[p].projectSlug !== projectSlug) continue;
|
|
158
|
-
var sessions = projectSessions[p].sessions || [];
|
|
159
|
-
for (var s = 0; s < sessions.length; s++) {
|
|
160
|
-
if (sessions[s].localId === sessionId) {
|
|
161
|
-
found = { project: projectSessions[p], session: sessions[s] };
|
|
162
|
-
break;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
if (found) break;
|
|
166
|
-
}
|
|
167
|
-
if (!found) {
|
|
168
|
-
return Promise.resolve({
|
|
169
|
-
content: [{ type: "text", text: "Session not found: " + projectSlug + "/" + sessionId }],
|
|
170
|
-
isError: true,
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
var history = found.session.history || [];
|
|
174
|
-
var slice = history.slice(offset, offset + limit);
|
|
175
|
-
if (slice.length === 0) {
|
|
176
|
-
return Promise.resolve({
|
|
177
|
-
content: [{ type: "text", text: "No turns in window (offset=" + offset + ", limit=" + limit + ", total=" + history.length + ")." }],
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
var out = [];
|
|
181
|
-
out.push("# " + (found.session.title || "untitled") + " — " + projectSlug + "/" + sessionId);
|
|
182
|
-
out.push("Showing turns " + (offset + 1) + "-" + (offset + slice.length) + " of " + history.length + "\n");
|
|
183
|
-
for (var i = 0; i < slice.length; i++) {
|
|
184
|
-
var entry = slice[i];
|
|
185
|
-
var label;
|
|
186
|
-
var text = "";
|
|
187
|
-
if (entry.type === "user_message") {
|
|
188
|
-
label = "USER";
|
|
189
|
-
text = entry.text || "";
|
|
190
|
-
} else if (entry.type === "delta") {
|
|
191
|
-
label = "ASSISTANT";
|
|
192
|
-
text = entry.text || "";
|
|
193
|
-
} else if (entry.type === "tool_executing" || entry.type === "tool_result") {
|
|
194
|
-
label = "TOOL";
|
|
195
|
-
text = (entry.name || "") + (entry.input ? " " + JSON.stringify(entry.input).substring(0, 120) : "");
|
|
196
|
-
} else {
|
|
197
|
-
continue;
|
|
198
|
-
}
|
|
199
|
-
if (text.length > 800) text = text.substring(0, 800) + "...";
|
|
200
|
-
out.push("[" + label + "] " + text);
|
|
201
|
-
}
|
|
202
|
-
return Promise.resolve({
|
|
203
|
-
content: [{ type: "text", text: out.join("\n") }],
|
|
204
|
-
});
|
|
205
|
-
} catch (e) {
|
|
206
|
-
return Promise.resolve({
|
|
207
|
-
content: [{ type: "text", text: "read_session failed: " + (e.message || String(e)) }],
|
|
208
|
-
isError: true,
|
|
209
|
-
});
|
|
210
|
-
}
|
|
48
|
+
{
|
|
49
|
+
name: "read_session",
|
|
50
|
+
description: "Read canonical user and assistant turns from an owned session. Raw tool payloads and internal prompts are excluded.",
|
|
51
|
+
inputSchema: z ? {
|
|
52
|
+
projectSlug: field("string", "Exact project slug."),
|
|
53
|
+
sessionId: field("string", "Opaque session reference returned by search_clay_history."),
|
|
54
|
+
offset: field("number", "Legacy numeric turn offset.", true),
|
|
55
|
+
limit: field("number", "Maximum turns, from 1 to 50.", true),
|
|
56
|
+
} : {},
|
|
57
|
+
handler: guarded(workspace, "readProjectSession", function (args) {
|
|
58
|
+
var cursor = args.offset > 0 ? Buffer.from(String(Math.floor(args.offset)), "utf8").toString("base64url") : null;
|
|
59
|
+
return { projectSlug: args.projectSlug, sessionRef: args.sessionId, cursor: cursor, limit: args.limit };
|
|
60
|
+
}),
|
|
211
61
|
},
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
until: { type: "string", description: "Optional. Latest activity date." },
|
|
225
|
-
maxResults: { type: "number", description: "Optional. Default 15, max 30." },
|
|
226
|
-
}),
|
|
227
|
-
handler: function (args) {
|
|
228
|
-
try {
|
|
229
|
-
var maxResults = Math.min(30, Math.max(1, args.maxResults || 15));
|
|
230
|
-
var sinceMs = parseTime(args.since);
|
|
231
|
-
var untilMs = parseTime(args.until);
|
|
232
|
-
var projectSessions = getAllProjectsWithSessions();
|
|
233
|
-
if (args.projectSlug) {
|
|
234
|
-
projectSessions = projectSessions.filter(function (p) {
|
|
235
|
-
return p.projectSlug === args.projectSlug;
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
var hits = [];
|
|
239
|
-
for (var p = 0; p < projectSessions.length; p++) {
|
|
240
|
-
var proj = projectSessions[p];
|
|
241
|
-
var sessions = proj.sessions || [];
|
|
242
|
-
for (var s = 0; s < sessions.length; s++) {
|
|
243
|
-
var session = sessions[s];
|
|
244
|
-
var t = session.lastActivity || session.createdAt || 0;
|
|
245
|
-
if (sinceMs != null && t < sinceMs) continue;
|
|
246
|
-
if (untilMs != null && t > untilMs) continue;
|
|
247
|
-
var history = session.history || [];
|
|
248
|
-
for (var h = 0; h < history.length; h++) {
|
|
249
|
-
var entry = history[h];
|
|
250
|
-
if (entry.type !== "user_message" && entry.type !== "delta") continue;
|
|
251
|
-
var text = entry.text || "";
|
|
252
|
-
if (!text) continue;
|
|
253
|
-
if (!matchesDecisionPattern(text)) continue;
|
|
254
|
-
hits.push({
|
|
255
|
-
projectSlug: proj.projectSlug,
|
|
256
|
-
projectTitle: proj.projectTitle,
|
|
257
|
-
sessionId: session.localId,
|
|
258
|
-
sessionTitle: session.title || "(untitled)",
|
|
259
|
-
lastActivity: t,
|
|
260
|
-
turnIdx: h,
|
|
261
|
-
turnType: entry.type === "user_message" ? "user" : "assistant",
|
|
262
|
-
text: text,
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
hits.sort(function (a, b) { return b.lastActivity - a.lastActivity; });
|
|
268
|
-
if (hits.length > maxResults) hits = hits.slice(0, maxResults);
|
|
269
|
-
if (hits.length === 0) {
|
|
270
|
-
return Promise.resolve({
|
|
271
|
-
content: [{ type: "text", text: "No decision-pattern matches in scope." }],
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
var lines = hits.map(function (h) {
|
|
275
|
-
var when = h.lastActivity ? new Date(h.lastActivity).toISOString().slice(0, 10) : "";
|
|
276
|
-
var ref = "[" + h.projectSlug + "/" + h.sessionId + " — " + when + "]";
|
|
277
|
-
var snippet = h.text.replace(/\s+/g, " ").trim();
|
|
278
|
-
if (snippet.length > 220) snippet = snippet.substring(0, 220) + "...";
|
|
279
|
-
return ref + " (" + h.turnType + ") " + snippet;
|
|
280
|
-
});
|
|
281
|
-
return Promise.resolve({
|
|
282
|
-
content: [{ type: "text", text: lines.join("\n") }],
|
|
283
|
-
});
|
|
284
|
-
} catch (e) {
|
|
285
|
-
return Promise.resolve({
|
|
286
|
-
content: [{ type: "text", text: "list_recent_decisions failed: " + (e.message || String(e)) }],
|
|
287
|
-
isError: true,
|
|
288
|
-
});
|
|
289
|
-
}
|
|
62
|
+
{
|
|
63
|
+
name: "list_recent_decisions",
|
|
64
|
+
description: "List recent canonical user or assistant turns containing explicit decision language in the owned workspace.",
|
|
65
|
+
inputSchema: z ? {
|
|
66
|
+
projectSlug: field("string", "Optional project slug.", true),
|
|
67
|
+
since: field("string", "Optional earliest ISO date.", true),
|
|
68
|
+
until: field("string", "Optional latest ISO date.", true),
|
|
69
|
+
maxResults: field("number", "Maximum results, from 1 to 50.", true),
|
|
70
|
+
} : {},
|
|
71
|
+
handler: guarded(workspace, "listRecentDecisions", function (args) {
|
|
72
|
+
return { projectSlug: args.projectSlug, since: args.since, until: args.until, limit: args.maxResults };
|
|
73
|
+
}),
|
|
290
74
|
},
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
return tools;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
function parseTime(input) {
|
|
297
|
-
if (input == null || input === "") return null;
|
|
298
|
-
if (typeof input === "number") return input;
|
|
299
|
-
var s = String(input).trim();
|
|
300
|
-
if (/^\d{10,}$/.test(s)) return parseInt(s, 10); // unix ms
|
|
301
|
-
var d = new Date(s);
|
|
302
|
-
var n = d.getTime();
|
|
303
|
-
return isNaN(n) ? null : n;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
function matchesDecisionPattern(text) {
|
|
307
|
-
for (var i = 0; i < DECISION_PATTERNS.length; i++) {
|
|
308
|
-
if (DECISION_PATTERNS[i].test(text)) return true;
|
|
309
|
-
}
|
|
310
|
-
return false;
|
|
75
|
+
];
|
|
311
76
|
}
|
|
312
77
|
|
|
313
78
|
module.exports = { getToolDefs: getToolDefs };
|
package/lib/daemon.js
CHANGED
|
@@ -34,6 +34,7 @@ var { checkAclSupport, grantProjectAccess, revokeProjectAccess, provisionAllUser
|
|
|
34
34
|
var usersModule = require("./users");
|
|
35
35
|
var { createWorktree, removeWorktree, isWorktree } = require("./worktree");
|
|
36
36
|
var mates = require("./mates");
|
|
37
|
+
var mateKnowledgeMigration = require("./mate-knowledge-migration");
|
|
37
38
|
var { isWorktreeSlug, scanAndRegisterWorktrees, rescanWorktrees, cleanupWorktreesForParent, getFilteredRemovedProjects, registerWorktreeSlug, unregisterWorktreeSlug } = require("./daemon-projects");
|
|
38
39
|
|
|
39
40
|
var daemonVersion = require("../package.json").version;
|
|
@@ -814,7 +815,7 @@ var relay = createServer({
|
|
|
814
815
|
var want = !!value;
|
|
815
816
|
config.matesEnabled = want;
|
|
816
817
|
saveConfig(config);
|
|
817
|
-
console.log("[daemon]
|
|
818
|
+
console.log("[daemon] Project Mate DMs:", want ? "shown" : "hidden", "(web)");
|
|
818
819
|
return { ok: true, matesEnabled: want };
|
|
819
820
|
},
|
|
820
821
|
onGetToolPalettes: function () {
|
|
@@ -1294,6 +1295,27 @@ for (var i = 0; i < projects.length; i++) {
|
|
|
1294
1295
|
// Migrate legacy mates storage before registration
|
|
1295
1296
|
mates.migrateLegacyMates();
|
|
1296
1297
|
|
|
1298
|
+
// Import durable Mate knowledge into the Clay-wide Knowledge backend. Runs on
|
|
1299
|
+
// every start, imports nothing when there is nothing new, and never touches
|
|
1300
|
+
// the legacy files that remain the live source for existing read paths.
|
|
1301
|
+
mateKnowledgeMigration.runAtStartup({
|
|
1302
|
+
extraRoots: (function () {
|
|
1303
|
+
var roots = [];
|
|
1304
|
+
try {
|
|
1305
|
+
if (!usersModule.isMultiUser()) return roots;
|
|
1306
|
+
var all = usersModule.getAllUsers() || [];
|
|
1307
|
+
for (var mi = 0; mi < all.length; mi++) {
|
|
1308
|
+
if (!all[mi] || !all[mi].linuxUser) continue;
|
|
1309
|
+
roots.push({
|
|
1310
|
+
userId: all[mi].id,
|
|
1311
|
+
matesRoot: mates.resolveMatesRoot({ userId: all[mi].id, multiUser: true, linuxUser: all[mi].linuxUser }),
|
|
1312
|
+
});
|
|
1313
|
+
}
|
|
1314
|
+
} catch (e) {}
|
|
1315
|
+
return roots;
|
|
1316
|
+
})(),
|
|
1317
|
+
});
|
|
1318
|
+
|
|
1297
1319
|
// Register existing mates as projects
|
|
1298
1320
|
if (usersModule.isMultiUser()) {
|
|
1299
1321
|
// Multi-user mode: iterate over all users and load each user's mates
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
var projectModels = require("./project-models");
|
|
2
|
+
|
|
3
|
+
var MAX_MODELS = 100;
|
|
4
|
+
|
|
5
|
+
function modelValue(entry) {
|
|
6
|
+
return projectModels.modelEntryValue(entry);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function modelLabel(entry) {
|
|
10
|
+
if (typeof entry === "string") return entry;
|
|
11
|
+
return entry && (entry.displayName || entry.label || entry.name || modelValue(entry)) || "Model";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function findModel(models, candidate) {
|
|
15
|
+
if (!candidate) return "";
|
|
16
|
+
for (var i = 0; i < models.length; i++) {
|
|
17
|
+
if (projectModels.modelEntryMatches(models[i], candidate)) return modelValue(models[i]);
|
|
18
|
+
}
|
|
19
|
+
return "";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function participantIds(moderatorId, panelists) {
|
|
23
|
+
var ids = [moderatorId];
|
|
24
|
+
for (var i = 0; i < panelists.length; i++) ids.push(panelists[i].mateId);
|
|
25
|
+
return ids;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function loadParticipant(ctx, ws, mateCtx, mateId, role, sourceSession) {
|
|
29
|
+
var mate = ctx.getMate(mateCtx, mateId);
|
|
30
|
+
if (!mate) return null;
|
|
31
|
+
var vendor = mate.vendor || "claude";
|
|
32
|
+
var catalog;
|
|
33
|
+
try {
|
|
34
|
+
if (sourceSession && typeof ctx.getVendorModelCatalogForSession === "function") catalog = await ctx.getVendorModelCatalogForSession(sourceSession, vendor);
|
|
35
|
+
else catalog = await ctx.getVendorModelCatalog(ws, vendor);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
catalog = { models: [], error: error && error.message ? error.message : String(error) };
|
|
38
|
+
}
|
|
39
|
+
var sourceModels = Array.isArray(catalog.models) ? catalog.models.slice(0, MAX_MODELS) : [];
|
|
40
|
+
var models = [];
|
|
41
|
+
var seen = {};
|
|
42
|
+
for (var i = 0; i < sourceModels.length; i++) {
|
|
43
|
+
var value = modelValue(sourceModels[i]);
|
|
44
|
+
if (typeof value !== "string" || !value || seen[value]) continue;
|
|
45
|
+
seen[value] = true;
|
|
46
|
+
models.push({ value: value.slice(0, 300), label: modelLabel(sourceModels[i]).slice(0, 160) });
|
|
47
|
+
}
|
|
48
|
+
var selected = findModel(sourceModels, mate.model) || findModel(sourceModels, catalog.defaultModel);
|
|
49
|
+
if (!selected && models.length) selected = models[0].value;
|
|
50
|
+
if (!selected && typeof mate.model === "string" && mate.model) {
|
|
51
|
+
selected = mate.model;
|
|
52
|
+
models.push({ value: mate.model, label: mate.model });
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
mateId: mateId,
|
|
56
|
+
role: role,
|
|
57
|
+
vendor: vendor,
|
|
58
|
+
selectedModel: selected || "",
|
|
59
|
+
models: models,
|
|
60
|
+
status: models.length ? "ready" : "unavailable",
|
|
61
|
+
error: models.length ? "" : (catalog.error || "No models are available for this provider."),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function loadSelections(ctx, ws, mateCtx, moderatorId, panelists, sourceSession) {
|
|
66
|
+
var ids = participantIds(moderatorId, panelists);
|
|
67
|
+
var selections = [];
|
|
68
|
+
for (var i = 0; i < ids.length; i++) {
|
|
69
|
+
var selection = await loadParticipant(ctx, ws, mateCtx, ids[i], i === 0 ? "moderator" : "panelist", sourceSession);
|
|
70
|
+
if (selection) selections.push(selection);
|
|
71
|
+
}
|
|
72
|
+
return selections;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function requestedByMate(overrides) {
|
|
76
|
+
if (overrides == null) return { values: {} };
|
|
77
|
+
if (!Array.isArray(overrides) || overrides.length > 12) return { error: "The debate model selection is invalid." };
|
|
78
|
+
var result = {};
|
|
79
|
+
for (var i = 0; i < overrides.length; i++) {
|
|
80
|
+
var item = overrides[i];
|
|
81
|
+
if (!item || typeof item.mateId !== "string" || typeof item.model !== "string" || !item.mateId || !item.model || result[item.mateId]) {
|
|
82
|
+
return { error: "The debate model selection is invalid." };
|
|
83
|
+
}
|
|
84
|
+
result[item.mateId] = item.model.slice(0, 300);
|
|
85
|
+
}
|
|
86
|
+
return { values: result };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function validateSelections(ctx, ws, mateCtx, moderatorId, panelists, overrides, sourceSession) {
|
|
90
|
+
var selections = await loadSelections(ctx, ws, mateCtx, moderatorId, panelists, sourceSession);
|
|
91
|
+
var requestResult = requestedByMate(overrides);
|
|
92
|
+
if (requestResult.error) return { error: requestResult.error };
|
|
93
|
+
var requested = requestResult.values;
|
|
94
|
+
var allowed = {};
|
|
95
|
+
var resolved = [];
|
|
96
|
+
for (var i = 0; i < selections.length; i++) {
|
|
97
|
+
var selection = selections[i];
|
|
98
|
+
allowed[selection.mateId] = true;
|
|
99
|
+
var requestedModel = requested[selection.mateId] || selection.selectedModel;
|
|
100
|
+
var selected = "";
|
|
101
|
+
for (var j = 0; j < selection.models.length; j++) {
|
|
102
|
+
if (selection.models[j].value === requestedModel) selected = requestedModel;
|
|
103
|
+
}
|
|
104
|
+
if (requested[selection.mateId] && !selected) {
|
|
105
|
+
return { error: "A selected debate model is no longer available. Review the panel models and try again." };
|
|
106
|
+
}
|
|
107
|
+
if (selected) resolved.push({ mateId: selection.mateId, vendor: selection.vendor, model: selected });
|
|
108
|
+
}
|
|
109
|
+
var requestedIds = Object.keys(requested);
|
|
110
|
+
for (var k = 0; k < requestedIds.length; k++) {
|
|
111
|
+
if (!allowed[requestedIds[k]]) return { error: "A model override does not belong to this debate panel." };
|
|
112
|
+
}
|
|
113
|
+
return { selections: resolved };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = {
|
|
117
|
+
loadSelections: loadSelections,
|
|
118
|
+
validateSelections: validateSelections,
|
|
119
|
+
};
|