clay-server 4.1.0-beta.4 → 4.1.0-beta.6

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 (91) hide show
  1. package/lib/autonomous-run-record.js +32 -0
  2. package/lib/autonomous-run-scheduler.js +92 -0
  3. package/lib/durable-scheduler-record.js +61 -0
  4. package/lib/durable-scheduler-store.js +185 -0
  5. package/lib/durable-scheduler.js +495 -0
  6. package/lib/loop-cron.js +47 -0
  7. package/lib/loop-durable-schedule.js +159 -0
  8. package/lib/loop-guidance.js +35 -0
  9. package/lib/loop-registry-occurrence.js +76 -0
  10. package/lib/project-autonomous-run.js +498 -0
  11. package/lib/project-connection.js +4 -1
  12. package/lib/project-full-access.js +86 -0
  13. package/lib/project-http.js +3 -1
  14. package/lib/project-loop-interview.js +163 -0
  15. package/lib/project-loop.js +150 -64
  16. package/lib/project-pair-autonomous-stop.js +16 -0
  17. package/lib/project-pair-owned-stop.js +18 -0
  18. package/lib/project-pair-task-control.js +14 -1
  19. package/lib/project-scheduled-messages.js +316 -0
  20. package/lib/project-scheduled-task-execution.js +236 -0
  21. package/lib/project-scheduled-tasks.js +483 -0
  22. package/lib/project-session-pair.js +16 -19
  23. package/lib/project-sessions.js +60 -28
  24. package/lib/project-user-message.js +24 -18
  25. package/lib/project.js +260 -52
  26. package/lib/public/app.js +60 -23
  27. package/lib/public/css/home-hub.css +15 -2
  28. package/lib/public/css/home-sidebar.css +50 -2
  29. package/lib/public/css/input.css +71 -0
  30. package/lib/public/css/mates.css +0 -1
  31. package/lib/public/css/pane.css +58 -7
  32. package/lib/public/css/rewind.css +11 -2
  33. package/lib/public/css/scheduled-tasks.css +123 -0
  34. package/lib/public/css/sticky-notes.css +24 -4
  35. package/lib/public/index.html +19 -134
  36. package/lib/public/modules/app-loop-ui.js +4 -8
  37. package/lib/public/modules/app-messages.js +22 -6
  38. package/lib/public/modules/app-projects.js +2 -0
  39. package/lib/public/modules/app-rate-limit.js +8 -5
  40. package/lib/public/modules/autonomous-run.js +285 -0
  41. package/lib/public/modules/home-sidebar.js +16 -8
  42. package/lib/public/modules/home-surface.js +5 -0
  43. package/lib/public/modules/input.js +5 -4
  44. package/lib/public/modules/loop-interview.js +151 -0
  45. package/lib/public/modules/project-logs.js +2 -2
  46. package/lib/public/modules/scheduled-message-state.js +46 -0
  47. package/lib/public/modules/scheduled-task-edit-state.js +7 -0
  48. package/lib/public/modules/scheduled-task-engine.js +98 -0
  49. package/lib/public/modules/scheduled-task-form.js +122 -0
  50. package/lib/public/modules/scheduled-task-recurrence.js +46 -0
  51. package/lib/public/modules/scheduled-task-schedule-rule.js +115 -0
  52. package/lib/public/modules/scheduled-tasks.js +468 -0
  53. package/lib/public/modules/scheduler-config.js +6 -52
  54. package/lib/public/modules/scheduler.js +9 -21
  55. package/lib/public/modules/sidebar.js +0 -11
  56. package/lib/public/modules/split-view.js +2 -0
  57. package/lib/public/modules/sticky-notes-browser.js +1 -1
  58. package/lib/public/modules/sticky-notes.js +117 -4
  59. package/lib/public/modules/tool-palette-order.js +2 -3
  60. package/lib/public/modules/tools.js +5 -2
  61. package/lib/public/style.css +1 -0
  62. package/lib/record-revision.js +11 -0
  63. package/lib/schedule-rule.js +151 -0
  64. package/lib/schedule-validation.js +124 -0
  65. package/lib/scheduled-run-state.js +87 -0
  66. package/lib/scheduled-task-records.js +127 -0
  67. package/lib/scheduler.js +179 -196
  68. package/lib/sdk-bridge.js +123 -11
  69. package/lib/sdk-message-processor.js +3 -0
  70. package/lib/server-durable-scheduler.js +26 -0
  71. package/lib/server.js +22 -0
  72. package/lib/session-pair-factory.js +42 -4
  73. package/lib/session-pair-query-start.js +22 -0
  74. package/lib/session-query-tool-bridge.js +52 -0
  75. package/lib/session-split-groups.js +35 -1
  76. package/lib/sessions.js +51 -3
  77. package/lib/users-home-surface-preferences.js +2 -1
  78. package/lib/users-scheduled-task-preferences.js +44 -0
  79. package/lib/users.js +6 -0
  80. package/lib/ws-schema.js +25 -0
  81. package/lib/yoke/adapters/antigravity.js +1 -0
  82. package/lib/yoke/adapters/claude-worker.js +7 -4
  83. package/lib/yoke/adapters/claude.js +31 -1
  84. package/lib/yoke/adapters/codex.js +3 -0
  85. package/lib/yoke/claude-user-input.js +2 -0
  86. package/lib/yoke/index.js +2 -0
  87. package/lib/yoke/mcp-bridge-server.js +7 -1
  88. package/lib/yoke/session-tool-transport.js +53 -0
  89. package/lib/yoke/user-input.js +21 -7
  90. package/package.json +1 -1
  91. package/lib/public/modules/app-loop-wizard.js +0 -439
package/lib/public/app.js CHANGED
@@ -28,9 +28,11 @@ import { initQrCode, triggerShare } from './modules/qrcode.js';
28
28
  import { initFileBrowser, loadRootDirectory, refreshTree, handleFsList, handleFsRead, handleDirChanged, refreshIfOpen, handleFileChanged, handleFileHistory, handleGitDiff, handleFileAt, getPendingNavigate, closeFileViewer, resetFileBrowser } from './modules/filebrowser.js';
29
29
  import { initGitPanel } from './modules/git-panel.js';
30
30
  import { initWorkerPaneLock } from './modules/worker-pane-lock.js';
31
+ import { initAutonomousRun } from './modules/autonomous-run.js';
32
+ import { initLoopInterview } from './modules/loop-interview.js';
31
33
  import { initTerminal, openTerminal, closeTerminal, resetTerminals, handleTermList, handleTermCreated, handleTermOutput, handleTermResized, handleTermExited, handleTermClosed, sendTerminalCommand } from './modules/terminal.js';
32
34
  import { initContextSources, updateTerminalList, updateBrowserTabList, handleContextSourcesState, getActiveSources, hasActiveSources } from './modules/context-sources.js';
33
- import { initStickyNotes, handleNotesList, handleNoteCreated, handleNoteUpdated, handleNoteDeleted, hideNotes, showNotes, isNotesVisible, createNote, setBrowserRefresh } from './modules/sticky-notes.js';
35
+ import { initStickyNotes, handleNotesList, handleNoteCreated, handleNoteUpdated, handleNoteDeleted, hideNotes, showNotes, isNotesVisible, createNote, setBrowserRefresh, toggleNotesTemporaryVisibility } from './modules/sticky-notes.js';
34
36
  import { initNotesBrowser, openNotesBrowser, closeNotesBrowser, isNotesBrowserOpen, renderNotesBrowser, registerExclusiveClosers } from './modules/sticky-notes-browser.js';
35
37
  import { initTheme, getThemeColor, getComputedVar, onThemeChange, getCurrentTheme, getChatLayout } from './modules/theme.js';
36
38
  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';
@@ -39,6 +41,7 @@ import { initProjectSettings, handleInstructionsRead, handleInstructionsWrite, h
39
41
  import { initSkills, handleSkillInstalled, handleSkillUninstalled } from './modules/skills.js';
40
42
  import { initMcp } from './modules/mcp-ui.js';
41
43
  import { initScheduler, resetScheduler, handleLoopRegistryUpdated, handleScheduleRunStarted, handleScheduleRunFinished, handleLoopScheduled, openSchedulerToTab, isSchedulerOpen, closeScheduler, enterCraftingMode, exitCraftingMode, handleLoopRegistryFiles, getUpcomingSchedules } from './modules/scheduler.js';
44
+ import { initScheduledTasks, closeScheduledTasks } from './modules/scheduled-tasks.js';
42
45
  import { initPlaybook, openPlaybook, getPlaybooks, getPlaybookForTip, isCompleted as isPlaybookCompleted } from './modules/playbook.js';
43
46
  import { initSTT } from './modules/stt.js';
44
47
  import { initProfile, getProfileLang } from './modules/profile.js';
@@ -73,7 +76,6 @@ import { initSkillInstall, requireSkills as _siRequireSkills, handleSkillInstall
73
76
  import { initDebateUi, showDebateConcludeConfirm as _debShowDebateConcludeConfirm, exitDebateConcludeMode as _debExitDebateConcludeMode, handleDebateConcludeSend as _debHandleDebateConcludeSend, showDebateEndedMode as _debShowDebateEndedMode, exitDebateEndedMode as _debExitDebateEndedMode, showDebateUserFloor as _debShowDebateUserFloor, exitDebateFloorMode as _debExitDebateFloorMode, handleDebateFloorSend as _debHandleDebateFloorSend, renderDebateUserFloorDone as _debRenderDebateUserFloorDone, showDebateSticky as _debShowDebateSticky, showDebateBottomBar as _debShowDebateBottomBar, removeDebateBottomBar as _debRemoveDebateBottomBar, sendDebateStickyComment as _debSendDebateStickyComment, updateDebateRound as _debUpdateDebateRound } from './modules/app-debate-ui.js';
74
77
  import { initLoopUi, updateLoopInputVisibility as _loopUpdateLoopInputVisibility, updateLoopButton as _loopUpdateLoopButton, showLoopBanner as _loopShowLoopBanner, updateLoopBanner as _loopUpdateLoopBanner, updateRalphBars as _loopUpdateRalphBars, showRalphCraftingBar as _loopShowRalphCraftingBar, showRalphApprovalBar as _loopShowRalphApprovalBar, updateRalphApprovalStatus as _loopUpdateRalphApprovalStatus, openRalphPreviewModal as _loopOpenRalphPreviewModal, showExecModal as _loopShowExecModal, closeExecModal as _loopCloseExecModal, updateExecModalStatus as _loopUpdateExecModalStatus } from './modules/app-loop-ui.js';
75
78
  import { initBackgroundTasksUi } from './modules/background-tasks-ui.js';
76
- import { initLoopWizard, openRalphWizard as _loopOpenRalphWizard, closeRalphWizard as _loopCloseRalphWizard, getWizardSource as _loopGetWizardSource } from './modules/app-loop-wizard.js';
77
79
  import { initAppNotifications, handleNotificationsState as _notifHandleState, handleNotificationCreated as _notifHandleCreated, handleNotificationDismissed as _notifHandleDismissed, handleNotificationDismissedAll as _notifHandleDismissedAll } from './modules/app-notifications.js';
78
80
  import { initWhatsNew, handleWhatsNewState as _wnHandleState, handleWhatsNewSeenResult as _wnHandleSeenResult } from './modules/whats-new.js';
79
81
  import { initWhatsNewArticle, openArticle as openWhatsNewArticle } from './modules/whats-new-article.js';
@@ -220,7 +222,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
220
222
  // connected, processing, activeSessionId, sessionDrafts -> store
221
223
  // loopActive, loopAvailable, loopIteration, loopMaxIterations, loopBannerName,
222
224
  // ralphPhase, ralphCraftingSessionId, ralphCraftingSource, ralphFilesReady, ralphPreviewContent -> modules/app-loop-ui.js
223
- // wizardStep, wizardSource, wizardData, loopModeChoice, promptAuthor, judgeAuthor -> modules/app-loop-wizard.js
224
225
  // slashCommands, cliSessionId -> store
225
226
  var projectName = ""; // kept for pre-store localStorage init
226
227
  // turnCounter -> modules/app-rendering.js
@@ -269,6 +270,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
269
270
  splitPanes: null,
270
271
  splitGroups: [],
271
272
  splitDelegations: {},
273
+ notesTemporarilyHidden: false,
272
274
  dmMode: false,
273
275
  historyFrom: 0,
274
276
  loadingMore: false,
@@ -284,8 +286,28 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
284
286
  currentProjectOwnerId: null,
285
287
  isOsUsers: false,
286
288
  skipPermsEnabled: false,
289
+ autonomousSelectedMode: "normal",
290
+ autonomousArming: false,
291
+ autonomousArmToken: null,
292
+ autonomousArmRequestId: null,
293
+ autonomousArmSessionId: null,
294
+ autonomousActionRequestId: null,
295
+ autonomousActionSessionId: null,
296
+ autonomousCriteria: "",
297
+ autonomousMaxContinuations: 10,
298
+ autonomousMaxMinutes: 60,
299
+ autonomousRun: null,
300
+ autonomousExpanded: false,
301
+ loopInterviewBrief: null,
302
+ loopInterviewEditing: false,
303
+ loopInterviewRunRequestId: null,
304
+ loopInterviewRunSessionId: null,
305
+ loopInterviewStarting: false,
306
+ loopInterviewRequestId: null,
307
+ loopInterviewSessionId: null,
287
308
  slashCommands: [],
288
309
  processing: false,
310
+ scheduledMessageCorrelation: null,
289
311
  activeSessionId: null,
290
312
  askUserRequests: {},
291
313
  activeBackgroundTasks: [],
@@ -305,6 +327,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
305
327
  homeActiveSessionByMate: {},
306
328
  homePreferredMateId: null,
307
329
  homeSidebarCollapsed: false,
330
+ homeMatesCollapsed: false,
308
331
  homeChatScope: "all",
309
332
  homeSubSurface: "chat",
310
333
  homeDebatesStatus: "idle",
@@ -344,6 +367,23 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
344
367
  projectLogsCanDelete: false,
345
368
  projectLogsUnread: 0,
346
369
  projectLogsSeenRevisions: {},
370
+ scheduledTasksOpen: false,
371
+ scheduledTasksWide: false,
372
+ scheduledTasksFullscreen: false,
373
+ scheduledTaskRecords: [],
374
+ scheduledTaskDraft: null,
375
+ scheduledTaskEditingId: null,
376
+ scheduledTaskNewSessionPending: false,
377
+ scheduledTaskInterviewRequestId: null,
378
+ scheduledTaskActionRequestId: null,
379
+ scheduledTaskListRequest: null,
380
+ scheduledTaskInterviewId: null,
381
+ scheduledTaskExpandedId: null,
382
+ scheduledTaskDeleteId: null,
383
+ scheduledTaskDraftForm: null,
384
+ scheduledTaskEditForm: null,
385
+ scheduledTaskCreateMenuOpen: false,
386
+ scheduledTaskManualRequest: null,
347
387
  installedTools: [],
348
388
  capsulesEnabled: false,
349
389
  capsulesPreferenceLoaded: false,
@@ -480,7 +520,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
480
520
  switchProject: function (slug) { switchProject(slug); },
481
521
  openTerminal: function () { openTerminal(); },
482
522
  showHomeHub: function () { showHomeHub(); },
483
- openRalphWizard: function (source) { openRalphWizard(source); },
484
523
  getUpcomingSchedules: getUpcomingSchedules,
485
524
  get multiUser() { return store.get('isMultiUserMode'); },
486
525
  get myUserId() { return store.get('myUserId'); },
@@ -501,6 +540,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
501
540
  // mcp-ui.js / etc.) attach click handlers by ID.
502
541
  initToolPalettes();
503
542
  initProjectLogs();
543
+ initScheduledTasks();
504
544
  initSidebar(sidebarCtx);
505
545
  var wsGetter = function () { return _getWsRef(); };
506
546
  initMateSidebar(wsGetter);
@@ -688,7 +728,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
688
728
 
689
729
  initLoopUi();
690
730
  initBackgroundTasksUi();
691
- initLoopWizard();
731
+ initAutonomousRun();
732
+ initLoopInterview();
692
733
 
693
734
  // --- Notifications module ---
694
735
  initAppNotifications();
@@ -975,8 +1016,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
975
1016
  if (msBtn) msBtn.style.display = "none";
976
1017
  }
977
1018
  if (!_perms.scheduledTasks) {
978
- var schBtn = document.getElementById("home-scheduler-btn");
979
- if (schBtn) schBtn.style.display = "none";
980
1019
  var schToolBtn = document.getElementById("scheduler-btn");
981
1020
  if (schToolBtn) schToolBtn.style.display = "none";
982
1021
  }
@@ -1119,13 +1158,14 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
1119
1158
  setBrowserRefresh(function () { if (isNotesBrowserOpen()) renderNotesBrowser(); });
1120
1159
  // Opening the browser claims the single right workbench slot. Registered here
1121
1160
  // so the browser module never imports the other tools.
1122
- registerExclusiveClosers([closeProjectLogs, closeScheduler, closeFileViewer, closeTerminal]);
1161
+ registerExclusiveClosers([closeProjectLogs, closeScheduledTasks, closeFileViewer, closeTerminal]);
1123
1162
 
1124
1163
  // --- Sticky Notes sidebar button (create new note) ---
1125
1164
  var stickyNotesSidebarBtn = $("sticky-notes-sidebar-btn");
1126
1165
  if (stickyNotesSidebarBtn) {
1127
1166
  stickyNotesSidebarBtn.addEventListener("click", function () {
1128
1167
  closeProjectLogs();
1168
+ closeScheduledTasks();
1129
1169
  if (isSchedulerOpen()) closeScheduler();
1130
1170
  if (isNotesBrowserOpen()) closeNotesBrowser();
1131
1171
  showNotes();
@@ -1133,12 +1173,20 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
1133
1173
  });
1134
1174
  }
1135
1175
 
1176
+ var stickyNotesToggleButtons = document.querySelectorAll("#sticky-notes-toggle-btn");
1177
+ for (var stickyToggleIndex = 0; stickyToggleIndex < stickyNotesToggleButtons.length; stickyToggleIndex++) {
1178
+ stickyNotesToggleButtons[stickyToggleIndex].addEventListener("click", function () {
1179
+ toggleNotesTemporaryVisibility();
1180
+ });
1181
+ }
1182
+
1136
1183
  // Sticky Notes badge click → archive toggle
1137
1184
  var stickyNotesBadge = $("sticky-notes-sidebar-count");
1138
1185
  if (stickyNotesBadge) {
1139
1186
  stickyNotesBadge.addEventListener("click", function (e) {
1140
1187
  e.stopPropagation();
1141
1188
  closeProjectLogs();
1189
+ closeScheduledTasks();
1142
1190
  if (isSchedulerOpen()) closeScheduler();
1143
1191
  if (isNotesBrowserOpen()) {
1144
1192
  closeNotesBrowser();
@@ -1152,11 +1200,11 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
1152
1200
  var fileBrowserBtn = $("file-browser-btn");
1153
1201
  var gitPlacardMoreBtn = $("git-placard-more");
1154
1202
  var terminalSidebarBtn = $("terminal-sidebar-btn");
1155
- if (fileBrowserBtn) fileBrowserBtn.addEventListener("click", function () { closeProjectLogs(); if (isNotesBrowserOpen()) closeNotesBrowser(); if (isSchedulerOpen()) closeScheduler(); });
1156
- if (gitPlacardMoreBtn) gitPlacardMoreBtn.addEventListener("click", function () { closeProjectLogs(); if (isNotesBrowserOpen()) closeNotesBrowser(); if (isSchedulerOpen()) closeScheduler(); });
1157
- if (terminalSidebarBtn) terminalSidebarBtn.addEventListener("click", function () { closeProjectLogs(); if (isNotesBrowserOpen()) closeNotesBrowser(); if (isSchedulerOpen()) closeScheduler(); });
1203
+ if (fileBrowserBtn) fileBrowserBtn.addEventListener("click", function () { closeProjectLogs(); closeScheduledTasks(); if (isNotesBrowserOpen()) closeNotesBrowser(); if (isSchedulerOpen()) closeScheduler(); });
1204
+ if (gitPlacardMoreBtn) gitPlacardMoreBtn.addEventListener("click", function () { closeProjectLogs(); closeScheduledTasks(); if (isNotesBrowserOpen()) closeNotesBrowser(); if (isSchedulerOpen()) closeScheduler(); });
1205
+ if (terminalSidebarBtn) terminalSidebarBtn.addEventListener("click", function () { closeProjectLogs(); closeScheduledTasks(); if (isNotesBrowserOpen()) closeNotesBrowser(); if (isSchedulerOpen()) closeScheduler(); });
1158
1206
 
1159
- // --- Ralph Loop UI (delegated to app-loop-ui.js + app-loop-wizard.js) ---
1207
+ // --- Legacy scheduled Loop UI ---
1160
1208
  function updateLoopInputVisibility(loop) { _loopUpdateLoopInputVisibility(loop); }
1161
1209
  function updateLoopButton() { _loopUpdateLoopButton(); }
1162
1210
  function showLoopBanner(show) { _loopShowLoopBanner(show); }
@@ -1193,9 +1241,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
1193
1241
  });
1194
1242
  }
1195
1243
 
1196
- // --- Ralph Wizard (delegated to app-loop-wizard.js) ---
1197
- function openRalphWizard(source) { _loopOpenRalphWizard(source); }
1198
- function closeRalphWizard() { _loopCloseRalphWizard(); }
1199
1244
 
1200
1245
  // --- Debate UI (delegated to app-debate-ui.js) ---
1201
1246
  // debateStickyState, debateHandRaiseOpen, debateFloorMode, debateConcludeMode, debateEndedMode -> modules/app-debate-ui.js
@@ -1229,14 +1274,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
1229
1274
  get activeSessionId() { return store.get('activeSessionId'); },
1230
1275
  basePath: basePath,
1231
1276
  currentSlug: currentSlug, // init-time snapshot, scheduler uses for initial setup
1232
- openRalphWizard: function (source) { openRalphWizard(source); },
1233
- requireClayRalph: function (cb) {
1234
- requireSkills({
1235
- title: "Skill Installation Required",
1236
- reason: "This feature requires the following skill to be installed.",
1237
- skills: [{ name: "clay-ralph", url: "https://github.com/chadbyte/clay-ralph", scope: "global" }]
1238
- }, cb);
1239
- },
1240
1277
  getProjects: function () { return getCachedProjects(); },
1241
1278
  });
1242
1279
 
@@ -9,6 +9,7 @@ body.home-active #mate-sidebar-column,
9
9
  body.home-active #sidebar-resize-handle,
10
10
  body.home-active #mate-sidebar-resize-handle,
11
11
  body.home-active #sidebar-overlay,
12
+ body.home-active #mobile-tab-bar,
12
13
  body.home-active .title-bar-content,
13
14
  body.home-active #user-island { display: none !important; }
14
15
 
@@ -935,7 +936,7 @@ body.home-surface-boot-pending #connect-overlay.hidden {
935
936
  }
936
937
 
937
938
  @media (max-width: 900px) {
938
- #home-hub { padding: calc(6px + var(--safe-top)) 8px calc(68px + var(--safe-bottom, 0px)); }
939
+ #home-hub { padding: calc(6px + var(--safe-top)) 8px calc(8px + var(--safe-bottom, 0px)); }
939
940
 
940
941
  .home-hub-inner {
941
942
  height: 100%;
@@ -980,9 +981,21 @@ body.home-surface-boot-pending #connect-overlay.hidden {
980
981
  }
981
982
 
982
983
  @media (max-width: 768px) {
984
+ #home-hub:not(.dock-split):not(.dock-focus) .home-mate-chat-stage {
985
+ padding-top: 52px;
986
+ }
987
+
988
+ #home-hub:not(.dock-split):not(.dock-focus) .home-mate-chat-messages {
989
+ padding-top: 8px;
990
+ }
991
+
992
+ #home-hub:not(.dock-split):not(.dock-focus) .home-mate-chat-composer-frame {
993
+ margin-bottom: 0;
994
+ }
995
+
983
996
  #home-hub.dock-split,
984
997
  #home-hub.dock-focus {
985
- padding: var(--safe-top) 0 calc(56px + var(--safe-bottom, 0px));
998
+ padding: var(--safe-top) 0 var(--safe-bottom, 0px);
986
999
  }
987
1000
 
988
1001
  .home-workspace { flex-direction: column; }
@@ -223,6 +223,50 @@
223
223
  padding-left: 7px;
224
224
  }
225
225
 
226
+ .home-sidebar-mate-toggle {
227
+ display: flex;
228
+ align-items: center;
229
+ justify-content: space-between;
230
+ width: 100%;
231
+ min-height: 25px;
232
+ border: 0;
233
+ background: transparent;
234
+ color: var(--text-dimmer);
235
+ font: inherit;
236
+ font-size: 9px;
237
+ font-weight: 680;
238
+ letter-spacing: 0.09em;
239
+ line-height: 1.2;
240
+ text-align: left;
241
+ text-transform: uppercase;
242
+ cursor: pointer;
243
+ }
244
+
245
+ .home-sidebar-mate-toggle:hover,
246
+ .home-sidebar-mate-toggle:focus-visible {
247
+ color: var(--text-secondary);
248
+ }
249
+
250
+ .home-sidebar-mate-toggle:focus-visible {
251
+ outline: 2px solid var(--accent);
252
+ outline-offset: -2px;
253
+ border-radius: 5px;
254
+ }
255
+
256
+ .home-sidebar-mate-toggle .lucide {
257
+ width: 12px;
258
+ height: 12px;
259
+ transition: transform 140ms ease;
260
+ }
261
+
262
+ .home-sidebar-mate-toggle[aria-expanded="false"] .lucide {
263
+ transform: rotate(-90deg);
264
+ }
265
+
266
+ .home-sidebar-mates-collapsed .home-mate-list {
267
+ display: none;
268
+ }
269
+
226
270
  .home-mate-list {
227
271
  flex: 0 0 var(--home-mate-list-height);
228
272
  display: flex;
@@ -693,7 +737,7 @@
693
737
  position: absolute;
694
738
  z-index: 8;
695
739
  top: calc(8px + var(--safe-top));
696
- bottom: calc(64px + var(--safe-bottom, 0px));
740
+ bottom: calc(8px + var(--safe-bottom, 0px));
697
741
  left: 8px;
698
742
  width: min(320px, calc(100vw - 24px));
699
743
  padding: 6px;
@@ -701,6 +745,10 @@
701
745
  border-radius: 12px;
702
746
  box-shadow: 12px 18px 44px rgba(var(--shadow-rgb), 0.22);
703
747
  }
748
+ .home-sidebar-mate-toggle {
749
+ width: 100%;
750
+ min-height: 36px;
751
+ }
704
752
  .home-sidebar-backdrop {
705
753
  position: absolute;
706
754
  z-index: 7;
@@ -710,7 +758,7 @@
710
758
  background: rgba(var(--shadow-rgb), 0.13);
711
759
  }
712
760
  #home-hub.home-sidebar-collapsed .home-sidebar-backdrop { display: none; }
713
- .home-conversations-sheet { align-items: flex-end; padding: 8px 8px calc(64px + var(--safe-bottom, 0px)); }
761
+ .home-conversations-sheet { align-items: flex-end; padding: 8px 8px calc(8px + var(--safe-bottom, 0px)); }
714
762
  .home-conversations-sheet-panel { width: 100%; max-height: calc(100vh - 84px); border-radius: 14px 14px 10px 10px; }
715
763
  }
716
764
 
@@ -747,6 +747,77 @@
747
747
  position: relative;
748
748
  }
749
749
 
750
+ /* Until complete keeps the composer's visual language: compact, quiet, and
751
+ explicit about the Driver assessment rather than presenting a second app. */
752
+ .execution-mode-wrap { position: relative; flex: none; }
753
+ .execution-mode-wrap.hidden { display: none; }
754
+ #loop-interview-btn { flex: none; }
755
+ #loop-interview-btn.arming { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); }
756
+ #loop-interview-card { max-width: var(--content-width); max-height: min(260px, 35vh); overflow-y: auto; margin: 0 auto 8px; padding: 12px 14px; border: 1px solid var(--border-subtle); border-radius: 12px; background: var(--surface); }
757
+ #loop-interview-card.hidden { display: none; }
758
+ .loop-interview-objective, .loop-interview-criteria { margin-top: 6px; white-space: pre-wrap; }
759
+ .loop-interview-criteria { color: var(--text-muted); font-size: 12px; }
760
+ .loop-interview-limits, .loop-interview-disclosure { margin-top: 6px; color: var(--text-muted); font-size: 11px; }
761
+ .loop-interview-actions { display: flex; gap: 8px; margin-top: 10px; }
762
+ .loop-interview-actions button { padding: 5px 10px; border: 1px solid var(--border-subtle); border-radius: 7px; background: transparent; color: var(--text); cursor: pointer; }
763
+ #execution-mode-btn {
764
+ display: inline-flex; align-items: center; gap: 5px; height: 30px; padding: 0 9px;
765
+ border: 1px solid var(--border-subtle); border-radius: 9px; background: transparent;
766
+ color: var(--text-muted); font: inherit; font-size: 11px; cursor: pointer;
767
+ transition: color .15s ease, border-color .15s ease, background .15s ease;
768
+ }
769
+ #execution-mode-btn:hover:not(:disabled) { color: var(--text); border-color: var(--border); }
770
+ #execution-mode-btn.active { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); background: color-mix(in srgb, var(--accent) 8%, transparent); }
771
+ #execution-mode-btn:disabled { cursor: default; opacity: .45; }
772
+ #execution-mode-btn .lucide { width: 12px; height: 12px; }
773
+ #execution-mode-btn .lucide:last-child { width: 10px; height: 10px; }
774
+ .execution-mode-popover {
775
+ position: absolute; z-index: 80; right: 0; bottom: calc(100% + 8px); width: min(310px, calc(100vw - 32px));
776
+ padding: 7px; border: 1px solid var(--border); border-radius: 14px; background: var(--bg-elevated, var(--bg));
777
+ box-shadow: 0 18px 48px rgba(0, 0, 0, .18);
778
+ }
779
+ .execution-mode-popover.hidden { display: none; }
780
+ .execution-mode-option, .execution-mode-enable { width: 100%; border: 0; font: inherit; cursor: pointer; }
781
+ .execution-mode-option { display: flex; align-items: baseline; justify-content: space-between; padding: 9px 10px; border-radius: 9px; background: transparent; color: var(--text); text-align: left; }
782
+ .execution-mode-option:hover { background: rgba(var(--overlay-rgb), .06); }
783
+ .execution-mode-option span, .execution-until-settings > div > span { color: var(--text-muted); font-size: 11px; }
784
+ .execution-until-settings { margin-top: 5px; padding: 11px; border: 1px solid color-mix(in srgb, var(--accent) 26%, var(--border)); border-radius: 10px; background: color-mix(in srgb, var(--accent) 5%, transparent); }
785
+ .execution-until-settings > div:first-child { display: flex; flex-direction: column; gap: 2px; margin-bottom: 10px; }
786
+ .execution-until-settings label { display: flex; flex-direction: column; gap: 5px; color: var(--text-muted); font-size: 10px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; }
787
+ .execution-until-settings textarea, .execution-until-settings input { box-sizing: border-box; width: 100%; border: 1px solid var(--border); border-radius: 7px; background: var(--input-bg); color: var(--text); font: inherit; font-size: 12px; text-transform: none; letter-spacing: 0; outline: none; }
788
+ .execution-until-settings textarea { padding: 7px 8px; resize: vertical; min-height: 50px; }
789
+ .execution-until-settings input { height: 30px; padding: 0 7px; }
790
+ .execution-until-settings textarea:focus, .execution-until-settings input:focus { border-color: var(--accent); }
791
+ .execution-limit-row { display: grid !important; grid-template-columns: 1fr 1fr; gap: 8px; margin: 9px 0 !important; }
792
+ .execution-mode-enable { padding: 8px 10px; border-radius: 8px; background: var(--accent); color: var(--bg); font-size: 12px; font-weight: 650; }
793
+ .autonomous-run-status { display: grid; grid-template-columns: 1fr auto; align-items: center; margin: 0 0 6px; border: 1px solid color-mix(in srgb, var(--accent) 26%, var(--border)); border-radius: 10px; background: color-mix(in srgb, var(--accent) 4%, transparent); overflow: hidden; }
794
+ .autonomous-run-status.hidden { display: none; }
795
+ .autonomous-run-summary { display: flex; align-items: center; gap: 8px; min-width: 0; padding: 7px 10px; border: 0; background: transparent; color: var(--text-secondary); font: inherit; font-size: 12px; cursor: pointer; text-align: left; }
796
+ .autonomous-run-summary #autonomous-run-state { font-weight: 650; color: var(--text); }
797
+ #autonomous-run-progress { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-muted); font-size: 11px; }
798
+ .autonomous-run-mark { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent); }
799
+ .autonomous-run-status.terminal .autonomous-run-mark { background: var(--text-muted); box-shadow: none; }
800
+ .autonomous-run-summary .lucide { width: 13px; height: 13px; transition: transform .15s ease; }
801
+ .autonomous-run-status.expanded .autonomous-run-summary .lucide { transform: rotate(180deg); }
802
+ .autonomous-run-actions { display: flex; gap: 5px; padding-right: 7px; }
803
+ .autonomous-run-actions button { border: 1px solid var(--border); border-radius: 7px; padding: 4px 8px; background: transparent; color: var(--text-muted); font: inherit; font-size: 11px; cursor: pointer; }
804
+ .autonomous-run-actions button:hover { color: var(--text); }
805
+ .autonomous-run-actions button.hidden { display: none; }
806
+ .autonomous-run-detail { display: none; grid-column: 1 / -1; padding: 2px 10px 9px; }
807
+ .autonomous-run-status.expanded .autonomous-run-detail { display: block; }
808
+ .autonomous-run-detail-row { display: grid; grid-template-columns: 105px 1fr; gap: 10px; padding: 6px 0; border-top: 1px solid var(--border-subtle); font-size: 11px; white-space: pre-wrap; }
809
+ .autonomous-run-detail-row > span:first-child { color: var(--text-muted); }
810
+ .autonomous-run-detail-row > span:last-child { color: var(--text-secondary); }
811
+
812
+ @media (max-width: 600px) {
813
+ #execution-mode-btn { width: auto; max-width: 116px; padding: 0 7px; justify-content: center; }
814
+ #execution-mode-label { display: inline; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
815
+ #execution-mode-btn .lucide:last-child { display: none; }
816
+ .autonomous-run-summary { gap: 6px; }
817
+ #autonomous-run-progress { display: none; }
818
+ .autonomous-run-detail-row { grid-template-columns: 1fr; gap: 3px; }
819
+ }
820
+
750
821
  /* Sidebar session-row badge. Formerly shared its rule with the composer's
751
822
  background-tasks chip; it is standalone now that the composer bar no longer
752
823
  uses a filled numeric badge. */
@@ -2790,7 +2790,6 @@ body.mate-dm-active .activity-inline:not(.mention-activity-bar):not(.mate-pre-ac
2790
2790
  body.mate-dm-active .title-bar-content #todo-sticky,
2791
2791
  body.mate-dm-active .title-bar-content #ralph-sticky,
2792
2792
  body.mate-dm-active .dm-header-bar,
2793
- body.mate-dm-active .title-bar-content .status #sticky-notes-toggle-btn,
2794
2793
  body.mate-dm-active .title-bar-content .status #terminal-toggle-btn {
2795
2794
  display: none !important;
2796
2795
  }
@@ -45,9 +45,11 @@ body.pane-mode #app {
45
45
  }
46
46
 
47
47
  /* Narrow panes cross the mobile breakpoint, but pane mode hides the mobile
48
- tab bar. Keep the normal composer inset instead of reserving its 56px. */
48
+ tab bar. The parent split shell owns the mobile safe-area reservation. */
49
49
  body.pane-mode #input-area {
50
- padding-bottom: calc(var(--safe-bottom) + 8px);
50
+ /* The parent split shell owns the mobile safe area. Keeping it out of the
51
+ iframe prevents the Driver composer from receiving the inset twice. */
52
+ padding-bottom: 8px;
51
53
  }
52
54
 
53
55
  #main-panels {
@@ -430,9 +432,31 @@ body.pane-mode #input-area {
430
432
  /* Portrait phones have enough height for two useful panes but not enough
431
433
  width for two readable transcripts. Keep the role order independent from
432
434
  the persisted member order so the Split Worker stays above its Driver. */
435
+ @media (max-width: 768px) {
436
+ /* The mobile tab bar is fixed outside this flex tree. Reserve its usable
437
+ height once in the parent shell, not independently in either iframe. */
438
+ #main-panels:has(> #split-host.visible) {
439
+ padding-bottom: calc(56px + var(--safe-bottom, 0px));
440
+ }
441
+
442
+ body.keyboard-open #main-panels:has(> #split-host.visible) {
443
+ padding-bottom: 0;
444
+ }
445
+ }
446
+
433
447
  @media (max-width: 768px) and (orientation: portrait) {
448
+ /* These dimensions are also used by the divider marker below. */
449
+ #split-host.visible {
450
+ --split-shell-inset: 8px;
451
+ --split-pane-gap: 8px;
452
+ --split-pane-gap-half: 4px;
453
+ --split-worker-height: calc(30% - 4.8px);
454
+ }
455
+
434
456
  #split-host.visible {
435
457
  flex-direction: column;
458
+ gap: var(--split-pane-gap);
459
+ padding: var(--split-shell-inset);
436
460
  }
437
461
 
438
462
  .split-pane {
@@ -453,16 +477,43 @@ body.pane-mode #input-area {
453
477
  order: 0;
454
478
  }
455
479
 
456
- .split-pane:first-child.split-pane-role-worker {
457
- border-top: 0;
480
+ /* A configured Worker is an execution summary; the Driver keeps the
481
+ generous lower surface for transcript review and composing. Ad-hoc
482
+ splits retain the equal fallback above. */
483
+ .split-pane.split-pane-role-worker {
484
+ flex: 0 0 30%;
485
+ border: 1px solid var(--border-subtle);
486
+ border-radius: 11px;
487
+ background: color-mix(in srgb, var(--bg-alt) 58%, var(--bg));
488
+ overflow: hidden;
458
489
  }
459
490
 
460
- .split-pane.split-pane-role-worker {
461
- border-top: 0;
491
+ .split-pane-role-worker .split-pane-header {
492
+ height: 26px;
493
+ background: transparent;
494
+ }
495
+
496
+ .split-pane-role-worker .split-pane-title {
497
+ display: none;
498
+ }
499
+
500
+ .split-pane-role-worker .split-pair-live {
501
+ order: 3;
502
+ }
503
+
504
+ .split-pane-role-worker .split-pane-close {
505
+ order: 2;
506
+ }
507
+
508
+ .split-pane-role-driver {
509
+ flex: 1 1 auto;
462
510
  }
463
511
 
464
- #split-host.split-delegating::after {
512
+ #split-host:has(.split-pane-role-worker).split-delegating::after {
465
513
  content: "↑";
514
+ /* Center on worker bottom + half the gap, accounting for the shell
515
+ inset and the 30% basis being relative to the inset content box. */
516
+ top: calc(var(--split-shell-inset) + var(--split-worker-height) + var(--split-pane-gap-half) - 10px);
466
517
  animation-name: pair-divider-flow-up;
467
518
  }
468
519
 
@@ -428,12 +428,20 @@
428
428
  .ask-user-other input:focus { border-color: var(--text-dimmer); }
429
429
  .ask-user-other input::placeholder { color: var(--text-muted); }
430
430
 
431
+ .ask-user-actions {
432
+ display: flex;
433
+ align-items: center;
434
+ gap: 8px;
435
+ margin-top: 14px;
436
+ }
437
+
431
438
  .ask-user-submit {
432
439
  background: var(--accent);
433
440
  color: #fff;
434
441
  border: none;
435
442
  border-radius: 10px;
436
- padding: 10px 18px;
443
+ min-height: 36px;
444
+ padding: 8px 18px;
437
445
  font-size: 13px;
438
446
  font-weight: 600;
439
447
  cursor: pointer;
@@ -448,7 +456,8 @@
448
456
  background: transparent;
449
457
  border: 1px solid var(--border);
450
458
  border-radius: 10px;
451
- padding: 7px 18px;
459
+ min-height: 36px;
460
+ padding: 8px 18px;
452
461
  font-size: 13px;
453
462
  font-weight: 500;
454
463
  font-family: inherit;