clay-server 5.2.0-beta.8 → 5.2.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/README.md +0 -4
- package/lib/clay-product-control-tools.js +1 -0
- package/lib/clay-product-control.js +14 -11
- package/lib/clay-vendor-usage.js +44 -0
- package/lib/github-star-count.js +147 -0
- package/lib/notes-checklist.js +43 -1
- package/lib/notes.js +2 -1
- package/lib/pane-pending-interactions.js +20 -0
- package/lib/pane-session-activation.js +114 -0
- package/lib/pane-session-transport.js +26 -0
- package/lib/project-session-notes.js +33 -8
- package/lib/project-sessions.js +78 -29
- package/lib/project-start-protocol.js +29 -0
- package/lib/project-vendor-login.js +2 -0
- package/lib/project.js +16 -4
- package/lib/public/app.js +41 -18
- package/lib/public/css/contextual-clay.css +2 -2
- package/lib/public/css/filebrowser.css +1 -1
- package/lib/public/css/input.css +6 -0
- package/lib/public/css/mate-loading-scene.css +21 -0
- package/lib/public/css/overlays.css +64 -256
- package/lib/public/css/project-mate-creation.css +5 -6
- package/lib/public/css/project-start.css +108 -0
- package/lib/public/css/projects-hub.css +53 -14
- package/lib/public/css/settings-shell.css +103 -0
- package/lib/public/css/sidebar.css +7 -0
- package/lib/public/css/sticky-notes.css +37 -11
- package/lib/public/css/title-bar.css +83 -0
- package/lib/public/index.html +50 -63
- package/lib/public/modules/account-transport-settings.js +8 -2
- package/lib/public/modules/admin-settings-email.js +7 -2
- package/lib/public/modules/admin-settings-invitations.js +2 -2
- package/lib/public/modules/admin-settings-projects.js +2 -2
- package/lib/public/modules/admin-settings-ui.js +20 -4
- package/lib/public/modules/admin-settings-users.js +4 -4
- package/lib/public/modules/app-connection.js +3 -0
- package/lib/public/modules/app-home-hub.js +2 -1
- package/lib/public/modules/app-message-router.js +13 -0
- package/lib/public/modules/app-messages.js +35 -7
- package/lib/public/modules/app-misc.js +3 -1
- package/lib/public/modules/app-projects.js +6 -407
- package/lib/public/modules/app-rate-limit.js +12 -1
- package/lib/public/modules/clay-owner-navigation.js +0 -3
- package/lib/public/modules/clay-studio-render.js +3 -1
- package/lib/public/modules/clay-tool-presentation.js +1 -0
- package/lib/public/modules/command-palette.js +52 -14
- package/lib/public/modules/contextual-clay-workspace.js +14 -2
- package/lib/public/modules/contextual-clay.js +19 -4
- package/lib/public/modules/contextual-mate-context.js +6 -4
- package/lib/public/modules/elicitation-form.js +5 -0
- package/lib/public/modules/github-star.js +66 -0
- package/lib/public/modules/history-replay-batch.js +8 -0
- package/lib/public/modules/home-surface-boot.js +0 -1
- package/lib/public/modules/input.js +55 -11
- package/lib/public/modules/mate-loading-scene.js +17 -0
- package/lib/public/modules/message-delivery.js +10 -2
- package/lib/public/modules/model-picker.js +2 -0
- package/lib/public/modules/pane-activation.js +214 -0
- package/lib/public/modules/pane-appearance-bridge.js +59 -0
- package/lib/public/modules/pane-binding.js +82 -0
- package/lib/public/modules/pane-bridge.js +5 -2
- package/lib/public/modules/pane-browser-bridge.js +5 -3
- package/lib/public/modules/pane-file-bridge.js +4 -0
- package/lib/public/modules/pane-issue-bridge.js +4 -1
- package/lib/public/modules/profile.js +11 -3
- package/lib/public/modules/project-mate-creation-workspace.js +13 -4
- package/lib/public/modules/project-session-visibility-settings.js +19 -16
- package/lib/public/modules/project-settings-environment.js +12 -1
- package/lib/public/modules/project-settings.js +119 -129
- package/lib/public/modules/project-start-dialog.js +130 -0
- package/lib/public/modules/project-start-folder-state.js +78 -0
- package/lib/public/modules/project-start-folder-view.js +190 -0
- package/lib/public/modules/project-start-forms.js +66 -0
- package/lib/public/modules/project-start-path.js +60 -0
- package/lib/public/modules/project-start-state.js +54 -0
- package/lib/public/modules/project-start-submit.js +67 -0
- package/lib/public/modules/projects-hub-view.js +32 -44
- package/lib/public/modules/projects-hub.js +39 -28
- package/lib/public/modules/rewind.js +5 -0
- package/lib/public/modules/server-settings.js +36 -91
- package/lib/public/modules/session-actions.js +5 -2
- package/lib/public/modules/session-context-menu.js +5 -0
- package/lib/public/modules/session-rich-drafts.js +21 -0
- package/lib/public/modules/session-switch-defer.js +67 -0
- package/lib/public/modules/settings-project-target.js +56 -0
- package/lib/public/modules/settings-select.js +1 -1
- package/lib/public/modules/settings-shell-registry.js +88 -0
- package/lib/public/modules/settings-shell-view.js +104 -0
- package/lib/public/modules/settings-shell.js +342 -0
- package/lib/public/modules/sidebar-mobile.js +8 -30
- package/lib/public/modules/sidebar-projects.js +2 -1
- package/lib/public/modules/split-group-restore.js +68 -0
- package/lib/public/modules/split-pair-ui.js +1 -0
- package/lib/public/modules/split-pane-reconciler.js +15 -0
- package/lib/public/modules/split-pane-renderer.js +87 -6
- package/lib/public/modules/split-session-boundary.js +1 -1
- package/lib/public/modules/split-view.js +51 -52
- package/lib/public/modules/sticky-notes-checklist.js +51 -6
- package/lib/public/modules/stt-controller.js +4 -1
- package/lib/public/modules/stt-recording.js +1 -1
- package/lib/public/modules/theme.js +31 -3
- package/lib/public/modules/tools.js +18 -2
- package/lib/public/modules/user-settings-integrations.js +2 -1
- package/lib/public/modules/user-settings-layout.js +12 -34
- package/lib/public/modules/user-settings-profile.js +1 -1
- package/lib/public/modules/user-settings.js +18 -85
- package/lib/public/modules/vendor-usage-format.js +93 -0
- package/lib/public/modules/vendor-usage-list.js +45 -0
- package/lib/public/modules/vendor-usage-model.js +215 -0
- package/lib/public/modules/vendor-usage-overview.js +323 -0
- package/lib/public/style.css +10 -7
- package/lib/public/welcome-art/conversation-desk.png +0 -0
- package/lib/public/welcome-art/mate-clay.png +0 -0
- package/lib/public/welcome-art/project-clay.png +0 -0
- package/lib/sdk-bridge.js +6 -1
- package/lib/sdk-message-processor.js +9 -1
- package/lib/sdk-quota-snapshot.js +20 -2
- package/lib/server-github-stars.js +39 -0
- package/lib/server-global-ws.js +21 -17
- package/lib/server.js +11 -0
- package/lib/session-notes-mcp-server.js +26 -4
- package/lib/session-notes-writes.js +88 -0
- package/lib/session-visibility.js +20 -8
- package/lib/sessions.js +27 -10
- package/lib/vendor-usage-acp-readers.js +97 -0
- package/lib/vendor-usage-capabilities.js +88 -0
- package/lib/vendor-usage-http-readers.js +214 -0
- package/lib/vendor-usage-metrics.js +47 -0
- package/lib/vendor-usage-native-readers.js +106 -0
- package/lib/vendor-usage-overview.js +406 -0
- package/lib/vendor-usage-service.js +281 -0
- package/lib/ws-schema.js +4 -2
- package/lib/yoke/adapters/claude.js +12 -0
- package/lib/yoke/adapters/codex-query-contract.js +1 -0
- package/lib/yoke/adapters/codex.js +45 -12
- package/lib/yoke/claude-hook-installer.js +1 -0
- package/lib/yoke/codex-dynamic-tool-names.js +80 -0
- package/lib/yoke/codex-model-catalog.js +37 -3
- package/lib/yoke/muse-services.js +16 -3
- package/lib/yoke/providers/claude-model-descriptions.js +22 -2
- package/lib/yoke/vendor-registry.js +6 -2
- package/package.json +5 -3
- package/lib/public/modules/server-settings-navigation.js +0 -39
package/lib/project-sessions.js
CHANGED
|
@@ -5,12 +5,16 @@ var { execFileSync } = require("child_process");
|
|
|
5
5
|
var providerSettings = require("./yoke/settings");
|
|
6
6
|
var updateSnooze = require("./update-snooze");
|
|
7
7
|
var yoke = require("./yoke");
|
|
8
|
+
var startProtocol = require("./project-start-protocol");
|
|
9
|
+
var startReply = startProtocol.withRequestId;
|
|
10
|
+
var browseMeta = startProtocol.browseMeta;
|
|
8
11
|
var sessionVisibility = require("./session-visibility");
|
|
9
12
|
var contextUsageModule = require("./context-usage");
|
|
10
13
|
var sessionDeleteModule = require("./project-session-delete");
|
|
11
14
|
var sessionFoldersModule = require("./project-session-folders");
|
|
12
15
|
var elicitationResponse = require("./project-elicitation-response");
|
|
13
16
|
var sessionCreationModule = require("./project-session-creation");
|
|
17
|
+
var vendorUsageOverviewModule = require("./vendor-usage-overview");
|
|
14
18
|
|
|
15
19
|
function vendorSupportsTui(vendor) {
|
|
16
20
|
var info = yoke.getVendorInfo(vendor);
|
|
@@ -223,6 +227,10 @@ function attachSessions(ctx) {
|
|
|
223
227
|
resolveSessionHome: resolveSessionHome, cancelPendingAskUser: cancelPendingAskUser,
|
|
224
228
|
}));
|
|
225
229
|
|
|
230
|
+
function boundedRequestId(msg) {
|
|
231
|
+
return typeof msg.requestId === "string" ? msg.requestId.substring(0, 200) : undefined;
|
|
232
|
+
}
|
|
233
|
+
|
|
226
234
|
function canAccessProjectSlug(ws, targetSlug) {
|
|
227
235
|
if (!targetSlug) return false;
|
|
228
236
|
if (!usersModule || typeof usersModule.isMultiUser !== "function" || !usersModule.isMultiUser()) return true;
|
|
@@ -361,6 +369,11 @@ function attachSessions(ctx) {
|
|
|
361
369
|
getProjectAccess: getProjectAccess,
|
|
362
370
|
getVendorAvailability: function (ws) { return ctx.getVendorAvailability(ws); },
|
|
363
371
|
});
|
|
372
|
+
var vendorUsage = vendorUsageOverviewModule.attachVendorUsageOverview({
|
|
373
|
+
slug: slug, sm: sm, usersModule: usersModule, clients: clients, sendTo: sendTo, getProjectAccess: getProjectAccess,
|
|
374
|
+
getVendorAvailability: function (ws) { return ctx.getVendorAvailability(ws); },
|
|
375
|
+
adapters: ctx.adapters, osUsers: osUsers, getLinuxUserForWs: ctx.getLinuxUserForWs,
|
|
376
|
+
});
|
|
364
377
|
// Kick off watchers for any TUI sessions already loaded from disk so
|
|
365
378
|
// their titles refresh as soon as Claude Code rewrites the jsonl, even
|
|
366
379
|
// before the user clicks them.
|
|
@@ -755,13 +768,15 @@ function attachSessions(ctx) {
|
|
|
755
768
|
if (msg.type === "set_project_session_visibility_default") {
|
|
756
769
|
sessionVisibility.handleDefaultChange({
|
|
757
770
|
slug: slug, isMate: isMate, osUsers: osUsers, usersModule: usersModule, getProjectAccess: getProjectAccess,
|
|
758
|
-
|
|
771
|
+
getTargetAccess: typeof opts.onGetProjectAccess === "function" ? opts.onGetProjectAccess : null,
|
|
772
|
+
canAccessProjectSlug: canAccessProjectSlug, opts: opts, sendTo: sendTo,
|
|
759
773
|
}, ws, msg);
|
|
760
774
|
return true;
|
|
761
775
|
}
|
|
762
776
|
|
|
763
777
|
if (sessionFolders.handleMessage(ws, msg)) return true;
|
|
764
778
|
if (sessionCreation.handleMessage(ws, msg)) return true;
|
|
779
|
+
if (vendorUsage.handleMessage(ws, msg)) return true;
|
|
765
780
|
|
|
766
781
|
if (msg.type === "bulk_delete_sessions") {
|
|
767
782
|
sessionDelete.bulkDeleteSessions(ws, msg);
|
|
@@ -804,6 +819,8 @@ function attachSessions(ctx) {
|
|
|
804
819
|
// adoptOrphanedCliSessions). Click a session in the sidebar instead.
|
|
805
820
|
|
|
806
821
|
if (msg.type === "switch_session") {
|
|
822
|
+
var paneActivation = require('./pane-session-activation').begin(ctx, ws, msg);
|
|
823
|
+
if (paneActivation === false) return true;
|
|
807
824
|
if (msg.id && sm.sessions.has(msg.id)) {
|
|
808
825
|
// resolveSessionForView sets runtimeMode / runtimeTerminalId /
|
|
809
826
|
// tuiSuspended (and hydrates the transcript) before sm.switchSession
|
|
@@ -817,6 +834,7 @@ function attachSessions(ctx) {
|
|
|
817
834
|
resolveSessionForView(xmTarget, ws);
|
|
818
835
|
}
|
|
819
836
|
var switchTargetSess = sm.sessions.get(msg.id);
|
|
837
|
+
if (paneActivation && !paneActivation.validate()) return true;
|
|
820
838
|
var switchTargetVendor = switchTargetSess && (switchTargetSess.vendor || sm.defaultVendor || "claude");
|
|
821
839
|
if (switchTargetSess && !switchTargetSess.effort) {
|
|
822
840
|
switchTargetSess.effort = yoke.clampEffort(
|
|
@@ -829,20 +847,20 @@ function attachSessions(ctx) {
|
|
|
829
847
|
if (usersModule.isMultiUser() && ws._clayUser) {
|
|
830
848
|
var switchTarget = sm.sessions.get(msg.id);
|
|
831
849
|
if (!usersModule.canAccessSession(ws._clayUser.id, switchTarget, { visibility: "public" })) return true;
|
|
832
|
-
ws.
|
|
833
|
-
sm.switchSession(msg.id, ws, hydrateImageRefs);
|
|
850
|
+
sm.switchSession(msg.id, ws, hydrateImageRefs, paneActivation && paneActivation.send, paneActivation && paneActivation.validate);
|
|
834
851
|
if (!ws._clayPane) broadcastPresence();
|
|
835
852
|
} else {
|
|
836
|
-
ws.
|
|
837
|
-
sm.switchSession(msg.id, ws, hydrateImageRefs);
|
|
853
|
+
sm.switchSession(msg.id, ws, hydrateImageRefs, paneActivation && paneActivation.send, paneActivation && paneActivation.validate);
|
|
838
854
|
}
|
|
839
855
|
// Send per-session context sources
|
|
840
856
|
if (typeof loadContextSources === "function") {
|
|
841
857
|
var switchedSources = loadContextSources(slug, msg.id);
|
|
842
|
-
|
|
858
|
+
if (paneActivation) paneActivation.send({ type: "context_sources_state", active: switchedSources });
|
|
859
|
+
else sendTo(ws, { type: "context_sources_state", active: switchedSources });
|
|
843
860
|
}
|
|
844
861
|
var swPresKey = ws._clayUser ? ws._clayUser.id : "_default";
|
|
845
862
|
if (!ws._clayPane) userPresence.setPresence(slug, swPresKey, userPresence.sessionIdForPersistence(switchTargetSess), null);
|
|
863
|
+
if (paneActivation) paneActivation.finish();
|
|
846
864
|
}
|
|
847
865
|
return true;
|
|
848
866
|
}
|
|
@@ -1084,6 +1102,12 @@ function attachSessions(ctx) {
|
|
|
1084
1102
|
|
|
1085
1103
|
if (msg.type === "stop") {
|
|
1086
1104
|
var session = getSessionForWs(ws);
|
|
1105
|
+
if (msg.sessionId != null || msg.sessionOriginId != null) {
|
|
1106
|
+
session = sm.sessions.get(msg.sessionId);
|
|
1107
|
+
if (!session || session.sessionOriginId !== msg.sessionOriginId ||
|
|
1108
|
+
!usersModule.isMultiUser() && session.ownerId ||
|
|
1109
|
+
usersModule.isMultiUser() && (!ws._clayUser || !usersModule.canAccessSession(ws._clayUser.id, session, getProjectAccess()))) return true;
|
|
1110
|
+
}
|
|
1087
1111
|
stopSession(session, ws && ws._clayUser);
|
|
1088
1112
|
return true;
|
|
1089
1113
|
}
|
|
@@ -1465,6 +1489,7 @@ function attachSessions(ctx) {
|
|
|
1465
1489
|
var sessionId = sm.permissionRequestIndex[requestId];
|
|
1466
1490
|
var session = sessionId ? sm.sessions.get(sessionId) : getSessionForWs(ws);
|
|
1467
1491
|
if (!session) return true;
|
|
1492
|
+
if (ws._clayPaneActivation && session.localId !== ws._clayPaneActivation.sessionId) return true;
|
|
1468
1493
|
var pending = session.pendingPermissions[requestId];
|
|
1469
1494
|
if (!pending) return true;
|
|
1470
1495
|
delete sm.permissionRequestIndex[requestId];
|
|
@@ -1646,8 +1671,9 @@ function attachSessions(ctx) {
|
|
|
1646
1671
|
parentDir = path.dirname(absTarget);
|
|
1647
1672
|
prefix = path.basename(absTarget).toLowerCase();
|
|
1648
1673
|
}
|
|
1649
|
-
|
|
1650
|
-
|
|
1674
|
+
var canList = function (candidate) { return !opts.canUsePath || opts.canUsePath(ws._clayUser && ws._clayUser.id, candidate); };
|
|
1675
|
+
if (!canList(parentDir)) {
|
|
1676
|
+
sendTo(ws, startReply(msg, { type: "browse_dir_result", path: msg.path, entries: [], error: "Directory access is not permitted" }));
|
|
1651
1677
|
return true;
|
|
1652
1678
|
}
|
|
1653
1679
|
try {
|
|
@@ -1663,9 +1689,9 @@ function attachSessions(ctx) {
|
|
|
1663
1689
|
dirEntries.push({ name: d.name, path: path.join(parentDir, d.name) });
|
|
1664
1690
|
}
|
|
1665
1691
|
dirEntries.sort(function (a, b) { return a.name.localeCompare(b.name); });
|
|
1666
|
-
sendTo(ws, { type: "browse_dir_result", path: msg.path, entries: dirEntries });
|
|
1692
|
+
sendTo(ws, Object.assign(browseMeta(msg, parentDir, prefix, canList), { type: "browse_dir_result", path: msg.path, entries: dirEntries }));
|
|
1667
1693
|
} catch (e) {
|
|
1668
|
-
sendTo(ws, { type: "browse_dir_result", path: msg.path, entries: [], error: e.message });
|
|
1694
|
+
sendTo(ws, startReply(msg, { type: "browse_dir_result", path: msg.path, entries: [], error: e.message }));
|
|
1669
1695
|
}
|
|
1670
1696
|
return true;
|
|
1671
1697
|
}
|
|
@@ -1675,24 +1701,24 @@ function attachSessions(ctx) {
|
|
|
1675
1701
|
var addPath = (msg.path || "").replace(/^~/, require("./config").REAL_HOME);
|
|
1676
1702
|
var addAbs = path.resolve(addPath);
|
|
1677
1703
|
if (opts.canUsePath && !opts.canUsePath(ws._clayUser && ws._clayUser.id, addAbs)) {
|
|
1678
|
-
sendTo(ws, { type: "add_project_result", ok: false, error: "Directory access is not permitted" });
|
|
1704
|
+
sendTo(ws, startReply(msg, { type: "add_project_result", ok: false, error: "Directory access is not permitted" }));
|
|
1679
1705
|
return true;
|
|
1680
1706
|
}
|
|
1681
1707
|
try {
|
|
1682
1708
|
var addStat = fs.statSync(addAbs);
|
|
1683
1709
|
if (!addStat.isDirectory()) {
|
|
1684
|
-
sendTo(ws, { type: "add_project_result", ok: false, error: "Not a directory" });
|
|
1710
|
+
sendTo(ws, startReply(msg, { type: "add_project_result", ok: false, error: "Not a directory" }));
|
|
1685
1711
|
return true;
|
|
1686
1712
|
}
|
|
1687
1713
|
} catch (e) {
|
|
1688
|
-
sendTo(ws, { type: "add_project_result", ok: false, error: "Directory not found" });
|
|
1714
|
+
sendTo(ws, startReply(msg, { type: "add_project_result", ok: false, error: "Directory not found" }));
|
|
1689
1715
|
return true;
|
|
1690
1716
|
}
|
|
1691
1717
|
if (typeof opts.onAddProject === "function") {
|
|
1692
1718
|
var result = opts.onAddProject(addAbs, ws._clayUser);
|
|
1693
|
-
sendTo(ws, Object.assign({}, result, { type: "add_project_result" }));
|
|
1719
|
+
sendTo(ws, startReply(msg, Object.assign({}, result, { type: "add_project_result" })));
|
|
1694
1720
|
} else {
|
|
1695
|
-
sendTo(ws, { type: "add_project_result", ok: false, error: "Not supported" });
|
|
1721
|
+
sendTo(ws, startReply(msg, { type: "add_project_result", ok: false, error: "Not supported" }));
|
|
1696
1722
|
}
|
|
1697
1723
|
return true;
|
|
1698
1724
|
}
|
|
@@ -1702,7 +1728,7 @@ function attachSessions(ctx) {
|
|
|
1702
1728
|
if (ws._clayUser) {
|
|
1703
1729
|
var cpPerms = usersModule.getEffectivePermissions(ws._clayUser, osUsers);
|
|
1704
1730
|
if (!cpPerms.createProject) {
|
|
1705
|
-
sendTo(ws, { type: "add_project_result", ok: false, error: "You do not have permission to create projects" });
|
|
1731
|
+
sendTo(ws, startReply(msg, { type: "add_project_result", ok: false, error: "You do not have permission to create projects" }));
|
|
1706
1732
|
return true;
|
|
1707
1733
|
}
|
|
1708
1734
|
}
|
|
@@ -1710,14 +1736,14 @@ function attachSessions(ctx) {
|
|
|
1710
1736
|
if (msg.type === "create_project") {
|
|
1711
1737
|
var createName = (msg.name || "").trim();
|
|
1712
1738
|
if (!createName || !/^[a-zA-Z0-9_-]+$/.test(createName)) {
|
|
1713
|
-
sendTo(ws, { type: "add_project_result", ok: false, error: "Invalid name. Use only letters, numbers, dashes, and underscores." });
|
|
1739
|
+
sendTo(ws, startReply(msg, { type: "add_project_result", ok: false, error: "Invalid name. Use only letters, numbers, dashes, and underscores." }));
|
|
1714
1740
|
return true;
|
|
1715
1741
|
}
|
|
1716
1742
|
if (typeof opts.onCreateProject === "function") {
|
|
1717
1743
|
var createResult = opts.onCreateProject(createName, ws._clayUser);
|
|
1718
|
-
sendTo(ws, Object.assign({}, createResult, { type: "add_project_result" }));
|
|
1744
|
+
sendTo(ws, startReply(msg, Object.assign({}, createResult, { type: "add_project_result" })));
|
|
1719
1745
|
} else {
|
|
1720
|
-
sendTo(ws, { type: "add_project_result", ok: false, error: "Not supported" });
|
|
1746
|
+
sendTo(ws, startReply(msg, { type: "add_project_result", ok: false, error: "Not supported" }));
|
|
1721
1747
|
}
|
|
1722
1748
|
return true;
|
|
1723
1749
|
}
|
|
@@ -1726,16 +1752,16 @@ function attachSessions(ctx) {
|
|
|
1726
1752
|
if (msg.type === "clone_project") {
|
|
1727
1753
|
var cloneUrl = (msg.url || "").trim();
|
|
1728
1754
|
if (!cloneUrl || (!/^https?:\/\//.test(cloneUrl) && !/^git@/.test(cloneUrl))) {
|
|
1729
|
-
sendTo(ws, { type: "add_project_result", ok: false, error: "Invalid URL. Use https:// or git@ format." });
|
|
1755
|
+
sendTo(ws, startReply(msg, { type: "add_project_result", ok: false, error: "Invalid URL. Use https:// or git@ format." }));
|
|
1730
1756
|
return true;
|
|
1731
1757
|
}
|
|
1732
|
-
sendTo(ws, { type: "clone_project_progress", status: "cloning" });
|
|
1758
|
+
sendTo(ws, startReply(msg, { type: "clone_project_progress", status: "cloning" }));
|
|
1733
1759
|
if (typeof opts.onCloneProject === "function") {
|
|
1734
1760
|
opts.onCloneProject(cloneUrl, ws._clayUser, function (cloneResult) {
|
|
1735
|
-
sendTo(ws, { type: "add_project_result", ok: cloneResult.ok, slug: cloneResult.slug, error: cloneResult.error });
|
|
1761
|
+
sendTo(ws, startReply(msg, { type: "add_project_result", ok: cloneResult.ok, slug: cloneResult.slug, error: cloneResult.error }));
|
|
1736
1762
|
});
|
|
1737
1763
|
} else {
|
|
1738
|
-
sendTo(ws, { type: "add_project_result", ok: false, error: "Not supported" });
|
|
1764
|
+
sendTo(ws, startReply(msg, { type: "add_project_result", ok: false, error: "Not supported" }));
|
|
1739
1765
|
}
|
|
1740
1766
|
return true;
|
|
1741
1767
|
}
|
|
@@ -1848,30 +1874,41 @@ function attachSessions(ctx) {
|
|
|
1848
1874
|
|
|
1849
1875
|
// --- Set project title (rename) ---
|
|
1850
1876
|
if (msg.type === "set_project_title") {
|
|
1877
|
+
var titleRequestId = boundedRequestId(msg);
|
|
1851
1878
|
if (!msg.slug) {
|
|
1852
|
-
sendTo(ws, { type: "set_project_title_result", ok: false, error: "Missing slug" });
|
|
1879
|
+
sendTo(ws, { type: "set_project_title_result", ok: false, error: "Missing slug", requestId: titleRequestId });
|
|
1880
|
+
return true;
|
|
1881
|
+
}
|
|
1882
|
+
// The target is named by the client; it must be a project this account can access.
|
|
1883
|
+
if (!canAccessProjectSlug(ws, msg.slug)) {
|
|
1884
|
+
sendTo(ws, { type: "set_project_title_result", ok: false, error: "Project access is not permitted", slug: msg.slug, requestId: titleRequestId });
|
|
1853
1885
|
return true;
|
|
1854
1886
|
}
|
|
1855
1887
|
if (typeof opts.onSetProjectTitle === "function") {
|
|
1856
1888
|
var titleResult = opts.onSetProjectTitle(msg.slug, msg.title || null);
|
|
1857
|
-
sendTo(ws, Object.assign({}, titleResult, { type: "set_project_title_result", slug: msg.slug }));
|
|
1889
|
+
sendTo(ws, Object.assign({}, titleResult, { type: "set_project_title_result", slug: msg.slug, requestId: titleRequestId }));
|
|
1858
1890
|
} else {
|
|
1859
|
-
sendTo(ws, { type: "set_project_title_result", ok: false, error: "Not supported" });
|
|
1891
|
+
sendTo(ws, { type: "set_project_title_result", ok: false, error: "Not supported", requestId: titleRequestId });
|
|
1860
1892
|
}
|
|
1861
1893
|
return true;
|
|
1862
1894
|
}
|
|
1863
1895
|
|
|
1864
1896
|
// --- Set project icon (emoji) ---
|
|
1865
1897
|
if (msg.type === "set_project_icon") {
|
|
1898
|
+
var iconRequestId = boundedRequestId(msg);
|
|
1866
1899
|
if (!msg.slug) {
|
|
1867
|
-
sendTo(ws, { type: "set_project_icon_result", ok: false, error: "Missing slug" });
|
|
1900
|
+
sendTo(ws, { type: "set_project_icon_result", ok: false, error: "Missing slug", requestId: iconRequestId });
|
|
1901
|
+
return true;
|
|
1902
|
+
}
|
|
1903
|
+
if (!canAccessProjectSlug(ws, msg.slug)) {
|
|
1904
|
+
sendTo(ws, { type: "set_project_icon_result", ok: false, error: "Project access is not permitted", slug: msg.slug, requestId: iconRequestId });
|
|
1868
1905
|
return true;
|
|
1869
1906
|
}
|
|
1870
1907
|
if (typeof opts.onSetProjectIcon === "function") {
|
|
1871
1908
|
var iconResult = opts.onSetProjectIcon(msg.slug, msg.icon || null);
|
|
1872
|
-
sendTo(ws, { type: "set_project_icon_result", ok: iconResult.ok, slug: msg.slug, error: iconResult.error });
|
|
1909
|
+
sendTo(ws, { type: "set_project_icon_result", ok: iconResult.ok, slug: msg.slug, error: iconResult.error, requestId: iconRequestId });
|
|
1873
1910
|
} else {
|
|
1874
|
-
sendTo(ws, { type: "set_project_icon_result", ok: false, error: "Not supported" });
|
|
1911
|
+
sendTo(ws, { type: "set_project_icon_result", ok: false, error: "Not supported", requestId: iconRequestId });
|
|
1875
1912
|
}
|
|
1876
1913
|
return true;
|
|
1877
1914
|
}
|
|
@@ -1997,6 +2034,18 @@ function attachSessions(ctx) {
|
|
|
1997
2034
|
}
|
|
1998
2035
|
|
|
1999
2036
|
return {
|
|
2037
|
+
invalidateVendorUsage: function () { vendorUsage.invalidateAll(); },
|
|
2038
|
+
// Canonical read-only inspection: the caller has already proven the owner and
|
|
2039
|
+
// project access; the OS user is re-derived from the live user record.
|
|
2040
|
+
readVendorUsage: function (request) {
|
|
2041
|
+
var installed = null;
|
|
2042
|
+
if (Array.isArray(sm.installedVendors)) {
|
|
2043
|
+
installed = Object.create(null);
|
|
2044
|
+
sm.installedVendors.forEach(function (vendor) { installed[vendor] = true; });
|
|
2045
|
+
}
|
|
2046
|
+
var linuxUser = osUsers && request.owner !== "default" ? ctx.getLinuxUserForSession({ ownerId: request.owner }) : null;
|
|
2047
|
+
return vendorUsage.readForOwner({ owner: request.owner, linuxUser: linuxUser, installed: installed, isCurrent: request.isCurrent });
|
|
2048
|
+
},
|
|
2000
2049
|
handleSessionsMessage: handleSessionsMessage,
|
|
2001
2050
|
resolveSessionForView: resolveSessionForView,
|
|
2002
2051
|
sendSessionFoldersState: sessionFolders.sendStateTo,
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Shared reply helpers for the project-start dialog (browse_dir and add/create/clone results).
|
|
2
|
+
// A string requestId on the request is echoed on its reply so the client can drop stale answers.
|
|
3
|
+
|
|
4
|
+
var path = require("path");
|
|
5
|
+
|
|
6
|
+
function requestIdOf(msg) {
|
|
7
|
+
return msg && typeof msg.requestId === "string" && msg.requestId.length <= 64 ? msg.requestId : undefined;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Canonical listing metadata. `dir` is the directory whose children are listed, `prefix` is
|
|
11
|
+
// non-empty when the requested path did not exist or was not a directory, and `parent` is set
|
|
12
|
+
// only when the caller may list the parent as well.
|
|
13
|
+
function browseMeta(msg, dir, prefix, canList) {
|
|
14
|
+
var parent = path.dirname(dir);
|
|
15
|
+
return {
|
|
16
|
+
requestId: requestIdOf(msg),
|
|
17
|
+
dir: dir,
|
|
18
|
+
prefix: prefix || "",
|
|
19
|
+
parent: parent !== dir && (!canList || canList(parent)) ? parent : null,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function withRequestId(msg, payload) {
|
|
24
|
+
var id = requestIdOf(msg);
|
|
25
|
+
if (id !== undefined) payload.requestId = id;
|
|
26
|
+
return payload;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = { requestIdOf: requestIdOf, browseMeta: browseMeta, withRequestId: withRequestId };
|
|
@@ -171,6 +171,8 @@ function attachVendorLogin(ctx) {
|
|
|
171
171
|
// reused by every project, so tearing one down here would kill unrelated
|
|
172
172
|
// sessions; those runtimes pick up new credentials on their own.
|
|
173
173
|
function refreshVendorAuth(vendor, linuxUser) {
|
|
174
|
+
// Cached account usage described the previous credentials.
|
|
175
|
+
if (typeof ctx.onVendorAuthChanged === "function") { try { ctx.onVendorAuthChanged(vendor, linuxUser || null); } catch (e) {} }
|
|
174
176
|
var adapter = adapters[vendor];
|
|
175
177
|
if (!adapter || typeof adapter.shutdown !== "function") return Promise.resolve(false);
|
|
176
178
|
if (adapter.shared) {
|
package/lib/project.js
CHANGED
|
@@ -459,7 +459,8 @@ function createProjectContext(opts) {
|
|
|
459
459
|
if (obj.type === "loop_registry_updated") payload.records = getHubSchedules(userId);
|
|
460
460
|
else payload.schedules = getHubSchedules(userId);
|
|
461
461
|
}
|
|
462
|
-
|
|
462
|
+
payload = require('./pane-session-transport').outbound(ws, payload);
|
|
463
|
+
if (payload) ws.send(JSON.stringify(payload));
|
|
463
464
|
}
|
|
464
465
|
|
|
465
466
|
function sendToAdmins(obj) {
|
|
@@ -555,7 +556,8 @@ function createProjectContext(opts) {
|
|
|
555
556
|
var data = JSON.stringify(obj), delivered = 0;
|
|
556
557
|
for (var ws of clients) {
|
|
557
558
|
if (ws.readyState === 1 && canReceiveMate(ws) && canReceiveYou(ws, sessionId) && ws._clayActiveSession === sessionId) {
|
|
558
|
-
|
|
559
|
+
var panePayload = require('./pane-session-transport').outbound(ws, obj, sessionId);
|
|
560
|
+
if (panePayload) { ws.send(JSON.stringify(panePayload)); delivered++; if (onSent) onSent(ws); }
|
|
559
561
|
}
|
|
560
562
|
}
|
|
561
563
|
homeDebateClients.forEach(function (ws) {
|
|
@@ -569,7 +571,8 @@ function createProjectContext(opts) {
|
|
|
569
571
|
var data = JSON.stringify(obj);
|
|
570
572
|
for (var ws of clients) {
|
|
571
573
|
if (ws !== sender && ws.readyState === 1 && canReceiveMate(ws) && canReceiveYou(ws, sessionId) && ws._clayActiveSession === sessionId) {
|
|
572
|
-
|
|
574
|
+
var panePayload = require('./pane-session-transport').outbound(ws, obj, sessionId);
|
|
575
|
+
if (panePayload) ws.send(JSON.stringify(panePayload));
|
|
573
576
|
}
|
|
574
577
|
}
|
|
575
578
|
}
|
|
@@ -655,7 +658,8 @@ function createProjectContext(opts) {
|
|
|
655
658
|
var access = opts.getProjectAccess ? opts.getProjectAccess() : { visibility: "public", ownerId: projectOwnerId || null };
|
|
656
659
|
if (!viewer || (opts.canAccessProjectSlug && !opts.canAccessProjectSlug(viewer.id, slug)) || !usersModule.canAccessSession(viewer.id, session, access)) return;
|
|
657
660
|
}
|
|
658
|
-
ws.
|
|
661
|
+
var panePayload = ws._clayPaneActivation ? require('./pane-session-transport').outbound(ws, message, session.localId) : message;
|
|
662
|
+
if (panePayload) ws.send(panePayload === message ? data : JSON.stringify(panePayload));
|
|
659
663
|
});
|
|
660
664
|
},
|
|
661
665
|
authorize: function (session, actor) {
|
|
@@ -1827,6 +1831,10 @@ function createProjectContext(opts) {
|
|
|
1827
1831
|
}
|
|
1828
1832
|
|
|
1829
1833
|
function handleMessage(ws, msg) {
|
|
1834
|
+
return require('./pane-session-transport').run(ws, msg, dispatchMessage);
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
function dispatchMessage(ws, msg) {
|
|
1830
1838
|
if (!_requestAccess.permitMessage(ws, msg)) return;
|
|
1831
1839
|
// --- Keep-alive (delegated to project-connection.js) ---
|
|
1832
1840
|
// Answered before any routing so a ping can never be forwarded elsewhere.
|
|
@@ -2147,6 +2155,7 @@ function createProjectContext(opts) {
|
|
|
2147
2155
|
});
|
|
2148
2156
|
sm.setSessionHydrator(_sessionSkillCatalog.hydrate);
|
|
2149
2157
|
var _sessions = attachSessions({
|
|
2158
|
+
splitStore: _splitGroups.store,
|
|
2150
2159
|
adapters: adapters,
|
|
2151
2160
|
isPendingQueuePaused: function (session) { return _pendingMessageQueue.isPaused(session); },
|
|
2152
2161
|
cwd: cwd,
|
|
@@ -2178,6 +2187,7 @@ function createProjectContext(opts) {
|
|
|
2178
2187
|
resolveDefaultAi: opts.resolveDefaultAi,
|
|
2179
2188
|
resolveMateSessionDefaults: opts.resolveMateSessionDefaults,
|
|
2180
2189
|
getVendorAvailability: function (ws) { return _models.getVendorAvailability(ws); },
|
|
2190
|
+
getLinuxUserForWs: getLinuxUserForWs,
|
|
2181
2191
|
canCreateScheduledTaskInterview: function (ws, session) { return !!(_scheduledTasks && _scheduledTasks.canCreateInterview(ws, session)); },
|
|
2182
2192
|
canStartScheduledTaskInterview: function (ws, session) { return !!(_scheduledTasks && _scheduledTasks.canStartInterview(ws, session)); },
|
|
2183
2193
|
onHumanPairStop: function (session) {
|
|
@@ -2390,6 +2400,7 @@ function createProjectContext(opts) {
|
|
|
2390
2400
|
|
|
2391
2401
|
// --- Vendor login flow (delegated to project-vendor-login.js) ---
|
|
2392
2402
|
var _vendorLogin = attachVendorLogin({
|
|
2403
|
+
onVendorAuthChanged: function () { _sessions.invalidateVendorUsage(); },
|
|
2393
2404
|
requestAccess: _requestAccess,
|
|
2394
2405
|
clients: clients,
|
|
2395
2406
|
slug: slug,
|
|
@@ -3031,6 +3042,7 @@ function createProjectContext(opts) {
|
|
|
3031
3042
|
requestProductControlReview: _productControl.requestProductControlReview,
|
|
3032
3043
|
applyProductSessionAction: _productControl.applyProductSessionAction,
|
|
3033
3044
|
inspectProductSessionQueue: _productControl.inspectProductSessionQueue,
|
|
3045
|
+
readVendorUsage: function (request) { return _sessions.readVendorUsage(request); },
|
|
3034
3046
|
inspectProductSessionRuntime: _sessions.sessionRuntimeActions.inspect,
|
|
3035
3047
|
inspectMateLifecycleRuntime: _sessions.sessionRuntimeActions.inspectLifecycle,
|
|
3036
3048
|
inspectDelegatedFollowUp: _delegatedFollowUp.inspectDelegatedFollowUp,
|
package/lib/public/app.js
CHANGED
|
@@ -31,10 +31,11 @@ import { initMateMemory, renderMemoryList, hideMemory } from './modules/mate-mem
|
|
|
31
31
|
import { initRewind, setRewindMode, showRewindModal, clearPendingRewindUuid, addRewindButton, onRewindComplete, onRewindError } from './modules/rewind.js';
|
|
32
32
|
import { initNotifications, showDoneNotification, playDoneSound, isNotifAlertEnabled, isNotifSoundEnabled } from './modules/notifications.js';
|
|
33
33
|
import { initInput, clearPendingImages, handleInputSync, autoResize, builtinCommands, sendMessage, hasSendableContent, setScheduleBtnDisabled, setScheduleDelayMs, clearScheduleDelay } from './modules/input.js';
|
|
34
|
-
import { initQrCode
|
|
34
|
+
import { initQrCode } from './modules/qrcode.js';
|
|
35
35
|
import { initFileBrowser, loadRootDirectory, reopenFileViewer, refreshTree, handleFsList, handleFsRead, handleDirChanged, refreshIfOpen, handleFileChanged, handleFileHistory, handleGitDiff, handleFileAt, getPendingNavigate, closeFileViewer, resetFileBrowser } from './modules/filebrowser.js';
|
|
36
36
|
import { initGitPanel } from './modules/git-panel.js';
|
|
37
37
|
import { initWorkerPaneLock } from './modules/worker-pane-lock.js';
|
|
38
|
+
import { initPaneActivation } from './modules/pane-activation.js';
|
|
38
39
|
import { initAutonomousRun } from './modules/autonomous-run.js';
|
|
39
40
|
import { initLoopInterview } from './modules/loop-interview.js';
|
|
40
41
|
import { initTerminal, openTerminal, closeTerminal, resetTerminals, handleTermList, handleTermCreated, handleTermOutput, handleTermResized, handleTermExited, handleTermClosed, sendTerminalCommand } from './modules/terminal.js';
|
|
@@ -45,6 +46,7 @@ import { initTheme, getThemeColor, getComputedVar, onThemeChange, getCurrentThem
|
|
|
45
46
|
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';
|
|
46
47
|
import { initServerSettings, updateSettingsStats, updateDaemonConfig, handleSetPinResult, handleKeepAwakeChanged, handleAutoContinueChanged, handleRestartResult, handleShutdownResult, handleSharedEnv, handleSharedEnvSaved } from './modules/server-settings.js';
|
|
47
48
|
import { initProjectSettings } from './modules/project-settings.js';
|
|
49
|
+
import { initSettingsShell, openSettings } from './modules/settings-shell.js';
|
|
48
50
|
import { initSkills, handleSkillInstalled, handleSkillUninstalled } from './modules/skills.js';
|
|
49
51
|
import { initMcp } from './modules/mcp-ui.js';
|
|
50
52
|
import { initScheduler, resetScheduler, handleLoopRegistryUpdated, handleScheduleRunStarted, handleScheduleRunFinished, handleLoopScheduled, openSchedulerToTab, isSchedulerOpen, closeScheduler, enterCraftingMode, exitCraftingMode, handleLoopRegistryFiles, getUpcomingSchedules } from './modules/scheduler.js';
|
|
@@ -62,6 +64,7 @@ import { initProjectLogs, closeProjectLogs } from './modules/project-logs.js';
|
|
|
62
64
|
import { initProjectSwitcher } from './modules/project-switcher.js';
|
|
63
65
|
import { initSplitView } from './modules/split-view.js';
|
|
64
66
|
import { initPaneBridge } from './modules/pane-bridge.js';
|
|
67
|
+
import { initPaneAppearanceBridge } from './modules/pane-appearance-bridge.js';
|
|
65
68
|
import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
66
69
|
import { initSessionSearch, toggleSearch, closeSearch, isSearchOpen, handleFindInSessionResults, onHistoryPrepended as onSessionSearchHistoryPrepended } from './modules/session-search.js';
|
|
67
70
|
import { initTooltips, registerTooltip } from './modules/tooltip.js';
|
|
@@ -71,10 +74,15 @@ import { initShellCommand } from './modules/shell-command.js';
|
|
|
71
74
|
import { initConnection, connect as _connConnect, setStatus as _connSetStatus, scheduleReconnect as _connScheduleReconnect, cancelReconnect as _connCancelReconnect } from './modules/app-connection.js';
|
|
72
75
|
import { processMessage as _msgProcessMessage } from './modules/app-messages.js';
|
|
73
76
|
import { getWs as _getWsRef, setWs as _setWsRef } from './modules/ws-ref.js';
|
|
77
|
+
import { initialProjectStart } from './modules/project-start-state.js';
|
|
78
|
+
import { emptyFolderState } from './modules/project-start-folder-state.js';
|
|
79
|
+
import { openAddProjectModal, initProjectStart } from './modules/project-start-dialog.js';
|
|
74
80
|
import { initProjectsHub, showProjectsHub, hideProjectsHub } from './modules/projects-hub.js';
|
|
75
81
|
import { initHomeSurfaceBoot } from './modules/home-surface-boot.js';
|
|
76
82
|
import { rememberHomePrimarySurface } from './modules/home-surface.js';
|
|
77
83
|
import { initRateLimit, handleRateLimitEvent as _rlHandleRateLimitEvent, updateRateLimitUsage as _rlUpdateRateLimitUsage, handleFastModeState as _rlHandleFastModeState, resetRateLimitState } from './modules/app-rate-limit.js';
|
|
84
|
+
import { initVendorUsageOverview } from './modules/vendor-usage-overview.js';
|
|
85
|
+
import { initGithubStar } from './modules/github-star.js';
|
|
78
86
|
import { initCursors, handleRemoteCursorMove as _curHandleRemoteCursorMove, handleRemoteCursorLeave as _curHandleRemoteCursorLeave, handleRemoteSelection as _curHandleRemoteSelection, clearRemoteCursors as _curClearRemoteCursors, initCursorToggle } from './modules/app-cursors.js';
|
|
79
87
|
import { initDefaultAi } from './modules/default-ai.js';
|
|
80
88
|
import { requestDefaultVendor } from './modules/default-vendor.js';
|
|
@@ -96,7 +104,7 @@ import { initProjectMateCreationWorkspace } from './modules/project-mate-creatio
|
|
|
96
104
|
import { initProjectDebatePlanningWorkspace } from './modules/project-debate-planning-workspace.js';
|
|
97
105
|
import { initProjectSessionNavigation } from './modules/project-session-navigation.js';
|
|
98
106
|
import { initPanels, updateConfigChip as _panUpdateConfigChip, getModelEffortLevels as _panGetModelEffortLevels, accumulateUsage as _panAccumulateUsage, updateUsagePanel as _panUpdateUsagePanel, resetUsage as _panResetUsage, toggleUsagePanel as _panToggleUsagePanel, formatTokens as _panFormatTokens, updateStatusPanel as _panUpdateStatusPanel, requestProcessStats as _panRequestProcessStats, toggleStatusPanel as _panToggleStatusPanel, accumulateContext as _panAccumulateContext, updateContextPanel as _panUpdateContextPanel, resetContext as _panResetContext, resetContextData as _panResetContextData, minimizeContext as _panMinimizeContext, expandContext as _panExpandContext, toggleContextPanel as _panToggleContextPanel, getContextView as _panGetContextView, renderCtxPopover as _panRenderCtxPopover, hideCtxPopover as _panHideCtxPopover, formatBytes as _panFormatBytes, formatUptime as _panFormatUptime, getModelSupportsEffort as _panGetModelSupportsEffort, getSessionUsage, setSessionUsage, getContextData, setContextData, setContextView as _panSetContextView, applyContextView as _panApplyContextView } from './modules/app-panels.js';
|
|
99
|
-
import {
|
|
107
|
+
import { updateProjectList as _projUpdateProjectList, renderProjectList as _projRenderProjectList, renderTopbarPresence as _projRenderTopbarPresence, switchProject as _projSwitchProject, resetClientState as _projResetClientState, confirmRemoveProject as _projConfirmRemoveProject, handleRemoveProjectCheckResult as _projHandleRemoveProjectCheckResult, handleRemoveProjectResult as _projHandleRemoveProjectResult, showUpdateAvailable as _projShowUpdateAvailable, getCachedProjects, setCachedProjects, getCachedProjectCount, getCachedRemovedProjects, setCachedRemovedProjects } from './modules/app-projects.js';
|
|
100
108
|
import { initRendering, addToMessages as _renAddToMessages, scrollToBottom as _renScrollToBottom, forceScrollToBottom as _renForceScrollToBottom, addUserMessage as _renAddUserMessage, getMsgTime as _renGetMsgTime, shouldGroupMessage as _renShouldGroupMessage, ensureAssistantBlock as _renEnsureAssistantBlock, addCopyHandler as _renAddCopyHandler, appendDelta as _renAppendDelta, flushStreamBuffer as _renFlushStreamBuffer, finalizeAssistantBlock as _renFinalizeAssistantBlock, addSystemMessage as _renAddSystemMessage, addConflictMessage as _renAddConflictMessage, addContextOverflowMessage as _renAddContextOverflowMessage, showClaudePreThinking as _renShowClaudePreThinking, showMatePreThinking as _renShowMatePreThinking, removeMatePreThinking as _renRemoveMatePreThinking, showSuggestionChips as _renShowSuggestionChips, hideSuggestionChips as _renHideSuggestionChips, getGhostSuggestion as _renGetGhostSuggestion, getTurnCounter, setTurnCounter, getPrependAnchor, setPrependAnchor, getActivityEl, setActivityEl, getIsUserScrolledUp, setIsUserScrolledUp, getStickyBottom, armStickyBottom, disarmStickyBottom } from './modules/app-rendering.js';
|
|
101
109
|
import { initDm, openDm as _dmOpenDm, enterDmMode as _dmEnterDmMode, exitDmMode as _dmExitDmMode, handleMateCreatedInApp as _dmHandleMateCreatedInApp, buildMateInterviewPrompt as _dmBuildMateInterviewPrompt, updateMateIconStatus as _dmUpdateMateIconStatus, connectMateProject as _dmConnectMateProject, disconnectMateProject as _dmDisconnectMateProject, appendDmMessage as _dmAppendDmMessage, showDmTypingIndicator as _dmShowDmTypingIndicator, handleDmSend as _dmHandleDmSend } from './modules/app-dm.js';
|
|
102
110
|
import { initMention, handleMentionStart, handleMentionStream, handleMentionDone, handleMentionError, handleMentionActivity, renderMentionUser, renderMentionResponse } from './modules/mention.js';
|
|
@@ -191,7 +199,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
191
199
|
function updateProjectList(msg) { _projUpdateProjectList(msg); }
|
|
192
200
|
function renderTopbarPresence(serverUsers) { _projRenderTopbarPresence(serverUsers); }
|
|
193
201
|
function renderProjectList() { _projRenderProjectList(); }
|
|
194
|
-
// projectListAddBtn listener -> modules/
|
|
202
|
+
// projectListAddBtn listener -> modules/project-start-dialog.js (initProjectStart)
|
|
195
203
|
|
|
196
204
|
// Prevent Cmd+Z / Cmd+Shift+Z from triggering browser back/forward (Arc, etc.)
|
|
197
205
|
// Always block browser default for Cmd+Z and manually invoke undo/redo via execCommand
|
|
@@ -279,6 +287,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
279
287
|
createStore({
|
|
280
288
|
networkSettings: { loaded: false, busy: false, confirming: false, draft: "", saved: "", status: "", errorKind: "", requestId: 0 },
|
|
281
289
|
vendorLoginBrowser: null,
|
|
290
|
+
githubStarCount: null,
|
|
282
291
|
sharedBrowser: null,
|
|
283
292
|
sharedBrowsers: [],
|
|
284
293
|
mcpSkillsWorkbench: {},
|
|
@@ -295,6 +304,16 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
295
304
|
paneMode: paneMode,
|
|
296
305
|
paneSessionId: paneSessionId,
|
|
297
306
|
panePinPending: paneMode && !!paneSessionId,
|
|
307
|
+
paneCommittedBinding: null, panePendingBinding: null, paneReady: false, paneSuspended: false,
|
|
308
|
+
paneActivationGeneration: 0, paneActivationTimer: null, panePointerBinding: null, paneRichDrafts: {},
|
|
309
|
+
sessionRichDrafts: {},
|
|
310
|
+
sessionActionEpoch: 0, composerUploadingCount: 0, deferredSessionSwitch: null,
|
|
311
|
+
paneCallbackBinding: null, paneActionEvents: [], paneHeldKeys: {}, rewindAction: null, handoffAction: null,
|
|
312
|
+
authIdentityLoaded: false,
|
|
313
|
+
splitIdentityBlockedSocket: null,
|
|
314
|
+
splitIdentityHydrated: false,
|
|
315
|
+
paneActivationUnsupported: false,
|
|
316
|
+
paneBindingSessions: [],
|
|
298
317
|
splitPanes: null,
|
|
299
318
|
splitGroups: [],
|
|
300
319
|
sessionFolders: null,
|
|
@@ -320,6 +339,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
320
339
|
replayingHistory: false,
|
|
321
340
|
historyReplayBatch: null,
|
|
322
341
|
pendingSessionEntryNavigation: null,
|
|
342
|
+
sessionEntryHighlight: null,
|
|
323
343
|
sessionNavigationRequestId: null,
|
|
324
344
|
projectName: projectName,
|
|
325
345
|
cwd: "",
|
|
@@ -408,7 +428,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
408
428
|
projectListLoaded: false,
|
|
409
429
|
projectsAccessLoaded: false,
|
|
410
430
|
projectsHubRestoreRequested: false,
|
|
411
|
-
|
|
431
|
+
projectStart: initialProjectStart(),
|
|
432
|
+
projectStartFolder: emptyFolderState(),
|
|
412
433
|
onboardingStep: 'welcome',
|
|
413
434
|
onboardingIntent: null,
|
|
414
435
|
currentProjectOwnerId: null,
|
|
@@ -633,6 +654,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
633
654
|
vendorInfo: {},
|
|
634
655
|
// Rate-limit data is projected only for the displayed session/vendor.
|
|
635
656
|
rateLimitState: {},
|
|
657
|
+
vendorUsageOverview: null,
|
|
658
|
+
vendorUsageOpen: null,
|
|
636
659
|
currentMode: "default",
|
|
637
660
|
effectivePermissionMode: null,
|
|
638
661
|
permissionCapabilities: { auto: false, mcpOverride: false },
|
|
@@ -686,6 +709,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
686
709
|
|
|
687
710
|
// --- Theme (module) ---
|
|
688
711
|
initTheme();
|
|
712
|
+
initPaneAppearanceBridge();
|
|
689
713
|
|
|
690
714
|
// --- Tooltips ---
|
|
691
715
|
initTooltips();
|
|
@@ -777,8 +801,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
777
801
|
switch (action) {
|
|
778
802
|
case "createMate": startClayMateCreation(); break;
|
|
779
803
|
case "openSettings":
|
|
780
|
-
|
|
781
|
-
if (sb) sb.click();
|
|
804
|
+
openSettings();
|
|
782
805
|
break;
|
|
783
806
|
case "showHome": showHomeHub(); break;
|
|
784
807
|
}
|
|
@@ -1150,7 +1173,10 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
1150
1173
|
basePath: basePath,
|
|
1151
1174
|
});
|
|
1152
1175
|
|
|
1153
|
-
// ---
|
|
1176
|
+
// --- Unified full-screen settings shell (Personal, Project, Server panes) ---
|
|
1177
|
+
initSettingsShell();
|
|
1178
|
+
|
|
1179
|
+
// --- User settings (personal pane) ---
|
|
1154
1180
|
initUserSettings({
|
|
1155
1181
|
basePath: basePath,
|
|
1156
1182
|
});
|
|
@@ -1169,6 +1195,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
1169
1195
|
if (document.body) document.body.classList.add('is-multi-user');
|
|
1170
1196
|
}
|
|
1171
1197
|
if (d.user && d.user.id) { store.set({ myUserId: d.user.id }); requestDefaultVendor(); }
|
|
1198
|
+
store.set({ authIdentityLoaded: true });
|
|
1172
1199
|
store.set({ permissions: d.permissions || null, projectsAccessLoaded: true });
|
|
1173
1200
|
if (d.mustChangePin) showForceChangePinOverlay();
|
|
1174
1201
|
// Single-user mode: clear user strip skeletons immediately (no presence message will arrive)
|
|
@@ -1217,11 +1244,11 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
1217
1244
|
}
|
|
1218
1245
|
}
|
|
1219
1246
|
}).catch(function () {});
|
|
1220
|
-
// Hide
|
|
1247
|
+
// Hide update controls for non-admin users in multi-user mode. The settings
|
|
1248
|
+
// gear stays for everyone: Personal and Project settings are not admin-only,
|
|
1249
|
+
// and the shell only offers Server settings to administrators.
|
|
1221
1250
|
checkAdminAccess().then(function (isAdmin) {
|
|
1222
1251
|
if (store.get('isMultiUserMode') && !isAdmin) {
|
|
1223
|
-
var settingsBtn = document.getElementById("server-settings-btn");
|
|
1224
|
-
if (settingsBtn) settingsBtn.style.display = "none";
|
|
1225
1252
|
var updatePill = document.getElementById("update-pill-wrap");
|
|
1226
1253
|
if (updatePill) updatePill.style.display = "none";
|
|
1227
1254
|
}
|
|
@@ -1249,8 +1276,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
1249
1276
|
|
|
1250
1277
|
// --- QR code ---
|
|
1251
1278
|
initQrCode();
|
|
1252
|
-
var sharePill = document.getElementById("share-pill");
|
|
1253
|
-
if (sharePill) sharePill.addEventListener("click", triggerShare);
|
|
1254
1279
|
|
|
1255
1280
|
// --- File browser ---
|
|
1256
1281
|
initFileBrowser({
|
|
@@ -1266,6 +1291,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
1266
1291
|
initSharedBrowser();
|
|
1267
1292
|
initStudioBridge();
|
|
1268
1293
|
initWorkerPaneLock();
|
|
1294
|
+
initPaneActivation();
|
|
1269
1295
|
|
|
1270
1296
|
// --- Terminal ---
|
|
1271
1297
|
initTerminal({
|
|
@@ -1433,11 +1459,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
1433
1459
|
function confirmRemoveProject(slug, name) { _projConfirmRemoveProject(slug, name); }
|
|
1434
1460
|
function handleRemoveProjectCheckResult(msg) { _projHandleRemoveProjectCheckResult(msg); }
|
|
1435
1461
|
function handleRemoveProjectResult(msg) { _projHandleRemoveProjectResult(msg); }
|
|
1436
|
-
function openAddProjectModal() { _projOpenAddProjectModal(); }
|
|
1437
|
-
function closeAddProjectModal() { _projCloseAddProjectModal(); }
|
|
1438
|
-
function handleBrowseDirResult(msg) { _projHandleBrowseDirResult(msg); }
|
|
1439
|
-
function handleAddProjectResult(msg) { _projHandleAddProjectResult(msg); }
|
|
1440
|
-
function handleCloneProgress(msg) { _projHandleCloneProgress(msg); }
|
|
1441
1462
|
|
|
1442
1463
|
// --- PWA install prompt -> modules/app-misc.js (set up in initMisc)
|
|
1443
1464
|
|
|
@@ -1453,9 +1474,11 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
1453
1474
|
|
|
1454
1475
|
// --- Rate Limit module ---
|
|
1455
1476
|
initRateLimit();
|
|
1477
|
+
initVendorUsageOverview();
|
|
1478
|
+
initGithubStar();
|
|
1456
1479
|
|
|
1457
1480
|
// --- Projects module ---
|
|
1458
|
-
|
|
1481
|
+
initProjectStart();
|
|
1459
1482
|
|
|
1460
1483
|
// --- Home Hub module ---
|
|
1461
1484
|
initProjectMateNavigation();
|
|
@@ -50,7 +50,7 @@ html.contextual-pane-boot #connect-overlay { display: none !important; }
|
|
|
50
50
|
#contextual-clay [data-conversation-notice]:not([hidden]) { display: flex; align-items: center; gap: 8px; flex-shrink: 0; padding: 6px 12px; border-bottom: 1px solid var(--border-subtle); font-size: 12px; color: var(--text-secondary); }
|
|
51
51
|
#contextual-clay [data-conversation-notice] span { flex: 1; }
|
|
52
52
|
#contextual-clay [data-conversation-notice] button { color: var(--accent); white-space: nowrap; }
|
|
53
|
-
#contextual-clay [data-clay-expand] span
|
|
53
|
+
#contextual-clay [data-clay-expand] span { display: none; }
|
|
54
54
|
@media (pointer: coarse) { #contextual-clay [data-mate-history] summary, #contextual-clay [data-mate-session-list] button { min-width: 44px; min-height: 44px; } }
|
|
55
55
|
@starting-style {
|
|
56
56
|
#contextual-clay[data-mode="popover"]:not([hidden]) { opacity: 0; transform: translateX(-4px); }
|
|
@@ -81,7 +81,7 @@ html.contextual-pane-boot #connect-overlay { display: none !important; }
|
|
|
81
81
|
#contextual-clay button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; color: var(--text); }
|
|
82
82
|
#contextual-clay button .lucide { width: 15px; height: 15px; }
|
|
83
83
|
#contextual-clay iframe { border: 0; flex: 1; width: 100%; min-height: 0; background: var(--bg); }
|
|
84
|
-
#contextual-clay [data-clay-loading]:not([hidden]) { position: absolute; inset: 0; margin: 0; padding: 18px 12px; display:
|
|
84
|
+
#contextual-clay [data-clay-loading]:not([hidden]) { position: absolute; inset: 0; margin: 0; padding: 18px 12px; display: flex; z-index: 1; color: var(--text-muted); font-size: 13px; background: var(--bg); pointer-events: none; }
|
|
85
85
|
body:is(.contextual-chat-pane, .contextual-clay-native) { --content-width: 760px; }
|
|
86
86
|
body:is(.contextual-chat-pane, .contextual-clay-native) #messages { padding-top: 14px; }
|
|
87
87
|
body:is(.contextual-chat-pane, .contextual-clay-native) #messages .msg-assistant .md-content,
|