clay-server 2.7.2 → 2.8.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.
Files changed (55) hide show
  1. package/bin/cli.js +31 -17
  2. package/lib/config.js +7 -4
  3. package/lib/project.js +343 -15
  4. package/lib/public/app.js +1039 -134
  5. package/lib/public/apple-touch-icon-dark.png +0 -0
  6. package/lib/public/apple-touch-icon.png +0 -0
  7. package/lib/public/clay-logo.png +0 -0
  8. package/lib/public/css/base.css +18 -1
  9. package/lib/public/css/filebrowser.css +1 -0
  10. package/lib/public/css/home-hub.css +455 -0
  11. package/lib/public/css/icon-strip.css +6 -5
  12. package/lib/public/css/loop.css +141 -23
  13. package/lib/public/css/messages.css +2 -0
  14. package/lib/public/css/mobile-nav.css +38 -12
  15. package/lib/public/css/overlays.css +205 -169
  16. package/lib/public/css/playbook.css +264 -0
  17. package/lib/public/css/profile.css +268 -0
  18. package/lib/public/css/scheduler-modal.css +1429 -0
  19. package/lib/public/css/scheduler.css +1305 -0
  20. package/lib/public/css/sidebar.css +305 -11
  21. package/lib/public/css/sticky-notes.css +23 -19
  22. package/lib/public/css/stt.css +155 -0
  23. package/lib/public/css/title-bar.css +14 -6
  24. package/lib/public/favicon-banded-32.png +0 -0
  25. package/lib/public/favicon-banded.png +0 -0
  26. package/lib/public/icon-192-dark.png +0 -0
  27. package/lib/public/icon-192.png +0 -0
  28. package/lib/public/icon-512-dark.png +0 -0
  29. package/lib/public/icon-512.png +0 -0
  30. package/lib/public/icon-banded-76.png +0 -0
  31. package/lib/public/icon-banded-96.png +0 -0
  32. package/lib/public/index.html +336 -44
  33. package/lib/public/modules/ascii-logo.js +442 -0
  34. package/lib/public/modules/markdown.js +18 -0
  35. package/lib/public/modules/notifications.js +50 -63
  36. package/lib/public/modules/playbook.js +578 -0
  37. package/lib/public/modules/profile.js +357 -0
  38. package/lib/public/modules/project-settings.js +1 -9
  39. package/lib/public/modules/scheduler.js +2826 -0
  40. package/lib/public/modules/server-settings.js +1 -1
  41. package/lib/public/modules/sidebar.js +376 -32
  42. package/lib/public/modules/stt.js +272 -0
  43. package/lib/public/modules/terminal.js +32 -0
  44. package/lib/public/modules/theme.js +3 -10
  45. package/lib/public/style.css +6 -0
  46. package/lib/public/sw.js +82 -3
  47. package/lib/public/wordmark-banded-20.png +0 -0
  48. package/lib/public/wordmark-banded-32.png +0 -0
  49. package/lib/public/wordmark-banded-64.png +0 -0
  50. package/lib/public/wordmark-banded-80.png +0 -0
  51. package/lib/scheduler.js +402 -0
  52. package/lib/sdk-bridge.js +3 -2
  53. package/lib/server.js +124 -3
  54. package/lib/sessions.js +35 -2
  55. package/package.json +1 -1
@@ -7,12 +7,12 @@
7
7
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
8
8
  <link rel="manifest" href="manifest.json">
9
9
  <meta name="theme-color" content="#2F2E2B">
10
- <link rel="icon" type="image/svg+xml" href="favicon.svg">
10
+ <link rel="icon" type="image/png" href="favicon-banded.png">
11
11
  <link rel="apple-touch-icon" href="apple-touch-icon.png">
12
12
  <title>Clay</title>
13
13
  <link rel="preconnect" href="https://fonts.googleapis.com">
14
14
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
15
- <link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;500&family=Nunito:wght@700;800&display=swap" rel="stylesheet">
15
+ <link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;500;700&family=Nunito:wght@700;800&display=swap" rel="stylesheet">
16
16
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@xterm/xterm@5/css/xterm.min.css">
17
17
  <script>
18
18
  (function(){try{var k="clay-theme-vars",v=localStorage.getItem(k),r=document.documentElement;if(v){var o=JSON.parse(v),p;for(p in o)r.style.setProperty(p,o[p]);var vt=localStorage.getItem(k.replace("-vars","-variant"));if(vt==="light"){r.classList.add("light-theme");r.classList.remove("dark-theme")}else{r.classList.add("dark-theme");r.classList.remove("light-theme")}var m=document.querySelector('meta[name="theme-color"]');if(m&&o["--bg"])m.setAttribute("content",o["--bg"])}else{var sl=window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches;if(sl){r.classList.add("light-theme");r.classList.remove("dark-theme")}}}catch(e){}})();
@@ -21,26 +21,23 @@
21
21
  </head>
22
22
  <body>
23
23
  <div id="layout">
24
- <!-- === Announce Bars (above top bar, full width) === -->
25
- <div id="update-banner" class="hidden">
26
- <span class="update-banner-text"><i data-lucide="arrow-up-circle"></i> A new version of Clay is available: <strong id="update-version"></strong></span>
27
- <button id="update-now">Update now</button>
28
- <button id="update-how" title="Manual update instructions">?</button>
29
- <button id="update-banner-close" aria-label="Dismiss"><i data-lucide="x"></i></button>
30
- </div>
31
- <div id="onboarding-banner" class="hidden">
32
- <span class="onboarding-banner-text" id="onboarding-banner-text"></span>
33
- <button id="onboarding-banner-close" aria-label="Dismiss"><i data-lucide="x"></i></button>
34
- </div>
35
- <div id="skip-perms-banner" class="hidden">
36
- <i data-lucide="shield-off"></i>
37
- <span>Skip permissions mode is active. All tool executions are auto-approved.</span>
38
- </div>
39
-
40
24
  <!-- === Top Bar (full width, forms reverse-ㄱ with icon strip) === -->
41
25
  <div id="top-bar">
42
- <a href="https://github.com/chadbyte/claude-relay" target="_blank" rel="noopener" class="top-bar-title"><img class="top-bar-icon" src="favicon.svg" width="16" height="16" alt="">Clay</a>
26
+ <a href="https://github.com/chadbyte/clay" target="_blank" rel="noopener" class="top-bar-title"><img class="top-bar-icon" src="favicon-banded.png" width="16" height="16" alt="">Clay <span id="footer-version" class="footer-version"></span></a>
43
27
  <div class="top-bar-actions">
28
+ <!-- Pill badges (formerly banners) -->
29
+ <div id="skip-perms-pill" class="top-bar-pill pill-error hidden"><i data-lucide="shield-off"></i> <span>Skip perms</span></div>
30
+ <div id="onboarding-pill" class="top-bar-pill pill-accent hidden">
31
+ <span class="onboarding-pill-text" id="onboarding-pill-text"></span>
32
+ <button id="onboarding-pill-close" class="pill-close" aria-label="Dismiss"><i data-lucide="x"></i></button>
33
+ </div>
34
+ <div id="update-pill-wrap" class="hidden">
35
+ <button id="update-pill" class="top-bar-pill pill-success"><i data-lucide="arrow-up-circle"></i> <span id="update-version"></span></button>
36
+ <div id="update-popover" class="top-bar-popover">
37
+ <div class="popover-row"><button id="update-now" class="popover-action popover-action-primary"><i data-lucide="download"></i> Update now</button></div>
38
+ <div class="popover-row"><div class="popover-label">Or run manually:</div><div class="popover-cmd"><code>npx clay-server@latest</code><button class="popover-copy" title="Copy"><i data-lucide="copy"></i></button></div></div>
39
+ </div>
40
+ </div>
44
41
  <span id="client-count" class="hidden"></span>
45
42
  <div id="debug-menu-wrap" class="hidden">
46
43
  <button id="debug-btn" title="Debug"><i data-lucide="bug"></i></button>
@@ -76,7 +73,7 @@
76
73
  <div id="icon-strip">
77
74
  <div class="icon-strip-home" title="Clay">
78
75
  <span class="icon-strip-pill"></span>
79
- <img class="footer-mascot icon-strip-logo" src="favicon.svg" width="38" height="38" alt="Clay">
76
+ <img class="icon-strip-logo" src="icon-banded-76.png" width="38" height="38" alt="Clay">
80
77
  </div>
81
78
  <div class="icon-strip-separator"></div>
82
79
  <div class="icon-strip-projects" id="icon-strip-projects"></div>
@@ -85,6 +82,65 @@
85
82
 
86
83
  <!-- === Main Area (sidebar + resize-handle + main-column) === -->
87
84
  <div id="main-area">
85
+ <div id="home-hub" class="hidden">
86
+ <button id="home-hub-close" class="home-hub-close-btn hidden">
87
+ <i data-lucide="x"></i>
88
+ <span>ESC</span>
89
+ </button>
90
+ <div class="home-hub-inner">
91
+ <div class="hub-greeting">
92
+ <h1 id="hub-greeting-text"></h1>
93
+ <p id="hub-greeting-date"></p>
94
+ </div>
95
+
96
+ <div class="hub-columns">
97
+ <div class="hub-card hub-upcoming">
98
+ <div class="hub-card-header">
99
+ <span class="hub-card-title">Upcoming</span>
100
+ <span class="hub-card-count" id="hub-upcoming-count"></span>
101
+ </div>
102
+ <div class="hub-upcoming-list" id="hub-upcoming-list"></div>
103
+ </div>
104
+ <div class="hub-card hub-projects-summary">
105
+ <div class="hub-card-header">
106
+ <span class="hub-card-title">Projects</span>
107
+ </div>
108
+ <div class="hub-projects-list" id="hub-projects-list"></div>
109
+ </div>
110
+ </div>
111
+
112
+ <div class="hub-card hub-week">
113
+ <div class="hub-card-header">
114
+ <span class="hub-card-title">This Week</span>
115
+ </div>
116
+ <div class="hub-week-strip" id="hub-week-strip"></div>
117
+ </div>
118
+
119
+ <div class="hub-card hub-playbooks" id="hub-playbooks">
120
+ <div class="hub-card-header">
121
+ <span class="hub-card-title">Quick Start</span>
122
+ </div>
123
+ <div class="hub-playbooks-grid" id="hub-playbooks-grid"></div>
124
+ </div>
125
+
126
+
127
+ <div class="hub-tip">
128
+ <div class="hub-tip-icon">💡</div>
129
+ <div class="hub-tip-body">
130
+ <div class="hub-tip-label">Did you know?</div>
131
+ <div class="hub-tip-text" id="hub-tip-text"></div>
132
+ </div>
133
+ <div class="hub-tip-nav">
134
+ <button class="hub-tip-prev" id="hub-tip-prev" title="Previous tip">
135
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
136
+ </button>
137
+ <button class="hub-tip-next" id="hub-tip-next" title="Next tip">
138
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 6 15 12 9 18"/></svg>
139
+ </button>
140
+ </div>
141
+ </div>
142
+ </div>
143
+ </div>
88
144
  <div id="sidebar-column">
89
145
  <div class="title-bar-sidebar">
90
146
  <button class="title-bar-project-dropdown" id="title-bar-project-dropdown">
@@ -100,6 +156,7 @@
100
156
  <button id="terminal-sidebar-btn"><i data-lucide="square-terminal"></i> <span>Terminal</span><span id="terminal-sidebar-count" class="sidebar-badge hidden"></span></button>
101
157
  <button id="sticky-notes-sidebar-btn"><i data-lucide="sticky-note"></i> <span>Sticky Notes</span><span id="sticky-notes-sidebar-count" class="sidebar-badge hidden"></span></button>
102
158
  <button id="skills-btn"><i data-lucide="puzzle"></i> <span>Skills</span></button>
159
+ <button id="scheduler-btn"><i data-lucide="calendar-clock"></i> <span>Scheduled Tasks</span></button>
103
160
  </div>
104
161
  </div>
105
162
  <div id="sidebar-sessions-header">
@@ -107,6 +164,7 @@
107
164
  <div class="session-list-header">
108
165
  <span>Sessions</span>
109
166
  <div class="session-list-header-actions">
167
+ <button id="new-ralph-btn" type="button" class="new-ralph-pill" data-tip="New Ralph Loop"><i data-lucide="repeat"></i> Ralph Loop</button>
110
168
  <button id="new-session-btn" type="button" data-tip="New session"><i data-lucide="plus"></i></button>
111
169
  <button id="resume-session-btn" type="button" data-tip="Import CLI session"><i data-lucide="import"></i></button>
112
170
  <button id="search-session-btn" type="button" data-tip="Search sessions"><i data-lucide="search"></i></button>
@@ -127,6 +185,7 @@
127
185
  </div>
128
186
  </div>
129
187
  </div>
188
+ <div id="ralph-loop-section"></div>
130
189
  <div id="sidebar-panel-projects" class="sidebar-panel hidden">
131
190
  <div id="project-list"></div>
132
191
  </div>
@@ -159,8 +218,8 @@
159
218
  <div id="main-panels">
160
219
  <div id="app">
161
220
  <div id="connect-overlay">
162
- <img class="connect-logo" src="favicon.svg" width="48" height="48" alt="Clay">
163
- <span class="connect-wordmark">Clay</span>
221
+ <canvas id="ascii-logo-canvas"></canvas>
222
+ <p id="connect-overlay-msg">Reconnecting to server…</p>
164
223
  </div>
165
224
  <div id="sticky-notes-container" class="hidden"></div>
166
225
  <div id="messages"></div>
@@ -258,6 +317,7 @@
258
317
  <div id="attach-wrap">
259
318
  <button id="attach-file-btn" type="button" aria-label="Attach file" title="Attach file"><i data-lucide="paperclip"></i></button>
260
319
  <button id="attach-image-btn" type="button" aria-label="Attach image" title="Attach image"><i data-lucide="image"></i></button>
320
+ <button id="stt-btn" type="button" aria-label="Voice input" title="Voice input"><i data-lucide="mic"></i></button>
261
321
  </div>
262
322
  <div id="input-bottom-right">
263
323
  <div id="config-chip-wrap" class="hidden">
@@ -314,7 +374,7 @@
314
374
  <div id="mobile-tab-bar">
315
375
  <button class="mobile-tab" data-tab="projects"><i data-lucide="folder-kanban"></i><span class="mobile-tab-label">Projects</span></button>
316
376
  <button class="mobile-tab" data-tab="sessions"><i data-lucide="messages-square"></i><span class="mobile-tab-label">Sessions</span></button>
317
- <button class="mobile-tab-new" id="mobile-new-session-btn"><i data-lucide="plus"></i></button>
377
+ <button class="mobile-tab-home" id="mobile-home-btn"><img src="/icon-banded-76.png" alt="Clay" class="mobile-home-icon"></button>
318
378
  <button class="mobile-tab" data-tab="files"><i data-lucide="folder-tree"></i><span class="mobile-tab-label">Files</span></button>
319
379
  <button class="mobile-tab" data-tab="terminal"><i data-lucide="square-terminal"></i><span id="mobile-terminal-count" class="mobile-tab-badge hidden"></span><span class="mobile-tab-label">Terminal</span></button>
320
380
  </div>
@@ -500,9 +560,11 @@
500
560
 
501
561
  <!-- === User Island === -->
502
562
  <div id="user-island">
503
- <div class="user-island-avatar"><span class="user-island-avatar-letter">C</span></div>
504
- <div class="user-island-info">
505
- <span class="user-island-name">Clay <span id="footer-version" class="footer-version"></span></span>
563
+ <div class="user-island-profile">
564
+ <div class="user-island-avatar"><span class="user-island-avatar-letter">?</span></div>
565
+ <div class="user-island-info">
566
+ <span class="user-island-name">Awesome Clay User</span>
567
+ </div>
506
568
  </div>
507
569
  <div class="user-island-actions">
508
570
  </div>
@@ -991,7 +1053,6 @@
991
1053
  <div class="ralph-wizard-progress">
992
1054
  <span class="ralph-dot active" data-step="1"></span>
993
1055
  <span class="ralph-dot" data-step="2"></span>
994
- <span class="ralph-dot" data-step="3"></span>
995
1056
  </div>
996
1057
  <div class="ralph-wizard-steps">
997
1058
  <div class="ralph-step active" data-step="1">
@@ -1014,28 +1075,17 @@
1014
1075
  <span class="ralph-dia-loop-label">Fail &mdash; retry</span>
1015
1076
  </div>
1016
1077
  </div>
1017
- <p class="ralph-intro-detail">In the next steps you'll describe what to build. Claude will draft the instructions, and you can preview and edit them before anything runs.</p>
1018
- <p class="ralph-intro-install-note">Clicking <em>Get Started</em> will install the <strong>clay-ralph</strong> skill to enable this feature.</p>
1078
+ <p class="ralph-intro-detail">In the next step you'll describe what to build. Claude will draft the instructions, and you can preview and edit them before anything runs.</p>
1019
1079
  <div id="ralph-install-status" class="hidden"></div>
1020
1080
  </div>
1021
1081
  </div>
1022
1082
  <div class="ralph-step" data-step="2">
1023
1083
  <h3>What do you want to build?</h3>
1024
- <label class="ralph-field-label" for="ralph-name">Loop name <span class="ralph-field-req">*</span></label>
1025
- <input type="text" id="ralph-name" maxlength="30" placeholder="e.g. auth-refactor" class="ralph-input-text" spellcheck="false" autocomplete="off">
1026
- <p class="ralph-field-hint">Alphanumeric, hyphens, underscores only. Used in session titles.</p>
1084
+ <p class="ralph-hint">Write a rough idea &mdash; Clay will refine it into detailed instructions. You can review and edit everything before the loop starts.</p>
1027
1085
  <label class="ralph-field-label" for="ralph-task">Task description <span class="ralph-field-req">*</span></label>
1028
- <textarea id="ralph-task" rows="5" placeholder="e.g. Add dark mode toggle to the settings page with system preference detection..."></textarea>
1029
- </div>
1030
- <div class="ralph-step" data-step="3">
1031
- <h3>Settings &amp; Review</h3>
1032
- <div class="ralph-settings-row">
1033
- <label for="ralph-max-iterations">Max iterations</label>
1034
- <input type="number" id="ralph-max-iterations" min="1" max="100" value="25" class="ralph-input-number">
1035
- <span class="ralph-settings-hint">How many code → judge cycles before stopping.</span>
1036
- </div>
1037
- <div id="ralph-review-summary"></div>
1086
+ <textarea id="ralph-task" rows="5" placeholder="e.g. Add dark mode toggle to the settings page"></textarea>
1038
1087
  </div>
1088
+ <input type="hidden" id="ralph-max-iterations" value="25">
1039
1089
  </div>
1040
1090
  <div class="ralph-wizard-footer">
1041
1091
  <button id="ralph-wizard-back" class="ralph-btn secondary">Back</button>
@@ -1051,15 +1101,258 @@
1051
1101
  <div id="ralph-preview-modal" class="hidden">
1052
1102
  <div class="confirm-backdrop"></div>
1053
1103
  <div class="ralph-preview-dialog">
1104
+ <div class="ralph-preview-header">
1105
+ <span class="ralph-preview-name" id="ralph-preview-name">Ralph Loop</span>
1106
+ <div class="ralph-preview-actions">
1107
+ <button class="ralph-preview-action-btn primary" id="ralph-preview-run" title="Start loop"><i data-lucide="play"></i> Run now</button>
1108
+ <button class="ralph-preview-action-icon" id="ralph-preview-delete" title="Cancel and discard"><i data-lucide="trash-2"></i></button>
1109
+ </div>
1110
+ </div>
1054
1111
  <div class="ralph-preview-tabs">
1055
1112
  <button class="ralph-tab active" data-tab="prompt">PROMPT.md</button>
1056
1113
  <button class="ralph-tab" data-tab="judge">JUDGE.md</button>
1057
1114
  </div>
1058
1115
  <div id="ralph-preview-body" class="ralph-preview-body"></div>
1059
- <button id="ralph-preview-close" class="ralph-btn secondary">Close</button>
1060
1116
  </div>
1061
1117
  </div>
1062
1118
 
1119
+ <!-- Scheduler panel is dynamically created in #app by scheduler.js -->
1120
+
1121
+ <!-- Schedule Edit Modal -->
1122
+ <div id="schedule-edit-modal" class="hidden">
1123
+ <div class="confirm-backdrop"></div>
1124
+ <div class="confirm-dialog schedule-edit-dialog">
1125
+ <div class="schedule-edit-header">
1126
+ <span class="schedule-edit-title" id="schedule-edit-title">New Schedule</span>
1127
+ <button class="schedule-edit-close" id="schedule-edit-close">&times;</button>
1128
+ </div>
1129
+ <div class="schedule-edit-body">
1130
+ <div class="sched-field">
1131
+ <label class="sched-field-label" for="sched-name">Name</label>
1132
+ <input type="text" class="sched-field-input" id="sched-name" placeholder="e.g. Daily Code Review" maxlength="60" spellcheck="false" autocomplete="off">
1133
+ </div>
1134
+ <div class="sched-field" id="sched-job-field">
1135
+ <label class="sched-field-label">Job</label>
1136
+ <div class="sched-field-hint" id="sched-job-name" style="font-weight:600;color:var(--text)"></div>
1137
+ </div>
1138
+ <div class="sched-field">
1139
+ <label class="sched-field-label">Repeat</label>
1140
+ <div class="sched-preset-group" id="sched-presets">
1141
+ <button class="sched-preset-btn" data-preset="daily">Every day</button>
1142
+ <button class="sched-preset-btn" data-preset="weekdays">Weekdays</button>
1143
+ <button class="sched-preset-btn" data-preset="weekly">Weekly</button>
1144
+ <button class="sched-preset-btn" data-preset="monthly">Monthly</button>
1145
+ <button class="sched-preset-btn" data-preset="custom">Custom</button>
1146
+ </div>
1147
+ </div>
1148
+ <div class="sched-field" id="sched-dow-field" style="display:none">
1149
+ <label class="sched-field-label">Days of week</label>
1150
+ <div class="sched-dow-row" id="sched-dow-row">
1151
+ <button class="sched-dow-btn" data-dow="0">Su</button>
1152
+ <button class="sched-dow-btn" data-dow="1">Mo</button>
1153
+ <button class="sched-dow-btn" data-dow="2">Tu</button>
1154
+ <button class="sched-dow-btn" data-dow="3">We</button>
1155
+ <button class="sched-dow-btn" data-dow="4">Th</button>
1156
+ <button class="sched-dow-btn" data-dow="5">Fr</button>
1157
+ <button class="sched-dow-btn" data-dow="6">Sa</button>
1158
+ </div>
1159
+ </div>
1160
+ <div class="sched-field">
1161
+ <label class="sched-field-label">Time</label>
1162
+ <div class="sched-time-row">
1163
+ <input type="time" class="sched-time-input" id="sched-time" value="09:00">
1164
+ </div>
1165
+ </div>
1166
+ <div class="sched-field">
1167
+ <label class="sched-field-label">Preview</label>
1168
+ <div class="sched-cron-preview" id="sched-cron-preview">
1169
+ <span class="human" id="sched-human-text">Every day at 09:00</span>
1170
+ <span id="sched-cron-text">0 9 * * *</span>
1171
+ </div>
1172
+ </div>
1173
+ <div class="sched-field">
1174
+ <div class="sched-toggle-row">
1175
+ <span class="sched-field-label" style="margin:0">Enabled</span>
1176
+ <label class="sched-toggle">
1177
+ <input type="checkbox" id="sched-enabled" checked>
1178
+ <span class="sched-toggle-track"></span>
1179
+ <span class="sched-toggle-thumb"></span>
1180
+ </label>
1181
+ </div>
1182
+ </div>
1183
+ <div class="sched-field" id="sched-history-field" style="display:none">
1184
+ <label class="sched-field-label">Run History</label>
1185
+ <div class="sched-history" id="sched-history"></div>
1186
+ </div>
1187
+ </div>
1188
+ <div class="schedule-edit-footer">
1189
+ <button class="sched-btn sched-btn-delete" id="sched-delete" style="display:none">Delete</button>
1190
+ <button class="sched-btn sched-btn-cancel" id="sched-cancel">Cancel</button>
1191
+ <button class="sched-btn sched-btn-save" id="sched-save">Save</button>
1192
+ </div>
1193
+ </div>
1194
+ </div>
1195
+
1196
+ <!-- Schedule Create Popover (inline) -->
1197
+ <div id="schedule-create-popover" class="sched-create-popover hidden">
1198
+ <input type="hidden" id="sched-create-date" value="">
1199
+ <!-- Top row: date + time + recurrence + close -->
1200
+ <div class="sched-create-top-row">
1201
+ <div class="sched-create-date-chips">
1202
+ <input type="date" class="sched-create-date-input" id="sched-create-date-picker" value="">
1203
+ <input type="time" class="sched-create-time-input" id="sched-create-time" value="09:00">
1204
+ <button class="sched-create-recurrence-btn" id="sched-create-recurrence-btn" title="Recurrence"><i data-lucide="repeat"></i></button>
1205
+ </div>
1206
+ <button class="sched-create-close-btn" id="sched-create-cancel" title="Close"><i data-lucide="x"></i></button>
1207
+ </div>
1208
+ <!-- Title with color picker -->
1209
+ <div class="sched-create-title-row">
1210
+ <div class="sched-create-color-picker-wrap">
1211
+ <button class="sched-create-color-btn" id="sched-create-color-btn" title="Pick color"><span class="sched-create-color-dot" id="sched-create-color-dot"></span></button>
1212
+ <div class="sched-create-color-palette hidden" id="sched-create-color-palette">
1213
+ <button class="sched-color-swatch" data-color="#ffb86c" style="background:#ffb86c"></button>
1214
+ <button class="sched-color-swatch" data-color="#f87171" style="background:#f87171"></button>
1215
+ <button class="sched-color-swatch" data-color="#fbbf24" style="background:#fbbf24"></button>
1216
+ <button class="sched-color-swatch" data-color="#34d399" style="background:#34d399"></button>
1217
+ <button class="sched-color-swatch" data-color="#22d3ee" style="background:#22d3ee"></button>
1218
+ <button class="sched-color-swatch" data-color="#f472b6" style="background:#f472b6"></button>
1219
+ <button class="sched-color-swatch" data-color="#6366f1" style="background:#6366f1"></button>
1220
+ <button class="sched-color-swatch" data-color="#a78bfa" style="background:#a78bfa"></button>
1221
+ <button class="sched-color-swatch" data-color="#3b82f6" style="background:#3b82f6"></button>
1222
+ <button class="sched-color-swatch" data-color="#e879f9" style="background:#e879f9"></button>
1223
+ <button class="sched-color-swatch" data-color="#10b981" style="background:#10b981"></button>
1224
+ <button class="sched-color-swatch" data-color="#8b5cf6" style="background:#8b5cf6"></button>
1225
+ </div>
1226
+ </div>
1227
+ <input type="text" class="sched-create-title-input" id="sched-create-title" placeholder="Schedule Title" maxlength="80" spellcheck="false" autocomplete="off">
1228
+ </div>
1229
+ <!-- Task (JS dropdown) -->
1230
+ <div class="sched-create-row">
1231
+ <i data-lucide="list-todo" class="sched-create-row-icon"></i>
1232
+ <div class="sched-create-task-dropdown" id="sched-create-task-wrap">
1233
+ <button class="sched-create-task-btn" id="sched-create-task-btn" type="button">
1234
+ <span class="sched-create-task-label" id="sched-create-task-label">Select a task</span>
1235
+ <i data-lucide="chevron-down"></i>
1236
+ </button>
1237
+ <input type="hidden" id="sched-create-task" value="">
1238
+ <div class="sched-create-task-list hidden" id="sched-create-task-list"></div>
1239
+ </div>
1240
+ </div>
1241
+ <!-- Description -->
1242
+ <div class="sched-create-row">
1243
+ <i data-lucide="align-left" class="sched-create-row-icon"></i>
1244
+ <textarea class="sched-create-row-textarea" id="sched-create-desc" rows="3" placeholder="Description"></textarea>
1245
+ </div>
1246
+ <!-- Bottom bar -->
1247
+ <div class="sched-create-bottom">
1248
+ <div class="sched-create-bottom-left">
1249
+ <label class="sched-create-iter-label" title="Number of code → judge cycles per run. Claude writes code, the judge reviews it, and repeats up to this many times."><i data-lucide="repeat" class="sched-create-iter-icon"></i> <input type="number" id="sched-create-iterations" min="1" max="100" value="3" class="sched-create-iter-input"> <span class="sched-create-iter-hint">rounds per run</span></label>
1250
+ </div>
1251
+ <div class="sched-create-bottom-right">
1252
+ <button class="sched-create-delete-btn hidden" id="sched-create-delete" title="Delete"><i data-lucide="trash-2"></i></button>
1253
+ <button class="sched-create-save-btn" id="sched-create-submit">Save</button>
1254
+ </div>
1255
+ </div>
1256
+ <!-- Recurrence dropdown -->
1257
+ <div class="sched-create-recurrence-dropdown hidden" id="sched-create-recurrence-dropdown">
1258
+ <div class="sched-recurrence-options" id="sched-create-recurrence-list">
1259
+ <button class="sched-recurrence-option active" data-recurrence="none">Does not repeat</button>
1260
+ <button class="sched-recurrence-option" data-recurrence="daily">Every day</button>
1261
+ <button class="sched-recurrence-option" data-recurrence="weekly" id="sched-recurrence-weekly">Weekly on Tuesday</button>
1262
+ <button class="sched-recurrence-option" data-recurrence="biweekly" id="sched-recurrence-biweekly">Every 2nd Tuesday of the month</button>
1263
+ <button class="sched-recurrence-option" data-recurrence="yearly" id="sched-recurrence-yearly">Every year on Mar 10</button>
1264
+ <button class="sched-recurrence-option" data-recurrence="monthly" id="sched-recurrence-monthly">Every month on the 10th</button>
1265
+ <button class="sched-recurrence-option" data-recurrence="weekdays">Every weekday</button>
1266
+ <button class="sched-recurrence-option" data-recurrence="custom">Custom&hellip;</button>
1267
+ </div>
1268
+ <div class="sched-custom-repeat-panel hidden" id="sched-custom-repeat-panel">
1269
+ <div class="sched-custom-header">
1270
+ <button class="sched-custom-back" id="sched-custom-back"><i data-lucide="chevron-left"></i> Back</button>
1271
+ </div>
1272
+ <div class="sched-custom-row">
1273
+ <span class="sched-custom-label">Every</span>
1274
+ <input type="number" class="sched-custom-interval" id="sched-custom-interval" value="1" min="1" max="99">
1275
+ <select class="sched-field-select sched-custom-unit" id="sched-custom-unit">
1276
+ <option value="day">Day</option>
1277
+ <option value="week" selected>Week</option>
1278
+ <option value="month">Month</option>
1279
+ <option value="year">Year</option>
1280
+ </select>
1281
+ </div>
1282
+ <div class="sched-custom-dow-section" id="sched-custom-dow-section">
1283
+ <span class="sched-custom-label">On</span>
1284
+ <div class="sched-dow-row" id="sched-custom-dow-row">
1285
+ <button class="sched-dow-btn" data-dow="0">Su</button>
1286
+ <button class="sched-dow-btn" data-dow="1">Mo</button>
1287
+ <button class="sched-dow-btn" data-dow="2">Tu</button>
1288
+ <button class="sched-dow-btn" data-dow="3">We</button>
1289
+ <button class="sched-dow-btn" data-dow="4">Th</button>
1290
+ <button class="sched-dow-btn" data-dow="5">Fr</button>
1291
+ <button class="sched-dow-btn" data-dow="6">Sa</button>
1292
+ </div>
1293
+ </div>
1294
+ <div class="sched-custom-row sched-custom-end-row" id="sched-custom-end-row">
1295
+ <span class="sched-custom-label">End</span>
1296
+ <div class="sched-custom-end-dropdown" id="sched-custom-end-wrap">
1297
+ <button class="sched-custom-end-btn" id="sched-custom-end-btn" type="button">
1298
+ <span id="sched-custom-end-label">Never</span>
1299
+ <i data-lucide="chevron-down"></i>
1300
+ </button>
1301
+ <input type="hidden" id="sched-custom-end" value="never">
1302
+ <div class="sched-custom-end-list hidden" id="sched-custom-end-list">
1303
+ <button class="sched-custom-end-item active" data-value="never" type="button">Never</button>
1304
+ <button class="sched-custom-end-item" data-value="until" type="button">Until</button>
1305
+ <button class="sched-custom-end-item" data-value="after" type="button">After</button>
1306
+ </div>
1307
+ </div>
1308
+ <button class="sched-custom-end-date-btn hidden" id="sched-custom-end-date-btn" type="button">
1309
+ <span id="sched-custom-end-date-label">Pick date</span>
1310
+ </button>
1311
+ <div class="sched-custom-end-after hidden" id="sched-custom-end-after-wrap">
1312
+ <input type="number" class="sched-custom-interval sched-custom-end-after-input" id="sched-custom-end-after" value="10" min="1" max="999">
1313
+ <span class="sched-custom-end-after-suffix">times</span>
1314
+ </div>
1315
+ </div>
1316
+ <!-- Inline calendar for "Until" date picking -->
1317
+ <div class="sched-custom-end-calendar hidden" id="sched-custom-end-calendar">
1318
+ <div class="sched-cal-header">
1319
+ <span class="sched-cal-title" id="sched-cal-title">April 2026</span>
1320
+ <div class="sched-cal-nav">
1321
+ <button class="sched-cal-nav-btn" id="sched-cal-prev"><i data-lucide="chevron-left"></i></button>
1322
+ <button class="sched-cal-nav-btn" id="sched-cal-next"><i data-lucide="chevron-right"></i></button>
1323
+ </div>
1324
+ </div>
1325
+ <div class="sched-cal-weekdays">
1326
+ <span>S</span><span>M</span><span>T</span><span>W</span><span>T</span><span>F</span><span>S</span>
1327
+ </div>
1328
+ <div class="sched-cal-grid" id="sched-cal-grid"></div>
1329
+ </div>
1330
+ <div class="sched-custom-actions">
1331
+ <button class="sched-btn sched-btn-cancel" id="sched-custom-cancel">Cancel</button>
1332
+ <button class="sched-btn sched-btn-save" id="sched-custom-ok">OK</button>
1333
+ </div>
1334
+ </div>
1335
+ </div>
1336
+ </div>
1337
+
1338
+ <!-- Delete recurring event dialog -->
1339
+ <div class="sched-delete-dialog-backdrop hidden" id="sched-delete-dialog">
1340
+ <div class="sched-delete-dialog">
1341
+ <div class="sched-delete-dialog-title">Delete recurring event</div>
1342
+ <div class="sched-delete-dialog-body">
1343
+ <button class="sched-delete-option" data-delete="this">This event only</button>
1344
+ <button class="sched-delete-option" data-delete="following">This and following events</button>
1345
+ <button class="sched-delete-option" data-delete="all">All events</button>
1346
+ </div>
1347
+ <div class="sched-delete-dialog-footer">
1348
+ <button class="sched-delete-option cancel" data-delete="cancel">Cancel</button>
1349
+ </div>
1350
+ </div>
1351
+ </div>
1352
+
1353
+ <!-- Schedule Popover -->
1354
+ <div id="schedule-popover" class="schedule-popover hidden"></div>
1355
+
1063
1356
  <script src="https://cdn.jsdelivr.net/npm/marked@14/marked.min.js"></script>
1064
1357
  <script src="https://cdn.jsdelivr.net/npm/dompurify@3/dist/purify.min.js"></script>
1065
1358
  <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/highlight.min.js"></script>
@@ -1068,7 +1361,6 @@
1068
1361
  <script src="https://cdn.jsdelivr.net/npm/qrcode-generator@1.4.4/qrcode.min.js"></script>
1069
1362
  <script src="https://cdn.jsdelivr.net/npm/@xterm/xterm@5/lib/xterm.min.js"></script>
1070
1363
  <script src="https://cdn.jsdelivr.net/npm/@xterm/addon-fit@0/lib/addon-fit.min.js"></script>
1071
- <script src="https://cdn.jsdelivr.net/npm/twemoji@14.0.2/dist/twemoji.min.js"></script>
1072
1364
  <script type="module" src="app.js"></script>
1073
1365
  </body>
1074
1366
  </html>