clay-server 3.8.1 → 4.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/ask-user-mcp-server.js +5 -119
- package/lib/builtin-mates.js +6 -6
- package/lib/claude-hook-installer.js +15 -0
- package/lib/clay-history-mcp-server.js +62 -297
- package/lib/daemon.js +1 -1
- package/lib/debate-model-selection.js +119 -0
- package/lib/home-debate-tool-policy.js +164 -0
- package/lib/home-response-notifications.js +26 -0
- package/lib/mate-creation-mcp-server.js +55 -0
- package/lib/mate-ready-creation.js +95 -0
- package/lib/mates.js +2 -0
- package/lib/notes.js +2 -1
- package/lib/project-ask-user.js +64 -0
- package/lib/project-capsule-catalog.js +101 -0
- package/lib/project-connection.js +4 -0
- package/lib/project-debate-proposal.js +133 -17
- package/lib/project-debate.js +214 -110
- package/lib/project-delegated-follow-up.js +84 -0
- package/lib/project-delegated-session.js +53 -0
- package/lib/project-filesystem.js +7 -9
- package/lib/project-knowledge.js +1 -0
- package/lib/project-mate-creation-proposal.js +120 -0
- package/lib/project-memory.js +14 -7
- package/lib/project-models.js +157 -32
- package/lib/project-session-notes.js +2 -2
- package/lib/project-session-pair.js +8 -8
- package/lib/project-sessions.js +66 -51
- package/lib/project-vendor-login.js +397 -0
- package/lib/project-worker-proposal.js +25 -25
- package/lib/project-workspace-query.js +144 -0
- package/lib/project.js +349 -102
- package/lib/public/app.js +85 -42
- package/lib/public/css/avatar-imprints.css +0 -1
- package/lib/public/css/base.css +4 -0
- package/lib/public/css/capsule-ui.css +389 -0
- package/lib/public/css/command-palette.css +306 -6
- package/lib/public/css/home-capsule-library.css +243 -0
- package/lib/public/css/home-capsule-source.css +192 -0
- package/lib/public/css/home-debate-live.css +146 -0
- package/lib/public/css/home-debate-planning.css +125 -0
- package/lib/public/css/home-debates-archive.css +281 -0
- package/lib/public/css/home-hub.css +896 -405
- package/lib/public/css/home-mate-creation.css +34 -0
- package/lib/public/css/home-mate-model-picker.css +131 -0
- package/lib/public/css/home-mate-settings.css +344 -0
- package/lib/public/css/home-session-actions.css +265 -0
- package/lib/public/css/home-sidebar.css +667 -0
- package/lib/public/css/icon-strip.css +1 -2
- package/lib/public/css/mates.css +7 -34
- package/lib/public/css/pane.css +1 -1
- package/lib/public/css/playbook.css +0 -80
- package/lib/public/css/sticky-notes.css +53 -117
- package/lib/public/css/tui-attention.css +0 -44
- package/lib/public/css/workspace-assignment.css +45 -0
- package/lib/public/fonts/source-serif-4/LICENSE.md +93 -0
- package/lib/public/fonts/source-serif-4/SourceSerif4Caption-Semibold.ttf.woff2 +0 -0
- package/lib/public/index.html +93 -74
- package/lib/public/modules/app-connection.js +10 -1
- package/lib/public/modules/app-dm.js +43 -160
- package/lib/public/modules/app-home-hub.js +328 -585
- package/lib/public/modules/app-message-cards.js +242 -0
- package/lib/public/modules/app-message-router.js +84 -0
- package/lib/public/modules/app-messages.js +102 -37
- package/lib/public/modules/app-notifications.js +8 -119
- package/lib/public/modules/app-projects.js +9 -1
- package/lib/public/modules/app-rendering.js +21 -602
- package/lib/public/modules/avatar-imprint.js +11 -8
- package/lib/public/modules/chat-bubble-renderer.js +152 -0
- package/lib/public/modules/chat-render-runtime.js +198 -0
- package/lib/public/modules/command-palette.js +225 -436
- package/lib/public/modules/dm-render.js +82 -0
- package/lib/public/modules/home-capsule-creation-intent.js +31 -0
- package/lib/public/modules/home-capsule-library.js +146 -0
- package/lib/public/modules/home-capsule-source.js +383 -0
- package/lib/public/modules/home-chat-identity.js +35 -0
- package/lib/public/modules/home-chat-scroll.js +77 -0
- package/lib/public/modules/home-chat-stream-state.js +34 -0
- package/lib/public/modules/home-composer-focus.js +25 -0
- package/lib/public/modules/home-conversations-sheet.js +179 -0
- package/lib/public/modules/home-debate-activity.js +48 -0
- package/lib/public/modules/home-debate-controls.js +295 -0
- package/lib/public/modules/home-debate-launch.js +41 -0
- package/lib/public/modules/home-debate-live.js +284 -0
- package/lib/public/modules/home-debate-models.js +73 -0
- package/lib/public/modules/home-debate-planning.js +335 -0
- package/lib/public/modules/home-debates-archive.js +279 -0
- package/lib/public/modules/home-dock-resize.js +74 -0
- package/lib/public/modules/home-dock.js +446 -0
- package/lib/public/modules/home-mate-chat.js +496 -0
- package/lib/public/modules/home-mate-creation.js +109 -0
- package/lib/public/modules/home-mate-model-picker.js +281 -0
- package/lib/public/modules/home-mate-selection.js +38 -0
- package/lib/public/modules/home-mate-settings-menu.js +131 -0
- package/lib/public/modules/home-mate-settings.js +383 -0
- package/lib/public/modules/home-session-actions.js +373 -0
- package/lib/public/modules/home-session-model-confirmation.js +13 -0
- package/lib/public/modules/home-shell.js +9 -0
- package/lib/public/modules/home-sidebar-chat-list.js +63 -0
- package/lib/public/modules/home-sidebar.js +158 -0
- package/lib/public/modules/home-sub-surface.js +19 -0
- package/lib/public/modules/home-surface-boot.js +68 -0
- package/lib/public/modules/home-surface.js +141 -0
- package/lib/public/modules/home-tools.js +271 -0
- package/lib/public/modules/markdown.js +50 -2
- package/lib/public/modules/mate-management.js +86 -0
- package/lib/public/modules/mate-wizard.js +0 -7
- package/lib/public/modules/mention.js +17 -19
- package/lib/public/modules/pane-bridge.js +9 -0
- package/lib/public/modules/profile.js +4 -5
- package/lib/public/modules/project-settings.js +34 -28
- package/lib/public/modules/project-switcher.js +11 -5
- package/lib/public/modules/project-workspace-assignment.js +23 -0
- package/lib/public/modules/search-clay-chat.js +402 -0
- package/lib/public/modules/server-settings.js +14 -12
- package/lib/public/modules/session-actions.js +1 -1
- package/lib/public/modules/sidebar-mates.js +56 -552
- package/lib/public/modules/sidebar-mobile.js +7 -64
- package/lib/public/modules/sidebar-presence.js +37 -0
- package/lib/public/modules/split-pair-ui.js +13 -13
- package/lib/public/modules/split-view.js +7 -0
- package/lib/public/modules/sticky-notes.js +7 -6
- package/lib/public/modules/tool-input-composition.js +48 -0
- package/lib/public/modules/tool-llm-status.js +167 -0
- package/lib/public/modules/tool-renderer-advanced.js +285 -0
- package/lib/public/modules/tool-renderer-chart.js +158 -0
- package/lib/public/modules/tool-renderer-semantics.js +35 -0
- package/lib/public/modules/tool-renderer.js +464 -0
- package/lib/public/modules/tool-runtime.js +309 -0
- package/lib/public/modules/tool-ui-evaluator.js +97 -0
- package/lib/public/modules/tool-ui-tree.js +21 -0
- package/lib/public/modules/tui-attention.js +10 -0
- package/lib/public/modules/user-settings.js +16 -23
- package/lib/public/modules/vendor-login.js +287 -0
- package/lib/public/modules/worker-proposal.js +2 -2
- package/lib/public/modules/workspace-assignment-card.js +149 -0
- package/lib/public/modules/workspace-assignment-routing.js +4 -0
- package/lib/public/style.css +13 -2
- package/lib/runtime-env.js +65 -0
- package/lib/sdk-bridge.js +120 -32
- package/lib/sdk-message-processor.js +10 -6
- package/lib/server-home-capsule-creation.js +36 -0
- package/lib/server-home-chat-events.js +287 -0
- package/lib/server-home-chat.js +518 -0
- package/lib/server-home-clay-entry.js +65 -0
- package/lib/server-home-clay-session-links.js +26 -0
- package/lib/server-home-debate-planning.js +214 -0
- package/lib/server-home-debates.js +137 -0
- package/lib/server-home-mate-creation.js +261 -0
- package/lib/server-home-models.js +241 -0
- package/lib/server-home-preferences.js +61 -0
- package/lib/server-mates.js +37 -0
- package/lib/server-tools.js +377 -0
- package/lib/server.js +111 -59
- package/lib/session-pair-mcp-server.js +6 -6
- package/lib/sessions.js +18 -3
- package/lib/tool-capsule-source.js +142 -0
- package/lib/tool-control-mcp-server.js +126 -0
- package/lib/tool-llm.js +48 -0
- package/lib/tool-storage.js +77 -0
- package/lib/tool-ui-spec-advanced.js +82 -0
- package/lib/tool-ui-spec.js +261 -0
- package/lib/tools-registry.js +286 -0
- package/lib/users-home-dock-preferences.js +77 -0
- package/lib/users-home-surface-preferences.js +99 -0
- package/lib/users-preferences.js +4 -7
- package/lib/users.js +12 -0
- package/lib/whats-new-content.js +3 -3
- package/lib/workspace-assignment-service.js +420 -0
- package/lib/workspace-query-mcp-server.js +154 -0
- package/lib/workspace-query-service.js +492 -0
- package/lib/ws-schema.js +93 -12
- package/lib/yoke/adapters/acp.js +2 -1
- package/lib/yoke/adapters/antigravity.js +2 -1
- package/lib/yoke/adapters/claude-worker.js +11 -4
- package/lib/yoke/adapters/claude.js +73 -43
- package/lib/yoke/adapters/codex.js +40 -10
- package/lib/yoke/adapters/kiro.js +2 -1
- package/lib/yoke/claude-user-input.js +38 -0
- package/lib/yoke/codex-app-server.js +20 -2
- package/lib/yoke/codex-user-input.js +64 -0
- package/lib/yoke/complete-once.js +164 -0
- package/lib/yoke/index.js +5 -1
- package/lib/yoke/interface.js +19 -0
- package/lib/yoke/mcp-bridge-server.js +2 -6
- package/lib/yoke/user-input.js +254 -0
- package/package.json +3 -2
- package/lib/public/css/home-chat.css +0 -380
- package/lib/public/modules/home-chat.js +0 -438
- package/lib/server-clay-home.js +0 -245
|
@@ -1,659 +1,402 @@
|
|
|
1
|
-
// app-home-hub.js - Home hub
|
|
2
|
-
// Extracted from app.js (PR-25)
|
|
1
|
+
// app-home-hub.js - Home work hub navigation and first-depth Mate list.
|
|
3
2
|
|
|
4
3
|
import { store } from './store.js';
|
|
5
4
|
import { getWs } from './ws-ref.js';
|
|
6
|
-
import {
|
|
7
|
-
import { switchProject, getCachedProjects, renderProjectList } from './app-projects.js';
|
|
8
|
-
import { openSchedulerToTab } from './scheduler.js';
|
|
9
|
-
import { getPlaybooks, openPlaybook, getPlaybookForTip } from './playbook.js';
|
|
5
|
+
import { getCachedProjects } from './app-projects.js';
|
|
10
6
|
import { mateAvatarUrl } from './avatar.js';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
import { exitDmMode } from './app-dm.js';
|
|
8
|
+
import { closeHomeDock, initHomeDock, renderDock, requestHomeDockPreference } from './home-dock.js';
|
|
9
|
+
import { openHomeChat, openHomeMateAction, renderHomeChat, resumeHomeChat, startHomeCapsuleCreation } from './home-mate-chat.js';
|
|
10
|
+
import { closeHomeSidebarAfterSelection } from './home-sidebar.js';
|
|
11
|
+
import { iconHtml, refreshIcons } from './icons.js';
|
|
12
|
+
import { getActiveMentionMateIds } from './sidebar-mates.js';
|
|
13
|
+
import { requestTools } from './home-tools.js';
|
|
14
|
+
import { showHomeShell, hideHomeShell } from './home-shell.js';
|
|
15
|
+
import { requestHomeSurfacePreference, rememberHomePrimarySurface } from './home-surface.js';
|
|
16
|
+
import { resolveHomeMate } from './home-mate-selection.js';
|
|
17
|
+
import { createHomeMateSettingsTrigger, disposeHomeMateSettingsMenu } from './home-mate-settings-menu.js';
|
|
18
|
+
import { closeHomeMateSettings, syncHomeMateSettingsTarget } from './home-mate-settings.js';
|
|
19
|
+
import { disposeHomeSessionActions } from './home-session-actions.js';
|
|
20
|
+
import { initHomeDebatesArchive, restoreHomeDebatesArchive } from './home-debates-archive.js';
|
|
21
|
+
import { isHomeDebatesSurface } from './home-sub-surface.js';
|
|
22
|
+
import { HOME_CAPSULE_CREATION_EVENT } from './home-capsule-creation-intent.js';
|
|
16
23
|
|
|
17
24
|
var homeHub = null;
|
|
18
25
|
var homeHubVisible = false;
|
|
19
|
-
var
|
|
26
|
+
var homeHubSuspended = false;
|
|
27
|
+
var lastRenderedMateId = null;
|
|
20
28
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"The file browser lets you explore and open any file in your project.",
|
|
26
|
-
"Paste images from your clipboard into the chat to include them in your message.",
|
|
27
|
-
"Use /commands (slash commands) for quick access to common actions.",
|
|
28
|
-
"You can resize the sidebar by dragging its edge.",
|
|
29
|
-
"Click the session info button in the header to see token usage and costs.",
|
|
30
|
-
"You can switch between projects without losing your conversation history.",
|
|
31
|
-
"The status dot on project icons shows whether Claude is currently processing.",
|
|
32
|
-
"Right-click on a project icon for quick actions like rename or delete.",
|
|
33
|
-
"Push notifications can alert you when Claude finishes a long task.",
|
|
34
|
-
"You can search through your conversation history within a session.",
|
|
35
|
-
"Session history is preserved — come back anytime to continue where you left off.",
|
|
36
|
-
"Use the rewind feature to go back to an earlier point in your conversation.",
|
|
37
|
-
"You can open multiple terminal tabs for parallel command execution.",
|
|
38
|
-
"Clay works offline as a PWA — install it from your browser for quick access.",
|
|
39
|
-
"Schedule recurring tasks with cron expressions to automate your workflow.",
|
|
40
|
-
"Use Ralph Loops to run autonomous coding sessions while you're away.",
|
|
41
|
-
"Right-click a project icon to set a custom emoji — make each project instantly recognizable.",
|
|
42
|
-
"Multiple people can connect to the same project at once — great for pair programming.",
|
|
43
|
-
"Drag and drop project icons to reorder them in the sidebar.",
|
|
44
|
-
"Drag a project icon to the trash to delete it.",
|
|
45
|
-
"Honey never spoils. 🍯",
|
|
46
|
-
"The Earth is round. 🌍",
|
|
47
|
-
"Computers use electricity. 🔌",
|
|
48
|
-
"Christmas is in summer in some countries. 🎄",
|
|
49
|
-
];
|
|
50
|
-
// Fisher-Yates shuffle
|
|
51
|
-
for (var _si = hubTips.length - 1; _si > 0; _si--) {
|
|
52
|
-
var _sj = Math.floor(Math.random() * (_si + 1));
|
|
53
|
-
var _tmp = hubTips[_si];
|
|
54
|
-
hubTips[_si] = hubTips[_sj];
|
|
55
|
-
hubTips[_sj] = _tmp;
|
|
29
|
+
function handleHomeCapsuleCreation(event) {
|
|
30
|
+
var detail = event && event.detail ? event.detail : {};
|
|
31
|
+
detail.accepted = startHomeCapsuleCreation(detail.mateId, detail.description);
|
|
32
|
+
if (detail.accepted) closeHomeDock();
|
|
56
33
|
}
|
|
57
|
-
var hubTipIndex = 0;
|
|
58
|
-
var hubTipTimer = null;
|
|
59
|
-
|
|
60
|
-
var DAY_NAMES = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
61
|
-
var MONTH_NAMES = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
62
|
-
var WEEKDAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
63
|
-
|
|
64
|
-
// --- Weather (hidden detail) ---
|
|
65
|
-
var weatherEmoji = null; // null = not yet fetched, "" = failed
|
|
66
|
-
var weatherCondition = ""; // e.g. "Light rain, Auckland"
|
|
67
|
-
var weatherFetchedAt = 0;
|
|
68
|
-
var WEATHER_CACHE_MS = 60 * 60 * 1000; // 1 hour
|
|
69
|
-
// WMO weather code -> emoji + description
|
|
70
|
-
var WMO_MAP = {
|
|
71
|
-
0: ["☀️", "Clear sky"], 1: ["🌤", "Mainly clear"], 2: ["⛅", "Partly cloudy"], 3: ["☁️", "Overcast"],
|
|
72
|
-
45: ["🌫", "Fog"], 48: ["🌫", "Depositing rime fog"],
|
|
73
|
-
51: ["🌦", "Light drizzle"], 53: ["🌦", "Moderate drizzle"], 55: ["🌧", "Dense drizzle"],
|
|
74
|
-
56: ["🌧", "Light freezing drizzle"], 57: ["🌧", "Dense freezing drizzle"],
|
|
75
|
-
61: ["🌧", "Slight rain"], 63: ["🌧", "Moderate rain"], 65: ["🌧", "Heavy rain"],
|
|
76
|
-
66: ["🌧", "Light freezing rain"], 67: ["🌧", "Heavy freezing rain"],
|
|
77
|
-
71: ["🌨", "Slight snow"], 73: ["🌨", "Moderate snow"], 75: ["❄️", "Heavy snow"],
|
|
78
|
-
77: ["🌨", "Snow grains"],
|
|
79
|
-
80: ["🌦", "Slight rain showers"], 81: ["🌧", "Moderate rain showers"], 82: ["🌧", "Violent rain showers"],
|
|
80
|
-
85: ["🌨", "Slight snow showers"], 86: ["❄️", "Heavy snow showers"],
|
|
81
|
-
95: ["⛈", "Thunderstorm"], 96: ["⛈", "Thunderstorm with slight hail"], 99: ["⛈", "Thunderstorm with heavy hail"],
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
var SLOT_EMOJIS = ["☀️", "🌤", "⛅", "☁️", "🌧", "🌦", "⛈", "🌨", "❄️", "🌫", "🌙", "✨"];
|
|
85
|
-
var weatherSlotPlayed = false;
|
|
86
34
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
35
|
+
function syncHomePresentation() {
|
|
36
|
+
var ws = getWs();
|
|
37
|
+
if (!ws || ws.readyState !== 1) return;
|
|
38
|
+
ws.send(JSON.stringify({ type: "home_mate_present", visible: homeHubVisible && !document.hidden }));
|
|
39
|
+
}
|
|
92
40
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (document.documentElement.classList.contains("pwa-standalone")) {
|
|
98
|
-
history.replaceState(null, "", "/p/" + store.get('currentSlug') + "/");
|
|
99
|
-
} else {
|
|
100
|
-
history.pushState(null, "", "/p/" + store.get('currentSlug') + "/");
|
|
101
|
-
}
|
|
102
|
-
// Restore icon strip active state
|
|
103
|
-
var homeIcon = document.querySelector(".icon-strip-home");
|
|
104
|
-
if (homeIcon) homeIcon.classList.remove("active");
|
|
105
|
-
renderProjectList();
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
}
|
|
41
|
+
function syncHomeCloseControl() {
|
|
42
|
+
var close = document.getElementById("home-close-control");
|
|
43
|
+
if (!close) return;
|
|
44
|
+
close.classList.toggle("hidden", !store.get('currentSlug'));
|
|
109
45
|
}
|
|
110
46
|
|
|
111
|
-
|
|
47
|
+
function getVisibleMates() {
|
|
48
|
+
var mates = (store.get('cachedMatesList') || []).filter(function (mate) {
|
|
49
|
+
return !!mate && !mate.archived;
|
|
50
|
+
});
|
|
51
|
+
mates.sort(function (a, b) {
|
|
52
|
+
var aClay = a.builtinKey === "clay" ? 0 : 1;
|
|
53
|
+
var bClay = b.builtinKey === "clay" ? 0 : 1;
|
|
54
|
+
if (aClay !== bClay) return aClay - bClay;
|
|
55
|
+
return (a.createdAt || 0) - (b.createdAt || 0);
|
|
56
|
+
});
|
|
57
|
+
return mates;
|
|
58
|
+
}
|
|
112
59
|
|
|
113
|
-
function
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// Try localStorage cache
|
|
117
|
-
if (!weatherEmoji) {
|
|
118
|
-
try {
|
|
119
|
-
var cached = JSON.parse(localStorage.getItem("clay-weather") || "null");
|
|
120
|
-
if (cached && cached.emoji && (Date.now() - cached.ts < WEATHER_CACHE_MS)) {
|
|
121
|
-
weatherEmoji = cached.emoji;
|
|
122
|
-
weatherCondition = cached.condition || "";
|
|
123
|
-
weatherFetchedAt = cached.ts;
|
|
124
|
-
if (homeHubVisible) updateGreetingWeather();
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
} catch (e) {}
|
|
128
|
-
}
|
|
129
|
-
if (weatherFetchedAt && (Date.now() - weatherFetchedAt < 30000)) return; // don't retry within 30s
|
|
130
|
-
weatherFetchedAt = Date.now();
|
|
131
|
-
// Step 1: IP geolocation -> lat/lon + city
|
|
132
|
-
fetch("https://ipapi.co/json/", { signal: AbortSignal.timeout(4000) })
|
|
133
|
-
.then(function (res) { return res.ok ? res.json() : Promise.reject(); })
|
|
134
|
-
.then(function (geo) {
|
|
135
|
-
var lat = geo.latitude;
|
|
136
|
-
var lon = geo.longitude;
|
|
137
|
-
var city = geo.city || geo.region || "";
|
|
138
|
-
var country = geo.country_name || "";
|
|
139
|
-
var locationStr = city + (country ? ", " + country : "");
|
|
140
|
-
// Step 2: Open-Meteo -> current weather
|
|
141
|
-
var meteoUrl = "https://api.open-meteo.com/v1/forecast?latitude=" + lat + "&longitude=" + lon + "¤t=weather_code&timezone=auto";
|
|
142
|
-
return fetch(meteoUrl, { signal: AbortSignal.timeout(4000) })
|
|
143
|
-
.then(function (res) { return res.ok ? res.json() : Promise.reject(); })
|
|
144
|
-
.then(function (data) {
|
|
145
|
-
var code = data && data.current && data.current.weather_code;
|
|
146
|
-
if (code === undefined || code === null) return;
|
|
147
|
-
var mapped = WMO_MAP[code] || WMO_MAP[0];
|
|
148
|
-
weatherEmoji = mapped[0];
|
|
149
|
-
weatherCondition = mapped[1] + (locationStr ? " in " + locationStr : "");
|
|
150
|
-
weatherFetchedAt = Date.now();
|
|
151
|
-
try {
|
|
152
|
-
localStorage.setItem("clay-weather", JSON.stringify({
|
|
153
|
-
emoji: weatherEmoji, condition: weatherCondition, ts: weatherFetchedAt
|
|
154
|
-
}));
|
|
155
|
-
} catch (e) {}
|
|
156
|
-
if (homeHubVisible) updateGreetingWeather();
|
|
157
|
-
});
|
|
158
|
-
})
|
|
159
|
-
.catch(function () {
|
|
160
|
-
if (!weatherEmoji) weatherEmoji = "";
|
|
161
|
-
});
|
|
60
|
+
function getMateName(mate) {
|
|
61
|
+
var profile = mate && mate.profile ? mate.profile : {};
|
|
62
|
+
return profile.displayName || (mate && (mate.displayName || mate.name)) || "Mate";
|
|
162
63
|
}
|
|
163
64
|
|
|
164
|
-
function
|
|
165
|
-
var
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
65
|
+
function syncMateContextControls(mate) {
|
|
66
|
+
var name = mate ? getMateName(mate) : "Mate";
|
|
67
|
+
var newChat = document.getElementById("home-sidebar-new");
|
|
68
|
+
if (newChat) {
|
|
69
|
+
newChat.disabled = !mate;
|
|
70
|
+
newChat.setAttribute("aria-label", mate ? "Start a new chat with " + name : "Start a new chat with the current Mate");
|
|
71
|
+
}
|
|
72
|
+
var debates = document.getElementById("home-sidebar-debate");
|
|
73
|
+
if (debates) {
|
|
74
|
+
debates.disabled = false;
|
|
75
|
+
debates.setAttribute("aria-label", "Browse debates");
|
|
172
76
|
}
|
|
173
|
-
// Normal update (no animation)
|
|
174
|
-
greetEl.textContent = getGreeting();
|
|
175
|
-
|
|
176
|
-
applyWeatherTooltip(greetEl);
|
|
177
77
|
}
|
|
178
78
|
|
|
179
|
-
function
|
|
180
|
-
|
|
181
|
-
var
|
|
182
|
-
var
|
|
183
|
-
|
|
184
|
-
lastEmoji.title = weatherCondition;
|
|
185
|
-
lastEmoji.style.cursor = "default";
|
|
79
|
+
function getMateActivity() {
|
|
80
|
+
var status = {};
|
|
81
|
+
var projects = getCachedProjects() || [];
|
|
82
|
+
for (var i = 0; i < projects.length; i++) {
|
|
83
|
+
if (projects[i] && projects[i].slug) status[projects[i].slug] = projects[i];
|
|
186
84
|
}
|
|
85
|
+
return status;
|
|
187
86
|
}
|
|
188
87
|
|
|
189
|
-
function
|
|
190
|
-
var
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
else if (h < 12) prefix = "Good morning";
|
|
194
|
-
else if (h < 18) prefix = "Good afternoon";
|
|
195
|
-
else prefix = "Good evening";
|
|
196
|
-
|
|
197
|
-
// Build schedule: fast ticks -> slow ticks -> land (~3s total)
|
|
198
|
-
var intervals = [50, 50, 50, 60, 70, 80, 100, 120, 150, 190, 240, 300, 370, 450, 530, 640];
|
|
199
|
-
var totalSteps = intervals.length;
|
|
200
|
-
var step = 0;
|
|
201
|
-
var startIdx = Math.floor(Math.random() * SLOT_EMOJIS.length);
|
|
202
|
-
|
|
203
|
-
function tick() {
|
|
204
|
-
if (step < totalSteps) {
|
|
205
|
-
var idx = (startIdx + step) % SLOT_EMOJIS.length;
|
|
206
|
-
greetEl.textContent = prefix + " " + SLOT_EMOJIS[idx];
|
|
207
|
-
|
|
208
|
-
step++;
|
|
209
|
-
setTimeout(tick, intervals[step - 1]);
|
|
210
|
-
} else {
|
|
211
|
-
// Final: land on actual weather
|
|
212
|
-
greetEl.textContent = prefix + " " + weatherEmoji;
|
|
88
|
+
function isMateBusy(mate, projectStatus, mentionActive) {
|
|
89
|
+
var project = projectStatus["mate-" + mate.id] || {};
|
|
90
|
+
return !!project.isProcessing || !!mentionActive[mate.id];
|
|
91
|
+
}
|
|
213
92
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
tick();
|
|
93
|
+
function selectHomeMate(mateId) {
|
|
94
|
+
if (mateId !== store.get('homeChatMateId') || isHomeDebatesSurface()) openHomeChat(mateId);
|
|
95
|
+
closeHomeSidebarAfterSelection();
|
|
218
96
|
}
|
|
219
97
|
|
|
220
|
-
function
|
|
221
|
-
var
|
|
222
|
-
var
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
98
|
+
function createMateListRow(mate, activeMateId, projectStatus, mentionActive, unread) {
|
|
99
|
+
var name = getMateName(mate);
|
|
100
|
+
var busy = isMateBusy(mate, projectStatus, mentionActive);
|
|
101
|
+
var count = unread[mate.id] || 0;
|
|
102
|
+
var item = document.createElement("div");
|
|
103
|
+
item.className = "home-mate-list-item";
|
|
104
|
+
item.setAttribute("role", "listitem");
|
|
105
|
+
var row = document.createElement("button");
|
|
106
|
+
row.type = "button";
|
|
107
|
+
row.className = "home-mate-list-row" + (mate.id === activeMateId ? " is-active" : "");
|
|
108
|
+
row.dataset.homeMateId = mate.id;
|
|
109
|
+
row.setAttribute("aria-label", name + (mate.id === activeMateId ? ", current Mate" : "") + (mate.model ? ", model " + mate.model : "") + (busy ? ", working" : "") + (count ? ", " + count + " unread" : ""));
|
|
110
|
+
if (mate.id === activeMateId) row.setAttribute("aria-current", "true");
|
|
111
|
+
|
|
112
|
+
var avatarWrap = document.createElement("span");
|
|
113
|
+
avatarWrap.className = "home-mate-list-avatar-wrap";
|
|
114
|
+
var avatar = document.createElement("img");
|
|
115
|
+
avatar.className = "home-mate-list-avatar";
|
|
116
|
+
avatar.src = mateAvatarUrl(mate, 32);
|
|
117
|
+
avatar.alt = "";
|
|
118
|
+
avatarWrap.appendChild(avatar);
|
|
119
|
+
if (busy) {
|
|
120
|
+
var activity = document.createElement("span");
|
|
121
|
+
activity.className = "home-mate-list-activity";
|
|
122
|
+
activity.title = "Working";
|
|
123
|
+
activity.setAttribute("aria-hidden", "true");
|
|
124
|
+
avatarWrap.appendChild(activity);
|
|
125
|
+
}
|
|
126
|
+
row.appendChild(avatarWrap);
|
|
127
|
+
|
|
128
|
+
var copy = document.createElement("span");
|
|
129
|
+
copy.className = "home-mate-list-copy";
|
|
130
|
+
var nameEl = document.createElement("span");
|
|
131
|
+
nameEl.className = "home-mate-list-name";
|
|
132
|
+
nameEl.textContent = name;
|
|
133
|
+
copy.appendChild(nameEl);
|
|
134
|
+
if (mate.model) {
|
|
135
|
+
var model = document.createElement("span");
|
|
136
|
+
model.className = "home-mate-list-model";
|
|
137
|
+
model.textContent = mate.model;
|
|
138
|
+
copy.appendChild(model);
|
|
229
139
|
}
|
|
230
|
-
|
|
231
|
-
if (
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
140
|
+
row.appendChild(copy);
|
|
141
|
+
if (count > 0) {
|
|
142
|
+
var badge = document.createElement("span");
|
|
143
|
+
badge.className = "home-mate-list-unread";
|
|
144
|
+
badge.textContent = count > 99 ? "99+" : String(count);
|
|
145
|
+
badge.setAttribute("aria-hidden", "true");
|
|
146
|
+
row.appendChild(badge);
|
|
147
|
+
}
|
|
148
|
+
row.addEventListener("click", function () { selectHomeMate(mate.id); });
|
|
149
|
+
item.appendChild(row);
|
|
150
|
+
item.appendChild(createHomeMateSettingsTrigger(mate));
|
|
151
|
+
if (mate.id === activeMateId) item.classList.add("is-active");
|
|
152
|
+
return item;
|
|
236
153
|
}
|
|
237
154
|
|
|
238
|
-
function
|
|
239
|
-
var
|
|
240
|
-
|
|
155
|
+
function createNewMateRow(disabled) {
|
|
156
|
+
var item = document.createElement("div");
|
|
157
|
+
item.className = "home-mate-list-item home-mate-list-create-item";
|
|
158
|
+
item.setAttribute("role", "listitem");
|
|
159
|
+
var row = document.createElement("button");
|
|
160
|
+
row.id = "home-sidebar-new-mate";
|
|
161
|
+
row.type = "button";
|
|
162
|
+
row.className = "home-mate-list-row home-mate-list-create";
|
|
163
|
+
row.disabled = disabled === true;
|
|
164
|
+
row.setAttribute("aria-label", "Create a new Mate with Clay");
|
|
165
|
+
var icon = document.createElement("span");
|
|
166
|
+
icon.className = "home-mate-list-create-icon";
|
|
167
|
+
icon.setAttribute("aria-hidden", "true");
|
|
168
|
+
icon.innerHTML = iconHtml("user-round-plus");
|
|
169
|
+
row.appendChild(icon);
|
|
170
|
+
var copy = document.createElement("span");
|
|
171
|
+
copy.className = "home-mate-list-copy";
|
|
172
|
+
var name = document.createElement("span");
|
|
173
|
+
name.className = "home-mate-list-name";
|
|
174
|
+
name.textContent = "Create new Mate";
|
|
175
|
+
copy.appendChild(name);
|
|
176
|
+
row.appendChild(copy);
|
|
177
|
+
row.addEventListener("click", function () {
|
|
178
|
+
openHomeMateAction("mate");
|
|
179
|
+
closeHomeSidebarAfterSelection();
|
|
180
|
+
});
|
|
181
|
+
item.appendChild(row);
|
|
182
|
+
return item;
|
|
241
183
|
}
|
|
242
184
|
|
|
243
|
-
function
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
var
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
var
|
|
250
|
-
var
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
if (
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
257
|
-
var tomStr = tomorrow.getFullYear() + "-" + String(tomorrow.getMonth() + 1).padStart(2, "0") + "-" + String(tomorrow.getDate()).padStart(2, "0");
|
|
258
|
-
if (schedStr === tomStr) return "Tomorrow";
|
|
259
|
-
return DAY_NAMES[d.getDay()] + " " + timeStr;
|
|
185
|
+
function handleMateListKeydown(event) {
|
|
186
|
+
if (event.key !== "ArrowDown" && event.key !== "ArrowUp" && event.key !== "Home" && event.key !== "End") return;
|
|
187
|
+
if (!event.target.classList.contains("home-mate-list-row")) return;
|
|
188
|
+
var rows = event.currentTarget.querySelectorAll(".home-mate-list-row");
|
|
189
|
+
if (!rows.length) return;
|
|
190
|
+
event.preventDefault();
|
|
191
|
+
var current = Array.prototype.indexOf.call(rows, event.target);
|
|
192
|
+
var next = current;
|
|
193
|
+
if (event.key === "Home") next = 0;
|
|
194
|
+
else if (event.key === "End") next = rows.length - 1;
|
|
195
|
+
else if (event.key === "ArrowDown") next = current === rows.length - 1 ? 0 : current + 1;
|
|
196
|
+
else next = current <= 0 ? rows.length - 1 : current - 1;
|
|
197
|
+
rows[next].focus();
|
|
260
198
|
}
|
|
261
199
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
var upcomingList = $hub("hub-upcoming-list");
|
|
272
|
-
var upcomingCount = $hub("hub-upcoming-count");
|
|
273
|
-
if (upcomingList) {
|
|
274
|
-
var now = Date.now();
|
|
275
|
-
var upcoming = hubSchedules.filter(function (s) {
|
|
276
|
-
return s.enabled && s.nextRunAt && s.nextRunAt > now;
|
|
277
|
-
}).sort(function (a, b) {
|
|
278
|
-
return a.nextRunAt - b.nextRunAt;
|
|
279
|
-
});
|
|
280
|
-
// Show up to next 48 hours
|
|
281
|
-
var cutoff = now + 48 * 60 * 60 * 1000;
|
|
282
|
-
var filtered = upcoming.filter(function (s) { return s.nextRunAt <= cutoff; });
|
|
283
|
-
|
|
284
|
-
if (upcomingCount) {
|
|
285
|
-
upcomingCount.textContent = filtered.length > 0 ? filtered.length : "";
|
|
286
|
-
}
|
|
200
|
+
function renderMateListLoading(list) {
|
|
201
|
+
list.innerHTML = "";
|
|
202
|
+
list.appendChild(createNewMateRow(true));
|
|
203
|
+
var empty = document.createElement("div");
|
|
204
|
+
empty.className = "home-mate-list-empty";
|
|
205
|
+
empty.textContent = "Loading Mates...";
|
|
206
|
+
list.appendChild(empty);
|
|
207
|
+
refreshIcons();
|
|
208
|
+
}
|
|
287
209
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
emptyDiv.className = "hub-upcoming-empty";
|
|
293
|
-
emptyDiv.innerHTML = '<div class="hub-upcoming-empty-icon">📋</div>' +
|
|
294
|
-
'<div class="hub-upcoming-empty-text">No upcoming tasks</div>' +
|
|
295
|
-
'<button class="hub-upcoming-cta" id="hub-upcoming-cta">' +
|
|
296
|
-
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14"/><path d="M5 12h14"/></svg>' +
|
|
297
|
-
'Create a schedule</button>';
|
|
298
|
-
upcomingList.appendChild(emptyDiv);
|
|
299
|
-
var ctaBtn = emptyDiv.querySelector("#hub-upcoming-cta");
|
|
300
|
-
if (ctaBtn) {
|
|
301
|
-
ctaBtn.addEventListener("click", function () {
|
|
302
|
-
hideHomeHub();
|
|
303
|
-
openSchedulerToTab("calendar");
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
} else {
|
|
307
|
-
var maxShow = 5;
|
|
308
|
-
var shown = filtered.slice(0, maxShow);
|
|
309
|
-
for (var i = 0; i < shown.length; i++) {
|
|
310
|
-
(function (sched) {
|
|
311
|
-
var item = document.createElement("div");
|
|
312
|
-
item.className = "hub-upcoming-item";
|
|
313
|
-
var dotColor = sched.color || "";
|
|
314
|
-
item.innerHTML = '<span class="hub-upcoming-dot"' + (dotColor ? ' style="background:' + dotColor + '"' : '') + '></span>' +
|
|
315
|
-
'<span class="hub-upcoming-time">' + formatScheduleTime(sched.nextRunAt) + '</span>' +
|
|
316
|
-
'<span class="hub-upcoming-name">' + escapeHtml(sched.name || "Untitled") + '</span>' +
|
|
317
|
-
'<span class="hub-upcoming-project">' + escapeHtml(sched.projectTitle || "") + '</span>';
|
|
318
|
-
item.addEventListener("click", function () {
|
|
319
|
-
if (sched.projectSlug) {
|
|
320
|
-
switchProject(sched.projectSlug);
|
|
321
|
-
setTimeout(function () {
|
|
322
|
-
openSchedulerToTab("library");
|
|
323
|
-
}, 300);
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
upcomingList.appendChild(item);
|
|
327
|
-
})(shown[i]);
|
|
328
|
-
}
|
|
329
|
-
if (filtered.length > maxShow) {
|
|
330
|
-
var moreEl = document.createElement("div");
|
|
331
|
-
moreEl.className = "hub-upcoming-more";
|
|
332
|
-
moreEl.textContent = "+" + (filtered.length - maxShow) + " more";
|
|
333
|
-
upcomingList.appendChild(moreEl);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
210
|
+
function findMateRow(list, mateId) {
|
|
211
|
+
var rows = list.querySelectorAll(".home-mate-list-row");
|
|
212
|
+
for (var i = 0; i < rows.length; i++) {
|
|
213
|
+
if (rows[i].dataset.homeMateId === mateId) return rows[i];
|
|
336
214
|
}
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
337
217
|
|
|
338
|
-
|
|
339
|
-
var
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
var hubProjects = projects.filter(function (p) { return !p.isMate; });
|
|
343
|
-
for (var p = 0; p < hubProjects.length; p++) {
|
|
344
|
-
(function (proj) {
|
|
345
|
-
var item = document.createElement("div");
|
|
346
|
-
item.className = "hub-project-item";
|
|
347
|
-
var dotClass = "hub-project-dot" + (proj.isProcessing ? " processing" : "");
|
|
348
|
-
var iconHtml = proj.icon ? '<span class="hub-project-icon">' + proj.icon + '</span>' : '';
|
|
349
|
-
var sessionsLabel = typeof proj.sessions === "number" ? proj.sessions : "";
|
|
350
|
-
item.innerHTML = '<span class="' + dotClass + '"></span>' +
|
|
351
|
-
iconHtml +
|
|
352
|
-
'<span class="hub-project-name">' + escapeHtml(proj.title || proj.project || proj.slug) + '</span>' +
|
|
353
|
-
(sessionsLabel !== "" ? '<span class="hub-project-sessions">' + sessionsLabel + '</span>' : '');
|
|
354
|
-
item.addEventListener("click", function () {
|
|
355
|
-
switchProject(proj.slug);
|
|
356
|
-
});
|
|
357
|
-
projectsList.appendChild(item);
|
|
358
|
-
})(hubProjects[p]);
|
|
359
|
-
}
|
|
360
|
-
// Render emoji icons
|
|
361
|
-
|
|
218
|
+
function findMateOverflow(list, mateId) {
|
|
219
|
+
var buttons = list.querySelectorAll(".home-mate-list-overflow");
|
|
220
|
+
for (var i = 0; i < buttons.length; i++) {
|
|
221
|
+
if (buttons[i].dataset.homeMateId === mateId) return buttons[i];
|
|
362
222
|
}
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
363
225
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
var todayYear = today.getFullYear();
|
|
372
|
-
// Find Monday of current week
|
|
373
|
-
var dayOfWeek = today.getDay();
|
|
374
|
-
var mondayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;
|
|
375
|
-
var monday = new Date(today);
|
|
376
|
-
monday.setDate(today.getDate() + mondayOffset);
|
|
226
|
+
function keepMateRowVisible(list, row) {
|
|
227
|
+
if (!list || !row || !list.getBoundingClientRect || !row.getBoundingClientRect) return;
|
|
228
|
+
var listRect = list.getBoundingClientRect();
|
|
229
|
+
var rowRect = row.getBoundingClientRect();
|
|
230
|
+
if (rowRect.top < listRect.top) list.scrollTop -= listRect.top - rowRect.top;
|
|
231
|
+
else if (rowRect.bottom > listRect.bottom) list.scrollTop += rowRect.bottom - listRect.bottom;
|
|
232
|
+
}
|
|
377
233
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
234
|
+
export function initHomeHub() {
|
|
235
|
+
homeHub = document.getElementById("home-hub");
|
|
236
|
+
window.addEventListener(HOME_CAPSULE_CREATION_EVENT, handleHomeCapsuleCreation);
|
|
237
|
+
initHomeDock();
|
|
238
|
+
initHomeDebatesArchive();
|
|
239
|
+
document.getElementById("home-mate-list").addEventListener("keydown", handleMateListKeydown);
|
|
240
|
+
document.getElementById("home-close-control").addEventListener("click", minimizeHomeHub);
|
|
241
|
+
window.addEventListener("clay:home-debate", function () { hideHomeHub(); });
|
|
242
|
+
document.addEventListener("visibilitychange", syncHomePresentation);
|
|
243
|
+
|
|
244
|
+
store.subscribe(function (state, prev) {
|
|
245
|
+
if (state.connected !== prev.connected && state.connected && homeHubVisible) syncHomePresentation();
|
|
246
|
+
if (state.currentSlug !== prev.currentSlug) syncHomeCloseControl();
|
|
247
|
+
if (state.homeChatMateId !== prev.homeChatMateId || state.cachedMatesList !== prev.cachedMatesList) renderHomeMateSwitcher();
|
|
248
|
+
if (state.homeSidebarCollapsed !== prev.homeSidebarCollapsed && !state.homeSidebarCollapsed) {
|
|
249
|
+
requestAnimationFrame(renderHomeMateSwitcher);
|
|
393
250
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
var isToday = dayDate.getDate() === todayDate && dayDate.getMonth() === todayMonth && dayDate.getFullYear() === todayYear;
|
|
399
|
-
var dateKey = dayDate.getFullYear() + "-" + dayDate.getMonth() + "-" + dayDate.getDate();
|
|
400
|
-
var eventCount = eventDates[dateKey] || 0;
|
|
401
|
-
|
|
402
|
-
var cell = document.createElement("div");
|
|
403
|
-
cell.className = "hub-week-day" + (isToday ? " today" : "");
|
|
404
|
-
var dotsHtml = '<div class="hub-week-dots">';
|
|
405
|
-
var dotCount = Math.min(eventCount, 3);
|
|
406
|
-
for (var di = 0; di < dotCount; di++) {
|
|
407
|
-
dotsHtml += '<span class="hub-week-dot"></span>';
|
|
408
|
-
}
|
|
409
|
-
dotsHtml += '</div>';
|
|
410
|
-
cell.innerHTML = '<span class="hub-week-label">' + DAY_NAMES[(dayDate.getDay())] + '</span>' +
|
|
411
|
-
'<span class="hub-week-num">' + dayDate.getDate() + '</span>' +
|
|
412
|
-
dotsHtml;
|
|
413
|
-
weekStrip.appendChild(cell);
|
|
251
|
+
if (state.homeSurfaceLoaded !== prev.homeSurfaceLoaded && homeHubVisible) {
|
|
252
|
+
syncHomePresentation();
|
|
253
|
+
if (!restoreHomeDebatesArchive() && state.homeChatMateId) resumeHomeChat();
|
|
254
|
+
renderHomeMateSwitcher();
|
|
414
255
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
var pbGrid = $hub("hub-playbooks-grid");
|
|
419
|
-
var pbSection = $hub("hub-playbooks");
|
|
420
|
-
if (pbGrid) {
|
|
421
|
-
var pbs = getPlaybooks();
|
|
422
|
-
if (pbs.length === 0) {
|
|
423
|
-
if (pbSection) pbSection.style.display = "none";
|
|
424
|
-
} else {
|
|
425
|
-
if (pbSection) pbSection.style.display = "";
|
|
426
|
-
pbGrid.innerHTML = "";
|
|
427
|
-
for (var pi = 0; pi < pbs.length; pi++) {
|
|
428
|
-
(function (pb) {
|
|
429
|
-
var card = document.createElement("div");
|
|
430
|
-
card.className = "hub-playbook-card" + (pb.completed ? " completed" : "");
|
|
431
|
-
card.innerHTML = '<span class="hub-playbook-card-icon">' + pb.icon + '</span>' +
|
|
432
|
-
'<div class="hub-playbook-card-body">' +
|
|
433
|
-
'<div class="hub-playbook-card-title">' + escapeHtml(pb.title) + '</div>' +
|
|
434
|
-
'<div class="hub-playbook-card-desc">' + escapeHtml(pb.description) + '</div>' +
|
|
435
|
-
'</div>' +
|
|
436
|
-
(pb.completed ? '<span class="hub-playbook-card-check">✓</span>' : '');
|
|
437
|
-
card.addEventListener("click", function () {
|
|
438
|
-
openPlaybook(pb.id, function () {
|
|
439
|
-
// Re-render hub after playbook closes to update completion state
|
|
440
|
-
renderHomeHub(getCachedProjects());
|
|
441
|
-
});
|
|
442
|
-
});
|
|
443
|
-
pbGrid.appendChild(card);
|
|
444
|
-
})(pbs[pi]);
|
|
445
|
-
}
|
|
446
|
-
|
|
256
|
+
if (state.homeSurfaceRestoreRequested === true && prev.homeSurfaceRestoreRequested !== true) {
|
|
257
|
+
showHomeHub(true);
|
|
258
|
+
store.set({ homeSurfaceRestoreRequested: false });
|
|
447
259
|
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
var currentTip = hubTips[hubTipIndex % hubTips.length];
|
|
453
|
-
var tipEl = $hub("hub-tip-text");
|
|
454
|
-
if (tipEl) tipEl.textContent = currentTip;
|
|
455
|
-
|
|
456
|
-
// "Try it" button if tip has a linked playbook
|
|
457
|
-
var existingTry = homeHub.querySelector(".hub-tip-try");
|
|
458
|
-
if (existingTry) existingTry.remove();
|
|
459
|
-
var linkedPb = getPlaybookForTip(currentTip);
|
|
460
|
-
if (linkedPb && tipEl) {
|
|
461
|
-
var tryBtn = document.createElement("button");
|
|
462
|
-
tryBtn.className = "hub-tip-try";
|
|
463
|
-
tryBtn.textContent = "Try it →";
|
|
464
|
-
tryBtn.addEventListener("click", function () {
|
|
465
|
-
openPlaybook(linkedPb, function () {
|
|
466
|
-
renderHomeHub(getCachedProjects());
|
|
467
|
-
});
|
|
468
|
-
});
|
|
469
|
-
tipEl.appendChild(tryBtn);
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
// Tip prev/next buttons
|
|
473
|
-
var prevBtn = $hub("hub-tip-prev");
|
|
474
|
-
if (prevBtn && !prevBtn._hubWired) {
|
|
475
|
-
prevBtn._hubWired = true;
|
|
476
|
-
prevBtn.addEventListener("click", function () {
|
|
477
|
-
hubTipIndex = (hubTipIndex - 1 + hubTips.length) % hubTips.length;
|
|
478
|
-
renderHomeHub(getCachedProjects());
|
|
479
|
-
startTipRotation();
|
|
480
|
-
});
|
|
481
|
-
}
|
|
482
|
-
var nextBtn = $hub("hub-tip-next");
|
|
483
|
-
if (nextBtn && !nextBtn._hubWired) {
|
|
484
|
-
nextBtn._hubWired = true;
|
|
485
|
-
nextBtn.addEventListener("click", function () {
|
|
486
|
-
hubTipIndex = (hubTipIndex + 1) % hubTips.length;
|
|
487
|
-
renderHomeHub(getCachedProjects());
|
|
488
|
-
startTipRotation();
|
|
489
|
-
});
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
// Render twemoji for all emoji in the hub
|
|
260
|
+
});
|
|
261
|
+
syncHomeCloseControl();
|
|
262
|
+
renderHomeChat();
|
|
263
|
+
}
|
|
493
264
|
|
|
494
|
-
|
|
495
|
-
|
|
265
|
+
export function isHomeHubVisible() {
|
|
266
|
+
return homeHubVisible;
|
|
496
267
|
}
|
|
497
268
|
|
|
498
|
-
function
|
|
499
|
-
var list =
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
var
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
list.innerHTML = "";
|
|
269
|
+
export function renderHomeMateSwitcher() {
|
|
270
|
+
var list = document.getElementById("home-mate-list");
|
|
271
|
+
if (!list) return;
|
|
272
|
+
var visibleMates = getVisibleMates();
|
|
273
|
+
var activeMateId = store.get('homeChatMateId');
|
|
274
|
+
var selectionChanged = activeMateId !== lastRenderedMateId;
|
|
275
|
+
var activeMate = resolveHomeMate(visibleMates, activeMateId, null);
|
|
276
|
+
if (!activeMate || activeMate.id !== activeMateId) activeMate = null;
|
|
277
|
+
if (homeHubVisible && !store.get('homeSurfaceLoaded') && !activeMate) {
|
|
278
|
+
syncMateContextControls(null);
|
|
279
|
+
renderMateListLoading(list);
|
|
510
280
|
return;
|
|
511
281
|
}
|
|
512
|
-
|
|
282
|
+
if (homeHubVisible && store.get('homeSurfaceLoaded') && !activeMate) {
|
|
283
|
+
var nextMate = resolveHomeMate(visibleMates, activeMateId, store.get('homePreferredMateId'));
|
|
284
|
+
if (nextMate) {
|
|
285
|
+
if (isHomeDebatesSurface()) {
|
|
286
|
+
store.set({ homeChatMateId: nextMate.id });
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
openHomeChat(nextMate.id);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
syncMateContextControls(activeMate);
|
|
294
|
+
var focusedMateId = list.contains(document.activeElement) ? document.activeElement.dataset.homeMateId : null;
|
|
295
|
+
var focusedOverflow = !!focusedMateId && document.activeElement.classList.contains("home-mate-list-overflow");
|
|
296
|
+
var mentionActive = getActiveMentionMateIds();
|
|
297
|
+
var projectStatus = getMateActivity();
|
|
298
|
+
var unread = store.get('dmUnread') || {};
|
|
299
|
+
disposeHomeMateSettingsMenu();
|
|
300
|
+
syncHomeMateSettingsTarget();
|
|
513
301
|
list.innerHTML = "";
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
var
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
dateEl.textContent = e.publishedAt || "";
|
|
523
|
-
var titleEl = document.createElement("h3");
|
|
524
|
-
titleEl.className = "hub-whats-new-item-title";
|
|
525
|
-
titleEl.textContent = e.title || "";
|
|
526
|
-
btn.appendChild(dateEl);
|
|
527
|
-
btn.appendChild(titleEl);
|
|
528
|
-
(function (id) {
|
|
529
|
-
btn.addEventListener("click", function () { openWhatsNewArticle(id); });
|
|
530
|
-
})(e.id);
|
|
531
|
-
list.appendChild(btn);
|
|
302
|
+
list.appendChild(createNewMateRow(false));
|
|
303
|
+
if (!visibleMates.length) {
|
|
304
|
+
var empty = document.createElement("div");
|
|
305
|
+
empty.className = "home-mate-list-empty";
|
|
306
|
+
empty.textContent = "No Mates are available.";
|
|
307
|
+
list.appendChild(empty);
|
|
308
|
+
refreshIcons();
|
|
309
|
+
return;
|
|
532
310
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
export function handleHubSchedules(msg) {
|
|
536
|
-
if (msg.schedules) {
|
|
537
|
-
hubSchedules = msg.schedules;
|
|
538
|
-
if (homeHubVisible) renderHomeHub(getCachedProjects());
|
|
311
|
+
for (var i = 0; i < visibleMates.length; i++) {
|
|
312
|
+
list.appendChild(createMateListRow(visibleMates[i], activeMateId, projectStatus, mentionActive, unread));
|
|
539
313
|
}
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
hubTipTimer = setInterval(function () {
|
|
545
|
-
hubTipIndex = (hubTipIndex + 1) % hubTips.length;
|
|
546
|
-
renderHomeHub(getCachedProjects());
|
|
547
|
-
}, 15000);
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
function stopTipRotation() {
|
|
551
|
-
if (hubTipTimer) {
|
|
552
|
-
clearInterval(hubTipTimer);
|
|
553
|
-
hubTipTimer = null;
|
|
314
|
+
var focusedRow = null;
|
|
315
|
+
if (focusedMateId) {
|
|
316
|
+
focusedRow = focusedOverflow ? findMateOverflow(list, focusedMateId) : findMateRow(list, focusedMateId);
|
|
317
|
+
if (focusedRow) focusedRow.focus({ preventScroll: true });
|
|
554
318
|
}
|
|
319
|
+
var activeRow = findMateRow(list, activeMateId);
|
|
320
|
+
keepMateRowVisible(list, selectionChanged ? activeRow : focusedRow || activeRow);
|
|
321
|
+
lastRenderedMateId = activeMateId;
|
|
322
|
+
refreshIcons();
|
|
555
323
|
}
|
|
556
324
|
|
|
557
|
-
function
|
|
558
|
-
var
|
|
559
|
-
if (!
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
if (!m || m.archived) return false;
|
|
566
|
-
if (m.builtinKey === "clay") return false;
|
|
567
|
-
return true;
|
|
568
|
-
});
|
|
569
|
-
if (visibleMates.length === 0) {
|
|
570
|
-
container.classList.add("hidden");
|
|
571
|
-
return;
|
|
325
|
+
export function updateHomeIconBadge() {
|
|
326
|
+
var badge = document.getElementById("icon-strip-home-badge");
|
|
327
|
+
if (!badge) return;
|
|
328
|
+
var mates = store.get('cachedMatesList') || [];
|
|
329
|
+
var unread = store.get('dmUnread') || {};
|
|
330
|
+
var total = 0;
|
|
331
|
+
for (var i = 0; i < mates.length; i++) {
|
|
332
|
+
total += unread[mates[i].id] || 0;
|
|
572
333
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
(
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
var avatarWrap = document.createElement("div");
|
|
580
|
-
avatarWrap.className = "home-hub-mate-avatar-wrap";
|
|
581
|
-
|
|
582
|
-
var mp = mate.profile || {};
|
|
583
|
-
var mateAvUrl = mateAvatarUrl(mate, 48);
|
|
584
|
-
var avatar = document.createElement("img");
|
|
585
|
-
avatar.className = "home-hub-mate-avatar";
|
|
586
|
-
avatar.src = mateAvUrl;
|
|
587
|
-
avatar.alt = mp.displayName || mate.displayName || mate.name || "";
|
|
588
|
-
avatarWrap.appendChild(avatar);
|
|
589
|
-
|
|
590
|
-
var dot = document.createElement("span");
|
|
591
|
-
dot.className = "home-hub-mate-dot";
|
|
592
|
-
avatarWrap.appendChild(dot);
|
|
593
|
-
|
|
594
|
-
item.appendChild(avatarWrap);
|
|
595
|
-
|
|
596
|
-
var nameEl = document.createElement("span");
|
|
597
|
-
nameEl.className = "home-hub-mate-name";
|
|
598
|
-
nameEl.textContent = mp.displayName || mate.displayName || mate.name || "";
|
|
599
|
-
if (mate.primary) {
|
|
600
|
-
var starEl = document.createElement("span");
|
|
601
|
-
starEl.className = "home-hub-mate-primary-star";
|
|
602
|
-
starEl.title = "System Agent: code-managed, auto-updated, sees across all mates";
|
|
603
|
-
starEl.textContent = "\u2605";
|
|
604
|
-
nameEl.appendChild(starEl);
|
|
605
|
-
}
|
|
606
|
-
item.appendChild(nameEl);
|
|
607
|
-
|
|
608
|
-
item.addEventListener("click", function () {
|
|
609
|
-
openDm(mate.id);
|
|
610
|
-
});
|
|
611
|
-
|
|
612
|
-
container.appendChild(item);
|
|
613
|
-
})(visibleMates[i]);
|
|
334
|
+
if (total > 0) {
|
|
335
|
+
badge.textContent = total > 99 ? "99+" : String(total);
|
|
336
|
+
badge.classList.add("has-unread");
|
|
337
|
+
} else {
|
|
338
|
+
badge.textContent = "";
|
|
339
|
+
badge.classList.remove("has-unread");
|
|
614
340
|
}
|
|
615
341
|
}
|
|
616
342
|
|
|
617
|
-
export function showHomeHub() {
|
|
618
|
-
// Home hub is a pure widget surface. Clay chat is reachable from
|
|
619
|
-
// anywhere via the persistent FAB (#clay-fab), not embedded here.
|
|
343
|
+
export function showHomeHub(fromHistory) {
|
|
620
344
|
if (store.get('dmMode')) exitDmMode();
|
|
345
|
+
var activeMateId = store.get('homeChatMateId');
|
|
346
|
+
var resume = homeHubSuspended || homeHubVisible;
|
|
621
347
|
homeHubVisible = true;
|
|
348
|
+
homeHubSuspended = false;
|
|
349
|
+
showHomeShell();
|
|
622
350
|
homeHub.classList.remove("hidden");
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
351
|
+
rememberHomePrimarySurface("home");
|
|
352
|
+
syncHomePresentation();
|
|
353
|
+
syncHomeCloseControl();
|
|
354
|
+
renderHomeMateSwitcher();
|
|
355
|
+
if (activeMateId && !resume && !isHomeDebatesSurface()) openHomeChat(activeMateId);
|
|
356
|
+
if (isHomeDebatesSurface()) restoreHomeDebatesArchive();
|
|
357
|
+
if (!resume && store.get('homeSurfaceRestoreRequested') !== true) {
|
|
358
|
+
requestTools();
|
|
359
|
+
requestHomeDockPreference();
|
|
360
|
+
requestHomeSurfacePreference();
|
|
361
|
+
renderDock();
|
|
633
362
|
}
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
history.pushState(null, "", "/");
|
|
363
|
+
if (!fromHistory && location.pathname !== "/") {
|
|
364
|
+
if (document.documentElement.classList.contains("pwa-standalone")) {
|
|
365
|
+
history.replaceState(null, "", "/");
|
|
366
|
+
} else {
|
|
367
|
+
history.pushState(null, "", "/");
|
|
368
|
+
}
|
|
641
369
|
}
|
|
642
|
-
// Update icon strip active state
|
|
643
370
|
var homeIcon = document.querySelector(".icon-strip-home");
|
|
644
371
|
if (homeIcon) homeIcon.classList.add("active");
|
|
645
|
-
var activeProj = document.querySelector("#icon-strip-projects .icon-strip-item.active");
|
|
646
|
-
if (activeProj) activeProj.classList.remove("active");
|
|
647
|
-
// Mobile home button active
|
|
648
372
|
var mobileHome = document.getElementById("mobile-home-btn");
|
|
649
373
|
if (mobileHome) mobileHome.classList.add("active");
|
|
650
374
|
}
|
|
651
375
|
|
|
652
376
|
export function hideHomeHub() {
|
|
653
377
|
if (!homeHubVisible) return;
|
|
378
|
+
disposeHomeMateSettingsMenu();
|
|
379
|
+
closeHomeMateSettings();
|
|
380
|
+
disposeHomeSessionActions();
|
|
654
381
|
homeHubVisible = false;
|
|
382
|
+
homeHubSuspended = true;
|
|
383
|
+
hideHomeShell();
|
|
655
384
|
homeHub.classList.add("hidden");
|
|
656
|
-
|
|
385
|
+
syncHomePresentation();
|
|
386
|
+
var homeIcon = document.querySelector(".icon-strip-home");
|
|
387
|
+
if (homeIcon) homeIcon.classList.remove("active");
|
|
657
388
|
var mobileHome = document.getElementById("mobile-home-btn");
|
|
658
389
|
if (mobileHome) mobileHome.classList.remove("active");
|
|
659
390
|
}
|
|
391
|
+
|
|
392
|
+
export function minimizeHomeHub() {
|
|
393
|
+
var slug = store.get('currentSlug');
|
|
394
|
+
if (!slug || !homeHubVisible) return;
|
|
395
|
+
rememberHomePrimarySurface("project");
|
|
396
|
+
hideHomeHub();
|
|
397
|
+
var route = "/p/" + slug + "/";
|
|
398
|
+
if (document.documentElement.classList.contains("pwa-standalone")) history.replaceState(null, "", route);
|
|
399
|
+
else history.pushState(null, "", route);
|
|
400
|
+
var projectInput = document.getElementById("input");
|
|
401
|
+
if (projectInput && !projectInput.disabled) projectInput.focus({ preventScroll: true });
|
|
402
|
+
}
|