clay-server 4.1.0-beta.8 → 4.1.0
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/context-usage.js +47 -0
- package/lib/issues-mcp-server.js +1 -1
- package/lib/issues-service.js +3 -1
- package/lib/loop-registry-occurrence.js +1 -0
- package/lib/notes.js +20 -3
- package/lib/os-users.js +6 -0
- package/lib/project-connection.js +14 -3
- package/lib/project-file-path.js +13 -0
- package/lib/project-file-watch.js +19 -8
- package/lib/project-filesystem.js +10 -16
- package/lib/project-http.js +53 -48
- package/lib/project-logs-mcp-server.js +8 -8
- package/lib/project-logs-schema.js +1 -1
- package/lib/project-logs-service.js +46 -13
- package/lib/project-logs-store.js +17 -15
- package/lib/project-logs.js +70 -0
- package/lib/project-loop.js +1 -0
- package/lib/project-notifications.js +1 -1
- package/lib/project-pending-message-queue.js +71 -7
- package/lib/project-scheduled-messages.js +235 -52
- package/lib/project-scheduled-result-store.js +131 -0
- package/lib/project-scheduled-task-execution.js +35 -2
- package/lib/project-session-notes.js +11 -4
- package/lib/project-sessions.js +7 -0
- package/lib/project-user-message.js +72 -5
- package/lib/project.js +60 -5
- package/lib/public/app.js +27 -12
- package/lib/public/css/avatar-imprints.css +1 -1
- package/lib/public/css/command-palette.css +20 -0
- package/lib/public/css/git-panel.css +13 -12
- package/lib/public/css/git-placard.css +4 -4
- package/lib/public/css/input.css +0 -109
- package/lib/public/css/issues.css +78 -31
- package/lib/public/css/mobile-nav.css +7 -0
- package/lib/public/css/notifications-center.css +3 -3
- package/lib/public/css/pending-message-queue.css +3 -0
- package/lib/public/css/project-logs.css +15 -0
- package/lib/public/css/sidebar.css +7 -0
- package/lib/public/css/sticky-notes.css +29 -0
- package/lib/public/modules/app-connection.js +9 -1
- package/lib/public/modules/app-favicon.js +10 -0
- package/lib/public/modules/app-messages.js +49 -37
- package/lib/public/modules/app-notifications.js +2 -0
- package/lib/public/modules/app-panels.js +77 -23
- package/lib/public/modules/app-projects.js +3 -0
- package/lib/public/modules/app-rate-limit.js +148 -243
- package/lib/public/modules/avatar-imprint.js +25 -70
- package/lib/public/modules/avatar.js +12 -4
- package/lib/public/modules/chat-render-runtime.js +20 -2
- package/lib/public/modules/clay-issue-links.js +23 -2
- package/lib/public/modules/clay-log-links.js +11 -1
- package/lib/public/modules/context-view-preference.js +143 -0
- package/lib/public/modules/default-vendor.js +116 -0
- package/lib/public/modules/filebrowser-tabs.js +1 -0
- package/lib/public/modules/filebrowser.js +45 -18
- package/lib/public/modules/input.js +81 -20
- package/lib/public/modules/issues-render.js +36 -10
- package/lib/public/modules/issues.js +95 -13
- package/lib/public/modules/markdown.js +3 -1
- package/lib/public/modules/pane-bridge.js +14 -8
- package/lib/public/modules/pane-issue-bridge.js +27 -0
- package/lib/public/modules/pending-message-queue.js +43 -1
- package/lib/public/modules/permission-hints.js +13 -0
- package/lib/public/modules/profile.js +9 -9
- package/lib/public/modules/project-activation.js +49 -0
- package/lib/public/modules/project-logs-render.js +13 -3
- package/lib/public/modules/project-logs.js +45 -15
- package/lib/public/modules/right-workbench.js +44 -0
- package/lib/public/modules/scheduled-message-state.js +12 -36
- package/lib/public/modules/scheduled-result-client.js +33 -0
- package/lib/public/modules/scheduled-result-display.js +50 -0
- package/lib/public/modules/scheduled-result-notification.js +31 -0
- package/lib/public/modules/scheduled-task-presentation.js +15 -0
- package/lib/public/modules/scheduled-tasks.js +9 -21
- package/lib/public/modules/sidebar-mobile.js +51 -3
- package/lib/public/modules/sidebar-sessions.js +65 -5
- package/lib/public/modules/split-session-boundary.js +28 -0
- package/lib/public/modules/split-view.js +42 -7
- package/lib/public/modules/sticky-notes-browser.js +130 -18
- package/lib/public/modules/sticky-notes.js +2 -3
- package/lib/public/modules/terminal.js +4 -4
- package/lib/public/modules/thinking-lifecycle.js +4 -1
- package/lib/public/modules/tools.js +5 -1
- package/lib/scheduled-run-state.js +10 -2
- package/lib/scheduler.js +1 -0
- package/lib/sdk-bridge.js +97 -61
- package/lib/sdk-message-processor.js +44 -13
- package/lib/sdk-skill-discovery.js +6 -28
- package/lib/sdk-turn-queue.js +14 -0
- package/lib/server-context-view.js +53 -0
- package/lib/server-default-vendor.js +60 -0
- package/lib/server.js +23 -6
- package/lib/session-notes-mcp-server.js +3 -5
- package/lib/session-pair-factory.js +2 -2
- package/lib/session-pair-mcp-server.js +5 -4
- package/lib/session-title-generator.js +89 -0
- package/lib/session-title-policy.js +8 -2
- package/lib/sessions.js +26 -1
- package/lib/user-presence.js +6 -0
- package/lib/users-context-view-preferences.js +65 -0
- package/lib/users-default-vendor-preferences.js +80 -0
- package/lib/users.js +12 -0
- package/lib/ws-schema.js +11 -0
- package/lib/yoke/acp-agent-profiles.js +15 -2
- package/lib/yoke/adapters/acp.js +3 -2
- package/lib/yoke/adapters/antigravity.js +2 -2
- package/lib/yoke/adapters/claude-worker.js +11 -12
- package/lib/yoke/adapters/claude.js +75 -22
- package/lib/yoke/adapters/codex.js +216 -29
- package/lib/yoke/adapters/kiro.js +6 -5
- package/lib/yoke/claude-context-usage.js +57 -0
- package/lib/yoke/claude-message-correlation.js +31 -0
- package/lib/yoke/claude-model-switch.js +15 -0
- package/lib/yoke/index.js +5 -1
- package/lib/yoke/mcp-bridge-server.js +18 -5
- package/lib/yoke/session-skill-catalog.js +45 -0
- package/lib/yoke/skill-discovery.js +60 -20
- package/lib/yoke/vendor-registry.js +1 -1
- package/package.json +5 -7
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
var sessionNotesMcp = require("./session-notes-mcp-server");
|
|
2
2
|
var lifecycle = require("./notes-lifecycle");
|
|
3
|
+
var driverEligibility = require("./session-driver-eligibility");
|
|
3
4
|
|
|
4
5
|
var MAX_NOTE_TEXT_CHARS = 20000;
|
|
5
6
|
var MAX_ACTIVE_NOTES = 20;
|
|
@@ -172,13 +173,19 @@ function attachSessionNotes(ctx) {
|
|
|
172
173
|
return toolResult(publicNote(created));
|
|
173
174
|
}
|
|
174
175
|
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
// in the arguments.
|
|
176
|
+
// Cross-session closure requires a live, authorized Project Driver.
|
|
177
|
+
// Reopening retains the existing creator-only permission.
|
|
178
178
|
function ownedNote(args, caller, verb) {
|
|
179
|
+
var authorized = typeof ctx.canUseSession === "function" && ctx.canUseSession(caller);
|
|
180
|
+
if (ctx.canUseSession && !authorized) {
|
|
181
|
+
return { error: "this session no longer has access to project notes" };
|
|
182
|
+
}
|
|
179
183
|
var note = findNote(nm.list() || [], args && args.id);
|
|
180
184
|
if (!note) return { error: "note not found: " + ((args && args.id) || "unknown") };
|
|
181
|
-
|
|
185
|
+
var driverCanClose = verb === "close" && !ctx.isMate &&
|
|
186
|
+
driverEligibility.isEligibleDriverSession(caller) &&
|
|
187
|
+
authorized;
|
|
188
|
+
if (!driverCanClose && (!note.origin || note.origin.sessionId !== caller.localId)) {
|
|
182
189
|
return { error: "this session can only " + verb + " notes it created" };
|
|
183
190
|
}
|
|
184
191
|
return { note: note };
|
package/lib/project-sessions.js
CHANGED
|
@@ -6,6 +6,7 @@ var { CODEX_DEFAULTS, getCodexConfig } = require("./codex-defaults");
|
|
|
6
6
|
var updateSnooze = require("./update-snooze");
|
|
7
7
|
var yoke = require("./yoke");
|
|
8
8
|
var sessionVisibility = require("./session-visibility");
|
|
9
|
+
var contextUsageModule = require("./context-usage");
|
|
9
10
|
|
|
10
11
|
function vendorSupportsTui(vendor) {
|
|
11
12
|
var info = yoke.getVendorInfo(vendor);
|
|
@@ -82,6 +83,7 @@ function formatAskUserAnswerAsMessage(input, answers) {
|
|
|
82
83
|
* getLatestVersion, setLatestVersion
|
|
83
84
|
*/
|
|
84
85
|
function attachSessions(ctx) {
|
|
86
|
+
var contextUsage = contextUsageModule.attachContextUsage(ctx);
|
|
85
87
|
var cwd = ctx.cwd;
|
|
86
88
|
var slug = ctx.slug;
|
|
87
89
|
var isMate = ctx.isMate;
|
|
@@ -108,6 +110,7 @@ function attachSessions(ctx) {
|
|
|
108
110
|
var getLinuxUserForSession = ctx.getLinuxUserForSession;
|
|
109
111
|
var ensureProjectAccessForSession = ctx.ensureProjectAccessForSession;
|
|
110
112
|
var getOsUserInfoForWs = ctx.getOsUserInfoForWs;
|
|
113
|
+
var hydrateSkillCatalog = ctx.hydrateSkillCatalog || function () { return []; };
|
|
111
114
|
function stopSession(session, actor) {
|
|
112
115
|
if (!session) return false;
|
|
113
116
|
session._pendingMessageDrainPaused = true;
|
|
@@ -568,6 +571,7 @@ function attachSessions(ctx) {
|
|
|
568
571
|
}
|
|
569
572
|
|
|
570
573
|
function handleSessionsMessage(ws, msg) {
|
|
574
|
+
if (contextUsage.handleMessage(ws, msg)) return true;
|
|
571
575
|
|
|
572
576
|
if (msg.type === "push_subscribe") {
|
|
573
577
|
var _pushUserId = ws._clayUser ? ws._clayUser.id : null;
|
|
@@ -981,6 +985,8 @@ function attachSessions(ctx) {
|
|
|
981
985
|
if (msg.id && sm.sessions.has(msg.id) && msg.title) {
|
|
982
986
|
var s = sm.sessions.get(msg.id);
|
|
983
987
|
s.title = String(msg.title).substring(0, 100);
|
|
988
|
+
s.titleProvisional = false;
|
|
989
|
+
s.titleAutoGenerated = false;
|
|
984
990
|
s.titleManuallySet = true;
|
|
985
991
|
sm.saveSessionFile(s);
|
|
986
992
|
sm.notifySessionRenamed(s.localId);
|
|
@@ -1679,6 +1685,7 @@ function attachSessions(ctx) {
|
|
|
1679
1685
|
return true;
|
|
1680
1686
|
}
|
|
1681
1687
|
|
|
1688
|
+
if (decision === "allow_always" && pending.suppressAlwaysAllowRule) decision = "allow";
|
|
1682
1689
|
if (decision === "allow" || decision === "allow_always") {
|
|
1683
1690
|
if (decision === "allow_always") {
|
|
1684
1691
|
if (!session.allowedTools) session.allowedTools = {};
|
|
@@ -24,6 +24,7 @@ var fs = require("fs");
|
|
|
24
24
|
* pendingMessageQueue,
|
|
25
25
|
* loadContextSources, saveContextSources,
|
|
26
26
|
* digestDmTurn, gateMemory,
|
|
27
|
+
* getProjectAccess, canAccessProjectSlug,
|
|
27
28
|
* adapter - YOKE adapter instance
|
|
28
29
|
*/
|
|
29
30
|
function attachUserMessage(ctx) {
|
|
@@ -55,6 +56,8 @@ function attachUserMessage(ctx) {
|
|
|
55
56
|
var getLinuxUserForSession = ctx.getLinuxUserForSession;
|
|
56
57
|
var ensureProjectAccessForSession = ctx.ensureProjectAccessForSession;
|
|
57
58
|
var getOsUserInfoForWs = ctx.getOsUserInfoForWs;
|
|
59
|
+
var getProjectAccess = ctx.getProjectAccess;
|
|
60
|
+
var canAccessProjectSlug = ctx.canAccessProjectSlug;
|
|
58
61
|
|
|
59
62
|
var hydrateImageRefs = ctx.hydrateImageRefs;
|
|
60
63
|
var saveImageFile = ctx.saveImageFile;
|
|
@@ -99,6 +102,21 @@ function attachUserMessage(ctx) {
|
|
|
99
102
|
}
|
|
100
103
|
}
|
|
101
104
|
|
|
105
|
+
function canHumanManageNotes(ws) {
|
|
106
|
+
if (!usersModule.isMultiUser()) return true;
|
|
107
|
+
if (!ws || !ws._clayUser || !ws._clayUser.id) return false;
|
|
108
|
+
var actor = usersModule.findUserById(ws._clayUser.id);
|
|
109
|
+
if (!actor) return false;
|
|
110
|
+
if (typeof canAccessProjectSlug === "function" && !canAccessProjectSlug(actor.id, slug)) return false;
|
|
111
|
+
var access = typeof getProjectAccess === "function" ? getProjectAccess() : null;
|
|
112
|
+
return !!(access && !access.error && usersModule.canAccessProject(actor.id, access));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function noteDeleteResult(ws, msg, ok, error) {
|
|
116
|
+
sendTo(ws, { type: "note_delete_result", projectSlug: slug, noteId: msg.id || null,
|
|
117
|
+
requestId: msg.requestId || null, ok: !!ok, error: error || null });
|
|
118
|
+
}
|
|
119
|
+
|
|
102
120
|
// --------------- Main handler ---------------
|
|
103
121
|
|
|
104
122
|
function handleUserMessage(ws, msg, forcedSession, internal) {
|
|
@@ -171,6 +189,31 @@ function attachUserMessage(ctx) {
|
|
|
171
189
|
return true;
|
|
172
190
|
}
|
|
173
191
|
|
|
192
|
+
if (msg.type === "note_delete_permanently") {
|
|
193
|
+
if (!msg.id || !canHumanManageNotes(ws)) {
|
|
194
|
+
noteDeleteResult(ws, msg, false, "You are not authorized to delete notes in this project.");
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
var current = nm.list().filter(function (item) { return item && item.id === msg.id; })[0];
|
|
198
|
+
if (!current) {
|
|
199
|
+
noteDeleteResult(ws, msg, false, "Note not found.");
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
if (!notesLifecycle.isClosed(current)) {
|
|
203
|
+
noteDeleteResult(ws, msg, false, "Only closed notes can be permanently deleted.");
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
var removed = nm.removeClosed(msg.id);
|
|
207
|
+
if (!removed) {
|
|
208
|
+
noteDeleteResult(ws, msg, false, "The note changed before it could be deleted.");
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
send({ type: "note_deleted", id: removed.id });
|
|
212
|
+
noteDeleteResult(ws, msg, true, null);
|
|
213
|
+
syncNotesKnowledge();
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
|
|
174
217
|
if (msg.type === "note_list_request") {
|
|
175
218
|
sendTo(ws, { type: "notes_list", notes: nm.list() });
|
|
176
219
|
return true;
|
|
@@ -303,22 +346,42 @@ function attachUserMessage(ctx) {
|
|
|
303
346
|
// --- Schedule message for after rate limit resets ---
|
|
304
347
|
if (msg.type === "schedule_message") {
|
|
305
348
|
var schedSession = getSessionForWs(ws);
|
|
306
|
-
|
|
307
|
-
|
|
349
|
+
var transportAccountId = (ws && ws._clayUser && ws._clayUser.id) ? String(ws._clayUser.id) : "default";
|
|
350
|
+
if (!schedSession || msg.projectSlug !== slug || String(msg.sessionId) !== String(schedSession && schedSession.localId) ||
|
|
351
|
+
(msg.accountId || "default") !== transportAccountId) {
|
|
352
|
+
if (msg.requestId) sendTo(ws, { type: "schedule_message_result", requestId: msg.requestId,
|
|
353
|
+
projectSlug: msg.projectSlug || slug, sessionId: msg.sessionId == null ? null : msg.sessionId,
|
|
354
|
+
accountId: transportAccountId, ok: false, error: "The scheduling session or account is stale.", scheduledMessage: null });
|
|
355
|
+
return true;
|
|
356
|
+
}
|
|
357
|
+
scheduleMessage(schedSession, msg.text || "", msg.resetsAt, ws._clayUser || null, ws,
|
|
358
|
+
{ images: msg.images, pastes: msg.pastes }, msg.requestId || null, transportAccountId);
|
|
308
359
|
return true;
|
|
309
360
|
}
|
|
310
361
|
|
|
311
362
|
if (msg.type === "cancel_scheduled_message") {
|
|
312
363
|
var cancelSession = getSessionForWs(ws);
|
|
313
364
|
if (!cancelSession) return true;
|
|
314
|
-
|
|
365
|
+
if (msg.projectSlug && msg.projectSlug !== slug) return true;
|
|
366
|
+
if (msg.sessionId != null && String(msg.sessionId) !== String(cancelSession.localId)) return true;
|
|
367
|
+
cancelScheduledMessage(cancelSession, ws._clayUser || null, ws, { jobId: msg.jobId, revision: msg.revision, queueRevision: msg.queueRevision, requestId: msg.requestId });
|
|
315
368
|
return true;
|
|
316
369
|
}
|
|
317
370
|
|
|
318
371
|
if (msg.type === "send_scheduled_now") {
|
|
319
372
|
var nowSession = getSessionForWs(ws);
|
|
320
|
-
|
|
321
|
-
|
|
373
|
+
var requestedContext = { projectSlug: slug, sessionId: nowSession ? nowSession.localId : msg.sessionId, revision: pendingMessageQueue ? pendingMessageQueue.getRevision() : 0, items: [], paused: false };
|
|
374
|
+
var controlResult;
|
|
375
|
+
if (!nowSession) controlResult = Object.assign({}, requestedContext, { ok: false, error: "The session is no longer available." });
|
|
376
|
+
else if (msg.projectSlug && msg.projectSlug !== slug) controlResult = Object.assign({}, requestedContext, { ok: false, error: "Project changed" });
|
|
377
|
+
else if (msg.sessionId != null && String(msg.sessionId) !== String(nowSession.localId)) controlResult = Object.assign({}, requestedContext, { ok: false, error: "Session changed" });
|
|
378
|
+
else if (!nowSession.scheduledMessage) controlResult = Object.assign({}, requestedContext, { ok: false, error: "The scheduled message is no longer available." });
|
|
379
|
+
else {
|
|
380
|
+
var sentNow = sendScheduledMessageNow(nowSession, ws._clayUser || null, ws, { jobId: msg.jobId, revision: msg.revision, queueRevision: msg.queueRevision, requestId: msg.requestId });
|
|
381
|
+
controlResult = pendingMessageQueue ? pendingMessageQueue.hydrate(nowSession, ws._clayUser || null) : { ok: sentNow === true, projectSlug: slug, sessionId: nowSession.localId, revision: 0, items: [], paused: false };
|
|
382
|
+
if (sentNow !== true) controlResult = Object.assign({}, controlResult, { ok: false, error: "Could not send the scheduled message." });
|
|
383
|
+
}
|
|
384
|
+
if (msg.requestId) sendTo(ws, { type: "pending_message_result", requestId: msg.requestId, result: controlResult });
|
|
322
385
|
return true;
|
|
323
386
|
}
|
|
324
387
|
|
|
@@ -459,6 +522,10 @@ function attachUserMessage(ctx) {
|
|
|
459
522
|
function recordSessionTitle() {
|
|
460
523
|
if (!session.title) {
|
|
461
524
|
session.title = (msg.text || "Image").substring(0, 50);
|
|
525
|
+
// This title is an optimistic first-message label, not a semantic or
|
|
526
|
+
// explicit title. Persist its provenance so startQuery can preserve
|
|
527
|
+
// eligibility for model generation after this function returns.
|
|
528
|
+
session.titleProvisional = true;
|
|
462
529
|
sm.saveSessionFile(session);
|
|
463
530
|
sm.broadcastSessionList();
|
|
464
531
|
// Sync auto-title to SDK
|
package/lib/project.js
CHANGED
|
@@ -46,6 +46,7 @@ var { attachVendorLogin } = require("./project-vendor-login");
|
|
|
46
46
|
var { attachConnection } = require("./project-connection");
|
|
47
47
|
var { attachProjectScheduledMessages } = require("./project-scheduled-messages");
|
|
48
48
|
var { attachMcp } = require("./project-mcp");
|
|
49
|
+
var { createSessionSkillCatalog } = require("./yoke/session-skill-catalog");
|
|
49
50
|
var { createLocalMcp } = require("./mcp-local");
|
|
50
51
|
var { attachEmail: attachEmailModule } = require("./project-email");
|
|
51
52
|
var { attachSessionSpawn } = require("./project-session-spawn");
|
|
@@ -256,11 +257,20 @@ function createProjectContext(opts) {
|
|
|
256
257
|
var serverPort = opts.port || 2633;
|
|
257
258
|
var serverTls = opts.tls || false;
|
|
258
259
|
var serverAuthToken = opts.authToken || null;
|
|
260
|
+
var mcpBridgeToken = opts.mcpBridgeToken || crypto.randomBytes(32).toString("hex");
|
|
259
261
|
var latestVersion = null;
|
|
260
262
|
var sessionTitleMigrationScheduled = false;
|
|
261
263
|
|
|
262
264
|
// --- YOKE adapters (multi-vendor, lazy init) ---
|
|
263
|
-
var _yokeState = yoke.createAdapters({
|
|
265
|
+
var _yokeState = yoke.createAdapters({
|
|
266
|
+
cwd: cwd,
|
|
267
|
+
slug: slug,
|
|
268
|
+
osUsers: osUsers,
|
|
269
|
+
clayPort: serverPort,
|
|
270
|
+
clayTls: serverTls,
|
|
271
|
+
clayAuthToken: serverAuthToken,
|
|
272
|
+
clayBridgeToken: mcpBridgeToken,
|
|
273
|
+
});
|
|
264
274
|
var adapters = _yokeState.adapters;
|
|
265
275
|
// A new project has no remembered vendor. Select the first installed
|
|
266
276
|
// provider by the shared Claude -> Codex -> Kiro preference order.
|
|
@@ -555,6 +565,7 @@ function createProjectContext(opts) {
|
|
|
555
565
|
// --- File/directory watcher engine (delegated to project-file-watch.js) ---
|
|
556
566
|
var _fileWatch = attachFileWatch({
|
|
557
567
|
requestAccess: _requestAccess, fsAsUser: fsAsUser,
|
|
568
|
+
osUsers: osUsers,
|
|
558
569
|
cwd: cwd,
|
|
559
570
|
send: send,
|
|
560
571
|
sendTo: sendTo,
|
|
@@ -634,6 +645,8 @@ function createProjectContext(opts) {
|
|
|
634
645
|
var access = opts.getProjectAccess ? opts.getProjectAccess() : { visibility: "public", ownerId: projectOwnerId || null };
|
|
635
646
|
return !usersModule.isMultiUser() || !!(freshActor && (!opts.canAccessProjectSlug || opts.canAccessProjectSlug(freshActor.id, slug)) && usersModule.canAccessSession(freshActor.id, session, access));
|
|
636
647
|
},
|
|
648
|
+
onItemCancelled: function (item) { return _scheduledMessages && _scheduledMessages.onQueueCancelled(item); },
|
|
649
|
+
onItemConsumed: function (item) { return _scheduledMessages && _scheduledMessages.onQueueConsumed(item); },
|
|
637
650
|
});
|
|
638
651
|
|
|
639
652
|
var sdk = null;
|
|
@@ -715,6 +728,15 @@ function createProjectContext(opts) {
|
|
|
715
728
|
var nm = createNotesManager({ cwd: cwd, send: send, sendTo: sendTo });
|
|
716
729
|
var _sessionNotes = attachSessionNotes({
|
|
717
730
|
nm: nm,
|
|
731
|
+
canUseSession: function (session) {
|
|
732
|
+
if (!session || sm.sessions.get(session.localId) !== session) return false;
|
|
733
|
+
if (!usersModule.isMultiUser()) return true;
|
|
734
|
+
var owner = session.ownerId && usersModule.findUserById(session.ownerId);
|
|
735
|
+
if (!owner) return false;
|
|
736
|
+
var access = opts.getProjectAccess ? opts.getProjectAccess() : { visibility: "public", ownerId: projectOwnerId || null };
|
|
737
|
+
if (opts.canAccessProjectSlug && !opts.canAccessProjectSlug(owner.id, slug)) return false;
|
|
738
|
+
return usersModule.canAccessSession(owner.id, session, access) && (!osUsers || !!getLinuxUserForSession(session));
|
|
739
|
+
},
|
|
718
740
|
send: send,
|
|
719
741
|
isMate: isMate,
|
|
720
742
|
broadcastWritten: function (message) {
|
|
@@ -1215,6 +1237,7 @@ function createProjectContext(opts) {
|
|
|
1215
1237
|
clayPort: serverPort,
|
|
1216
1238
|
clayTls: serverTls,
|
|
1217
1239
|
clayAuthToken: serverAuthToken,
|
|
1240
|
+
clayBridgeToken: mcpBridgeToken,
|
|
1218
1241
|
getWorkerPermissionRouter: function () {
|
|
1219
1242
|
return isMate ? null : _sessionPair.workerPermission;
|
|
1220
1243
|
},
|
|
@@ -1360,6 +1383,8 @@ function createProjectContext(opts) {
|
|
|
1360
1383
|
isDriverOperatedSession: function (session) {
|
|
1361
1384
|
return !isMate && _sessionPair.workerPermission.isDriverOperated(session);
|
|
1362
1385
|
},
|
|
1386
|
+
pendingMessageQueue: _pendingMessageQueue,
|
|
1387
|
+
consumePendingMessage: function (session) { return _userMessage && _userMessage.consumePendingMessage(session); },
|
|
1363
1388
|
});
|
|
1364
1389
|
|
|
1365
1390
|
// --- Loop engine (delegated to project-loop.js) ---
|
|
@@ -1409,6 +1434,9 @@ function createProjectContext(opts) {
|
|
|
1409
1434
|
canExecuteScheduledTask: function (record) {
|
|
1410
1435
|
return !!(_scheduledTaskExecution && _scheduledTaskExecution.runnable(record).ok);
|
|
1411
1436
|
},
|
|
1437
|
+
onScheduledRunTerminal: function (record, run) {
|
|
1438
|
+
if (_scheduledTaskExecution) _scheduledTaskExecution.recordTerminal(record, run);
|
|
1439
|
+
},
|
|
1412
1440
|
onProcessingChanged: onProcessingChanged,
|
|
1413
1441
|
hydrateImageRefs: hydrateImageRefs,
|
|
1414
1442
|
});
|
|
@@ -1424,6 +1452,7 @@ function createProjectContext(opts) {
|
|
|
1424
1452
|
getSdk: function () { return sdk; }, getLinuxUserForSession: getLinuxUserForSession,
|
|
1425
1453
|
requiresLinuxUser: function () { return osUsers; },
|
|
1426
1454
|
onProcessingChanged: onProcessingChanged,
|
|
1455
|
+
recordResult: function (result) { return _projectLogs.recordScheduledResult(result); },
|
|
1427
1456
|
authorize: function (record) {
|
|
1428
1457
|
return authorizeStoredOwner(record, {
|
|
1429
1458
|
usersModule: usersModule, osUsers: osUsers,
|
|
@@ -1433,6 +1462,7 @@ function createProjectContext(opts) {
|
|
|
1433
1462
|
});
|
|
1434
1463
|
},
|
|
1435
1464
|
});
|
|
1465
|
+
setTimeout(function () { _scheduledTaskExecution.syncTerminalResults(); }, 0);
|
|
1436
1466
|
|
|
1437
1467
|
_scheduledTasks = attachScheduledTasks({
|
|
1438
1468
|
cwd: cwd,
|
|
@@ -1544,8 +1574,8 @@ function createProjectContext(opts) {
|
|
|
1544
1574
|
}
|
|
1545
1575
|
|
|
1546
1576
|
// --- Schedule / cancel a message (used by WS handler and auto-continue) ---
|
|
1547
|
-
function scheduleMessage(session, text, resetsAt, actorUser, targetWs) {
|
|
1548
|
-
return _scheduledMessages ? _scheduledMessages.schedule(session, text, resetsAt, actorUser, targetWs) : null;
|
|
1577
|
+
function scheduleMessage(session, text, resetsAt, actorUser, targetWs, attachments, requestId, transportAccountId) {
|
|
1578
|
+
return _scheduledMessages ? _scheduledMessages.schedule(session, text, resetsAt, actorUser, targetWs, attachments, requestId, transportAccountId) : null;
|
|
1549
1579
|
}
|
|
1550
1580
|
|
|
1551
1581
|
function cancelScheduledMessage(session, actorUser, targetWs, correlation) {
|
|
@@ -1579,8 +1609,8 @@ function createProjectContext(opts) {
|
|
|
1579
1609
|
}
|
|
1580
1610
|
|
|
1581
1611
|
// --- DM messages (delegated to server-level handler) ---
|
|
1582
|
-
if (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 === "cursor_sharing_get" || msg.type === "cursor_sharing_set") {
|
|
1583
|
-
if (typeof opts.onDmMessage === "function") opts.onDmMessage(ws, msg);
|
|
1612
|
+
if (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") {
|
|
1613
|
+
if (typeof opts.onDmMessage === "function") opts.onDmMessage(ws, msg, slug);
|
|
1584
1614
|
return;
|
|
1585
1615
|
}
|
|
1586
1616
|
if (msg.type === "issue_reference_resolve" || msg.type === "home_clay_ask" || msg.type === "home_clay_session_resolve" || msg.type === "home_clay_log_resolve") {
|
|
@@ -1859,6 +1889,12 @@ function createProjectContext(opts) {
|
|
|
1859
1889
|
}
|
|
1860
1890
|
|
|
1861
1891
|
// --- Sessions/config/project handler (delegated to project-sessions.js) ---
|
|
1892
|
+
var _sessionSkillCatalog = createSessionSkillCatalog({
|
|
1893
|
+
cwd: cwd,
|
|
1894
|
+
osUsers: osUsers,
|
|
1895
|
+
getLinuxUser: getLinuxUserForSession,
|
|
1896
|
+
});
|
|
1897
|
+
sm.setSessionHydrator(_sessionSkillCatalog.hydrate);
|
|
1862
1898
|
var _sessions = attachSessions({
|
|
1863
1899
|
cwd: cwd,
|
|
1864
1900
|
slug: slug,
|
|
@@ -1898,6 +1934,7 @@ function createProjectContext(opts) {
|
|
|
1898
1934
|
getLinuxUserForSession: getLinuxUserForSession,
|
|
1899
1935
|
ensureProjectAccessForSession: ensureProjectAccessForSession,
|
|
1900
1936
|
getOsUserInfoForWs: getOsUserInfoForWs,
|
|
1937
|
+
hydrateSkillCatalog: _sessionSkillCatalog.hydrate,
|
|
1901
1938
|
hydrateImageRefs: hydrateImageRefs,
|
|
1902
1939
|
onProcessingChanged: onProcessingChanged,
|
|
1903
1940
|
broadcastPresence: broadcastPresence,
|
|
@@ -1927,6 +1964,7 @@ function createProjectContext(opts) {
|
|
|
1927
1964
|
saveContextSources: saveContextSources,
|
|
1928
1965
|
_email: _email,
|
|
1929
1966
|
_notifications: _notifications,
|
|
1967
|
+
_projectLogs: _projectLogs,
|
|
1930
1968
|
});
|
|
1931
1969
|
|
|
1932
1970
|
var _models = attachModels({
|
|
@@ -1996,6 +2034,7 @@ function createProjectContext(opts) {
|
|
|
1996
2034
|
beginHumanPairTurn: function (session) { return _sessionPair.beginHumanTurn(session); },
|
|
1997
2035
|
authorizePendingDispatch: function (session, actor, item) {
|
|
1998
2036
|
if (!session || sm.sessions.get(session.localId) !== session || !item || item.projectSlug !== slug) return false;
|
|
2037
|
+
if (_scheduledMessages && !_scheduledMessages.authorizePending(item, session)) return false;
|
|
1999
2038
|
if (!isMate && _sessionPair.workerPermission && _sessionPair.workerPermission.isDriverOperated(session)) return false;
|
|
2000
2039
|
if (!usersModule.isMultiUser()) return item.actorId === "default" || !!(actor && String(actor.id) === item.actorId);
|
|
2001
2040
|
var freshActor = actor && actor.id && usersModule.findUserById(actor.id);
|
|
@@ -2025,6 +2064,8 @@ function createProjectContext(opts) {
|
|
|
2025
2064
|
getSessionForWs: getSessionForWs,
|
|
2026
2065
|
getLinuxUserForSession: getLinuxUserForSession,
|
|
2027
2066
|
ensureProjectAccessForSession: ensureProjectAccessForSession,
|
|
2067
|
+
getProjectAccess: function () { return opts.getProjectAccess ? opts.getProjectAccess() : { visibility: "public", ownerId: projectOwnerId || null }; },
|
|
2068
|
+
canAccessProjectSlug: opts.canAccessProjectSlug || function () { return !usersModule.isMultiUser(); },
|
|
2028
2069
|
getOsUserInfoForWs: getOsUserInfoForWs,
|
|
2029
2070
|
hydrateImageRefs: hydrateImageRefs,
|
|
2030
2071
|
saveImageFile: saveImageFile,
|
|
@@ -2107,6 +2148,12 @@ function createProjectContext(opts) {
|
|
|
2107
2148
|
function getMcpBridgeHandler(sessionId, sessionOnly, queryGeneration) {
|
|
2108
2149
|
var boundSession = Number.isInteger(sessionId) ? sm.sessions.get(sessionId) : null;
|
|
2109
2150
|
var queryToolBridge = createSessionQueryToolBridge({ session: boundSession, sdk: sdk });
|
|
2151
|
+
function sessionQueryValid() {
|
|
2152
|
+
return !!boundSession
|
|
2153
|
+
&& Number.isInteger(queryGeneration)
|
|
2154
|
+
&& sm.sessions.get(boundSession.localId) === boundSession
|
|
2155
|
+
&& Number(boundSession._sdkQueryGeneration || 0) === queryGeneration;
|
|
2156
|
+
}
|
|
2110
2157
|
// Build set of local MCP server names to exclude (Codex handles these natively)
|
|
2111
2158
|
var localMcpNames = {};
|
|
2112
2159
|
try {
|
|
@@ -2121,6 +2168,7 @@ function createProjectContext(opts) {
|
|
|
2121
2168
|
return {
|
|
2122
2169
|
listTools: function () {
|
|
2123
2170
|
var tools = [];
|
|
2171
|
+
if (sessionOnly && !sessionQueryValid()) return Promise.resolve(tools);
|
|
2124
2172
|
var toJSONSchema;
|
|
2125
2173
|
var zod;
|
|
2126
2174
|
try { zod = require("zod"); toJSONSchema = zod.toJSONSchema; } catch (e) { /* fallback */ }
|
|
@@ -2246,6 +2294,9 @@ function createProjectContext(opts) {
|
|
|
2246
2294
|
return Promise.resolve(tools);
|
|
2247
2295
|
},
|
|
2248
2296
|
callTool: function (serverName, toolName, args) {
|
|
2297
|
+
if (sessionOnly && !sessionQueryValid()) {
|
|
2298
|
+
return Promise.reject(new Error("Session tool unavailable or older query: " + serverName + "/" + toolName));
|
|
2299
|
+
}
|
|
2249
2300
|
var queryCall = queryToolBridge.callTool(queryGeneration, serverName, toolName, args);
|
|
2250
2301
|
if (queryCall) return queryCall;
|
|
2251
2302
|
if (boundSession && serverName === "clay-sessions") {
|
|
@@ -2404,6 +2455,7 @@ function createProjectContext(opts) {
|
|
|
2404
2455
|
getLatestVersion: function () { return latestVersion; },
|
|
2405
2456
|
getTitle: function () { return title; },
|
|
2406
2457
|
getProject: function () { return project; },
|
|
2458
|
+
hydrateSkillCatalog: _sessionSkillCatalog.hydrate,
|
|
2407
2459
|
// Exposed so the first websocket connection can lazily warm up the
|
|
2408
2460
|
// adapters for this project (see project-connection handleConnection).
|
|
2409
2461
|
warmup: function (linuxUser) {
|
|
@@ -2628,6 +2680,9 @@ function createProjectContext(opts) {
|
|
|
2628
2680
|
handleDisconnection: handleDisconnection,
|
|
2629
2681
|
handleHTTP: handleHTTP,
|
|
2630
2682
|
getMcpBridgeHandler: getMcpBridgeHandler,
|
|
2683
|
+
isMcpBridgeAuthenticated: function (req) {
|
|
2684
|
+
return !!(req && req.headers && req.headers["x-clay-bridge-token"] && req.headers["x-clay-bridge-token"] === mcpBridgeToken);
|
|
2685
|
+
},
|
|
2631
2686
|
getStatus: getStatus,
|
|
2632
2687
|
getSessionManager: function () { return sm; },
|
|
2633
2688
|
createDelegatedSession: _delegatedSession.createDelegatedSession,
|
package/lib/public/app.js
CHANGED
|
@@ -28,7 +28,7 @@ import { initRewind, setRewindMode, showRewindModal, clearPendingRewindUuid, add
|
|
|
28
28
|
import { initNotifications, showDoneNotification, playDoneSound, isNotifAlertEnabled, isNotifSoundEnabled } from './modules/notifications.js';
|
|
29
29
|
import { initInput, clearPendingImages, handleInputSync, autoResize, builtinCommands, sendMessage, hasSendableContent, setScheduleBtnDisabled, setScheduleDelayMs, clearScheduleDelay } from './modules/input.js';
|
|
30
30
|
import { initQrCode, triggerShare } from './modules/qrcode.js';
|
|
31
|
-
import { initFileBrowser, loadRootDirectory, refreshTree, handleFsList, handleFsRead, handleDirChanged, refreshIfOpen, handleFileChanged, handleFileHistory, handleGitDiff, handleFileAt, getPendingNavigate, closeFileViewer, resetFileBrowser } from './modules/filebrowser.js';
|
|
31
|
+
import { initFileBrowser, loadRootDirectory, reopenFileViewer, refreshTree, handleFsList, handleFsRead, handleDirChanged, refreshIfOpen, handleFileChanged, handleFileHistory, handleGitDiff, handleFileAt, getPendingNavigate, closeFileViewer, resetFileBrowser } from './modules/filebrowser.js';
|
|
32
32
|
import { initGitPanel } from './modules/git-panel.js';
|
|
33
33
|
import { initWorkerPaneLock } from './modules/worker-pane-lock.js';
|
|
34
34
|
import { initAutonomousRun } from './modules/autonomous-run.js';
|
|
@@ -36,7 +36,7 @@ import { initLoopInterview } from './modules/loop-interview.js';
|
|
|
36
36
|
import { initTerminal, openTerminal, closeTerminal, resetTerminals, handleTermList, handleTermCreated, handleTermOutput, handleTermResized, handleTermExited, handleTermClosed, sendTerminalCommand } from './modules/terminal.js';
|
|
37
37
|
import { initContextSources, updateTerminalList, updateBrowserTabList, handleContextSourcesState, getActiveSources, hasActiveSources } from './modules/context-sources.js';
|
|
38
38
|
import { initStickyNotes, handleNotesList, handleNoteCreated, handleNoteUpdated, handleNoteDeleted, hideNotes, showNotes, isNotesVisible, createNote, setBrowserRefresh, toggleNotesTemporaryVisibility } from './modules/sticky-notes.js';
|
|
39
|
-
import { initNotesBrowser, openNotesBrowser, closeNotesBrowser, isNotesBrowserOpen, renderNotesBrowser
|
|
39
|
+
import { initNotesBrowser, openNotesBrowser, closeNotesBrowser, isNotesBrowserOpen, renderNotesBrowser } from './modules/sticky-notes-browser.js';
|
|
40
40
|
import { initTheme, getThemeColor, getComputedVar, onThemeChange, getCurrentTheme, getChatLayout } from './modules/theme.js';
|
|
41
41
|
import { initTools, resetToolState, saveToolState, restoreToolState, renderAskUserQuestion, markAskUserAnswered, renderPermissionRequest, markPermissionResolved, markPermissionCancelled, renderElicitationRequest, markElicitationResolved, renderPlanBanner, renderPlanCard, handleTodoWrite, handleTaskCreate, handleTaskUpdate, startThinking, appendThinking, stopThinking, resetThinkingGroup, createToolItem, updateToolExecuting, updateToolResult, markAllToolsDone, addTurnMeta, resetTurnMetaCost, enableMainInput, getTools, getPlanContent, setPlanContent, isPlanFilePath, getTodoTools, updateSubagentActivity, addSubagentToolEntry, markSubagentDone, updateSubagentProgress, initSubagentStop, closeToolGroup, removeToolFromGroup } from './modules/tools.js';
|
|
42
42
|
import { initServerSettings, updateSettingsStats, updateDaemonConfig, handleSetPinResult, handleKeepAwakeChanged, handleAutoContinueChanged, handleRestartResult, handleShutdownResult, handleSharedEnv, handleSharedEnvSaved, handleGlobalClaudeMdRead, handleGlobalClaudeMdWrite } from './modules/server-settings.js';
|
|
@@ -68,9 +68,10 @@ import { initHomeSidebar } from './modules/home-sidebar.js';
|
|
|
68
68
|
import { openHomeMateAction } from './modules/home-mate-chat.js';
|
|
69
69
|
import { initHomeSurfaceBoot } from './modules/home-surface-boot.js';
|
|
70
70
|
import { rememberHomePrimarySurface } from './modules/home-surface.js';
|
|
71
|
-
import { initRateLimit, handleRateLimitEvent as _rlHandleRateLimitEvent, updateRateLimitUsage as _rlUpdateRateLimitUsage,
|
|
71
|
+
import { initRateLimit, handleRateLimitEvent as _rlHandleRateLimitEvent, updateRateLimitUsage as _rlUpdateRateLimitUsage, handleFastModeState as _rlHandleFastModeState, resetRateLimitState } from './modules/app-rate-limit.js';
|
|
72
72
|
import { initCursors, handleRemoteCursorMove as _curHandleRemoteCursorMove, handleRemoteCursorLeave as _curHandleRemoteCursorLeave, handleRemoteSelection as _curHandleRemoteSelection, clearRemoteCursors as _curClearRemoteCursors, initCursorToggle } from './modules/app-cursors.js';
|
|
73
73
|
import { initDefaultAi } from './modules/default-ai.js';
|
|
74
|
+
import { requestDefaultVendor } from './modules/default-vendor.js';
|
|
74
75
|
import { initFavicon, updateFavicon as _favUpdateFavicon, setSendBtnMode as _favSetSendBtnMode, blinkIO as _favBlinkIO, blinkSessionDot as _favBlinkSessionDot, updateCrossProjectBlink as _favUpdateCrossProjectBlink, startUrgentBlink as _favStartUrgentBlink, stopUrgentBlink as _favStopUrgentBlink, setActivity as _favSetActivity } from './modules/app-favicon.js';
|
|
75
76
|
import { initHeader, closeSessionInfoPopover as _hdrCloseSessionInfoPopover, updateHistorySentinel as _hdrUpdateHistorySentinel, requestMoreHistory as _hdrRequestMoreHistory, prependOlderHistory as _hdrPrependOlderHistory } from './modules/app-header.js';
|
|
76
77
|
import { initSessionActions } from './modules/session-actions.js';
|
|
@@ -286,6 +287,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
286
287
|
currentSlug: currentSlug,
|
|
287
288
|
activeProjectSlug: null,
|
|
288
289
|
sessionActivatedProjectSlug: null,
|
|
290
|
+
sessionListProjectSlug: null,
|
|
291
|
+
splitGroupsProjectSlug: null,
|
|
289
292
|
socketPath: null,
|
|
290
293
|
pendingHomeProjectSlug: null,
|
|
291
294
|
currentProjectOwnerId: null,
|
|
@@ -323,6 +326,9 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
323
326
|
connected: false,
|
|
324
327
|
fileReadRequest: null,
|
|
325
328
|
pendingFileNavigation: null,
|
|
329
|
+
rightWorkbenchOwner: null,
|
|
330
|
+
rightWorkbenchRevision: 0,
|
|
331
|
+
fileViewerOpenRevision: 0,
|
|
326
332
|
cursorSharingEnabled: false,
|
|
327
333
|
cursorSharingHydrated: false,
|
|
328
334
|
pendingOutboundMessages: [],
|
|
@@ -381,6 +387,12 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
381
387
|
projectLogsCanDelete: false,
|
|
382
388
|
projectLogsUnread: 0,
|
|
383
389
|
projectLogsSeenRevisions: {},
|
|
390
|
+
scheduledResultUnread: 0,
|
|
391
|
+
scheduledResultAutoFocusHandled: false,
|
|
392
|
+
scheduledResultFocusRef: null,
|
|
393
|
+
scheduledResultPendingReadRef: null,
|
|
394
|
+
scheduledResultSeenRefs: {},
|
|
395
|
+
scheduledResultSessionRequestId: null,
|
|
384
396
|
issuesOpen: false,
|
|
385
397
|
issuesView: "list",
|
|
386
398
|
issuesSelected: null,
|
|
@@ -388,6 +400,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
388
400
|
issuesRequests: {},
|
|
389
401
|
issuesViewRequest: null,
|
|
390
402
|
issuesViewGeneration: 0,
|
|
403
|
+
issuesUpdateAvailable: null,
|
|
391
404
|
issuesCache: {},
|
|
392
405
|
issuesEpoch: 0,
|
|
393
406
|
issuesSearchTimer: null,
|
|
@@ -418,6 +431,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
418
431
|
defaultAiState: { loading: false, saving: false, refreshRequestId: null, saveRequestId: null, catalogRequestIds: {}, catalogs: {}, preference: null, selection: null, installedVendors: [], accountAvailable: true, accountId: null, serverEpoch: null, canonicalRevision: 0, error: "" },
|
|
419
432
|
defaultAiDraft: { vendor: "", model: "", effort: "" },
|
|
420
433
|
defaultAiDraftDirty: false,
|
|
434
|
+
defaultVendorState: { loading: false, saving: false, getRequestId: null, saveRequestId: null, preference: null, preferencePresent: false, installedVendors: [], accountId: null, projectSlug: null, serverEpoch: null, canonicalRevision: 0, error: "" },
|
|
421
435
|
|
|
422
436
|
// dm
|
|
423
437
|
dmTargetUser: null,
|
|
@@ -434,6 +448,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
434
448
|
pendingShellCommandId: null,
|
|
435
449
|
mateProjectSlug: null,
|
|
436
450
|
myUserId: null,
|
|
451
|
+
contextViewPreferenceState: { mode: "off", canonicalMode: "off", preferencePresent: false, loading: false, saving: false, requestId: null, saveRequestId: null, pendingSaves: [], accountId: null, serverEpoch: null, rejectedEpoch: null, canonicalRevision: 0, error: "" },
|
|
452
|
+
contextViewOverride: null,
|
|
437
453
|
isMultiUserMode: false,
|
|
438
454
|
dmUnread: {},
|
|
439
455
|
dmRemovedUsers: {},
|
|
@@ -469,6 +485,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
469
485
|
lastVendor: "",
|
|
470
486
|
// Static adapter metadata sent before any vendor is initialized.
|
|
471
487
|
vendorInfo: {},
|
|
488
|
+
// Rate-limit data is projected only for the displayed session/vendor.
|
|
489
|
+
rateLimitState: {},
|
|
472
490
|
// How Claude sessions open: "gui" (default) or "tui". The server sends
|
|
473
491
|
// claude_open_mode_changed on connect; this seeds it beforehand so the
|
|
474
492
|
// new-session menu doesn't flash the TUI-only entry.
|
|
@@ -544,7 +562,11 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
544
562
|
newSessionBtn: newSessionBtn,
|
|
545
563
|
headerTitleEl: headerTitleEl,
|
|
546
564
|
showConfirm: showConfirm,
|
|
547
|
-
onFilesTabOpen: function () {
|
|
565
|
+
onFilesTabOpen: function () {
|
|
566
|
+
reopenFileViewer();
|
|
567
|
+
loadRootDirectory();
|
|
568
|
+
if (isSchedulerOpen()) closeScheduler();
|
|
569
|
+
},
|
|
548
570
|
requestKnowledgeList: function () { requestKnowledgeList(); },
|
|
549
571
|
switchProject: function (slug) { switchProject(slug); },
|
|
550
572
|
openTerminal: function () { openTerminal(); },
|
|
@@ -844,8 +866,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
844
866
|
// --- Rate Limit / Scheduled Messages / Fast Mode (delegated to app-rate-limit.js) ---
|
|
845
867
|
function handleRateLimitEvent(msg) { _rlHandleRateLimitEvent(msg); }
|
|
846
868
|
function updateRateLimitUsage(msg) { _rlUpdateRateLimitUsage(msg); }
|
|
847
|
-
function addScheduledMessageBubble(text, resetsAt) { _rlAddScheduledMessageBubble(text, resetsAt); }
|
|
848
|
-
function removeScheduledMessageBubble() { _rlRemoveScheduledMessageBubble(); }
|
|
849
869
|
function handleFastModeState(state) { _rlHandleFastModeState(state); }
|
|
850
870
|
|
|
851
871
|
// --- Prompt suggestion chips (delegated to app-rendering.js) ---
|
|
@@ -1011,7 +1031,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
1011
1031
|
// the project Mate DM preference therefore hides only Mate shortcuts.
|
|
1012
1032
|
if (document.body) document.body.classList.add('is-multi-user');
|
|
1013
1033
|
}
|
|
1014
|
-
if (d.user && d.user.id) { store.set({ myUserId: d.user.id }); }
|
|
1034
|
+
if (d.user && d.user.id) { store.set({ myUserId: d.user.id }); requestDefaultVendor(); }
|
|
1015
1035
|
if (d.permissions) store.set({ permissions: d.permissions });
|
|
1016
1036
|
if (d.mustChangePin) showForceChangePinOverlay();
|
|
1017
1037
|
// Single-user mode: clear user strip skeletons immediately (no presence message will arrive)
|
|
@@ -1190,9 +1210,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
1190
1210
|
// The browser refreshes from note messages without the canvas module having
|
|
1191
1211
|
// to import it, which would be a cycle.
|
|
1192
1212
|
setBrowserRefresh(function () { if (isNotesBrowserOpen()) renderNotesBrowser(); });
|
|
1193
|
-
// Opening the browser claims the single right workbench slot. Registered here
|
|
1194
|
-
// so the browser module never imports the other tools.
|
|
1195
|
-
registerExclusiveClosers([closeIssues, closeProjectLogs, closeScheduledTasks, closeFileViewer, closeTerminal]);
|
|
1196
1213
|
|
|
1197
1214
|
// --- Sticky Notes sidebar button (create new note) ---
|
|
1198
1215
|
var stickyNotesSidebarBtn = $("sticky-notes-sidebar-btn");
|
|
@@ -1231,10 +1248,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
1231
1248
|
}
|
|
1232
1249
|
|
|
1233
1250
|
// Close the notes browser / scheduler panel when switching to other sidebar panels
|
|
1234
|
-
var fileBrowserBtn = $("file-browser-btn");
|
|
1235
1251
|
var gitPlacardMoreBtn = $("git-placard-more");
|
|
1236
1252
|
var terminalSidebarBtn = $("terminal-sidebar-btn");
|
|
1237
|
-
if (fileBrowserBtn) fileBrowserBtn.addEventListener("click", function () { closeIssues(); closeProjectLogs(); closeScheduledTasks(); if (isNotesBrowserOpen()) closeNotesBrowser(); if (isSchedulerOpen()) closeScheduler(); });
|
|
1238
1253
|
if (gitPlacardMoreBtn) gitPlacardMoreBtn.addEventListener("click", function () { closeIssues(); closeProjectLogs(); closeScheduledTasks(); if (isNotesBrowserOpen()) closeNotesBrowser(); if (isSchedulerOpen()) closeScheduler(); });
|
|
1239
1254
|
if (terminalSidebarBtn) terminalSidebarBtn.addEventListener("click", function () { closeIssues(); closeProjectLogs(); closeScheduledTasks(); if (isNotesBrowserOpen()) closeNotesBrowser(); if (isSchedulerOpen()) closeScheduler(); });
|
|
1240
1255
|
|
|
@@ -513,6 +513,7 @@ body.mate-dm-active .search-clay-transcript .search-clay-message-user .bubble,
|
|
|
513
513
|
@keyframes searchClaySpin { to { transform: rotate(360deg); } }
|
|
514
514
|
|
|
515
515
|
.clayos-session-link,
|
|
516
|
+
.clayos-issue-link,
|
|
516
517
|
.clayos-log-link {
|
|
517
518
|
display: inline-flex;
|
|
518
519
|
align-items: center;
|
|
@@ -531,6 +532,7 @@ body.mate-dm-active .search-clay-transcript .search-clay-message-user .bubble,
|
|
|
531
532
|
cursor: pointer;
|
|
532
533
|
}
|
|
533
534
|
.clayos-session-link::before,
|
|
535
|
+
.clayos-issue-link::before,
|
|
534
536
|
.clayos-log-link::before {
|
|
535
537
|
content: "\2197";
|
|
536
538
|
display: grid;
|
|
@@ -542,20 +544,28 @@ body.mate-dm-active .search-clay-transcript .search-clay-message-user .bubble,
|
|
|
542
544
|
color: var(--accent);
|
|
543
545
|
font-size: 12px;
|
|
544
546
|
}
|
|
547
|
+
.clayos-issue-link::before,
|
|
545
548
|
.clayos-log-link::before { content: "\2261"; }
|
|
546
549
|
.clayos-session-link > span,
|
|
550
|
+
.clayos-issue-link > span,
|
|
547
551
|
.clayos-log-link > span { font-weight: 620; }
|
|
548
552
|
.clayos-session-link > small,
|
|
553
|
+
.clayos-issue-link > small,
|
|
549
554
|
.clayos-log-link > small { color: var(--text-muted); font-size: 10px; }
|
|
550
555
|
.clayos-session-link:hover,
|
|
556
|
+
.clayos-issue-link:hover,
|
|
551
557
|
.clayos-log-link:hover { border-color: color-mix(in srgb, var(--accent) 52%, var(--border)); background: color-mix(in srgb, var(--accent) 11%, var(--bg-alt)); }
|
|
552
558
|
.clayos-session-link:focus-visible,
|
|
559
|
+
.clayos-issue-link:focus-visible,
|
|
553
560
|
.clayos-log-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
554
561
|
.clayos-session-link.is-loading,
|
|
562
|
+
.clayos-issue-link.is-loading,
|
|
555
563
|
.clayos-log-link.is-loading { opacity: 0.62; cursor: progress; }
|
|
556
564
|
.clayos-session-link.is-loading::before,
|
|
565
|
+
.clayos-issue-link.is-loading::before,
|
|
557
566
|
.clayos-log-link.is-loading::before { animation: searchClaySpin 1.2s linear infinite; }
|
|
558
567
|
.clayos-session-link.is-error,
|
|
568
|
+
.clayos-issue-link.is-error,
|
|
559
569
|
.clayos-log-link.is-error { border-color: color-mix(in srgb, var(--warning) 48%, var(--border)); }
|
|
560
570
|
|
|
561
571
|
.search-clay-pending {
|
|
@@ -913,3 +923,13 @@ body.mate-dm-active .search-clay-transcript .search-clay-message-user .bubble,
|
|
|
913
923
|
font-family: inherit;
|
|
914
924
|
color: var(--text-muted);
|
|
915
925
|
}
|
|
926
|
+
|
|
927
|
+
.clayos-issue-link { max-width: min(100%, 30em); box-sizing: border-box; }
|
|
928
|
+
.clayos-issue-link::before { content: "\25CE"; flex: 0 0 17px; }
|
|
929
|
+
.clayos-issue-link[data-status="in_progress"]::before { color: #bd923f; }
|
|
930
|
+
.clayos-issue-link[data-status="resolved"]::before { content: "\2713"; color: var(--brand-green); }
|
|
931
|
+
.clayos-issue-link[data-status="closed"]::before { content: "\00D7"; color: var(--text-dimmer); }
|
|
932
|
+
.clayos-issue-link > span { flex-shrink: 0; }
|
|
933
|
+
.clayos-issue-link > small { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
|
934
|
+
.clayos-log-link { max-width: 100%; box-sizing: border-box; }
|
|
935
|
+
.clayos-log-link > small { min-width: 0; overflow-wrap: anywhere; line-height: 1.35; }
|