clay-server 5.2.0-beta.4 → 5.2.0-beta.5

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 (171) hide show
  1. package/lib/account-auth-socket.js +1 -0
  2. package/lib/builtin-mates.js +17 -14
  3. package/lib/canonical-clay-record-authority.js +15 -0
  4. package/lib/canonical-clay-scheduling-authority.js +19 -0
  5. package/lib/claude-hook-installer.js +28 -0
  6. package/lib/clay-mate-chat-receipts.js +26 -0
  7. package/lib/clay-mate-chat.js +87 -0
  8. package/lib/clay-mate-knowledge-input.js +26 -0
  9. package/lib/clay-mate-knowledge.js +95 -0
  10. package/lib/clay-mate-lifecycle.js +95 -0
  11. package/lib/clay-product-control-input.js +33 -0
  12. package/lib/clay-product-control-tools.js +51 -0
  13. package/lib/clay-product-control.js +237 -0
  14. package/lib/clay-project-lifecycle.js +154 -0
  15. package/lib/clay-project-record-input.js +44 -0
  16. package/lib/clay-project-records.js +83 -0
  17. package/lib/clay-scheduling-input.js +21 -0
  18. package/lib/clay-scheduling-receipts.js +26 -0
  19. package/lib/clay-scheduling.js +119 -0
  20. package/lib/clay-screen-controls.js +96 -0
  21. package/lib/clay-workspace-controls.js +83 -0
  22. package/lib/clay-workspace-input.js +17 -0
  23. package/lib/clay-workspace-receipts.js +26 -0
  24. package/lib/daemon-project-access.js +11 -0
  25. package/lib/daemon-project-lifecycle-callbacks.js +15 -0
  26. package/lib/daemon-project-lifecycle.js +262 -0
  27. package/lib/daemon-projects.js +1 -1
  28. package/lib/daemon.js +73 -221
  29. package/lib/issues-service.js +29 -15
  30. package/lib/knowledge-db-import.js +5 -4
  31. package/lib/knowledge-db-service.js +9 -6
  32. package/lib/knowledge-document-index.js +2 -1
  33. package/lib/knowledge-product-operations.js +46 -0
  34. package/lib/mate-creation-mcp-server.js +2 -0
  35. package/lib/mate-knowledge-canonical-access.js +10 -0
  36. package/lib/mate-knowledge-service.js +7 -4
  37. package/lib/mate-lifecycle-service.js +94 -0
  38. package/lib/mate-message-delivery.js +43 -0
  39. package/lib/mate-ready-creation.js +9 -1
  40. package/lib/mate-schedule-input.js +29 -0
  41. package/lib/mate-schedule-lifecycle.js +151 -0
  42. package/lib/mate-scheduling.js +103 -0
  43. package/lib/mates.js +4 -3
  44. package/lib/notes-checklist.js +50 -0
  45. package/lib/notes.js +49 -3
  46. package/lib/os-users.js +20 -5
  47. package/lib/project-admin-overview.js +51 -0
  48. package/lib/project-ask-user.js +4 -2
  49. package/lib/project-delegated-follow-up.js +2 -1
  50. package/lib/project-directory-claim.js +65 -0
  51. package/lib/project-file-operations.js +61 -0
  52. package/lib/project-filesystem.js +13 -87
  53. package/lib/project-full-access.js +23 -2
  54. package/lib/project-knowledge.js +32 -18
  55. package/lib/project-lifecycle-operations.js +98 -0
  56. package/lib/project-lifecycle-process-witness.js +32 -0
  57. package/lib/project-lifecycle-runtime.js +50 -0
  58. package/lib/project-linux-access.js +22 -0
  59. package/lib/project-logs-canonical-clay.js +27 -0
  60. package/lib/project-logs-clay-query.js +16 -0
  61. package/lib/project-logs-schema.js +4 -2
  62. package/lib/project-logs-service.js +8 -7
  63. package/lib/project-logs.js +1 -0
  64. package/lib/project-loop.js +1 -0
  65. package/lib/project-mate-chat-control.js +55 -0
  66. package/lib/project-mate-creation-proposal.js +18 -3
  67. package/lib/project-models.js +14 -31
  68. package/lib/project-notifications.js +74 -16
  69. package/lib/project-ownership.js +77 -0
  70. package/lib/project-pair-result-delivery.js +14 -3
  71. package/lib/project-pending-message-queue.js +1 -0
  72. package/lib/project-product-control.js +87 -0
  73. package/lib/project-product-session-queue.js +46 -0
  74. package/lib/project-push-access.js +28 -0
  75. package/lib/project-scheduled-message-queue.js +30 -0
  76. package/lib/project-scheduled-messages.js +63 -64
  77. package/lib/project-scheduled-task-control.js +83 -0
  78. package/lib/project-scheduled-tasks.js +13 -2
  79. package/lib/project-scheduling-access.js +10 -0
  80. package/lib/project-session-actions.js +65 -0
  81. package/lib/project-session-delete.js +8 -1
  82. package/lib/project-session-github.js +47 -12
  83. package/lib/project-session-history-actions.js +165 -0
  84. package/lib/project-session-runtime-actions.js +63 -0
  85. package/lib/project-session-vendor.js +54 -0
  86. package/lib/project-sessions.js +64 -241
  87. package/lib/project-user-message.js +30 -1
  88. package/lib/project-workspace-operations.js +126 -0
  89. package/lib/project-workspace-query.js +9 -2
  90. package/lib/project.js +95 -3
  91. package/lib/public/css/clay-tool-activity.css +51 -0
  92. package/lib/public/css/home-mate-creation.css +5 -0
  93. package/lib/public/css/overlays.css +4 -2
  94. package/lib/public/css/project-admin-overview.css +13 -0
  95. package/lib/public/css/session-folders.css +11 -0
  96. package/lib/public/css/session-github.css +3 -0
  97. package/lib/public/css/sticky-notes.css +61 -1
  98. package/lib/public/index.html +1 -1
  99. package/lib/public/modules/admin-settings-projects.js +6 -2
  100. package/lib/public/modules/app-connection.js +8 -1
  101. package/lib/public/modules/app-message-router.js +1 -1
  102. package/lib/public/modules/app-messages.js +18 -3
  103. package/lib/public/modules/app-projects.js +5 -0
  104. package/lib/public/modules/clay-owner-navigation.js +27 -0
  105. package/lib/public/modules/clay-tool-activity.js +140 -0
  106. package/lib/public/modules/clay-tool-presentation.js +338 -0
  107. package/lib/public/modules/command-palette.js +1 -1
  108. package/lib/public/modules/default-ai.js +11 -3
  109. package/lib/public/modules/home-debate-planning.js +5 -5
  110. package/lib/public/modules/home-mate-chat.js +8 -6
  111. package/lib/public/modules/home-mate-creation.js +73 -1
  112. package/lib/public/modules/personal-settings-dialog.js +7 -1
  113. package/lib/public/modules/project-access-recovery.js +17 -0
  114. package/lib/public/modules/project-admin-overview.js +21 -0
  115. package/lib/public/modules/session-folder-layout.js +1 -1
  116. package/lib/public/modules/session-folder-view-menu.js +9 -0
  117. package/lib/public/modules/session-github.js +65 -8
  118. package/lib/public/modules/sidebar-session-folders-ui.js +1 -1
  119. package/lib/public/modules/sticky-note-markdown.js +72 -6
  120. package/lib/public/modules/sticky-notes-actions.js +30 -0
  121. package/lib/public/modules/sticky-notes-browser.js +9 -2
  122. package/lib/public/modules/sticky-notes-card.js +23 -7
  123. package/lib/public/modules/sticky-notes-checklist.js +71 -0
  124. package/lib/public/modules/sticky-notes-editor.js +108 -44
  125. package/lib/public/modules/sticky-notes-shared.js +50 -2
  126. package/lib/public/modules/sticky-notes-state.js +66 -0
  127. package/lib/public/modules/sticky-notes.js +34 -51
  128. package/lib/public/modules/thinking-lifecycle.js +33 -3
  129. package/lib/public/modules/thinking-view.js +23 -1
  130. package/lib/public/modules/tools.js +34 -6
  131. package/lib/public/modules/user-settings-appearance.js +10 -3
  132. package/lib/public/modules/user-settings-editors.js +1 -1
  133. package/lib/public/modules/user-settings-layout.js +11 -2
  134. package/lib/public/modules/user-settings-preferences.js +6 -2
  135. package/lib/public/modules/user-settings-profile.js +12 -2
  136. package/lib/public/modules/user-settings.js +3 -2
  137. package/lib/public/style.css +2 -0
  138. package/lib/scheduled-task-records.js +3 -1
  139. package/lib/scheduler.js +2 -0
  140. package/lib/sdk-bridge.js +220 -21
  141. package/lib/sdk-message-processor.js +2 -0
  142. package/lib/sdk-response-recovery.js +155 -0
  143. package/lib/server-admin.js +63 -16
  144. package/lib/server-dm.js +1 -1
  145. package/lib/server-global-ws.js +10 -20
  146. package/lib/server-home-chat-events.js +7 -3
  147. package/lib/server-home-chat.js +4 -16
  148. package/lib/server-home-mate-creation.js +1 -0
  149. package/lib/server-home-mcp-consent.js +3 -3
  150. package/lib/server-mates.js +25 -67
  151. package/lib/server-owner-ui.js +77 -0
  152. package/lib/server-path-access.js +38 -0
  153. package/lib/server-project-removal.js +22 -0
  154. package/lib/server.js +99 -29
  155. package/lib/session-config-transition.js +45 -0
  156. package/lib/session-folders.js +7 -2
  157. package/lib/session-github.js +9 -2
  158. package/lib/session-visibility.js +5 -2
  159. package/lib/sessions.js +10 -0
  160. package/lib/terminal-manager.js +52 -0
  161. package/lib/users-permissions.js +2 -8
  162. package/lib/users.js +4 -0
  163. package/lib/workspace-query-access.js +4 -1
  164. package/lib/ws-schema.js +8 -2
  165. package/lib/yoke/adapters/claude.js +47 -8
  166. package/lib/yoke/adapters/codex.js +52 -111
  167. package/lib/yoke/claude-worker-startup.js +28 -0
  168. package/lib/yoke/codex-idle-recovery.js +81 -1
  169. package/lib/yoke/codex-recovery-admission.js +164 -0
  170. package/lib/yoke/session-tool-transport.js +3 -0
  171. package/package.json +1 -1
@@ -0,0 +1,338 @@
1
+ // Exact Clay catalogs: project-user-knowledge, session-notes/project-logs/issues-mcp-server,
2
+ // session-pair-mcp-server, mate-scheduling and the query-bound SDK bridge catalogs.
3
+ var definitions = Object.create(null);
4
+ var aliases = Object.create(null);
5
+
6
+ function register(server, name, running, completed, noun, subject, rule) {
7
+ definitions[name] = { name: name, running: running, completed: completed, noun: noun, subject: subject, rule: rule };
8
+ [name, server + '__' + name, 'mcp__' + server + '__' + name,
9
+ 'mcp__clay-session-tools__' + server + '__' + name].forEach(function (alias) { aliases[alias] = name; });
10
+ }
11
+ function rows(server, entries) {
12
+ entries.forEach(function (entry) { register.apply(null, [server].concat(entry)); });
13
+ }
14
+ rows('clay-you', [
15
+ ['search_user_knowledge', 'Checking your preferences', 'Preferences checked', 'Preference search', 'query'],
16
+ ['read_user_knowledge', 'Reading your preference', 'Preference read', 'Preference'],
17
+ ['report_user_observation', 'Submitting preference for review', 'Preference submitted for review', 'Preference submission', null, 'observation'],
18
+ ['list_user_observations', 'Checking preferences awaiting review', 'Pending preferences checked', 'Preference review'],
19
+ ['curate_user_knowledge', 'Reviewing preference', 'Preference review returned', 'Preference review', 'title', 'curation']
20
+ ]);
21
+ rows('clay-notes', [
22
+ ['list_notes', 'Checking sticky notes', 'Sticky notes checked', 'Sticky notes'],
23
+ ['write_note', 'Adding sticky note', 'Sticky note added', 'Sticky note', 'note', 'note'],
24
+ ['close_note', 'Closing sticky note', 'Sticky note closed', 'Sticky note'],
25
+ ['remove_note', 'Closing sticky note', 'Sticky note closed', 'Sticky note'],
26
+ ['reopen_note', 'Reopening sticky note', 'Sticky note reopened', 'Sticky note']
27
+ ]);
28
+ rows('clay-logs', [
29
+ ['list_logs', 'Checking project logs', 'Project logs checked', 'Project logs'],
30
+ ['search_logs', 'Searching project logs', 'Project logs searched', 'Log search', 'query'],
31
+ ['read_log', 'Reading project log', 'Project log read', 'Project log'],
32
+ ['log_history', 'Reading log history', 'Log history read', 'Log history'],
33
+ ['read_log_revision', 'Reading log revision', 'Log revision read', 'Log revision'],
34
+ ['create_log', 'Adding project log', 'Project log added', 'Project log', 'title'],
35
+ ['update_log', 'Updating project log', 'Project log updated', 'Project log', 'title'],
36
+ ['link_log', 'Linking project log', 'Project log linked', 'Project log'],
37
+ ['revert_log', 'Restoring log revision', 'Log revision restored', 'Log revision'],
38
+ ['list_log_feedback', 'Checking log comments', 'Log comments checked', 'Log comments'],
39
+ ['review_log_comment', 'Reviewing log comment', 'Log comment reviewed', 'Log comment'],
40
+ ['list_project_logs', 'Checking project logs', 'Project logs checked', 'Project logs'],
41
+ ['search_project_logs', 'Searching project logs', 'Project logs searched', 'Log search', 'query'],
42
+ ['read_project_log', 'Reading project log', 'Project log read', 'Project log'],
43
+ ['read_project_log_revision', 'Reading log revision', 'Log revision read', 'Log revision'],
44
+ ['project_log_history', 'Reading log history', 'Log history read', 'Log history']
45
+ ]);
46
+ rows('clay-issues', [
47
+ ['list_issues', 'Checking project issues', 'Project issues checked', 'Project issues'],
48
+ ['search_issues', 'Searching project issues', 'Project issues searched', 'Issue search', 'query'],
49
+ ['read_issue', 'Reading project issue', 'Project issue read', 'Project issue'],
50
+ ['create_issue', 'Adding project issue', 'Project issue added', 'Project issue', 'title'],
51
+ ['update_issue', 'Updating project issue', 'Project issue updated', 'Project issue', 'title'],
52
+ ['issue_history', 'Reading issue history', 'Issue history read', 'Issue history'],
53
+ ['read_issue_revision', 'Reading issue revision', 'Issue revision read', 'Issue revision'],
54
+ ['list_issue_feedback', 'Checking issue comments', 'Issue comments checked', 'Issue comments'],
55
+ ['review_issue_comment', 'Reviewing issue comment', 'Issue comment reviewed', 'Issue comment']
56
+ ]);
57
+ rows('clay-sessions', [
58
+ ['send_to_partner', 'Sending task to Worker', 'Worker task request returned', 'Worker task', 'worker', 'worker'],
59
+ ['message_partner', 'Sending message to Worker', 'Worker message request returned', 'Worker message', 'worker', 'message'],
60
+ ['read_partner', 'Checking Worker conversation', 'Worker conversation checked', 'Worker conversation', 'worker'],
61
+ ['partner_status', 'Checking Worker status', 'Worker status checked', 'Worker status', 'worker'],
62
+ ['interrupt_partner', 'Requesting Worker stop', 'Worker stop requested', 'Worker stop', 'worker'],
63
+ ['close_partner', 'Closing Worker pane', 'Worker pane closed', 'Worker pane', 'worker'],
64
+ ['propose_worker', 'Proposing Worker', 'Worker proposal returned', 'Worker proposal', null, 'proposal'],
65
+ ['replace_partner', 'Proposing Worker replacement', 'Worker replacement proposal returned', 'Worker replacement', 'worker', 'proposal'],
66
+ ['inspect_worker_proposal', 'Checking Worker proposal', 'Worker proposal checked', 'Worker proposal'],
67
+ ['cancel_worker_proposal', 'Cancelling Worker proposal', 'Worker proposal cancelled', 'Worker proposal'],
68
+ ['worker_runtime_catalog', 'Checking Worker runtimes', 'Worker runtimes checked', 'Worker runtimes'],
69
+ ['queue_partner_followup', 'Queuing Worker follow-up', 'Worker follow-up request returned', 'Worker follow-up', 'worker', 'message'],
70
+ ['inspect_partner_followups', 'Checking Worker follow-ups', 'Worker follow-ups checked', 'Worker follow-ups', 'worker'],
71
+ ['cancel_partner_followup', 'Cancelling Worker follow-up', 'Worker follow-up cancellation returned', 'Worker follow-up', 'worker'],
72
+ ['replace_partner_task', 'Replacing Worker task', 'Worker task replacement returned', 'Worker task', 'worker'],
73
+ ['resume_partner_task', 'Resuming Worker task', 'Worker task resume returned', 'Worker task', 'worker'],
74
+ ['report_partner_outcome', 'Reporting Worker result', 'Worker result reported', 'Worker result'],
75
+ ['record_partner_evaluation', 'Recording Worker assessment', 'Worker assessment recorded', 'Worker assessment', 'worker'],
76
+ ['respond_to_worker_permission', 'Responding to Worker permission', 'Worker permission response returned', 'Worker permission', 'worker'],
77
+ ['respond_to_worker_question', 'Responding to Worker question', 'Worker question response returned', 'Worker question', 'worker']
78
+ ]);
79
+ rows('clay-shared-browser', [['shared_browser', 'Using browser', 'Browser action returned', 'Browser action', 'site', 'browser']]);
80
+ ['github', 'linear'].forEach(function (provider) {
81
+ var title = provider === 'github' ? 'GitHub work' : 'Linear issue';
82
+ rows('clay-' + provider, [
83
+ ['get_session_' + provider, 'Checking linked ' + title, 'Linked ' + title + ' checked', title],
84
+ ['link_session_' + provider, 'Linking ' + title, title + ' linked', title],
85
+ ['unlink_session_' + provider, 'Unlinking ' + title, title + ' unlinked', title]
86
+ ]);
87
+ });
88
+ rows('clay-linear', [['search_linear_issues', 'Searching Linear issues', 'Linear issues searched', 'Linear search', 'query'], ['read_linear_issue', 'Reading Linear issue', 'Linear issue read', 'Linear issue']]);
89
+ ['mate', 'scheduled_task'].forEach(function (kind) {
90
+ var mate = kind === 'mate';
91
+ var server = mate ? 'clay-mate-schedules' : 'clay-scheduled-tasks';
92
+ var suffix = mate ? 'mate_schedule' : 'scheduled_task';
93
+ rows(server, [
94
+ ['begin_' + suffix + '_interview', 'Preparing schedule review', 'Schedule interview started', 'Schedule review'],
95
+ ['propose_' + suffix, 'Proposing schedule for approval', 'Schedule proposal returned', 'Schedule proposal', mate ? null : 'name', 'schedule'],
96
+ ['list_' + suffix + 's', 'Checking schedules', 'Schedules checked', 'Schedules'],
97
+ ['read_' + suffix, 'Reading schedule', 'Schedule read', 'Schedule'],
98
+ ['update_' + suffix, 'Proposing schedule changes', 'Schedule change proposal returned', 'Schedule changes', mate ? null : 'name', 'schedule']
99
+ ]);
100
+ });
101
+ rows('clay-mate-schedules', [['cancel_mate_schedule', 'Requesting schedule cancellation', 'Schedule cancellation returned', 'Schedule cancellation', null, 'schedule']]);
102
+ rows('clay-scheduled-tasks', [['report_scheduled_task_outcome', 'Reporting scheduled task result', 'Scheduled task result reported', 'Scheduled task result']]);
103
+ rows('clay-knowledge', [
104
+ ['list_knowledge', 'Checking Mate Knowledge', 'Mate Knowledge checked', 'Mate Knowledge'],
105
+ ['search_knowledge', 'Searching Mate Knowledge', 'Mate Knowledge searched', 'Knowledge search', 'query'],
106
+ ['read_knowledge', 'Reading Mate Knowledge', 'Mate Knowledge read', 'Mate Knowledge'],
107
+ ['list_mate_knowledge', 'Checking Mate Knowledge', 'Mate Knowledge checked', 'Mate Knowledge'],
108
+ ['search_mate_knowledge', 'Searching Mate Knowledge', 'Mate Knowledge searched', 'Knowledge search', 'query'],
109
+ ['read_mate_knowledge', 'Reading Mate Knowledge', 'Mate Knowledge read', 'Mate Knowledge'],
110
+ ['read_knowledge_document', 'Reading knowledge document', 'Knowledge document read', 'Knowledge document', 'name'],
111
+ ['create_knowledge_document', 'Adding knowledge document', 'Knowledge document added', 'Knowledge document', 'name'],
112
+ ['update_knowledge_document', 'Updating knowledge document', 'Knowledge document updated', 'Knowledge document', 'name'],
113
+ ['list_knowledge_document_history', 'Reading knowledge history', 'Knowledge history read', 'Knowledge history', 'name'],
114
+ ['restore_knowledge_document', 'Restoring knowledge document', 'Knowledge document restored', 'Knowledge document', 'name']
115
+ ]);
116
+ rows('clay-knowledge', [
117
+ ['list_databases', 'Checking knowledge databases', 'Knowledge databases checked', 'Knowledge databases'],
118
+ ['create_database', 'Adding knowledge database', 'Knowledge database added', 'Knowledge database', 'name'],
119
+ ['read_database', 'Reading knowledge database', 'Knowledge database read', 'Knowledge database'],
120
+ ['update_database_schema', 'Updating database fields', 'Database fields updated', 'Database fields'],
121
+ ['archive_database', 'Archiving knowledge database', 'Knowledge database archived', 'Knowledge database'],
122
+ ['recover_database', 'Recovering knowledge database', 'Knowledge database recovered', 'Knowledge database'],
123
+ ['save_table_view', 'Saving database view', 'Database view saved', 'Database view'],
124
+ ['query_database', 'Searching database records', 'Database records searched', 'Database records'],
125
+ ['create_database_record', 'Adding database record', 'Database record added', 'Database record'],
126
+ ['read_database_record', 'Reading database record', 'Database record read', 'Database record'],
127
+ ['update_database_record', 'Updating database record', 'Database record updated', 'Database record'],
128
+ ['archive_database_record', 'Archiving database record', 'Database record archived', 'Database record'],
129
+ ['recover_database_record', 'Recovering database record', 'Database record recovered', 'Database record'],
130
+ ['retry_database_sync', 'Retrying knowledge sync', 'Knowledge sync retry returned', 'Knowledge sync'],
131
+ ['import_database_records', 'Importing database records', 'Database record import returned', 'Database import'],
132
+ ['read_database_import_progress', 'Checking database import', 'Database import checked', 'Database import']
133
+ ]);
134
+ rows('clay-tools', [
135
+ ['clay_tool_list', 'Checking Capsules', 'Capsules checked', 'Capsules'],
136
+ ['clay_tool_snapshot', 'Reading Capsule state', 'Capsule state read', 'Capsule'],
137
+ ['clay_tool_act', 'Requesting Capsule action', 'Capsule action returned', 'Capsule action'],
138
+ ['clay_tool_set', 'Updating Capsule state', 'Capsule state update returned', 'Capsule'],
139
+ ['clay_tool_source', 'Reading Capsule source', 'Capsule source read', 'Capsule'],
140
+ ['clay_tool_install', 'Installing Capsule', 'Capsule installation returned', 'Capsule', 'name'],
141
+ ['clay_tool_update', 'Updating Capsule', 'Capsule update returned', 'Capsule', 'name'],
142
+ ['clay_tool_uninstall', 'Removing Capsule', 'Capsule removal returned', 'Capsule']
143
+ ]);
144
+ rows('clay-email', [
145
+ ['clay_send_email', 'Sending email', 'Email request returned', 'Email', null, 'email'],
146
+ ['clay_reply_email', 'Replying to email', 'Email reply returned', 'Email reply', null, 'email'],
147
+ ['clay_read_email', 'Checking email', 'Email checked', 'Email'],
148
+ ['clay_read_email_body', 'Reading email', 'Email read', 'Email'],
149
+ ['clay_search_email', 'Searching email', 'Email searched', 'Email search'],
150
+ ['clay_list_labels', 'Checking email labels', 'Email labels checked', 'Email labels'],
151
+ ['clay_mark_read', 'Updating email read status', 'Email read status updated', 'Email'],
152
+ ['clay_move_email', 'Moving email', 'Email move returned', 'Email']
153
+ ]);
154
+ rows('clay-history', [['search_clay_history', 'Searching conversations', 'Conversations searched', 'Conversation search', 'query'], ['read_session', 'Reading conversation', 'Conversation read', 'Conversation'], ['list_recent_decisions', 'Checking recent decisions', 'Recent decisions checked', 'Recent decisions']]);
155
+ rows('clay-workspace', [
156
+ ['read_owner_screen', 'Checking your screen context', 'Screen context request returned', 'Screen context'],
157
+ ['inspect_owner_screen_change', 'Inspecting screen change', 'Screen change inspected', 'Screen control'],
158
+ ['control_owner_screen', 'Requesting screen change', 'Screen change request returned', 'Screen control', 'why'],
159
+ ['list_project_session_pull_requests', 'Checking conversation pull requests', 'Conversation pull requests checked', 'Conversation pull requests', 'projectSlug'],
160
+ ['begin_schedule_control_interview', 'Preparing schedule interview', 'Schedule interview prepared', 'Scheduling'],
161
+ ['read_schedule_controls', 'Reading schedules', 'Schedules read', 'Scheduling'],
162
+ ['inspect_schedule_change', 'Inspecting schedule change', 'Schedule change inspected', 'Scheduling'],
163
+ ['read_project_workspace', 'Reading selected project workspace', 'Selected project workspace read', 'Project workspace'],
164
+ ['read_workspace_receipt', 'Checking workspace request receipt', 'Workspace receipt checked', 'Workspace receipt'],
165
+ ['inspect_workspace_change', 'Inspecting project workspace change', 'Project workspace change inspected', 'Project workspace'],
166
+ ['control_project_workspace', 'Requesting project workspace change', 'Workspace change request returned', 'Project workspace', 'why', 'workspace-control'],
167
+ ['read_mate_chat_control', 'Checking Mate conversation', 'Mate conversation checked', 'Mate conversation'],
168
+ ['inspect_mate_chat_change', 'Inspecting Mate conversation change', 'Mate conversation change inspected', 'Mate conversation'],
169
+ ['control_mate_chat', 'Requesting Mate conversation change', 'Mate conversation request returned', 'Mate conversation', 'why', 'mate-chat'],
170
+ ['control_schedules', 'Requesting schedule change', 'Schedule change request returned', 'Scheduling', 'why', 'schedule-control'],
171
+ ['read_project_records', 'Reading project records', 'Project records read', 'Project records', 'projectSlug'],
172
+ ['inspect_project_record_change', 'Inspecting record change', 'Record change inspected', 'Project records', 'projectSlug'],
173
+ ['control_project_records', 'Requesting record change', 'Record change request returned', 'Project records', 'why'],
174
+ ['read_mate_knowledge_control', 'Reading Mate Knowledge', 'Mate Knowledge read', 'Mate Knowledge', 'mateId'],
175
+ ['inspect_mate_knowledge_change', 'Inspecting Knowledge change', 'Knowledge change inspected', 'Mate Knowledge', 'mateId'],
176
+ ['control_mate_knowledge', 'Requesting Knowledge change', 'Knowledge change request returned', 'Mate Knowledge', 'why'],
177
+ ['list_owned_mates', 'Checking your Mates', 'Your Mates checked', 'Mates'],
178
+ ['inspect_mate_control', 'Inspecting Mate controls', 'Mate controls inspected', 'Mate controls', 'mateId'],
179
+ ['control_mate_lifecycle', 'Requesting Mate change', 'Mate change request returned', 'Mate change', 'why'],
180
+ ['discover_product_controls', 'Checking product controls', 'Product controls checked', 'Product controls'],
181
+ ['inspect_project_control', 'Inspecting project change', 'Project change inspected', 'Project inspection', 'projectSlug'],
182
+ ['control_project_lifecycle', 'Requesting project change', 'Project change request returned', 'Project change', 'why', 'project-lifecycle'],
183
+ ['inspect_session_control', 'Inspecting conversation controls', 'Conversation controls inspected', 'Conversation controls'],
184
+ ['control_project_session', 'Requesting conversation change', 'Conversation change request returned', 'Conversation change', 'why', 'product-control'],
185
+ ['list_projects', 'Checking projects', 'Projects checked', 'Projects'],
186
+ ['list_project_sessions', 'Checking project conversations', 'Project conversations checked', 'Project conversations'],
187
+ ['search_project_history', 'Searching project conversations', 'Project conversations searched', 'Conversation search', 'query'],
188
+ ['read_project_session', 'Reading project conversation', 'Project conversation read', 'Project conversation'],
189
+ ['search_workspace_history', 'Searching conversations', 'Conversations searched', 'Conversation search', 'query'],
190
+ ['list_workspace_activity', 'Checking workspace activity', 'Workspace activity checked', 'Workspace activity'],
191
+ ['propose_project_assignment', 'Proposing project assignment', 'Project assignment proposal returned', 'Project assignment', 'title', 'proposal'],
192
+ ['propose_project_follow_up', 'Proposing project follow-up', 'Project follow-up proposal returned', 'Project follow-up', 'title', 'proposal'],
193
+ ['get_assignment_status', 'Checking assignment status', 'Assignment status checked', 'Assignment status']
194
+ ]);
195
+ rows('clay-debate', [['propose_debate', 'Proposing debate', 'Debate proposal returned', 'Debate proposal', 'topic', 'proposal']]);
196
+ rows('clay-mate-creation', [['propose_mate', 'Proposing Mate', 'Mate proposal returned', 'Mate proposal', 'name', 'proposal']]);
197
+ rows('clay-documents', [['present_markdown_edit', 'Opening document', 'Document opened', 'Document'], ['present_wireframe', 'Showing wireframe', 'Wireframe shown', 'Wireframe', 'title']]);
198
+ rows('clay-handoff', [['read_handoff_source', 'Reading handoff context', 'Handoff context read', 'Handoff context'], ['list_other_driver_sessions', 'Checking other Driver sessions', 'Driver sessions checked', 'Driver sessions'], ['search_other_driver_sessions', 'Searching Driver sessions', 'Driver sessions searched', 'Driver search', 'query'], ['read_other_driver_session', 'Reading Driver conversation', 'Driver conversation read', 'Driver conversation']]);
199
+
200
+ export function clayToolDefinition(name) {
201
+ return typeof name === 'string' && aliases[name] ? definitions[aliases[name]] : null;
202
+ }
203
+
204
+ function safeSubject(value) {
205
+ if (typeof value !== 'string') return '';
206
+ value = value.slice(0, 200).replace(/[\u0000-\u001f\u007f]/g, ' ').replace(/\s+/g, ' ').trim();
207
+ // Subjects come only from declared display fields, never bodies, evidence or tool output.
208
+ if (/secret|password|token|api[ _-]?key|bearer|https?:\/\/|@|[A-Za-z0-9_/-]{32,}/i.test(value)) return '';
209
+ return value.length > 72 ? value.slice(0, 71).trimEnd() + '…' : value;
210
+ }
211
+ function subjectFor(def, input) {
212
+ input = input || {};
213
+ if (def.subject === 'note') return safeSubject(typeof input.text === 'string' ? input.text.split('\n', 1)[0] : '');
214
+ if (def.subject === 'worker') return Number.isSafeInteger(input.workerId) ? 'Worker ' + input.workerId : '';
215
+ if (def.subject === 'site') {
216
+ try { return safeSubject(new URL(input.url).hostname); } catch (error) { return ''; }
217
+ }
218
+ return safeSubject(input[def.subject]);
219
+ }
220
+
221
+ // Called once per terminal result, never per streaming delta. Large results stay opaque.
222
+ export function clayToolOutcome(content, isError, level) {
223
+ level = level || 0;
224
+ if (level >= 3) return { phase: 'returned' };
225
+ if (isError) return { phase: 'error' };
226
+ var value = content;
227
+ if (typeof value === 'string') {
228
+ if (/^\s*(?:Error:|Error\b|Rejected\b|Cancelled\b|Canceled\b)/i.test(value)) return { phase: /^\s*Cancel/i.test(value) ? 'cancelled' : 'error' };
229
+ if (value.length > 65536) return { phase: 'returned' };
230
+ try { value = JSON.parse(value); } catch (error) { return { phase: 'returned' }; }
231
+ }
232
+ for (var depth = 0; depth < 3 && value && typeof value === 'object'; depth++) {
233
+ if (value.isError || value.is_error || value.error || value.rejected === true || (Array.isArray(value.errors) && value.errors.length > 0)) return { phase: 'error' };
234
+ var status = typeof value.status === 'string' ? value.status.toLowerCase() : '';
235
+ if (['error', 'failed', 'rejected', 'declined', 'denied', 'blocked', 'expired', 'unavailable'].indexOf(status) !== -1) return { phase: 'error', status: status };
236
+ if (value.cancelled === true || value.canceled === true || ['cancelled', 'canceled', 'interrupted', 'stopped', 'killed', 'abandoned'].indexOf(status) !== -1) return { phase: 'cancelled', status: status, value: value };
237
+ if (value.ok === false || value.success === false) return { phase: 'error' };
238
+ if (Array.isArray(value.content)) {
239
+ var text = value.content.filter(function (block) { return block && block.type === 'text'; });
240
+ if (text.length !== 1) return { phase: 'returned' };
241
+ return clayToolOutcome(text[0].text, false, level + 1);
242
+ }
243
+ if (value.result && typeof value.result === 'object') { value = value.result; continue; }
244
+ return { phase: 'done', status: status, value: value };
245
+ }
246
+ return { phase: 'returned' };
247
+ }
248
+
249
+ export function clayToolPresentation(name, input, outcome) {
250
+ var def = clayToolDefinition(name);
251
+ if (!def) return null;
252
+ input = input || {};
253
+ var phase = outcome ? outcome.phase : 'running';
254
+ var label = outcome ? def.completed : def.running;
255
+ if (name && def.name === 'update_scheduled_task') label = outcome ? 'Scheduled task update returned' : 'Updating scheduled task';
256
+ var noun = def.noun;
257
+ if (def.rule === 'browser') {
258
+ var browserActions = {
259
+ open: ['Opening browser page', 'Browser page opened'], navigate: ['Opening browser page', 'Browser page opened'],
260
+ inspect: ['Checking browser page', 'Browser page checked'], status: ['Checking browser tabs', 'Browser tabs checked'],
261
+ click: ['Clicking browser control', 'Browser control clicked'], text: ['Entering browser text', 'Browser text entered'],
262
+ select: ['Selecting browser option', 'Browser option selected'], key: ['Pressing browser key', 'Browser key pressed'],
263
+ wheel: ['Scrolling browser page', 'Browser page scrolled'], resize: ['Resizing browser viewport', 'Browser viewport resized'],
264
+ reload: ['Refreshing browser page', 'Browser page refreshed'], back: ['Going to previous browser page', 'Previous browser page opened'],
265
+ forward: ['Going to next browser page', 'Next browser page opened'], finish: ['Finishing browser activity', 'Browser activity finished']
266
+ };
267
+ var browserAction = browserActions[input.action];
268
+ if (browserAction) label = browserAction[outcome ? 1 : 0];
269
+ }
270
+ if (def.rule === 'note' && input.id) label = outcome ? 'Sticky note updated' : 'Updating sticky note';
271
+ if (phase === 'error') label = noun + (outcome.status === 'rejected' || outcome.status === 'declined' || outcome.status === 'denied' ? ' rejected' : ' failed');
272
+ else if (phase === 'cancelled') label = noun + ' cancelled';
273
+ else if (phase === 'returned') label = noun + (outcome.status === 'result_unavailable' ? ' result unavailable' : ' request returned');
274
+ else if (outcome) {
275
+ var status = outcome.status;
276
+ if (def.rule === 'workspace-control') {
277
+ if (status === 'completed') label = outcome.value.runtimeEffect === 'closed' ? 'Terminal exit confirmed' : 'Project workspace change completed';
278
+ } else if (def.rule === 'mate-chat') {
279
+ if (status === 'queued') { phase = 'pending'; label = outcome.value.action === 'stop' ? 'Mate Stop requested · runtime pending' : 'Mate message queued'; }
280
+ else if (status === 'started') { phase = 'pending'; label = 'Mate message admitted · completion pending'; }
281
+ else if (status === 'completed') label = 'Mate conversation change completed';
282
+ } else if (def.rule === 'schedule-control') {
283
+ if (status === 'proposed') { phase = 'pending'; label = 'Task draft awaiting Create task'; }
284
+ else if (status === 'queued') { phase = 'pending'; label = 'Scheduled run queued'; }
285
+ else if (status === 'completed') label = 'Schedule change saved';
286
+ else { phase = 'returned'; label = 'Schedule change request returned'; }
287
+ } else if (def.rule === 'project-lifecycle') {
288
+ if (status === 'completed') label = 'Project change completed';
289
+ else { phase = 'returned'; label = 'Project change request returned'; }
290
+ } else if (def.rule === 'product-control') {
291
+ if (status === 'queued') { phase = 'pending'; label = input.action === 'stop' ? 'Stop requested · runtime pending' : input.action === 'queue_add' ? 'Message queued for project Driver' : 'Conversation change queued'; }
292
+ else if (status === 'completed') label = input.action === 'queue_add' ? 'Message delivered to project Driver' : input.action === 'queue_edit' ? 'Queued message updated' : input.action === 'queue_cancel' ? 'Queued message cancelled' : input.action === 'queue_reorder' ? 'Message queue reordered' : input.action === 'vendor' ? 'Driver provider selected' : 'Conversation change completed';
293
+ else { phase = 'returned'; label = 'Conversation change request returned'; }
294
+ } else if (def.rule === 'observation') {
295
+ if (status !== 'pending') { label = 'Preference submission returned'; phase = 'returned'; }
296
+ } else if (def.rule === 'email') {
297
+ if (status === 'sent') label = 'Email sent';
298
+ else phase = 'returned';
299
+ } else if (def.rule === 'worker' || def.rule === 'message') {
300
+ if (status === 'queued') label = def.rule === 'worker' ? 'Task queued for Worker' : 'Message queued for Worker';
301
+ else if (status === 'running') label = 'Task sent to Worker';
302
+ else if (status === 'complete' || status === 'completed') label = 'Worker task completed';
303
+ else phase = 'returned';
304
+ } else if (def.rule === 'proposal' || def.rule === 'schedule') {
305
+ phase = 'returned'; label = noun + ' returned';
306
+ if (['pending', 'proposed', 'awaiting_approval', 'approval_required'].indexOf(status) !== -1) { phase = 'pending'; label = noun + ' awaiting approval'; }
307
+ if (status === 'created' && def.rule === 'schedule') { phase = 'done'; label = 'Schedule created'; }
308
+ else if (status === 'updated' && def.rule === 'schedule') { phase = 'done'; label = 'Schedule updated'; }
309
+ else if (status === 'unchanged') { phase = 'returned'; label = 'Schedule unchanged'; }
310
+ else if (status && ['pending', 'proposed', 'awaiting_approval', 'approval_required'].indexOf(status) === -1) { phase = 'returned'; label = noun + ' returned'; }
311
+ } else if (status && ['pending', 'queued', 'submitted', 'capture_pending'].indexOf(status) !== -1) { phase = 'pending'; label = noun + ' pending'; }
312
+ if (outcome.value && (outcome.value.indexSyncPending || outcome.value.projectionPending)) label += ' · sync pending';
313
+ }
314
+ if (def.name === 'cancel_mate_schedule' && phase === 'cancelled' && outcome.value && outcome.value.schedule) { phase = 'done'; label = 'Schedule cancelled'; }
315
+ if (def.name === 'update_scheduled_task' && outcome && outcome.phase === 'done' && outcome.value && outcome.value.ok === true) { phase = 'done'; label = 'Scheduled task updated'; }
316
+ return { label: label, subject: subjectFor(def, input), phase: phase, name: def.name };
317
+ }
318
+
319
+ export function clayToolGroupSummary(group, tools) {
320
+ if (!group.toolNames.some(function (name) { return !!clayToolDefinition(name); })) { group.clayActivityPhase = null; return null; }
321
+ var items = (group.toolIds || []).map(function (id) { return group.toolRecords ? group.toolRecords[id] : tools[id]; }).filter(function (tool) { return tool && tool.groupId === group.id && !tool.hidden; });
322
+ if (!items.some(function (tool) { return !!tool.clayActivity; })) return null;
323
+ if (items.length === 1 && items[0].clayActivity) {
324
+ var one = items[0].clayActivity;
325
+ group.clayActivityPhase = one.phase;
326
+ return one.label + (one.subject ? ' · ' + one.subject : '');
327
+ }
328
+ var failed = 0, pending = 0, running = 0, returned = 0;
329
+ items.forEach(function (tool) {
330
+ var phase = tool.clayActivity ? tool.clayActivity.phase : (tool.done ? (tool.el && tool.el.classList.contains('error') ? 'error' : 'done') : 'running');
331
+ if (phase === 'error' || phase === 'cancelled') failed++;
332
+ if (phase === 'pending') pending++;
333
+ if (phase === 'running') running++;
334
+ if (phase === 'returned') returned++;
335
+ });
336
+ group.clayActivityPhase = failed ? 'error' : pending ? 'pending' : running ? 'running' : returned ? 'returned' : 'done';
337
+ return items.length + ' activities' + (running ? ' · ' + running + ' running' : '') + (failed ? ' · ' + failed + ' failed or cancelled' : '') + (pending ? ' · ' + pending + ' awaiting review' : '');
338
+ }
@@ -435,7 +435,7 @@ function activateItem(entry) {
435
435
  if (entry.type === "mate-session" || entry.type === "session") navigateToSession(entry.data, entry.query);
436
436
  }
437
437
 
438
- function navigateToSession(item, query, entryIndex) {
438
+ export function navigateToSession(item, query, entryIndex) {
439
439
  closeCommandPalette();
440
440
  pendingNav = null;
441
441
  var hasEntry = entryIndex !== null && entryIndex !== undefined && Number.isSafeInteger(Number(entryIndex)) && Number(entryIndex) >= 0;
@@ -110,6 +110,13 @@ function inlineCurrentSelection(state, draft) {
110
110
  return state.preference || state.selection || draft || {};
111
111
  }
112
112
 
113
+ function updateDraft(draft) {
114
+ var state = store.get('defaultAiState') || {};
115
+ var saved = state.preference || state.selection || {};
116
+ var dirty = ['vendor', 'model', 'effort'].some(function (key) {return (draft[key] || '') !== (saved[key] || '');});
117
+ store.set({defaultAiDraft:draft, defaultAiDraftDirty:dirty});
118
+ }
119
+
113
120
  function renderInlineSummary() {
114
121
  var state = store.get("defaultAiState") || {};
115
122
  var draft = store.get("defaultAiDraft") || {};
@@ -209,16 +216,16 @@ function render() {
209
216
  effort.disabled = !models.length || state.saving === true;
210
217
 
211
218
  vendor.addEventListener("change", function () {
212
- store.set({ defaultAiDraft: { vendor: vendor.value, model: "", effort: "" }, defaultAiDraftDirty: true });
219
+ updateDraft({ vendor: vendor.value, model: "", effort: "" });
213
220
  requestCatalog(vendor.value);
214
221
  render();
215
222
  });
216
223
  model.addEventListener("change", function () {
217
- store.set({ defaultAiDraft: { vendor: vendor.value, model: model.value, effort: "" }, defaultAiDraftDirty: true });
224
+ updateDraft({ vendor: vendor.value, model: model.value, effort: "" });
218
225
  render();
219
226
  });
220
227
  effort.addEventListener("change", function () {
221
- store.set({ defaultAiDraft: { vendor: vendor.value, model: model.value, effort: effort.value }, defaultAiDraftDirty: true });
228
+ updateDraft({ vendor: vendor.value, model: model.value, effort: effort.value });
222
229
  render();
223
230
  });
224
231
  addFieldLabel("Provider", vendor);
@@ -304,6 +311,7 @@ function applyCatalogMessage(msg, state) {
304
311
  draft = Object.assign({}, draft, { model: msg.selection.model, effort: msg.selection.effort || "" });
305
312
  }
306
313
  store.set({ defaultAiState: next, defaultAiDraft: draft });
314
+ updateDraft(draft);
307
315
  }
308
316
 
309
317
  function applyStateMessage(msg, state) {
@@ -126,8 +126,8 @@ export function createHomeDebateQuestionCard(message, respond) {
126
126
  card.className = "home-debate-question" + (message.flow === "mcp_import" ? " mcp-import-consent" : "");
127
127
  card.dataset.toolId = message.toolId || "";
128
128
  card.setAttribute("aria-busy", message.status === "submitting" ? "true" : "false");
129
- var isMateCreation = message.flow === "mate_creation", isMcpImport = message.flow === "mcp_import";
130
- card.setAttribute("aria-label", (isMcpImport ? "MCP import consent: " : isMateCreation ? "Mate creation interview question: " : "Debate planning question: ") + (question.question || "Question"));
129
+ var isMateQuestion = message.flow === "mate_question", isMateCreation = message.flow === "mate_creation", isMcpImport = message.flow === "mcp_import";
130
+ card.setAttribute("aria-label", (isMateQuestion ? "Mate question: " : isMcpImport ? "MCP import consent: " : isMateCreation ? "Mate creation interview question: " : "Debate planning question: ") + (question.question || "Question"));
131
131
  if (question.header) card.appendChild(textElement("div", "home-debate-question-header", question.header));
132
132
  card.appendChild(textElement("h3", "home-debate-question-text", question.question || "Clay has a question."));
133
133
  var form = document.createElement("div");
@@ -163,7 +163,7 @@ export function createHomeDebateQuestionCard(message, respond) {
163
163
  answerControl.placeholder = freeform ? (isMateCreation ? "Describe what you want in your own words" : "Describe the topic in your own words") : "Type another answer";
164
164
  answerLabel.appendChild(answerControl);
165
165
  if (freeform || question.allowOther !== false) form.appendChild(answerLabel);
166
- var submit = textElement("button", "home-debate-question-submit", message.status === "submitting" ? "Submitting…" : isMcpImport ? "Confirm choice" : "Submit answer");
166
+ var submit = textElement("button", "home-debate-question-submit", message.status === "submitting" ? "Submitting…" : (isMcpImport || isMateQuestion) ? "Confirm choice" : "Submit answer");
167
167
  submit.type = "button";
168
168
  submit.disabled = message.status !== "pending" || !selected;
169
169
  function submitAnswer() {
@@ -253,7 +253,7 @@ export function normalizeHomeTranscript(raw) {
253
253
  export function applyHomeDebateQuestion(messages, msg) {
254
254
  if (!msg || !msg.toolId) return messages;
255
255
  for (var i = 0; i < messages.length; i++) if (messages[i].role === "question" && messages[i].toolId === msg.toolId) return messages;
256
- return messages.concat([{ role: "question", flow: msg.type === "home_mcp_import_question" ? "mcp_import" : msg.type === "home_mate_creation_question" ? "mate_creation" : "debate", toolId: msg.toolId, questions: msg.questions || [], status: "pending", error: "" }]);
256
+ return messages.concat([{ role: "question", flow: msg.type === "home_mate_question" ? "mate_question" : msg.type === "home_mcp_import_question" ? "mcp_import" : msg.type === "home_mate_creation_question" ? "mate_creation" : "debate", toolId: msg.toolId, questions: msg.questions || [], status: "pending", error: "" }]);
257
257
  }
258
258
 
259
259
  export function resolveHomeDebateQuestion(messages, msg) {
@@ -296,7 +296,7 @@ export function markHomeDebateQuestionSubmitting(message, opener) {
296
296
  export function createHomeDebateResponder(sendMessage, getContext, onChange) {
297
297
  return function respond(message, action, opener, answers, modelOverrides) {
298
298
  if (!message || message.status === "submitting") return;
299
- var payload = message.role === "question" ? { type: message.flow === "mcp_import" ? "home_mcp_import_response" : message.flow === "mate_creation" ? "home_mate_creation_question_response" : "home_debate_question_response", toolId: message.toolId, answers: answers || {} } : { type: "home_debate_proposal_response", proposalId: message.proposal.proposalId, action: action, modelOverrides: Array.isArray(modelOverrides) ? modelOverrides : [] };
299
+ var payload = message.role === "question" ? { type: message.flow === "mate_question" ? "home_mate_question_response" : message.flow === "mcp_import" ? "home_mcp_import_response" : message.flow === "mate_creation" ? "home_mate_creation_question_response" : "home_debate_question_response", toolId: message.toolId, answers: answers || {} } : { type: "home_debate_proposal_response", proposalId: message.proposal.proposalId, action: action, modelOverrides: Array.isArray(modelOverrides) ? modelOverrides : [] };
300
300
  Object.assign(payload, getContext());
301
301
  if (!sendMessage(payload)) return;
302
302
  if (message.role === "question") markHomeDebateQuestionSubmitting(message, opener);
@@ -340,24 +340,26 @@ export function handleHomeDebateTranscript(msg) {
340
340
  if (!isCurrentSessionMessage(msg)) return;
341
341
  markHomeChatActivity();
342
342
  settleHomeDebateLaunch(msg);
343
- if (msg.type === "home_debate_proposal" || (msg.type === "home_debate_question" || msg.type === "home_mcp_import_question") || msg.type === "home_debate_event" || msg.type === "home_mate_creation_proposal" || msg.type === "home_mate_creation_question") messages = finalizeHomeAssistant(messages, streamingText, "", Date.now());
343
+ var questionMessage = ["home_debate_question", "home_mcp_import_question", "home_mate_question"].indexOf(msg.type) >= 0;
344
+ var questionResolved = ["home_debate_question_resolved", "home_mcp_import_question_resolved", "home_mate_question_resolved"].indexOf(msg.type) >= 0;
345
+ if (msg.type === "home_debate_proposal" || questionMessage || msg.type === "home_debate_event" || msg.type === "home_mate_creation_proposal" || msg.type === "home_mate_creation_question") messages = finalizeHomeAssistant(messages, streamingText, "", Date.now());
344
346
  if (msg.type === "home_debate_event") messages = applyHomeDebateEvent(messages, msg);
345
347
  if (msg.type === "home_debate_proposal") messages = applyHomeDebateProposal(messages, msg);
346
348
  if (msg.type === "home_debate_proposal_resolved") messages = resolveHomeDebateProposal(messages, msg);
347
- if ((msg.type === "home_debate_question" || msg.type === "home_mcp_import_question")) messages = applyHomeDebateQuestion(messages, msg);
348
- if ((msg.type === "home_debate_question_resolved" || msg.type === "home_mcp_import_question_resolved")) messages = resolveHomeDebateQuestion(messages, msg);
349
+ if (questionMessage) messages = applyHomeDebateQuestion(messages, msg);
350
+ if (questionResolved) messages = resolveHomeDebateQuestion(messages, msg);
349
351
  if (msg.type === "home_mate_creation_question") messages = applyHomeDebateQuestion(messages, msg);
350
352
  if (msg.type === "home_mate_creation_question_resolved") messages = resolveHomeDebateQuestion(messages, msg);
351
353
  if (msg.type === "home_mate_creation_proposal") messages = applyHomeMateProposal(messages, msg);
352
354
  if (msg.type === "home_mate_creation_proposal_resolved") messages = resolveHomeMateProposal(messages, msg);
353
355
  if (msg.type === "home_mate_error" && /^question_/.test(msg.code || "")) messages = failHomeDebateQuestion(messages, msg);
354
- if (msg.type === "home_debate_proposal" || (msg.type === "home_debate_question" || msg.type === "home_mcp_import_question") || msg.type === "home_debate_event" || msg.type === "home_mate_creation_proposal" || msg.type === "home_mate_creation_question") { clearHomeDebatePlanningPending(); streaming = false; streamingText = ""; }
355
- if (((msg.type === "home_debate_question_resolved" || msg.type === "home_mcp_import_question_resolved") || msg.type === "home_mate_creation_question_resolved") && msg.status === "expired") clearHomeDebatePlanningPending();
356
+ if (msg.type === "home_debate_proposal" || questionMessage || msg.type === "home_debate_event" || msg.type === "home_mate_creation_proposal" || msg.type === "home_mate_creation_question") { clearHomeDebatePlanningPending(); streaming = false; streamingText = ""; }
357
+ if ((questionResolved || msg.type === "home_mate_creation_question_resolved") && msg.status === "expired") clearHomeDebatePlanningPending();
356
358
  renderHomeChat();
357
359
  if (msg.proposalId) restoreHomeDebateProposalFocus(msg.proposalId);
358
360
  if (msg.proposalId && msg.type === "home_mate_creation_proposal_resolved") restoreHomeMateProposalFocus(msg.proposalId);
359
361
  if (msg.toolId && msg.type === "home_mate_creation_question") restoreHomeDebateQuestionFocus(msg.toolId);
360
- if (msg.toolId && (msg.type === "home_debate_question_resolved" || msg.type === "home_mcp_import_question_resolved")) restoreHomeDebateQuestionFocus(msg.toolId);
362
+ if (msg.toolId && questionResolved) restoreHomeDebateQuestionFocus(msg.toolId);
361
363
  if (msg.toolId && msg.type === "home_mate_error") restoreHomeDebateQuestionFocus(msg.toolId);
362
364
  }
363
365
  export function handleHomeMateDelta(msg) {
@@ -7,6 +7,67 @@ function textElement(tag, className, text) {
7
7
  return element;
8
8
  }
9
9
 
10
+ function scheduleDate(value) {
11
+ var parts = String(value || "").split("-").map(Number);
12
+ var date = new Date(Date.UTC(parts[0], parts[1] - 1, parts[2]));
13
+ return Number.isFinite(date.getTime()) ? date.toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric", timeZone: "UTC" }) : value;
14
+ }
15
+
16
+ function exactScheduleFact(proposal) {
17
+ var intent = proposal.scheduleIntent;
18
+ var schedule = intent.scheduleRule;
19
+ var recurrence = schedule.recurrence;
20
+ var timing = "On " + scheduleDate(schedule.anchorDate);
21
+ if (recurrence) {
22
+ var days = (recurrence.weekdays || []).map(function (day) { return ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][day]; });
23
+ if (recurrence.unit === "week" && recurrence.every === 1 && (recurrence.weekdays || []).join(",") === "1,2,3,4,5") timing = "Every weekday";
24
+ else if (recurrence.unit === "week" && recurrence.every === 1 && days.length) timing = "Every " + days.join(", ");
25
+ else timing = "Every " + (recurrence.every === 1 ? recurrence.unit : recurrence.every + " " + recurrence.unit + "s") + (days.length ? " on " + days.join(", ") : "");
26
+ }
27
+ timing += " at " + schedule.time + " (" + (proposal.scheduleTimezone || "server local") + ")";
28
+ if (recurrence) timing += ", starting " + scheduleDate(schedule.anchorDate);
29
+ if (schedule.recurrenceEnd) timing += schedule.recurrenceEnd.type === "after" ? "; for " + schedule.recurrenceEnd.count + " deliveries" : "; through " + scheduleDate(schedule.recurrenceEnd.date);
30
+ if (schedule.interval) {
31
+ var interval = schedule.interval;
32
+ timing += "; every " + interval.every + " " + interval.unit + (interval.every === 1 ? "" : "s");
33
+ timing += !interval.end ? " until end of day" : interval.end.type === "after" ? ", " + interval.end.count + " deliveries per day" : " until " + interval.end.time;
34
+ }
35
+ return timing + ": " + intent.message;
36
+ }
37
+
38
+ function friendlyTime(value) {
39
+ var parts = value.split(":");
40
+ var hour = Number(parts[0]);
41
+ if (parts[1] === "00" && (hour === 0 || hour === 12)) return hour === 0 ? "midnight" : "noon";
42
+ return (hour % 12 || 12) + (parts[1] === "00" ? "" : ":" + parts[1]) + (hour < 12 ? " AM" : " PM");
43
+ }
44
+
45
+ function scheduleSummary(proposal) {
46
+ var intent = proposal.scheduleIntent;
47
+ var schedule = intent.scheduleRule;
48
+ var recurrence = schedule.recurrence;
49
+ var timing = scheduleDate(schedule.anchorDate);
50
+ if (recurrence) {
51
+ var days = (recurrence.weekdays || []).map(function (day) { return ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][day]; });
52
+ if (recurrence.unit === "week" && recurrence.every === 1 && (recurrence.weekdays || []).join(",") === "1,2,3,4,5") timing = "Every weekday";
53
+ else if (recurrence.unit === "week" && recurrence.every === 1 && days.length) timing = "Every " + days.join(", ");
54
+ else timing = "Every " + (recurrence.every === 1 ? recurrence.unit : recurrence.every + " " + recurrence.unit + "s") + (days.length ? " on " + days.join(", ") : "");
55
+ }
56
+ var hour = Number(schedule.time.split(":")[0]);
57
+ var time = friendlyTime(schedule.time);
58
+ var period = hour >= 5 && hour < 12 ? "morning" : hour >= 13 && hour < 17 ? "afternoon" : hour >= 17 && hour < 21 ? "evening" : "";
59
+ if (recurrence && period && recurrence.unit === "day" && recurrence.every === 1) timing = "Every " + period + " at " + time.replace(/ (AM|PM)$/, "");
60
+ else if (recurrence && period && timing === "Every weekday") timing += " " + period + " at " + time.replace(/ (AM|PM)$/, "");
61
+ else timing += " at " + time;
62
+ if (schedule.recurrenceEnd) timing += schedule.recurrenceEnd.type === "after" ? ", for " + schedule.recurrenceEnd.count + (schedule.recurrenceEnd.count === 1 ? " delivery" : " deliveries") : ", through " + scheduleDate(schedule.recurrenceEnd.date);
63
+ if (schedule.interval) {
64
+ var interval = schedule.interval;
65
+ timing += ", then every " + interval.every + " " + interval.unit + (interval.every === 1 ? "" : "s");
66
+ timing += !interval.end ? " until the end of the day" : interval.end.type === "after" ? ", " + interval.end.count + " deliveries a day" : " until " + friendlyTime(interval.end.time);
67
+ }
68
+ return timing + ": " + intent.message;
69
+ }
70
+
10
71
  export function createHomeMateProposalCard(message, respond, openMate) {
11
72
  var proposal = message.proposal || {};
12
73
  var card = document.createElement("section");
@@ -21,12 +82,23 @@ export function createHomeMateProposalCard(message, respond, openMate) {
21
82
  function fact(label, value) {
22
83
  if (!value) return;
23
84
  facts.appendChild(textElement("dt", "", label));
24
- facts.appendChild(textElement("dd", "", value));
85
+ var description = textElement("dd", "", typeof value === "string" ? value : "");
86
+ if (typeof value !== "string") description.appendChild(value);
87
+ facts.appendChild(description);
88
+ return description;
25
89
  }
26
90
  fact("Relationship", proposal.relationship);
27
91
  fact("Activities", Array.isArray(proposal.activities) ? proposal.activities.join(", ") : "");
28
92
  fact("Communication", Array.isArray(proposal.communicationStyle) ? proposal.communicationStyle.join(", ") : "");
29
93
  fact("Autonomy", proposal.autonomy);
94
+ if (proposal.scheduleIntent && proposal.scheduleIntent.message && proposal.scheduleIntent.scheduleRule) {
95
+ var scheduleItem = fact("Schedule", textElement("span", "home-mate-proposal-schedule-summary", scheduleSummary(proposal)));
96
+ var exactTiming = document.createElement("details");
97
+ exactTiming.className = "home-mate-proposal-schedule-details";
98
+ exactTiming.appendChild(textElement("summary", "", "Exact timing"));
99
+ exactTiming.appendChild(textElement("div", "", exactScheduleFact(proposal)));
100
+ scheduleItem.appendChild(exactTiming);
101
+ }
30
102
  card.appendChild(facts);
31
103
  if (proposal.identityMarkdown) {
32
104
  var details = document.createElement("details");
@@ -17,7 +17,13 @@ export function preparePersonalConnectionDialog(overlay, inline) {
17
17
  if (label && input) label.htmlFor = input.id;
18
18
  });
19
19
  enhanceSettingsSelects(overlay);
20
- function markDirty() { dirty = true; if (inline) store.set({personalEmailDirty:true}); }
20
+ var fields = Array.from(overlay.querySelectorAll('input,select,textarea'));
21
+ function value(field) {return field.type === 'checkbox' ? field.checked : field.value;}
22
+ var baseline = fields.map(value);
23
+ function markDirty() {
24
+ dirty = fields.some(function (field, index) {return value(field) !== baseline[index];});
25
+ if (inline) store.set({personalEmailDirty:dirty});
26
+ }
21
27
  overlay.addEventListener('input', markDirty);
22
28
  overlay.addEventListener('change', markDirty);
23
29
  var unsubscribe = inline ? store.subscribe(function (state, previousState) {
@@ -0,0 +1,17 @@
1
+ import { store } from './store.js';
2
+
3
+ // Hard navigation destroys detached panels, cached transcripts and sockets.
4
+ // Clear the rendered document first so revoked content cannot linger while the
5
+ // replacement page is loading or when that request fails.
6
+ export function leaveRevokedProject(url) {
7
+ store.set({ activeSessionId: null, activeProjectSlug: null, sessionActivatedProjectSlug: null, sessions: [], splitPanes: null });
8
+ document.body.replaceChildren();
9
+ window.location.replace(url || "/");
10
+ }
11
+
12
+ export function reconnectDestination(info, slug) {
13
+ if (!slug || !info || !Array.isArray(info.projects)) return null;
14
+ var project = info.projects.find(function (item) { return item.slug === slug; });
15
+ if (!project) return "/";
16
+ return project.contentAccess === false ? "/p/" + encodeURIComponent(slug) + "/" : null;
17
+ }