clay-server 5.1.0-beta.1 → 5.1.0-beta.3
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/LICENSES/README.md +4 -0
- package/LICENSES/dicebear-avatars.md +16 -0
- package/bin/cli.js +9 -91
- package/lib/builtin-mates.js +7 -7
- package/lib/daemon-project-access.js +7 -1
- package/lib/daemon-settings.js +11 -0
- package/lib/daemon.js +10 -37
- package/lib/dicebear-avatar.js +62 -0
- package/lib/knowledge-db-service.js +175 -0
- package/lib/knowledge-db-validation.js +0 -0
- package/lib/knowledge-document-index.js +49 -0
- package/lib/knowledge-draft-store.js +56 -0
- package/lib/knowledge-file-store.js +199 -0
- package/lib/knowledge-markdown.js +128 -0
- package/lib/linear-store.js +35 -8
- package/lib/mate-identity-file.js +39 -0
- package/lib/mate-knowledge-mcp-server.js +29 -6
- package/lib/mate-knowledge-service.js +23 -2
- package/lib/mate-knowledge-sync.js +37 -22
- package/lib/mate-ready-creation.js +2 -1
- package/lib/mate-workspace-color.js +4 -0
- package/lib/mates-identity.js +4 -4
- package/lib/mates-prompts.js +4 -3
- package/lib/mates.js +30 -11
- package/lib/os-users.js +5 -16
- package/lib/project-connection.js +36 -9
- package/lib/project-debate-proposal.js +6 -0
- package/lib/project-debate-workspace.js +43 -0
- package/lib/project-debate.js +4 -2
- package/lib/project-filesystem.js +21 -39
- package/lib/project-knowledge.js +315 -136
- package/lib/project-mate-creation-proposal.js +1 -0
- package/lib/project-mate-interaction.js +7 -6
- package/lib/project-server-settings.js +31 -0
- package/lib/project-sessions.js +92 -182
- package/lib/project-user-knowledge.js +60 -0
- package/lib/project.js +62 -21
- package/lib/public/app.js +79 -71
- package/lib/public/clay-studio-wordmark-bold.svg +20 -0
- package/lib/public/css/clay-workspace.css +105 -0
- package/lib/public/css/debates-workbench.css +47 -0
- package/lib/public/css/home-debate-live.css +26 -0
- package/lib/public/css/home-hub.css +3 -1
- package/lib/public/css/home-mate-model-picker.css +15 -131
- package/lib/public/css/home-mate-settings.css +168 -16
- package/lib/public/css/icon-strip.css +249 -32
- package/lib/public/css/input.css +3 -1
- package/lib/public/css/mate-conversation.css +176 -0
- package/lib/public/css/mate-knowledge-workbench.css +118 -0
- package/lib/public/css/mate-workspace-color.css +16 -0
- package/lib/public/css/mates.css +28 -28
- package/lib/public/css/menus.css +3 -0
- package/lib/public/css/messages.css +1 -114
- package/lib/public/css/mobile-nav.css +16 -16
- package/lib/public/css/overlays.css +15 -0
- package/lib/public/css/project-logs.css +7 -0
- package/lib/public/css/project-mate-creation.css +105 -0
- package/lib/public/css/project-settings-modal.css +56 -0
- package/lib/public/css/right-workbench.css +3 -3
- package/lib/public/css/server-settings-system.css +125 -0
- package/lib/public/css/session-folders.css +80 -21
- package/lib/public/css/session-github.css +25 -16
- package/lib/public/css/settings-ui.css +247 -22
- package/lib/public/css/shared-browser.css +7 -3
- package/lib/public/css/sidebar.css +183 -107
- package/lib/public/css/title-bar.css +156 -1
- package/lib/public/css/worker-delegation.css +47 -0
- package/lib/public/css/worker-proposal.css +72 -150
- package/lib/public/css/you.css +74 -0
- package/lib/public/index.html +206 -548
- package/lib/public/modules/account-island.js +232 -0
- package/lib/public/modules/admin-settings-email.js +197 -0
- package/lib/public/modules/admin-settings-invitations.js +183 -0
- package/lib/public/modules/admin-settings-projects.js +198 -0
- package/lib/public/modules/admin-settings-ui.js +100 -0
- package/lib/public/modules/admin-settings-users.js +331 -0
- package/lib/public/modules/admin.js +19 -949
- package/lib/public/modules/app-cursors.js +19 -43
- package/lib/public/modules/app-debate-ui.js +4 -3
- package/lib/public/modules/app-dm.js +0 -2
- package/lib/public/modules/app-header.js +106 -0
- package/lib/public/modules/app-message-router.js +12 -3
- package/lib/public/modules/app-messages.js +47 -61
- package/lib/public/modules/app-notifications.js +4 -7
- package/lib/public/modules/app-projects.js +5 -38
- package/lib/public/modules/app-rate-limit.js +70 -12
- package/lib/public/modules/app-rendering.js +12 -13
- package/lib/public/modules/avatar.js +30 -9
- package/lib/public/modules/chat-render-runtime.js +16 -4
- package/lib/public/modules/command-palette.js +2 -15
- package/lib/public/modules/context-sources.js +27 -18
- package/lib/public/modules/cursor-sharing-preference.js +3 -3
- package/lib/public/modules/debate-controls.js +299 -0
- package/lib/public/modules/debate.js +2 -0
- package/lib/public/modules/debates-workbench.js +339 -0
- package/lib/public/modules/default-ai.js +88 -65
- package/lib/public/modules/header-tui-font.js +10 -20
- package/lib/public/modules/home-debate-controls.js +18 -289
- package/lib/public/modules/home-mate-avatar-editor.js +228 -0
- package/lib/public/modules/home-mate-color-picker.js +66 -0
- package/lib/public/modules/home-mate-creation.js +1 -1
- package/lib/public/modules/home-mate-instructions.js +90 -0
- package/lib/public/modules/home-mate-model-picker.js +80 -271
- package/lib/public/modules/home-mate-profile-editor.js +72 -0
- package/lib/public/modules/home-mate-settings.js +118 -125
- package/lib/public/modules/home-shell.js +3 -0
- package/lib/public/modules/home-surface-boot.js +1 -9
- package/lib/public/modules/icon-strip-tooltip.js +95 -0
- package/lib/public/modules/knowledge-db-edit-state.js +35 -0
- package/lib/public/modules/knowledge-db-workbench.js +234 -0
- package/lib/public/modules/knowledge-history-state.js +55 -0
- package/lib/public/modules/knowledge-markdown-editor.js +57 -0
- package/lib/public/modules/knowledge-preview-links.js +70 -0
- package/lib/public/modules/knowledge-workbench-shell.js +21 -0
- package/lib/public/modules/linear-settings.js +3 -2
- package/lib/public/modules/markdown.js +5 -6
- package/lib/public/modules/mate-knowledge-workbench-state.js +174 -0
- package/lib/public/modules/mate-knowledge-workbench.js +500 -0
- package/lib/public/modules/mate-knowledge.js +11 -3
- package/lib/public/modules/mate-management.js +54 -10
- package/lib/public/modules/mate-sidebar.js +11 -1
- package/lib/public/modules/mate-workspace-color.js +33 -0
- package/lib/public/modules/mention.js +5 -13
- package/lib/public/modules/notification-settings.js +81 -0
- package/lib/public/modules/notifications.js +44 -28
- package/lib/public/modules/personal-settings-dialog.js +51 -0
- package/lib/public/modules/profile.js +66 -24
- package/lib/public/modules/project-chat-identity.js +79 -0
- package/lib/public/modules/project-debate-planning-workspace.js +250 -0
- package/lib/public/modules/project-debate-workspace.js +185 -0
- package/lib/public/modules/project-header-identity.js +127 -0
- package/lib/public/modules/project-logs-render.js +9 -4
- package/lib/public/modules/project-mate-creation-workspace.js +414 -0
- package/lib/public/modules/project-mate-navigation.js +238 -0
- package/lib/public/modules/project-session-navigation.js +29 -0
- package/lib/public/modules/project-settings-environment.js +106 -0
- package/lib/public/modules/project-settings.js +72 -628
- package/lib/public/modules/project-switcher.js +6 -8
- package/lib/public/modules/projects-hub-view.js +5 -6
- package/lib/public/modules/projects-hub.js +2 -6
- package/lib/public/modules/qrcode.js +27 -8
- package/lib/public/modules/search-clay-chat.js +8 -11
- package/lib/public/modules/server-settings-controls.js +316 -0
- package/lib/public/modules/server-settings-environment.js +194 -0
- package/lib/public/modules/server-settings-navigation.js +39 -0
- package/lib/public/modules/server-settings-state.js +54 -0
- package/lib/public/modules/server-settings.js +116 -788
- package/lib/public/modules/server-storage-settings.js +84 -0
- package/lib/public/modules/session-activity-tooltip.js +12 -0
- package/lib/public/modules/session-create-form.js +86 -14
- package/lib/public/modules/session-create.js +50 -7
- package/lib/public/modules/session-github.js +2 -1
- package/lib/public/modules/session-list-visibility.js +41 -0
- package/lib/public/modules/session-presence-ui.js +3 -0
- package/lib/public/modules/session-title-marquee.js +51 -0
- package/lib/public/modules/settings-env-values.js +34 -0
- package/lib/public/modules/settings-select.js +121 -0
- package/lib/public/modules/shared-browser.js +22 -12
- package/lib/public/modules/sidebar-mates.js +3 -50
- package/lib/public/modules/sidebar-mobile.js +63 -60
- package/lib/public/modules/sidebar-projects.js +84 -97
- package/lib/public/modules/sidebar-session-folders-ui.js +2 -2
- package/lib/public/modules/sidebar-session-hierarchy.js +149 -70
- package/lib/public/modules/sidebar-sessions.js +49 -50
- package/lib/public/modules/sidebar.js +11 -13
- package/lib/public/modules/stt-picker.js +14 -5
- package/lib/public/modules/terminal-prefs.js +22 -0
- package/lib/public/modules/theme.js +88 -52
- package/lib/public/modules/thinking-lifecycle.js +7 -6
- package/lib/public/modules/tool-palette-order.js +4 -3
- package/lib/public/modules/tool-palette.js +13 -3
- package/lib/public/modules/tools.js +22 -22
- package/lib/public/modules/user-settings-account.js +318 -0
- package/lib/public/modules/user-settings-appearance.js +55 -0
- package/lib/public/modules/user-settings-editors.js +24 -0
- package/lib/public/modules/user-settings-integrations.js +104 -0
- package/lib/public/modules/user-settings-layout.js +80 -0
- package/lib/public/modules/user-settings-preferences.js +48 -0
- package/lib/public/modules/user-settings-profile.js +53 -0
- package/lib/public/modules/user-settings-themes.js +38 -0
- package/lib/public/modules/user-settings-voice.js +75 -0
- package/lib/public/modules/user-settings.js +53 -480
- package/lib/public/modules/worker-proposal.js +42 -8
- package/lib/public/modules/worker-runtime-picker.js +115 -0
- package/lib/public/modules/you-activity.js +121 -0
- package/lib/public/modules/you.js +251 -0
- package/lib/public/style.css +20 -8
- package/lib/public/vendor/codemirror/LICENSE +21 -0
- package/lib/public/vendor/codemirror/codemirror.css +344 -0
- package/lib/public/vendor/codemirror/codemirror.js +9884 -0
- package/lib/public/vendor/codemirror/continuelist.js +101 -0
- package/lib/public/vendor/codemirror/markdown.js +886 -0
- package/lib/public/vendor/codemirror/show-hint.css +37 -0
- package/lib/public/vendor/codemirror/show-hint.js +523 -0
- package/lib/sdk-bridge.js +15 -3
- package/lib/sdk-message-processor.js +16 -4
- package/lib/sdk-quota-snapshot.js +37 -0
- package/lib/server-admin.js +11 -0
- package/lib/server-appearance-settings.js +71 -0
- package/lib/server-home-chat-events.js +1 -1
- package/lib/server-home-chat.js +25 -3
- package/lib/server-home-debate-planning.js +4 -1
- package/lib/server-home-debates.js +2 -0
- package/lib/server-home-mate-creation.js +4 -1
- package/lib/server-linear.js +14 -8
- package/lib/server-mate-instructions.js +44 -0
- package/lib/server-mates.js +14 -4
- package/lib/server-notification-settings.js +67 -0
- package/lib/server-palette.js +1 -1
- package/lib/server-settings.js +69 -1
- package/lib/server-storage.js +57 -0
- package/lib/server-user-knowledge.js +119 -0
- package/lib/server.js +31 -3
- package/lib/session-visibility.js +7 -2
- package/lib/sessions.js +35 -10
- package/lib/startup-projects.js +40 -0
- package/lib/storage-native-walk.js +85 -0
- package/lib/storage-usage.js +144 -0
- package/lib/user-knowledge-service.js +167 -0
- package/lib/users-permissions.js +7 -0
- package/lib/users-preferences.js +0 -74
- package/lib/users-project-mate-filter-preferences.js +39 -0
- package/lib/users.js +6 -4
- package/lib/workspace-query-access.js +4 -1
- package/lib/ws-schema.js +52 -4
- package/lib/yoke/acp-process-manager.js +2 -2
- package/lib/yoke/adapters/codex.js +12 -52
- package/lib/yoke/codex-app-server.js +2 -2
- package/lib/yoke/codex-model-catalog.js +52 -0
- package/lib/yoke/codex-rate-limits.js +26 -0
- package/package.json +12 -3
package/lib/mates.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
var resolveMateIdentityFile = require('./mate-identity-file').resolveMateIdentityFile;
|
|
1
2
|
var fs = require("fs");
|
|
2
3
|
var path = require("path");
|
|
3
4
|
var crypto = require("crypto");
|
|
4
5
|
var config = require("./config");
|
|
6
|
+
var workspaceColor = require("./mate-workspace-color");
|
|
5
7
|
|
|
6
8
|
var crisisSafety = require("./crisis-safety");
|
|
7
9
|
var matesPrompts = require("./mates-prompts");
|
|
@@ -160,7 +162,7 @@ function createMate(ctx, seedData) {
|
|
|
160
162
|
yaml += "model: " + JSON.stringify(seedData.model || null) + "\n";
|
|
161
163
|
fs.writeFileSync(path.join(mateDir, "mate.yaml"), yaml);
|
|
162
164
|
|
|
163
|
-
// Write initial
|
|
165
|
+
// Write initial AGENTS.md (will be replaced by interview)
|
|
164
166
|
var claudeMd = "# Mate Identity\n\n";
|
|
165
167
|
claudeMd += "This mate is currently being interviewed. Identity will be generated after the interview.\n\n";
|
|
166
168
|
claudeMd += "## Seed Data\n\n";
|
|
@@ -175,7 +177,7 @@ function createMate(ctx, seedData) {
|
|
|
175
177
|
claudeMd += TEAM_SECTION;
|
|
176
178
|
claudeMd += SESSION_MEMORY_SECTION;
|
|
177
179
|
claudeMd += crisisSafety.getSection();
|
|
178
|
-
fs.writeFileSync(
|
|
180
|
+
fs.writeFileSync(resolveMateIdentityFile(mateDir), claudeMd);
|
|
179
181
|
|
|
180
182
|
// Log creation (identity is placeholder, will be replaced by interview)
|
|
181
183
|
logIdentityChange(mateDir, "create_custom", initialIdentity, "");
|
|
@@ -192,9 +194,17 @@ function getMate(ctx, id) {
|
|
|
192
194
|
}
|
|
193
195
|
|
|
194
196
|
function updateMate(ctx, id, updates) {
|
|
197
|
+
updates = Object.assign({}, updates);
|
|
198
|
+
delete updates.id;
|
|
199
|
+
delete updates.createdBy;
|
|
200
|
+
delete updates.builtinKey;
|
|
195
201
|
var data = loadMates(ctx);
|
|
196
202
|
for (var i = 0; i < data.mates.length; i++) {
|
|
197
203
|
if (data.mates[i].id === id) {
|
|
204
|
+
if (Object.prototype.hasOwnProperty.call(updates, "workspaceColor")) {
|
|
205
|
+
if (data.mates[i].primary || data.mates[i].builtinKey === "clay") delete updates.workspaceColor;
|
|
206
|
+
else if (!workspaceColor.valid(updates.workspaceColor)) return { error: "Choose a supported workspace color." };
|
|
207
|
+
}
|
|
198
208
|
// Primary mates: protect name and core identity fields
|
|
199
209
|
if (data.mates[i].primary) {
|
|
200
210
|
delete updates.name;
|
|
@@ -206,6 +216,15 @@ function updateMate(ctx, id, updates) {
|
|
|
206
216
|
delete updates.profile.displayName;
|
|
207
217
|
}
|
|
208
218
|
}
|
|
219
|
+
// Locked built-in artwork is server-managed. Preserve it even when a
|
|
220
|
+
// stale or crafted client submits a replacement profile object.
|
|
221
|
+
if (data.mates[i].profile && data.mates[i].profile.avatarLocked && updates.profile) {
|
|
222
|
+
updates.profile.avatarStyle = data.mates[i].profile.avatarStyle;
|
|
223
|
+
updates.profile.avatarSeed = data.mates[i].profile.avatarSeed;
|
|
224
|
+
updates.profile.avatarColor = data.mates[i].profile.avatarColor;
|
|
225
|
+
updates.profile.avatarCustom = data.mates[i].profile.avatarCustom;
|
|
226
|
+
updates.profile.avatarLocked = true;
|
|
227
|
+
}
|
|
209
228
|
var keys = Object.keys(updates);
|
|
210
229
|
for (var j = 0; j < keys.length; j++) {
|
|
211
230
|
data.mates[i][keys[j]] = updates[keys[j]];
|
|
@@ -326,7 +345,7 @@ function migrateLegacyMates() {
|
|
|
326
345
|
}
|
|
327
346
|
|
|
328
347
|
/**
|
|
329
|
-
* Strip all system sections from
|
|
348
|
+
* Strip all system sections from AGENTS.md content, returning only identity.
|
|
330
349
|
*/
|
|
331
350
|
function stripAllSystemSections(content) {
|
|
332
351
|
return extractIdentity(content);
|
|
@@ -336,10 +355,10 @@ function stripAllSystemSections(content) {
|
|
|
336
355
|
var _warnedPaths = {};
|
|
337
356
|
|
|
338
357
|
/**
|
|
339
|
-
* Atomic enforce: read
|
|
358
|
+
* Atomic enforce: read AGENTS.md once, enforce all system sections, write once.
|
|
340
359
|
* Includes identity backup, validation, and change tracking.
|
|
341
360
|
* Returns true if the file was modified, false if already correct.
|
|
342
|
-
* @param {string} filePath - path to
|
|
361
|
+
* @param {string} filePath - path to AGENTS.md
|
|
343
362
|
* @param {object} opts - optional { ctx, mateId } for dynamic team section
|
|
344
363
|
*/
|
|
345
364
|
function enforceAllSections(filePath, opts) {
|
|
@@ -511,7 +530,7 @@ function createBuiltinMate(ctx, builtinKey) {
|
|
|
511
530
|
yaml += "autonomy: " + (seedData.autonomy || "always_ask") + "\n";
|
|
512
531
|
fs.writeFileSync(path.join(mateDir, "mate.yaml"), yaml);
|
|
513
532
|
|
|
514
|
-
// Write
|
|
533
|
+
// Write AGENTS.md with full template + system sections
|
|
515
534
|
var claudeMd = def.getClaudeMd();
|
|
516
535
|
var builtinIdentity = claudeMd.trimEnd();
|
|
517
536
|
claudeMd += TEAM_SECTION;
|
|
@@ -519,7 +538,7 @@ function createBuiltinMate(ctx, builtinKey) {
|
|
|
519
538
|
claudeMd += STICKY_NOTES_SECTION;
|
|
520
539
|
claudeMd += DEBATE_AWARENESS_SECTION;
|
|
521
540
|
claudeMd += crisisSafety.getSection();
|
|
522
|
-
fs.writeFileSync(
|
|
541
|
+
fs.writeFileSync(resolveMateIdentityFile(mateDir), claudeMd);
|
|
523
542
|
|
|
524
543
|
// Backup identity and log creation
|
|
525
544
|
backupIdentity(mateDir, builtinIdentity);
|
|
@@ -603,7 +622,7 @@ function syncArchivedBuiltinMates(ctx) {
|
|
|
603
622
|
*
|
|
604
623
|
* What gets synced:
|
|
605
624
|
* - Metadata: bio, name, profile, globalSearch, primary flag
|
|
606
|
-
* -
|
|
625
|
+
* - AGENTS.md identity: re-applied when templateVersion changes
|
|
607
626
|
* - templateVersion is stored on the mate object to track updates
|
|
608
627
|
*
|
|
609
628
|
* What is NOT synced (regular builtin mates):
|
|
@@ -653,10 +672,10 @@ function syncPrimaryMates(ctx) {
|
|
|
653
672
|
}
|
|
654
673
|
}
|
|
655
674
|
|
|
656
|
-
// --- Sync
|
|
675
|
+
// --- Sync AGENTS.md identity (only when templateVersion changes) ---
|
|
657
676
|
// Uses 3-way comparison to preserve user/Ally modifications:
|
|
658
677
|
// - base-template.md = the template that was last synced (what code wrote)
|
|
659
|
-
// - current identity = what's in
|
|
678
|
+
// - current identity = what's in AGENTS.md now (may have been modified)
|
|
660
679
|
// - new template = latest code definition
|
|
661
680
|
//
|
|
662
681
|
// If current identity === old base → user didn't touch it → safe to replace
|
|
@@ -666,7 +685,7 @@ function syncPrimaryMates(ctx) {
|
|
|
666
685
|
|
|
667
686
|
if (latestVersion > currentVersion) {
|
|
668
687
|
var mateDir = getMateDir(ctx, mate.id);
|
|
669
|
-
var claudePath =
|
|
688
|
+
var claudePath = resolveMateIdentityFile(mateDir);
|
|
670
689
|
var basePath = path.join(mateDir, "knowledge", "base-template.md");
|
|
671
690
|
var latestIdentity = def.getClaudeMd().trimEnd();
|
|
672
691
|
|
package/lib/os-users.js
CHANGED
|
@@ -17,20 +17,11 @@ function isSafeLinuxUsername(username) {
|
|
|
17
17
|
// --- Supplementary group inheritance (issue #367) ---
|
|
18
18
|
// Node's child_process { uid, gid } options call setuid/setgid but never
|
|
19
19
|
// initgroups(), so spawned sessions drop all supplementary groups (docker,
|
|
20
|
-
// video, wheel, ...).
|
|
20
|
+
// video, wheel, ...). Route user-switched spawns through
|
|
21
21
|
// `setpriv --init-groups` so the child gets the same groups as a normal login.
|
|
22
|
-
var _inheritGroups = true; // default: behave like a normal login shell
|
|
23
22
|
var _setprivAvail = null;
|
|
24
23
|
var _warnedNoSetpriv = false;
|
|
25
24
|
|
|
26
|
-
function setInheritGroups(value) {
|
|
27
|
-
_inheritGroups = !!value;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function getInheritGroups() {
|
|
31
|
-
return _inheritGroups;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
25
|
function setprivAvailable() {
|
|
35
26
|
if (_setprivAvail !== null) return _setprivAvail;
|
|
36
27
|
try {
|
|
@@ -50,7 +41,7 @@ function setprivAvailable() {
|
|
|
50
41
|
* spawn()/execFileSync()/pty.spawn().
|
|
51
42
|
*
|
|
52
43
|
* - Same-user spawns (no uid/gid in options) are returned unchanged.
|
|
53
|
-
* - When
|
|
44
|
+
* - When setpriv is unavailable, falls back to
|
|
54
45
|
* Node's uid/gid options (primary group only) so behavior degrades safely.
|
|
55
46
|
* Requires the parent process to be root, which is the case in os-users mode.
|
|
56
47
|
*/
|
|
@@ -62,7 +53,7 @@ function wrapSpawnAsUser(command, args, options, setprivCheck) {
|
|
|
62
53
|
if (uid == null || gid == null) return { command: command, args: args, options: options };
|
|
63
54
|
|
|
64
55
|
var hasSetpriv = typeof setprivCheck === "function" ? setprivCheck() : setprivAvailable();
|
|
65
|
-
if (
|
|
56
|
+
if (hasSetpriv) {
|
|
66
57
|
var wrappedArgs = ["--reuid", String(uid), "--regid", String(gid), "--init-groups", "--", command].concat(args);
|
|
67
58
|
var newOpts = Object.assign({}, options);
|
|
68
59
|
delete newOpts.uid;
|
|
@@ -70,9 +61,9 @@ function wrapSpawnAsUser(command, args, options, setprivCheck) {
|
|
|
70
61
|
return { command: "setpriv", args: wrappedArgs, options: newOpts };
|
|
71
62
|
}
|
|
72
63
|
|
|
73
|
-
if (
|
|
64
|
+
if (!_warnedNoSetpriv) {
|
|
74
65
|
_warnedNoSetpriv = true;
|
|
75
|
-
console.warn("[os-users]
|
|
66
|
+
console.warn("[os-users] `setpriv` not found; supplementary groups will be dropped. Install util-linux to restore them.");
|
|
76
67
|
}
|
|
77
68
|
return { command: command, args: args, options: options };
|
|
78
69
|
}
|
|
@@ -673,8 +664,6 @@ module.exports = {
|
|
|
673
664
|
grantAllUsersAccess: grantAllUsersAccess,
|
|
674
665
|
installClaudeCli: installClaudeCli,
|
|
675
666
|
claudeAvailableForUser: claudeAvailableForUser,
|
|
676
|
-
setInheritGroups: setInheritGroups,
|
|
677
|
-
getInheritGroups: getInheritGroups,
|
|
678
667
|
wrapSpawnAsUser: wrapSpawnAsUser,
|
|
679
668
|
deactivateLinuxUser: deactivateLinuxUser,
|
|
680
669
|
ensureProjectsDir: ensureProjectsDir,
|
|
@@ -6,6 +6,7 @@ var emailAccounts = require("./email-accounts");
|
|
|
6
6
|
var { getCodexConfig } = require("./codex-defaults");
|
|
7
7
|
var yoke = require("./yoke");
|
|
8
8
|
var permissionModes = require("./session-permission-mode");
|
|
9
|
+
var sessionProvenance = require("./session-provenance");
|
|
9
10
|
|
|
10
11
|
function dispatchMessageSafely(handleMessage, sendTo, slug, ws, msg) {
|
|
11
12
|
try {
|
|
@@ -45,6 +46,36 @@ function buildInitialModelInfo(sm, initialVendor, initialModel, initialModels, s
|
|
|
45
46
|
};
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
function buildRestoredSessionMessage(active, initialEffort, capabilities, permissionState) {
|
|
50
|
+
return {
|
|
51
|
+
type: "session_switched",
|
|
52
|
+
id: active.localId,
|
|
53
|
+
sessionOriginId: active.sessionOriginId || null,
|
|
54
|
+
sessionRole: sessionProvenance.isWorker(active) ? "worker" : "driver",
|
|
55
|
+
cliSessionId: active.cliSessionId || null,
|
|
56
|
+
loop: active.loop || null,
|
|
57
|
+
vendor: active.vendor || null,
|
|
58
|
+
model: active.model || null,
|
|
59
|
+
effort: active.effort || initialEffort || null,
|
|
60
|
+
hasHistory: !!(active.history && active.history.length > 0),
|
|
61
|
+
capabilities: capabilities,
|
|
62
|
+
isProcessing: !!active.isProcessing,
|
|
63
|
+
mateCreation: active.mateCreationMode === true,
|
|
64
|
+
mateCreationPhase: active.homeMateCreationPhase || null,
|
|
65
|
+
debatePlanning: active.debateSetupMode === true,
|
|
66
|
+
debatePhase: active.homeDebatePhase || null,
|
|
67
|
+
mode: active.mode || "gui",
|
|
68
|
+
terminalId: typeof active.terminalId === "number" ? active.terminalId : null,
|
|
69
|
+
runtimeMode: active.runtimeMode || null,
|
|
70
|
+
runtimeTerminalId: typeof active.runtimeTerminalId === "number" ? active.runtimeTerminalId : null,
|
|
71
|
+
tuiSuspended: !!active.tuiSuspended,
|
|
72
|
+
permissionMode: permissionState.requestedPermissionMode,
|
|
73
|
+
effectivePermissionMode: permissionState.effectivePermissionMode,
|
|
74
|
+
permissionCapabilities: permissionState.permissionCapabilities,
|
|
75
|
+
mcpPermissionModeOverrides: permissionState.mcpPermissionModeOverrides,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
48
79
|
/**
|
|
49
80
|
* Attach connection/disconnection handlers to a project context.
|
|
50
81
|
*
|
|
@@ -63,6 +94,8 @@ function attachConnection(ctx) {
|
|
|
63
94
|
var cwd = ctx.cwd;
|
|
64
95
|
var slug = ctx.slug;
|
|
65
96
|
var isMate = ctx.isMate;
|
|
97
|
+
var mateId = ctx.mateId || null;
|
|
98
|
+
var mateDisplayName = ctx.mateDisplayName || "";
|
|
66
99
|
var osUsers = ctx.osUsers;
|
|
67
100
|
var debug = ctx.debug;
|
|
68
101
|
var dangerouslySkipPermissions = ctx.dangerouslySkipPermissions;
|
|
@@ -184,7 +217,7 @@ function attachConnection(ctx) {
|
|
|
184
217
|
sm.saveSessionFile(restoredActive);
|
|
185
218
|
}
|
|
186
219
|
var initialModels = (sm.modelsByVendor && sm.modelsByVendor[initialVendor]) || sm.availableModels || [];
|
|
187
|
-
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, vendors: yoke.VENDOR_REGISTRY });
|
|
220
|
+
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, vendors: yoke.VENDOR_REGISTRY, isMate: isMate, mateId: isMate ? mateId : null, mateDisplayName: isMate ? (mateDisplayName || title || project || "Mate") : "" });
|
|
188
221
|
if (typeof sendCursorSharingState === "function") sendCursorSharingState(ws);
|
|
189
222
|
// Update notifications are pushed on a scheduled interval (see
|
|
190
223
|
// scheduleUpdateBroadcast). We no longer push on connect to avoid
|
|
@@ -213,13 +246,6 @@ function attachConnection(ctx) {
|
|
|
213
246
|
sendTo(ws, { type: "email_accounts_list", accounts: emailAccountsList, providers: emailAccounts.PROVIDER_PRESETS });
|
|
214
247
|
sendTo(ws, { type: "notes_list", notes: nm.list() });
|
|
215
248
|
sendTo(ws, { type: "loop_registry_updated", records: getHubSchedules() });
|
|
216
|
-
// Initial per-user preference: how to render Claude sessions.
|
|
217
|
-
if (usersModule && typeof usersModule.getClaudeOpenMode === "function") {
|
|
218
|
-
var _comUid = (wsUser && wsUser.id) || null;
|
|
219
|
-
var _comVal = _comUid ? usersModule.getClaudeOpenMode(_comUid) : "gui";
|
|
220
|
-
sendTo(ws, { type: "claude_open_mode_changed", claudeOpenMode: _comVal || "gui" });
|
|
221
|
-
}
|
|
222
|
-
|
|
223
249
|
_loop.sendConnectionState(ws);
|
|
224
250
|
if (_mcp) _mcp.sendConnectionState(ws);
|
|
225
251
|
if (_notifications) _notifications.sendConnectionState(ws, sendTo);
|
|
@@ -262,7 +288,7 @@ function attachConnection(ctx) {
|
|
|
262
288
|
}
|
|
263
289
|
var _vendorCaps = (sm.capabilitiesByVendor && sm.capabilitiesByVendor[active.vendor || sm.defaultVendor || "claude"]) || {};
|
|
264
290
|
var activePermissionState = permissionModes.clientState(active, sm.currentPermissionMode, sm.defaultVendor);
|
|
265
|
-
sendTo(ws,
|
|
291
|
+
sendTo(ws, buildRestoredSessionMessage(active, initialEffort, _vendorCaps, activePermissionState));
|
|
266
292
|
if (ctx.autonomousRun) sendTo(ws, { type: "autonomous_run_state", sessionId: active.localId, run: ctx.autonomousRun.project(active.autonomousRun) });
|
|
267
293
|
// Send per-session context sources
|
|
268
294
|
var sessionSources = loadContextSources(slug, active.localId);
|
|
@@ -382,5 +408,6 @@ function attachConnection(ctx) {
|
|
|
382
408
|
module.exports = {
|
|
383
409
|
attachConnection: attachConnection,
|
|
384
410
|
buildInitialModelInfo: buildInitialModelInfo,
|
|
411
|
+
buildRestoredSessionMessage: buildRestoredSessionMessage,
|
|
385
412
|
dispatchMessageSafely: dispatchMessageSafely,
|
|
386
413
|
};
|
|
@@ -227,6 +227,12 @@ function attachDebateProposal(ctx) {
|
|
|
227
227
|
|
|
228
228
|
var found = findPendingProposal(ws, msg);
|
|
229
229
|
if (!found) return true;
|
|
230
|
+
if (msg.sessionId != null && (String(found.pending.session.localId) !== String(msg.sessionId)
|
|
231
|
+
|| String(ws._clayActiveSession) !== String(msg.sessionId)
|
|
232
|
+
|| (found.pending.session.ownerId && (!ws._clayUser || ws._clayUser.id !== found.pending.session.ownerId)))) {
|
|
233
|
+
ctx.sendTo(ws, { type: "debate_error", error: "This proposal belongs to a different session." });
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
230
236
|
startApprovedProposal(ws, msg, found).catch(function (error) {
|
|
231
237
|
delete pendingProposals[found.key];
|
|
232
238
|
rejectProposal(ws, found.pending, error && error.message ? error.message : "The selected debate models could not be verified.");
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Project-bound access to the same participation actions used by Home debates.
|
|
2
|
+
function handleProjectDebateControl(ws, msg, session, engine, sendTo) {
|
|
3
|
+
if (msg.type !== "project_debate_control" && msg.type !== "project_debate_state") return false;
|
|
4
|
+
var userId = ws && ws._clayUser && ws._clayUser.id;
|
|
5
|
+
var valid = session && msg.sessionId != null && String(session.localId) === String(msg.sessionId)
|
|
6
|
+
&& (!session.ownerId || session.ownerId === userId);
|
|
7
|
+
if (msg.type === "project_debate_state") {
|
|
8
|
+
sendTo(ws, { type: "project_debate_state", sessionId: msg.sessionId, header: valid ? debateHeader(session) : null });
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
var ok = false;
|
|
12
|
+
if (valid) {
|
|
13
|
+
if (session.homeDebatePlanning) ok = engine.handleHomeControl(ws, msg, session);
|
|
14
|
+
else if (msg.action === "hand_raise") { engine.handleDebateHandRaise(ws, session); ok = true; }
|
|
15
|
+
else if (msg.action === "stop") ok = engine.handleDebateStop(ws, session);
|
|
16
|
+
else if (msg.action === "cancel_stop") ok = engine.handleDebateCancelStop(ws, session);
|
|
17
|
+
else if (msg.action === "user_floor") { engine.handleDebateUserFloorResponse(ws, msg, session); ok = true; }
|
|
18
|
+
else if (msg.action === "conclude" || msg.action === "resume") {
|
|
19
|
+
engine.handleDebateConcludeResponse(ws, { action: msg.action === "resume" ? "continue" : msg.response, text: msg.text || "" }, session);
|
|
20
|
+
ok = true;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
sendTo(ws, { type: "project_debate_control_result", sessionId: msg.sessionId, ok: !!ok, error: ok ? null : "This debate action is no longer available. Reopen the debate and try again." });
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
function debateHeader(session) {
|
|
27
|
+
var header = null;
|
|
28
|
+
(session.history || []).forEach(function (event) {
|
|
29
|
+
if (event.type === "debate_started") header = Object.assign({}, event, { role: "debate_header", phase: "live", round: 1, interaction: null, handRaised: false });
|
|
30
|
+
if (!header) return;
|
|
31
|
+
if (event.round) header.round = event.round;
|
|
32
|
+
if (event.type === "debate_conclude_confirm") header.interaction = "conclude";
|
|
33
|
+
if (event.type === "debate_user_floor") header.interaction = "user_floor";
|
|
34
|
+
if (event.type === "debate_user_floor_done") { header.interaction = null; header.handRaised = false; }
|
|
35
|
+
if (event.type === "debate_hand_raised") header.handRaised = true;
|
|
36
|
+
if (event.type === "debate_stop_requested") header.stopping = true;
|
|
37
|
+
if (event.type === "debate_stop_cancelled") header.stopping = false;
|
|
38
|
+
if (event.type === "debate_turn" || event.type === "debate_resumed") { header.interaction = null; header.phase = "live"; }
|
|
39
|
+
if (event.type === "debate_ended") { header.phase = event.reason === "interrupted" ? "interrupted" : "ended"; header.reason = event.reason; header.interaction = null; header.stopping = false; }
|
|
40
|
+
});
|
|
41
|
+
return header;
|
|
42
|
+
}
|
|
43
|
+
module.exports = { handleProjectDebateControl: handleProjectDebateControl, debateHeader: debateHeader };
|
package/lib/project-debate.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
var resolveMateIdentityFile = require('./mate-identity-file').resolveMateIdentityFile;
|
|
1
2
|
var fs = require("fs");
|
|
2
3
|
var path = require("path");
|
|
3
4
|
var crypto = require("crypto");
|
|
@@ -15,10 +16,10 @@ var debateToolPolicy = require("./home-debate-tool-policy");
|
|
|
15
16
|
*/
|
|
16
17
|
function attachDebate(ctx) {
|
|
17
18
|
|
|
18
|
-
// For mate projects, enforce latest debate awareness prompt in
|
|
19
|
+
// For mate projects, enforce latest debate awareness prompt in AGENTS.md
|
|
19
20
|
// so mates use the propose_debate MCP tool instead of writing files.
|
|
20
21
|
if (ctx.isMate) {
|
|
21
|
-
var _debateClaudeMdPath =
|
|
22
|
+
var _debateClaudeMdPath = resolveMateIdentityFile(ctx.cwd);
|
|
22
23
|
try { matesModule.enforceDebateAwareness(_debateClaudeMdPath); } catch (e) {}
|
|
23
24
|
}
|
|
24
25
|
|
|
@@ -1859,6 +1860,7 @@ function attachDebate(ctx) {
|
|
|
1859
1860
|
handleDebateHandRaise: handleDebateHandRaise,
|
|
1860
1861
|
handleDebateComment: handleDebateComment,
|
|
1861
1862
|
handleDebateStop: handleDebateStop,
|
|
1863
|
+
handleDebateCancelStop: handleDebateCancelStop,
|
|
1862
1864
|
handleDebateConcludeResponse: handleDebateConcludeResponse,
|
|
1863
1865
|
handleDebateConfirmBrief: handleDebateConfirmBrief,
|
|
1864
1866
|
handleDebateUserFloorResponse: handleDebateUserFloorResponse,
|
|
@@ -204,26 +204,28 @@ function attachFilesystem(ctx) {
|
|
|
204
204
|
|
|
205
205
|
// --- Project settings permission gate ---
|
|
206
206
|
if (msg.type === "get_project_env" || msg.type === "set_project_env" ||
|
|
207
|
-
msg.type === "read_global_claude_md" || msg.type === "write_global_claude_md" ||
|
|
208
207
|
msg.type === "get_shared_env" || msg.type === "set_shared_env" ||
|
|
209
208
|
msg.type === "transfer_project_owner") {
|
|
210
|
-
var globalSetting = /^(
|
|
209
|
+
var globalSetting = /^(get_shared_env|set_shared_env)$/.test(msg.type);
|
|
211
210
|
var targetSlug = msg.slug || slug;
|
|
212
211
|
if (!access.hasPermission(ws, "projectSettings") ||
|
|
213
212
|
(globalSetting ? !access.isAdmin(ws) : !access.canAccessProject(ws, targetSlug))) {
|
|
214
|
-
sendTo(ws, { type:
|
|
213
|
+
sendTo(ws, { type: globalSetting ? (msg.type === 'get_shared_env' ? 'shared_env_result' : 'set_shared_env_result') : (msg.type === 'get_project_env' ? 'project_env_result' : msg.type === 'set_project_env' ? 'set_project_env_result' : 'error'), slug: targetSlug, requestId: msg.requestId, ok: false, error: 'Project settings access is not permitted', text: "Project settings access is not permitted" });
|
|
215
214
|
return true;
|
|
216
215
|
}
|
|
217
216
|
}
|
|
218
217
|
|
|
219
218
|
// --- Project environment variables ---
|
|
220
219
|
if (msg.type === "get_project_env") {
|
|
220
|
+
if (typeof opts.onGetProjectEnv !== "function") { sendTo(ws, { type: "project_env_result", slug: targetSlug, requestId: msg.requestId, error: "Project environment is unavailable in this runtime." }); return true; }
|
|
221
221
|
var envrc = "";
|
|
222
222
|
if (typeof opts.onGetProjectEnv === "function") {
|
|
223
|
-
var envResult
|
|
223
|
+
var envResult;
|
|
224
|
+
try { envResult = opts.onGetProjectEnv(targetSlug); }
|
|
225
|
+
catch (error) { sendTo(ws, { type: "project_env_result", slug: targetSlug, requestId: msg.requestId, error: error.message }); return true; }
|
|
224
226
|
envrc = envResult.envrc || "";
|
|
225
227
|
}
|
|
226
|
-
sendTo(ws, { type: "project_env_result", slug: msg.
|
|
228
|
+
sendTo(ws, { type: "project_env_result", slug: targetSlug, requestId: msg.requestId, envrc: envrc });
|
|
227
229
|
return true;
|
|
228
230
|
}
|
|
229
231
|
|
|
@@ -231,41 +233,16 @@ function attachFilesystem(ctx) {
|
|
|
231
233
|
if (typeof opts.onSetProjectEnv === "function") {
|
|
232
234
|
var envError = validateEnvString(msg.envrc || "");
|
|
233
235
|
if (envError) {
|
|
234
|
-
sendTo(ws, { type: "set_project_env_result", ok: false, slug: msg.
|
|
236
|
+
sendTo(ws, { type: "set_project_env_result", ok: false, slug: targetSlug, requestId: msg.requestId, error: envError });
|
|
235
237
|
return true;
|
|
236
238
|
}
|
|
237
|
-
var setResult
|
|
239
|
+
var setResult;
|
|
240
|
+
try { setResult = opts.onSetProjectEnv(targetSlug, msg.envrc || ""); }
|
|
241
|
+
catch (error) { sendTo(ws, { type: "set_project_env_result", slug: targetSlug, requestId: msg.requestId, ok: false, error: error.message }); return true; }
|
|
238
242
|
if (setResult.ok) onEnvironmentChanged();
|
|
239
|
-
sendTo(ws, { type: "set_project_env_result", ok: setResult.ok, slug: msg.
|
|
243
|
+
sendTo(ws, { type: "set_project_env_result", ok: setResult.ok, slug: targetSlug, requestId: msg.requestId, error: setResult.error, timing: setResult.ok ? "Applies to newly created coding-agent processes. Active processes keep their current environment." : undefined });
|
|
240
244
|
} else {
|
|
241
|
-
sendTo(ws, { type: "set_project_env_result", ok: false, error: "Not supported" });
|
|
242
|
-
}
|
|
243
|
-
return true;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// --- Global CLAUDE.md ---
|
|
247
|
-
if (msg.type === "read_global_claude_md") {
|
|
248
|
-
var globalMdPath = path.join(require("./config").REAL_HOME, ".claude", "CLAUDE.md");
|
|
249
|
-
try {
|
|
250
|
-
var globalMdContent = fs.readFileSync(globalMdPath, "utf8");
|
|
251
|
-
sendTo(ws, { type: "global_claude_md_result", content: globalMdContent });
|
|
252
|
-
} catch (e) {
|
|
253
|
-
sendTo(ws, { type: "global_claude_md_result", error: e.message });
|
|
254
|
-
}
|
|
255
|
-
return true;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
if (msg.type === "write_global_claude_md") {
|
|
259
|
-
var globalMdDir = path.join(require("./config").REAL_HOME, ".claude");
|
|
260
|
-
var globalMdWritePath = path.join(globalMdDir, "CLAUDE.md");
|
|
261
|
-
try {
|
|
262
|
-
if (!fs.existsSync(globalMdDir)) {
|
|
263
|
-
fs.mkdirSync(globalMdDir, { recursive: true });
|
|
264
|
-
}
|
|
265
|
-
fs.writeFileSync(globalMdWritePath, msg.content || "", "utf8");
|
|
266
|
-
sendTo(ws, { type: "write_global_claude_md_result", ok: true });
|
|
267
|
-
} catch (e) {
|
|
268
|
-
sendTo(ws, { type: "write_global_claude_md_result", ok: false, error: e.message });
|
|
245
|
+
sendTo(ws, { type: "set_project_env_result", slug: targetSlug, requestId: msg.requestId, ok: false, error: "Not supported" });
|
|
269
246
|
}
|
|
270
247
|
return true;
|
|
271
248
|
}
|
|
@@ -274,9 +251,12 @@ function attachFilesystem(ctx) {
|
|
|
274
251
|
if (msg.type === "get_shared_env") {
|
|
275
252
|
var sharedEnvrc = "";
|
|
276
253
|
if (typeof opts.onGetSharedEnv === "function") {
|
|
277
|
-
|
|
278
|
-
|
|
254
|
+
try {
|
|
255
|
+
var sharedResult = opts.onGetSharedEnv();
|
|
256
|
+
sharedEnvrc = sharedResult.envrc || "";
|
|
257
|
+
} catch (error) { sendTo(ws, { type: "shared_env_result", error: error.message }); return true; }
|
|
279
258
|
}
|
|
259
|
+
if (typeof opts.onGetSharedEnv !== "function") { sendTo(ws, { type: "shared_env_result", error: "Shared environment is unavailable in this runtime." }); return true; }
|
|
280
260
|
sendTo(ws, { type: "shared_env_result", envrc: sharedEnvrc });
|
|
281
261
|
return true;
|
|
282
262
|
}
|
|
@@ -288,7 +268,9 @@ function attachFilesystem(ctx) {
|
|
|
288
268
|
sendTo(ws, { type: "set_shared_env_result", ok: false, error: sharedEnvError });
|
|
289
269
|
return true;
|
|
290
270
|
}
|
|
291
|
-
var sharedSetResult
|
|
271
|
+
var sharedSetResult;
|
|
272
|
+
try { sharedSetResult = opts.onSetSharedEnv(msg.envrc || ""); }
|
|
273
|
+
catch (error) { sendTo(ws, { type: "set_shared_env_result", ok: false, error: error.message }); return true; }
|
|
292
274
|
if (sharedSetResult.ok) onEnvironmentChanged();
|
|
293
275
|
sendTo(ws, { type: "set_shared_env_result", ok: sharedSetResult.ok, error: sharedSetResult.error, timing: sharedSetResult.ok ? "Applies to newly created coding-agent processes. Active processes keep their current environment." : undefined });
|
|
294
276
|
} else {
|