clay-server 2.32.0-beta.1 → 2.32.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/codex-defaults.js +18 -0
- package/lib/project-connection.js +5 -4
- package/lib/project-debate.js +8 -0
- package/lib/project-mate-interaction.js +102 -16
- package/lib/project-notifications.js +9 -0
- package/lib/project-sessions.js +12 -6
- package/lib/project.js +30 -9
- package/lib/public/app.js +13 -7
- package/lib/public/css/input.css +158 -5
- package/lib/public/css/notifications-center.css +7 -0
- package/lib/public/css/tooltip.css +47 -0
- package/lib/public/index.html +34 -4
- package/lib/public/modules/app-dm.js +5 -0
- package/lib/public/modules/app-messages.js +8 -5
- package/lib/public/modules/app-notifications.js +42 -20
- package/lib/public/modules/app-panels.js +3 -3
- package/lib/public/modules/app-projects.js +2 -0
- package/lib/public/modules/context-sources.js +92 -27
- package/lib/public/modules/input.js +36 -0
- package/lib/public/modules/markdown.js +5 -1
- package/lib/public/modules/sidebar-mates.js +13 -1
- package/lib/public/modules/terminal.js +12 -0
- package/lib/public/modules/tools.js +4 -4
- package/lib/public/modules/tooltip.js +32 -5
- package/lib/sdk-bridge.js +57 -7
- package/lib/sdk-message-processor.js +28 -2
- package/lib/sessions.js +35 -2
- package/lib/yoke/adapters/claude.js +65 -0
- package/lib/yoke/adapters/codex.js +161 -8
- package/lib/yoke/adapters/gemini.js +41 -0
- package/lib/yoke/interface.js +6 -0
- package/package.json +1 -1
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
var CODEX_DEFAULTS = {
|
|
2
|
+
approval: "on-failure",
|
|
3
|
+
sandbox: "danger-full-access",
|
|
4
|
+
webSearch: "live",
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
function getCodexConfig(sm) {
|
|
8
|
+
return {
|
|
9
|
+
approval: (sm && sm.codexApproval) || CODEX_DEFAULTS.approval,
|
|
10
|
+
sandbox: (sm && sm.codexSandbox) || CODEX_DEFAULTS.sandbox,
|
|
11
|
+
webSearch: (sm && sm.codexWebSearch) || CODEX_DEFAULTS.webSearch,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
CODEX_DEFAULTS: CODEX_DEFAULTS,
|
|
17
|
+
getCodexConfig: getCodexConfig,
|
|
18
|
+
};
|
|
@@ -3,6 +3,7 @@ var path = require("path");
|
|
|
3
3
|
var usersModule = require("./users");
|
|
4
4
|
var userPresence = require("./user-presence");
|
|
5
5
|
var emailAccounts = require("./email-accounts");
|
|
6
|
+
var { getCodexConfig } = require("./codex-defaults");
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Attach connection/disconnection handlers to a project context.
|
|
@@ -84,10 +85,9 @@ function attachConnection(ctx) {
|
|
|
84
85
|
var project = getProject();
|
|
85
86
|
var ownerLocked = !!(osUsers && osUsers.length > 0 && /^\/home\/[^/]+\//.test(cwd));
|
|
86
87
|
sendTo(ws, { type: "info", cwd: cwd, slug: slug, project: title || project, version: currentVersion, debug: !!debug, dangerouslySkipPermissions: dangerouslySkipPermissions, osUsers: osUsers, lanHost: lanHost, projectCount: _filteredProjects.length, projects: _filteredProjects, projectOwnerId: projectOwnerId, ownerLocked: ownerLocked });
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
88
|
+
// Update notifications are pushed on a scheduled interval (see
|
|
89
|
+
// scheduleUpdateBroadcast). We no longer push on connect to avoid
|
|
90
|
+
// re-triggering the banner on every page refresh.
|
|
91
91
|
if (sm.slashCommands) {
|
|
92
92
|
sendTo(ws, { type: "slash_commands", commands: sm.slashCommands });
|
|
93
93
|
}
|
|
@@ -96,6 +96,7 @@ function attachConnection(ctx) {
|
|
|
96
96
|
sendTo(ws, { type: "model_info", model: sm.currentModel, models: sm.availableModels || [], vendor: sm.defaultVendor || "claude", availableVendors: sm.availableVendors || [], installedVendors: sm.installedVendors || [] });
|
|
97
97
|
}
|
|
98
98
|
sendTo(ws, { type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode || "default", effort: sm.currentEffort || "medium", betas: sm.currentBetas || [], thinking: sm.currentThinking || "adaptive", thinkingBudget: sm.currentThinkingBudget || 10000 });
|
|
99
|
+
sendTo(ws, Object.assign({ type: "codex_config" }, getCodexConfig(sm)));
|
|
99
100
|
sendTo(ws, { type: "term_list", terminals: tm.list() });
|
|
100
101
|
// Context sources sent after session is resolved (per-session storage)
|
|
101
102
|
// Send email accounts list for context sources picker
|
package/lib/project-debate.js
CHANGED
|
@@ -601,7 +601,9 @@ function attachDebate(ctx) {
|
|
|
601
601
|
var digests = ctx.loadMateDigests(mateCtx, debate.moderatorId, debate.topic);
|
|
602
602
|
|
|
603
603
|
var briefText = "";
|
|
604
|
+
var _modMate = matesModule.getMate(mateCtx, debate.moderatorId);
|
|
604
605
|
ctx.sdk.createMentionSession({
|
|
606
|
+
vendor: _modMate ? _modMate.vendor : null,
|
|
605
607
|
claudeMd: claudeMd,
|
|
606
608
|
initialContext: digests,
|
|
607
609
|
initialMessage: quickBriefPrompt,
|
|
@@ -794,7 +796,9 @@ function attachDebate(ctx) {
|
|
|
794
796
|
var digests = ctx.loadMateDigests(mateCtx, debate.moderatorId, debate.topic);
|
|
795
797
|
var moderatorContext = buildModeratorContext(debate) + digests;
|
|
796
798
|
|
|
799
|
+
var _modMate2 = matesModule.getMate(mateCtx, debate.moderatorId);
|
|
797
800
|
ctx.sdk.createMentionSession({
|
|
801
|
+
vendor: _modMate2 ? _modMate2.vendor : null,
|
|
798
802
|
claudeMd: claudeMd,
|
|
799
803
|
initialContext: moderatorContext,
|
|
800
804
|
initialMessage: "Begin the debate on: " + debate.topic,
|
|
@@ -987,7 +991,9 @@ function attachDebate(ctx) {
|
|
|
987
991
|
historyContext += "---";
|
|
988
992
|
}
|
|
989
993
|
|
|
994
|
+
var _panMate = matesModule.getMate(debate.mateCtx, mateId);
|
|
990
995
|
ctx.sdk.createMentionSession({
|
|
996
|
+
vendor: _panMate ? _panMate.vendor : null,
|
|
991
997
|
claudeMd: claudeMd,
|
|
992
998
|
initialContext: panelistContext + historyContext,
|
|
993
999
|
initialMessage: "The moderator addresses you:\n\n" + moderatorText,
|
|
@@ -1521,7 +1527,9 @@ function attachDebate(ctx) {
|
|
|
1521
1527
|
}
|
|
1522
1528
|
moderatorContext += "---\n";
|
|
1523
1529
|
|
|
1530
|
+
var _modMate3 = matesModule.getMate(mateCtx, debate.moderatorId);
|
|
1524
1531
|
ctx.sdk.createMentionSession({
|
|
1532
|
+
vendor: _modMate3 ? _modMate3.vendor : null,
|
|
1525
1533
|
claudeMd: claudeMd,
|
|
1526
1534
|
initialContext: moderatorContext,
|
|
1527
1535
|
initialMessage: resumePrompt,
|
|
@@ -4,6 +4,7 @@ var crypto = require("crypto");
|
|
|
4
4
|
|
|
5
5
|
function attachMateInteraction(ctx) {
|
|
6
6
|
var cwd = ctx.cwd;
|
|
7
|
+
var slug = ctx.slug || "";
|
|
7
8
|
var sm = ctx.sm;
|
|
8
9
|
var sdk = ctx.sdk;
|
|
9
10
|
var send = ctx.send;
|
|
@@ -21,6 +22,7 @@ function attachMateInteraction(ctx) {
|
|
|
21
22
|
var loadMateDigests = ctx.loadMateDigests;
|
|
22
23
|
var updateMemorySummary = ctx.updateMemorySummary;
|
|
23
24
|
var initMemorySummary = ctx.initMemorySummary;
|
|
25
|
+
var getNotificationsModule = ctx.getNotificationsModule || function () { return null; };
|
|
24
26
|
// checkForDmDebateBrief is accessed via ctx at call time because
|
|
25
27
|
// it comes from the debate module initialized after this one.
|
|
26
28
|
|
|
@@ -104,6 +106,30 @@ function attachMateInteraction(ctx) {
|
|
|
104
106
|
return lines.join("\n") + "\n\n";
|
|
105
107
|
}
|
|
106
108
|
|
|
109
|
+
function getHostMateId() {
|
|
110
|
+
if (typeof slug === "string" && slug.indexOf("mate-") === 0) {
|
|
111
|
+
return slug.substring(5) || null;
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function notifyMentionResponse(session, mentionMateId, mentionMateName, fullText) {
|
|
117
|
+
var notificationsModule = getNotificationsModule();
|
|
118
|
+
var hostMateId = getHostMateId();
|
|
119
|
+
var preview = (fullText || "").replace(/\s+/g, " ").trim();
|
|
120
|
+
if (preview.length > 140) preview = preview.substring(0, 140) + "...";
|
|
121
|
+
if (!notificationsModule || !hostMateId) return;
|
|
122
|
+
notificationsModule.notify("mention_response", {
|
|
123
|
+
title: (mentionMateName || "Mate") + " responded",
|
|
124
|
+
preview: preview,
|
|
125
|
+
slug: slug,
|
|
126
|
+
sessionId: session.localId,
|
|
127
|
+
mateId: hostMateId,
|
|
128
|
+
avatarMateId: mentionMateId || null,
|
|
129
|
+
ownerId: session.ownerId || null,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
107
133
|
// --- Shared digest worker: one reusable Haiku session for gate+digest ---
|
|
108
134
|
// Combines gate check and digest generation into a single prompt,
|
|
109
135
|
// processes jobs sequentially from a queue, reuses the session across calls.
|
|
@@ -136,12 +162,19 @@ function attachMateInteraction(ctx) {
|
|
|
136
162
|
} catch (e) {}
|
|
137
163
|
|
|
138
164
|
// Combined gate + digest in one prompt (saves a full round-trip vs separate gate)
|
|
139
|
-
var
|
|
165
|
+
var promptParts = [
|
|
140
166
|
"[SYSTEM: Memory Gate + Digest]",
|
|
141
167
|
"You are a memory system for an AI Mate (role: " + (mateRole || "assistant") + ").",
|
|
142
168
|
"",
|
|
143
|
-
|
|
144
|
-
|
|
169
|
+
];
|
|
170
|
+
if (job.priorSummary) {
|
|
171
|
+
promptParts.push("Prior conversation context (memory summary so far):");
|
|
172
|
+
promptParts.push(job.priorSummary);
|
|
173
|
+
promptParts.push("");
|
|
174
|
+
}
|
|
175
|
+
promptParts.push("Conversation (" + job.type + "):");
|
|
176
|
+
promptParts.push(job.conversationContent);
|
|
177
|
+
var prompt = promptParts.concat([
|
|
145
178
|
"",
|
|
146
179
|
"STEP 1: Should this be saved to memory?",
|
|
147
180
|
'Answer "no" ONLY if the entire conversation is trivial (e.g. just "hi"/"hello").',
|
|
@@ -171,7 +204,7 @@ function attachMateInteraction(ctx) {
|
|
|
171
204
|
"user_observations: OPTIONAL array. Include ONLY if you noticed meaningful patterns about the USER themselves (not the topic).",
|
|
172
205
|
"Categories: pattern (repeated behavior 2+ times), decision (explicit choice with reasoning), reaction (emotional/attitude signal), preference (tool/style/communication preference).",
|
|
173
206
|
"Omit the field entirely if nothing notable about the user.",
|
|
174
|
-
].join("\n");
|
|
207
|
+
]).join("\n");
|
|
175
208
|
|
|
176
209
|
function handleResult(text) {
|
|
177
210
|
var cleaned = text.trim();
|
|
@@ -225,9 +258,14 @@ function attachMateInteraction(ctx) {
|
|
|
225
258
|
}
|
|
226
259
|
}
|
|
227
260
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
261
|
+
// Skip summary update for failed parses -- the fallback digest would degrade quality
|
|
262
|
+
if (digestObj.topic !== "parse_failed") {
|
|
263
|
+
updateMemorySummary(job.mateCtx, job.mateId, digestObj);
|
|
264
|
+
maybeSynthesizeUserProfile(job.mateCtx, job.mateId);
|
|
265
|
+
if (job.onDone) job.onDone();
|
|
266
|
+
} else {
|
|
267
|
+
if (job.onError) job.onError(new Error("parse_failed"));
|
|
268
|
+
}
|
|
231
269
|
processDigestQueue();
|
|
232
270
|
}
|
|
233
271
|
|
|
@@ -249,7 +287,7 @@ function attachMateInteraction(ctx) {
|
|
|
249
287
|
console.error("[digest-worker] Error:", err);
|
|
250
288
|
_digestWorker = null;
|
|
251
289
|
_digestWorkerTurns = 0;
|
|
252
|
-
if (job.
|
|
290
|
+
if (job.onError) job.onError(err);
|
|
253
291
|
processDigestQueue();
|
|
254
292
|
},
|
|
255
293
|
});
|
|
@@ -265,11 +303,11 @@ function attachMateInteraction(ctx) {
|
|
|
265
303
|
onError: function (err) {
|
|
266
304
|
console.error("[digest-worker] Create error:", err);
|
|
267
305
|
_digestWorker = null;
|
|
268
|
-
if (job.
|
|
306
|
+
if (job.onError) job.onError(err);
|
|
269
307
|
processDigestQueue();
|
|
270
308
|
},
|
|
271
|
-
}).then(function (ws) { _digestWorker = ws; _digestWorkerTurns = 1; }).catch(function () {
|
|
272
|
-
if (job.
|
|
309
|
+
}).then(function (ws) { _digestWorker = ws; _digestWorkerTurns = 1; }).catch(function (err) {
|
|
310
|
+
if (job.onError) job.onError(err || new Error("digest worker creation failed"));
|
|
273
311
|
processDigestQueue();
|
|
274
312
|
});
|
|
275
313
|
}
|
|
@@ -303,10 +341,14 @@ function attachMateInteraction(ctx) {
|
|
|
303
341
|
type: "mention",
|
|
304
342
|
conversationContent: conversationContent,
|
|
305
343
|
onDone: function () { mentionSession._digesting = false; },
|
|
344
|
+
onError: function () { mentionSession._digesting = false; },
|
|
306
345
|
});
|
|
307
346
|
}
|
|
308
347
|
|
|
309
|
-
// Digest DM turn for mate projects - uses shared digest worker
|
|
348
|
+
// Digest DM turn for mate projects - uses shared digest worker.
|
|
349
|
+
// Delta-based: only collects new turns since the last successful digest.
|
|
350
|
+
// Concurrency debounce: turns that arrive while a digest is in-flight
|
|
351
|
+
// are naturally batched into the next flush.
|
|
310
352
|
var _dmDigestPending = false;
|
|
311
353
|
function digestDmTurn(session, responsePreview) {
|
|
312
354
|
if (!isMate || _dmDigestPending) return;
|
|
@@ -314,11 +356,26 @@ function attachMateInteraction(ctx) {
|
|
|
314
356
|
var mateCtx = matesModule.buildMateCtx(projectOwnerId);
|
|
315
357
|
if (!matesModule.isMate(mateCtx, mateId)) return;
|
|
316
358
|
|
|
317
|
-
//
|
|
359
|
+
// Track digest index per session so switching sessions doesn't misalign.
|
|
360
|
+
// On resumed sessions (after restart), recover index from the last
|
|
361
|
+
// digest_checkpoint entry in history so undigested turns aren't lost.
|
|
362
|
+
if (typeof session._dmLastDigestedIndex !== "number") {
|
|
363
|
+
session._dmLastDigestedIndex = 0;
|
|
364
|
+
for (var ci = session.history.length - 1; ci >= 0; ci--) {
|
|
365
|
+
if (session.history[ci].type === "digest_checkpoint") {
|
|
366
|
+
session._dmLastDigestedIndex = session.history[ci].digestedIndex;
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Collect only new turns since the last successful digest
|
|
318
373
|
var conversationParts = [];
|
|
319
374
|
var totalLen = 0;
|
|
320
375
|
var CONV_CAP = 6000;
|
|
321
|
-
|
|
376
|
+
var startIndex = session._dmLastDigestedIndex;
|
|
377
|
+
for (var hi = startIndex; hi < session.history.length; hi++) {
|
|
378
|
+
if (totalLen >= CONV_CAP) break;
|
|
322
379
|
var entry = session.history[hi];
|
|
323
380
|
if (entry.type === "user_message" && entry.text) {
|
|
324
381
|
var uText = entry.text;
|
|
@@ -335,8 +392,8 @@ function attachMateInteraction(ctx) {
|
|
|
335
392
|
conversationParts.push("Mate: " + aText);
|
|
336
393
|
totalLen += aText.length;
|
|
337
394
|
}
|
|
338
|
-
if (totalLen >= CONV_CAP) break;
|
|
339
395
|
}
|
|
396
|
+
// If the latest response hasn't landed in history yet, append it
|
|
340
397
|
var lastResponseText = responsePreview || "";
|
|
341
398
|
if (lastResponseText && conversationParts.length > 0) {
|
|
342
399
|
var lastPart = conversationParts[conversationParts.length - 1];
|
|
@@ -362,14 +419,34 @@ function attachMateInteraction(ctx) {
|
|
|
362
419
|
});
|
|
363
420
|
}
|
|
364
421
|
|
|
422
|
+
// Read existing summary to give the digest worker context for delta content
|
|
423
|
+
var priorSummary = "";
|
|
424
|
+
try {
|
|
425
|
+
if (fs.existsSync(summaryFile)) {
|
|
426
|
+
priorSummary = fs.readFileSync(summaryFile, "utf8").trim();
|
|
427
|
+
}
|
|
428
|
+
} catch (e) {}
|
|
429
|
+
|
|
365
430
|
_dmDigestPending = true;
|
|
431
|
+
var snapshotIndex = session.history.length;
|
|
366
432
|
|
|
367
433
|
enqueueDigest({
|
|
368
434
|
mateCtx: mateCtx,
|
|
369
435
|
mateId: mateId,
|
|
370
436
|
type: "dm",
|
|
437
|
+
priorSummary: priorSummary || "",
|
|
371
438
|
conversationContent: conversationParts.join("\n"),
|
|
372
|
-
onDone: function () {
|
|
439
|
+
onDone: function () {
|
|
440
|
+
session._dmLastDigestedIndex = snapshotIndex;
|
|
441
|
+
// Persist checkpoint so resumed sessions know where to continue
|
|
442
|
+
var checkpoint = { type: "digest_checkpoint", digestedIndex: snapshotIndex };
|
|
443
|
+
session.history.push(checkpoint);
|
|
444
|
+
sm.appendToSessionFile(session, checkpoint);
|
|
445
|
+
_dmDigestPending = false;
|
|
446
|
+
},
|
|
447
|
+
onError: function () {
|
|
448
|
+
_dmDigestPending = false;
|
|
449
|
+
},
|
|
373
450
|
});
|
|
374
451
|
}
|
|
375
452
|
|
|
@@ -445,6 +522,7 @@ function attachMateInteraction(ctx) {
|
|
|
445
522
|
}
|
|
446
523
|
|
|
447
524
|
session._mentionInProgress = true;
|
|
525
|
+
session._mentionActiveMateId = msg.mateId;
|
|
448
526
|
|
|
449
527
|
// Send mention start indicator
|
|
450
528
|
sendToSession(session.localId, {
|
|
@@ -478,6 +556,7 @@ function attachMateInteraction(ctx) {
|
|
|
478
556
|
},
|
|
479
557
|
onDone: function (fullText) {
|
|
480
558
|
session._mentionInProgress = false;
|
|
559
|
+
session._mentionActiveMateId = null;
|
|
481
560
|
|
|
482
561
|
// Save mention response to session history
|
|
483
562
|
var mentionResponseEntry = {
|
|
@@ -504,6 +583,10 @@ function attachMateInteraction(ctx) {
|
|
|
504
583
|
sendToSession(session.localId, { type: "mention_done", mateId: msg.mateId });
|
|
505
584
|
send({ type: "mention_processing", mateId: msg.mateId, active: false });
|
|
506
585
|
|
|
586
|
+
if (isMate) {
|
|
587
|
+
notifyMentionResponse(session, msg.mateId, mateName, fullText);
|
|
588
|
+
}
|
|
589
|
+
|
|
507
590
|
// Check if the mate wrote a debate brief during this turn
|
|
508
591
|
ctx.checkForDmDebateBrief(session, msg.mateId, mateCtx);
|
|
509
592
|
|
|
@@ -512,6 +595,7 @@ function attachMateInteraction(ctx) {
|
|
|
512
595
|
},
|
|
513
596
|
onError: function (errMsg) {
|
|
514
597
|
session._mentionInProgress = false;
|
|
598
|
+
session._mentionActiveMateId = null;
|
|
515
599
|
// Clean up dead session
|
|
516
600
|
if (session._mentionSessions && session._mentionSessions[msg.mateId]) {
|
|
517
601
|
delete session._mentionSessions[msg.mateId];
|
|
@@ -560,6 +644,7 @@ function attachMateInteraction(ctx) {
|
|
|
560
644
|
|
|
561
645
|
// Create new persistent mention session
|
|
562
646
|
sdk.createMentionSession({
|
|
647
|
+
vendor: mate.vendor || null,
|
|
563
648
|
claudeMd: claudeMd,
|
|
564
649
|
initialContext: mentionContext,
|
|
565
650
|
initialMessage: mentionFullInput,
|
|
@@ -614,6 +699,7 @@ function attachMateInteraction(ctx) {
|
|
|
614
699
|
}
|
|
615
700
|
}).catch(function (err) {
|
|
616
701
|
session._mentionInProgress = false;
|
|
702
|
+
session._mentionActiveMateId = null;
|
|
617
703
|
console.error("[mention] Failed to create session for mate " + msg.mateId + ":", err.message || err);
|
|
618
704
|
sendToSession(session.localId, { type: "mention_error", mateId: msg.mateId, error: "Failed to create mention session." });
|
|
619
705
|
});
|
|
@@ -60,6 +60,15 @@ var formatters = {
|
|
|
60
60
|
body: data.preview || "Sent you a message",
|
|
61
61
|
};
|
|
62
62
|
},
|
|
63
|
+
|
|
64
|
+
mention_response: function (data) {
|
|
65
|
+
return {
|
|
66
|
+
type: "mention_response",
|
|
67
|
+
title: data.title || "Mention response ready",
|
|
68
|
+
body: data.preview || "",
|
|
69
|
+
meta: { avatarMateId: data.avatarMateId || null },
|
|
70
|
+
};
|
|
71
|
+
},
|
|
63
72
|
};
|
|
64
73
|
|
|
65
74
|
// ========================================================
|
package/lib/project-sessions.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
var fs = require("fs");
|
|
2
2
|
var path = require("path");
|
|
3
3
|
var { execFileSync } = require("child_process");
|
|
4
|
+
var { CODEX_DEFAULTS, getCodexConfig } = require("./codex-defaults");
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Attach session management, config, project management, and mid-section
|
|
@@ -280,6 +281,7 @@ function attachSessions(ctx) {
|
|
|
280
281
|
if (msg.id && sm.sessions.has(msg.id) && msg.title) {
|
|
281
282
|
var s = sm.sessions.get(msg.id);
|
|
282
283
|
s.title = String(msg.title).substring(0, 100);
|
|
284
|
+
s.titleManuallySet = true;
|
|
283
285
|
sm.saveSessionFile(s);
|
|
284
286
|
sm.broadcastSessionList();
|
|
285
287
|
// Sync title to SDK session
|
|
@@ -519,18 +521,18 @@ function attachSessions(ctx) {
|
|
|
519
521
|
|
|
520
522
|
// Codex-specific settings (stored on sessionManager, passed to adapter via adapterOptions)
|
|
521
523
|
if (msg.type === "set_codex_approval") {
|
|
522
|
-
sm.codexApproval = msg.approval ||
|
|
523
|
-
send({ type: "codex_config"
|
|
524
|
+
sm.codexApproval = msg.approval || CODEX_DEFAULTS.approval;
|
|
525
|
+
send(Object.assign({ type: "codex_config" }, getCodexConfig(sm)));
|
|
524
526
|
return true;
|
|
525
527
|
}
|
|
526
528
|
if (msg.type === "set_codex_sandbox") {
|
|
527
|
-
sm.codexSandbox = msg.sandbox ||
|
|
528
|
-
send({ type: "codex_config"
|
|
529
|
+
sm.codexSandbox = msg.sandbox || CODEX_DEFAULTS.sandbox;
|
|
530
|
+
send(Object.assign({ type: "codex_config" }, getCodexConfig(sm)));
|
|
529
531
|
return true;
|
|
530
532
|
}
|
|
531
533
|
if (msg.type === "set_codex_websearch") {
|
|
532
|
-
sm.codexWebSearch = msg.webSearch ||
|
|
533
|
-
send({ type: "codex_config"
|
|
534
|
+
sm.codexWebSearch = msg.webSearch || CODEX_DEFAULTS.webSearch;
|
|
535
|
+
send(Object.assign({ type: "codex_config" }, getCodexConfig(sm)));
|
|
534
536
|
return true;
|
|
535
537
|
}
|
|
536
538
|
|
|
@@ -596,6 +598,10 @@ function attachSessions(ctx) {
|
|
|
596
598
|
}
|
|
597
599
|
session.history = session.history.slice(0, trimTo);
|
|
598
600
|
session.messageUUIDs = session.messageUUIDs.slice(0, targetIdx);
|
|
601
|
+
// Reset digest checkpoint if it points past the trimmed history
|
|
602
|
+
if (typeof session._dmLastDigestedIndex === "number" && session._dmLastDigestedIndex > trimTo) {
|
|
603
|
+
session._dmLastDigestedIndex = trimTo;
|
|
604
|
+
}
|
|
599
605
|
}
|
|
600
606
|
|
|
601
607
|
// Notify adapter of conversation rollback (e.g. Codex thread/rollback)
|
package/lib/project.js
CHANGED
|
@@ -615,15 +615,33 @@ function createProjectContext(opts) {
|
|
|
615
615
|
var tm = createTerminalManager({ cwd: cwd, send: send, sendTo: sendTo });
|
|
616
616
|
var nm = createNotesManager({ cwd: cwd, send: send, sendTo: sendTo });
|
|
617
617
|
|
|
618
|
-
// Check for updates in background (admin only)
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
618
|
+
// Check for updates in background (admin only). The result is stored in
|
|
619
|
+
// latestVersion; broadcast is handled by the hourly scheduler below, so
|
|
620
|
+
// page refreshes don't re-trigger the banner.
|
|
621
|
+
function runVersionCheck(broadcast) {
|
|
622
|
+
fetchVersion(updateChannel).then(function (v) {
|
|
623
|
+
if (v && isNewer(v, currentVersion)) {
|
|
624
|
+
latestVersion = v;
|
|
625
|
+
if (broadcast) sendToAdmins({ type: "update_available", version: v });
|
|
626
|
+
}
|
|
627
|
+
}).catch(function (e) {
|
|
628
|
+
console.error("[project] Background version check failed:", e.message || e);
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
runVersionCheck(false);
|
|
632
|
+
|
|
633
|
+
// Push update_available on every hour boundary. Clients can dismiss the
|
|
634
|
+
// banner; the next hourly push acts as a fresh ping. This avoids needing
|
|
635
|
+
// any dismissed-state persistence.
|
|
636
|
+
function scheduleNextHourlyBroadcast() {
|
|
637
|
+
var now = Date.now();
|
|
638
|
+
var msUntilNextHour = 60 * 60 * 1000 - (now % (60 * 60 * 1000));
|
|
639
|
+
setTimeout(function tick() {
|
|
640
|
+
runVersionCheck(true);
|
|
641
|
+
setTimeout(tick, 60 * 60 * 1000);
|
|
642
|
+
}, msUntilNextHour);
|
|
643
|
+
}
|
|
644
|
+
scheduleNextHourlyBroadcast();
|
|
627
645
|
|
|
628
646
|
// --- WS connection handler (delegated to project-connection.js) ---
|
|
629
647
|
function handleConnection(ws, wsUser) {
|
|
@@ -726,6 +744,7 @@ function createProjectContext(opts) {
|
|
|
726
744
|
delete session._mentionSessions[mateId];
|
|
727
745
|
}
|
|
728
746
|
session._mentionInProgress = false;
|
|
747
|
+
session._mentionActiveMateId = null;
|
|
729
748
|
sendToSession(session.localId, { type: "mention_done", mateId: mateId, stopped: true });
|
|
730
749
|
send({ type: "mention_processing", mateId: mateId, active: false });
|
|
731
750
|
}
|
|
@@ -849,6 +868,7 @@ function createProjectContext(opts) {
|
|
|
849
868
|
// so we use a lazy getter that resolves at call time.
|
|
850
869
|
var _mateInteraction = attachMateInteraction({
|
|
851
870
|
cwd: cwd,
|
|
871
|
+
slug: slug,
|
|
852
872
|
sm: sm,
|
|
853
873
|
sdk: sdk,
|
|
854
874
|
send: send,
|
|
@@ -866,6 +886,7 @@ function createProjectContext(opts) {
|
|
|
866
886
|
loadMateDigests: loadMateDigests,
|
|
867
887
|
updateMemorySummary: updateMemorySummary,
|
|
868
888
|
initMemorySummary: initMemorySummary,
|
|
889
|
+
getNotificationsModule: function () { return _notifications; },
|
|
869
890
|
get checkForDmDebateBrief() { return checkForDmDebateBrief; },
|
|
870
891
|
});
|
|
871
892
|
var handleMention = _mateInteraction.handleMention;
|
package/lib/public/app.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from './modules/sidebar-projects.js';
|
|
13
13
|
import {
|
|
14
14
|
renderUserStrip, closeDmUserPicker, setCurrentDmUser,
|
|
15
|
-
updateDmBadge, renderSidebarPresence
|
|
15
|
+
updateDmBadge, renderSidebarPresence, setMentionActive, clearAllMentionActive
|
|
16
16
|
} from './modules/sidebar-mates.js';
|
|
17
17
|
import {
|
|
18
18
|
openMobileSheet, setMobileSheetMateData, refreshMobileChatSheet
|
|
@@ -309,6 +309,9 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
309
309
|
currentBetas: [],
|
|
310
310
|
currentThinking: "adaptive",
|
|
311
311
|
currentThinkingBudget: 10000,
|
|
312
|
+
codexApproval: null,
|
|
313
|
+
codexSandbox: null,
|
|
314
|
+
codexWebSearch: null,
|
|
312
315
|
ctxPopoverVisible: false,
|
|
313
316
|
headerContextEl: null,
|
|
314
317
|
// loop
|
|
@@ -386,7 +389,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
386
389
|
openDm: function (userId) { openDm(userId); },
|
|
387
390
|
openMateWizard: function () { requireClayMateInterview(function () { openMateWizard(); }); },
|
|
388
391
|
openAddProjectModal: function () { openAddProjectModal(); },
|
|
389
|
-
sendWs: function (msg) { if (
|
|
392
|
+
sendWs: function (msg) { var _ws = _getWsRef(); if (_ws && _ws.readyState === 1) _ws.send(JSON.stringify(msg)); },
|
|
390
393
|
onDmRemoveUser: function (userId) { var dr = Object.assign({}, store.get('dmRemovedUsers')); dr[userId] = true; store.set({ dmRemovedUsers: dr }); },
|
|
391
394
|
getHistoryFrom: function () { return store.get('historyFrom'); },
|
|
392
395
|
get permissions() { return store.get('permissions'); },
|
|
@@ -399,7 +402,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
399
402
|
initMateKnowledge(wsGetter);
|
|
400
403
|
initMateMemory(wsGetter, { onShow: function () { hideKnowledge(); hideNotes(); } });
|
|
401
404
|
initMateWizard(
|
|
402
|
-
function (msg) { if (
|
|
405
|
+
function (msg) { var _ws = _getWsRef(); if (_ws && _ws.readyState === 1) _ws.send(JSON.stringify(msg)); },
|
|
403
406
|
function (mate) { handleMateCreatedInApp(mate); }
|
|
404
407
|
);
|
|
405
408
|
|
|
@@ -420,8 +423,9 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
420
423
|
var stickyBtn = document.getElementById("sticky-notes-sidebar-btn");
|
|
421
424
|
if (stickyBtn) stickyBtn.click();
|
|
422
425
|
}
|
|
423
|
-
|
|
424
|
-
|
|
426
|
+
var _ws = _getWsRef();
|
|
427
|
+
if (_ws && _ws.readyState === 1) {
|
|
428
|
+
_ws.send(JSON.stringify({ type: "switch_session", id: id }));
|
|
425
429
|
}
|
|
426
430
|
},
|
|
427
431
|
openDm: function (userId) { openDm(userId); },
|
|
@@ -700,7 +704,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
700
704
|
isDebateFloorMode: function () { return store.get('debateFloorMode'); },
|
|
701
705
|
handleDebateFloorSend: function () { handleDebateFloorSend(); },
|
|
702
706
|
isMateDm: function () { return store.get('dmMode') && store.get('dmTargetUser') && store.get('dmTargetUser').isMate; },
|
|
703
|
-
getDmMateId: function () {
|
|
707
|
+
getDmMateId: function () { var _dmt = store.get('dmTargetUser'); return (store.get('dmMode') && _dmt && _dmt.isMate) ? _dmt.id : null; },
|
|
704
708
|
getMateName: function () { return store.get('dmTargetUser') ? (store.get('dmTargetUser').displayName || "Mate") : "Mate"; },
|
|
705
709
|
getMateAvatarUrl: function () { return document.body.dataset.mateAvatarUrl || ""; },
|
|
706
710
|
showMatePreThinking: function () { showMatePreThinking(); },
|
|
@@ -726,7 +730,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
726
730
|
// --- Debate module ---
|
|
727
731
|
initDebate({
|
|
728
732
|
get ws() { return _getWsRef(); },
|
|
729
|
-
sendWs: function (obj) { if (
|
|
733
|
+
sendWs: function (obj) { var _ws = _getWsRef(); if (_ws && _ws.readyState === 1) _ws.send(JSON.stringify(obj)); },
|
|
730
734
|
messagesEl: messagesEl,
|
|
731
735
|
addToMessages: function (el) { addToMessages(el); },
|
|
732
736
|
scrollToBottom: scrollToBottom,
|
|
@@ -781,6 +785,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
781
785
|
var _perms = store.get('permissions');
|
|
782
786
|
if (_perms) {
|
|
783
787
|
if (!_perms.terminal) {
|
|
788
|
+
var termBtn = document.getElementById("terminal-toggle-btn");
|
|
789
|
+
if (termBtn) termBtn.style.display = "none";
|
|
784
790
|
var termSideBtn = document.getElementById("terminal-sidebar-btn");
|
|
785
791
|
if (termSideBtn) termSideBtn.style.display = "none";
|
|
786
792
|
}
|