manigent-server 0.1.0__py3-none-any.whl

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 (1004) hide show
  1. manigent/_catalog/mcps/chess/README.md +38 -0
  2. manigent/_catalog/mcps/chess/mcp.json +9 -0
  3. manigent/_catalog/mcps/registry.json +9 -0
  4. manigent/_catalog/skills/brief/SKILL.md +339 -0
  5. manigent/_catalog/skills/broaden-options/SKILL.md +133 -0
  6. manigent/_catalog/skills/calendar/SKILL.md +44 -0
  7. manigent/_catalog/skills/calendar/starter_config.jsonc +25 -0
  8. manigent/_catalog/skills/gmail/SKILL.md +73 -0
  9. manigent/_catalog/skills/google-calendar/SKILL.md +44 -0
  10. manigent/_catalog/skills/google-drive/SKILL.md +42 -0
  11. manigent/_catalog/skills/google-drive-write/SKILL.md +45 -0
  12. manigent/_catalog/skills/google-drive-write/starter_config.jsonc +45 -0
  13. manigent/_catalog/skills/grill-me/SKILL.md +173 -0
  14. manigent/_catalog/skills/homekit/SKILL.md +37 -0
  15. manigent/_catalog/skills/http-api/SKILL.md +117 -0
  16. manigent/_catalog/skills/ib/SKILL.md +89 -0
  17. manigent/_catalog/skills/ib/starter_config.jsonc +35 -0
  18. manigent/_catalog/skills/mailbox/SKILL.md +47 -0
  19. manigent/_catalog/skills/mailbox/starter_config.jsonc +38 -0
  20. manigent/_catalog/skills/media/SKILL.md +93 -0
  21. manigent/_catalog/skills/media/starter_config.jsonc +63 -0
  22. manigent/_catalog/skills/osxphotos/SKILL.md +41 -0
  23. manigent/_catalog/skills/photo-story/SKILL.md +285 -0
  24. manigent/_catalog/skills/playwright-browser/SKILL.md +291 -0
  25. manigent/_catalog/skills/playwright-browser/starter_config.jsonc +44 -0
  26. manigent/_catalog/skills/playwright-save-skill/SKILL.md +149 -0
  27. manigent/_catalog/skills/registry.json +166 -0
  28. manigent/_catalog/skills/web-artifacts/SKILL.md +194 -0
  29. manigent/api/action_executor.py +404 -0
  30. manigent/api/action_validator.py +531 -0
  31. manigent/api/actions.py +221 -0
  32. manigent/api/client.py +558 -0
  33. manigent/api/control.py +806 -0
  34. manigent/api/edge_protocol.py +123 -0
  35. manigent/api/fs_protocol.py +450 -0
  36. manigent/api/host_protocol.py +298 -0
  37. manigent/api/managed_job_client.py +124 -0
  38. manigent/api/responses.py +342 -0
  39. manigent/api/retry_transport.py +178 -0
  40. manigent/api/turn_protocol.py +78 -0
  41. manigent/cli_lifecycle.py +467 -0
  42. manigent/cli_server.py +978 -0
  43. manigent/doctor.py +1167 -0
  44. manigent/hub_protocol/canonical.py +375 -0
  45. manigent/hub_protocol/codes.py +171 -0
  46. manigent/hub_protocol/constants.py +71 -0
  47. manigent/hub_protocol/envelope.py +218 -0
  48. manigent/hub_protocol/frames.py +788 -0
  49. manigent/hub_protocol/http.py +260 -0
  50. manigent/hub_protocol/ids.py +170 -0
  51. manigent/hub_protocol/keys.py +195 -0
  52. manigent/hub_protocol/text.py +75 -0
  53. manigent/llm/base.py +1072 -0
  54. manigent/llm/prompt_builder.py +2450 -0
  55. manigent/llm/triggers.py +68 -0
  56. manigent/models/agent.py +2905 -0
  57. manigent/models/agent_bundle.py +298 -0
  58. manigent/models/brief_tab.py +311 -0
  59. manigent/models/chat_message.py +231 -0
  60. manigent/models/chatroom.py +1108 -0
  61. manigent/models/context.py +1159 -0
  62. manigent/models/desk_label.py +836 -0
  63. manigent/models/desk_read_state.py +220 -0
  64. manigent/models/desk_sign_off.py +267 -0
  65. manigent/models/desk_sop.py +965 -0
  66. manigent/models/desk_todo.py +1603 -0
  67. manigent/models/desk_todo_link.py +404 -0
  68. manigent/models/file_cache.py +75 -0
  69. manigent/models/host.py +732 -0
  70. manigent/models/install_token.py +401 -0
  71. manigent/models/invitation_code.py +162 -0
  72. manigent/models/knowledge_pack.py +552 -0
  73. manigent/models/managed_job.py +295 -0
  74. manigent/models/model_config.py +564 -0
  75. manigent/models/model_defaults.py +238 -0
  76. manigent/models/onboarding_plan.py +161 -0
  77. manigent/models/participant.py +449 -0
  78. manigent/models/persistable.py +892 -0
  79. manigent/models/plan_markdown.py +1774 -0
  80. manigent/models/project.py +1343 -0
  81. manigent/models/project_plan.py +8104 -0
  82. manigent/models/project_report.py +145 -0
  83. manigent/models/provenance.py +261 -0
  84. manigent/models/provider_agents.py +101 -0
  85. manigent/models/public_request.py +108 -0
  86. manigent/models/reflection_schedule.py +191 -0
  87. manigent/models/scheduled_message.py +285 -0
  88. manigent/models/share_token.py +190 -0
  89. manigent/models/skill_version.py +31 -0
  90. manigent/models/sop_template.py +187 -0
  91. manigent/models/thinking_partner_plan.py +187 -0
  92. manigent/models/tunnel_binding.py +129 -0
  93. manigent/models/user.py +1276 -0
  94. manigent/models/work_tracker.py +510 -0
  95. manigent/runner/invocation_registry.py +187 -0
  96. manigent/server/agent_capabilities.py +119 -0
  97. manigent/server/agent_visibility.py +119 -0
  98. manigent/server/announcements.py +119 -0
  99. manigent/server/app.py +807 -0
  100. manigent/server/auth.py +355 -0
  101. manigent/server/batch_timeout.py +94 -0
  102. manigent/server/channels/access.py +194 -0
  103. manigent/server/channels/adapter.py +295 -0
  104. manigent/server/channels/config.py +693 -0
  105. manigent/server/channels/contacts.py +39 -0
  106. manigent/server/channels/email_adapter.py +436 -0
  107. manigent/server/channels/email_address.py +145 -0
  108. manigent/server/channels/email_form.py +242 -0
  109. manigent/server/channels/email_format.py +285 -0
  110. manigent/server/channels/email_mail.py +427 -0
  111. manigent/server/channels/email_mailgun.py +164 -0
  112. manigent/server/channels/email_text.py +280 -0
  113. manigent/server/channels/file_links.py +127 -0
  114. manigent/server/channels/gateway.py +2998 -0
  115. manigent/server/channels/hub_delivery.py +211 -0
  116. manigent/server/channels/hub_store.py +1730 -0
  117. manigent/server/channels/line.py +645 -0
  118. manigent/server/channels/line_format.py +589 -0
  119. manigent/server/channels/log_redaction.py +145 -0
  120. manigent/server/channels/store.py +3316 -0
  121. manigent/server/channels/telegram.py +422 -0
  122. manigent/server/channels/telegram_format.py +312 -0
  123. manigent/server/channels/webchat.py +261 -0
  124. manigent/server/channels/webchat_widget.js +1310 -0
  125. manigent/server/channels/whatsapp.py +707 -0
  126. manigent/server/channels/whatsapp_format.py +511 -0
  127. manigent/server/chat_search_index.py +1203 -0
  128. manigent/server/config.py +61 -0
  129. manigent/server/context.py +121 -0
  130. manigent/server/coordinator_rule.py +115 -0
  131. manigent/server/desk_todo_notify.py +300 -0
  132. manigent/server/edge_hub.py +577 -0
  133. manigent/server/email.py +354 -0
  134. manigent/server/errors.py +83 -0
  135. manigent/server/home_fs_relay.py +392 -0
  136. manigent/server/hub/adapter.py +1395 -0
  137. manigent/server/hub/agent_send_guard.py +196 -0
  138. manigent/server/hub/avatar.py +342 -0
  139. manigent/server/hub/browser.py +778 -0
  140. manigent/server/hub/client.py +859 -0
  141. manigent/server/hub/demand.py +49 -0
  142. manigent/server/hub/directory.py +385 -0
  143. manigent/server/hub/enroll.py +400 -0
  144. manigent/server/hub/http.py +134 -0
  145. manigent/server/hub/identity.py +61 -0
  146. manigent/server/hub/keys.py +588 -0
  147. manigent/server/hub/mirror.py +802 -0
  148. manigent/server/hub/operator.py +817 -0
  149. manigent/server/hub/retain.py +361 -0
  150. manigent/server/hub/room_bridge.py +741 -0
  151. manigent/server/hub/runtime.py +691 -0
  152. manigent/server/hub/trust.py +182 -0
  153. manigent/server/hub/views.py +316 -0
  154. manigent/server/idempotency.py +205 -0
  155. manigent/server/in_flight_restore.py +181 -0
  156. manigent/server/inspection.py +816 -0
  157. manigent/server/isolation_gate.py +516 -0
  158. manigent/server/isolation_notice.py +310 -0
  159. manigent/server/managed_job_events.py +242 -0
  160. manigent/server/mcp_registry.py +118 -0
  161. manigent/server/message_forward.py +78 -0
  162. manigent/server/message_scheduler.py +176 -0
  163. manigent/server/notification_assets.py +164 -0
  164. manigent/server/oauth_login/cli_state.py +120 -0
  165. manigent/server/oauth_login/config.py +90 -0
  166. manigent/server/oauth_login/errors.py +78 -0
  167. manigent/server/oauth_login/flow.py +223 -0
  168. manigent/server/oauth_login/handoff.py +63 -0
  169. manigent/server/oauth_login/providers.py +45 -0
  170. manigent/server/oauth_state.py +81 -0
  171. manigent/server/owner_isolation.py +466 -0
  172. manigent/server/participant_liveness.py +82 -0
  173. manigent/server/public_profile.py +149 -0
  174. manigent/server/public_requests/candidates.py +116 -0
  175. manigent/server/public_requests/dispatch.py +121 -0
  176. manigent/server/public_requests/ranking.py +153 -0
  177. manigent/server/recent_activity.py +250 -0
  178. manigent/server/reflection_completion_subscriber.py +151 -0
  179. manigent/server/reflection_scheduler.py +239 -0
  180. manigent/server/requester_key_migration.py +261 -0
  181. manigent/server/room_flow.py +139 -0
  182. manigent/server/routes/_batch.py +218 -0
  183. manigent/server/routes/_fd_routing.py +155 -0
  184. manigent/server/routes/_mentions.py +70 -0
  185. manigent/server/routes/agent_env.py +188 -0
  186. manigent/server/routes/agent_fs.py +450 -0
  187. manigent/server/routes/agents.py +1206 -0
  188. manigent/server/routes/announcements.py +79 -0
  189. manigent/server/routes/auth.py +387 -0
  190. manigent/server/routes/brief_tabs.py +404 -0
  191. manigent/server/routes/changelog.py +237 -0
  192. manigent/server/routes/channels.py +993 -0
  193. manigent/server/routes/chatrooms.py +871 -0
  194. manigent/server/routes/desk_labels.py +298 -0
  195. manigent/server/routes/desk_latest_messages.py +116 -0
  196. manigent/server/routes/desk_read_state.py +110 -0
  197. manigent/server/routes/desk_sign_off.py +88 -0
  198. manigent/server/routes/desk_sops.py +216 -0
  199. manigent/server/routes/desk_todos.py +692 -0
  200. manigent/server/routes/desk_tour.py +44 -0
  201. manigent/server/routes/files.py +572 -0
  202. manigent/server/routes/hosts.py +484 -0
  203. manigent/server/routes/hub.py +534 -0
  204. manigent/server/routes/hub_channels.py +234 -0
  205. manigent/server/routes/inbox.py +581 -0
  206. manigent/server/routes/install.ps1 +436 -0
  207. manigent/server/routes/install.py +324 -0
  208. manigent/server/routes/install.sh +566 -0
  209. manigent/server/routes/isolation_check.py +145 -0
  210. manigent/server/routes/knowledge_packs.py +477 -0
  211. manigent/server/routes/managed_jobs.py +196 -0
  212. manigent/server/routes/mcps.py +271 -0
  213. manigent/server/routes/messages.py +1972 -0
  214. manigent/server/routes/model_defaults.py +279 -0
  215. manigent/server/routes/oauth.py +237 -0
  216. manigent/server/routes/oauth_login.py +351 -0
  217. manigent/server/routes/owner_isolation.py +91 -0
  218. manigent/server/routes/project_plans.py +1521 -0
  219. manigent/server/routes/project_reports.py +235 -0
  220. manigent/server/routes/projects.py +2047 -0
  221. manigent/server/routes/public_agents.py +151 -0
  222. manigent/server/routes/public_requests.py +181 -0
  223. manigent/server/routes/reflection.py +93 -0
  224. manigent/server/routes/scheduled_messages.py +263 -0
  225. manigent/server/routes/search.py +94 -0
  226. manigent/server/routes/sharing.py +156 -0
  227. manigent/server/routes/skills.py +406 -0
  228. manigent/server/routes/templates.py +219 -0
  229. manigent/server/routes/turn_tokens.py +119 -0
  230. manigent/server/routes/webchat.py +406 -0
  231. manigent/server/routes/websocket.py +431 -0
  232. manigent/server/serving_only.py +200 -0
  233. manigent/server/signup_policy.py +120 -0
  234. manigent/server/skill_registry.py +164 -0
  235. manigent/server/socket_events.py +858 -0
  236. manigent/server/timeout_checker.py +446 -0
  237. manigent/server/tunnel_subscriber.py +1000 -0
  238. manigent/server/turn_tokens.py +285 -0
  239. manigent/server/ws_hub.py +556 -0
  240. manigent/server_cli.py +31 -0
  241. manigent/sync/changelog.py +885 -0
  242. manigent/sync/console_subscriber.py +222 -0
  243. manigent/sync/runloop.py +619 -0
  244. manigent/sync/runloop_manager.py +197 -0
  245. manigent/sync/subscriber.py +98 -0
  246. manigent/utils/agent_processes.py +276 -0
  247. manigent/utils/agent_storage.py +125 -0
  248. manigent/utils/email.py +563 -0
  249. manigent/utils/env_store.py +174 -0
  250. manigent/utils/extra_dirs.py +85 -0
  251. manigent/utils/file_io.py +485 -0
  252. manigent/utils/invoke_timeout.py +87 -0
  253. manigent/utils/jsonc.py +78 -0
  254. manigent/utils/knowledge_index.py +148 -0
  255. manigent/utils/nofollow_fs.py +279 -0
  256. manigent/utils/notification_center.py +67 -0
  257. manigent/utils/version.py +57 -0
  258. manigent/web/frontend/.design-sync-entry.tsx +74 -0
  259. manigent/web/frontend/.design-sync-provider.tsx +46 -0
  260. manigent/web/frontend/.eslintrc.cjs +183 -0
  261. manigent/web/frontend/.gitignore +6 -0
  262. manigent/web/frontend/app/page.tsx +39 -0
  263. manigent/web/frontend/hub-terms.html +192 -0
  264. manigent/web/frontend/index.html +15 -0
  265. manigent/web/frontend/landing.html +15 -0
  266. manigent/web/frontend/package-lock.json +8028 -0
  267. manigent/web/frontend/package.json +55 -0
  268. manigent/web/frontend/postcss.config.js +6 -0
  269. manigent/web/frontend/privacy.html +217 -0
  270. manigent/web/frontend/private-beta-announcement.html +19 -0
  271. manigent/web/frontend/public/apple-touch-icon.png +0 -0
  272. manigent/web/frontend/public/brand-hero-banner.png +0 -0
  273. manigent/web/frontend/public/brand-hero.png +0 -0
  274. manigent/web/frontend/public/favicon.png +0 -0
  275. manigent/web/frontend/public/favicon.svg +8 -0
  276. manigent/web/frontend/public/icon-transparent-sm.png +0 -0
  277. manigent/web/frontend/public/icon.png +0 -0
  278. manigent/web/frontend/public/manigent-mark.svg +7 -0
  279. manigent/web/frontend/public/vite.svg +5 -0
  280. manigent/web/frontend/public.html +15 -0
  281. manigent/web/frontend/src/App.activeAccountRedirect.test.tsx +236 -0
  282. manigent/web/frontend/src/App.hubHostDm.test.tsx +119 -0
  283. manigent/web/frontend/src/App.hubHostProject.test.tsx +142 -0
  284. manigent/web/frontend/src/App.hubRoutes.test.tsx +187 -0
  285. manigent/web/frontend/src/App.oauthAddCallback.test.tsx +263 -0
  286. manigent/web/frontend/src/App.tsx +246 -0
  287. manigent/web/frontend/src/api/attachments.ts +32 -0
  288. manigent/web/frontend/src/api/batchLoader.test.ts +212 -0
  289. manigent/web/frontend/src/api/batchLoader.ts +124 -0
  290. manigent/web/frontend/src/api/chatroomsBatch.test.tsx +392 -0
  291. manigent/web/frontend/src/api/client.ts +321 -0
  292. manigent/web/frontend/src/api/crossAccountAuth.test.ts +388 -0
  293. manigent/web/frontend/src/api/endpoints/agentEnv.ts +24 -0
  294. manigent/web/frontend/src/api/endpoints/agentFs.ts +125 -0
  295. manigent/web/frontend/src/api/endpoints/agentSearch.ts +19 -0
  296. manigent/web/frontend/src/api/endpoints/agents.ts +66 -0
  297. manigent/web/frontend/src/api/endpoints/announcements.ts +26 -0
  298. manigent/web/frontend/src/api/endpoints/auth.ts +361 -0
  299. manigent/web/frontend/src/api/endpoints/authLogin.test.ts +236 -0
  300. manigent/web/frontend/src/api/endpoints/batch.ts +64 -0
  301. manigent/web/frontend/src/api/endpoints/briefTabs.ts +81 -0
  302. manigent/web/frontend/src/api/endpoints/channels.ts +285 -0
  303. manigent/web/frontend/src/api/endpoints/computers.ts +212 -0
  304. manigent/web/frontend/src/api/endpoints/deskLabels.ts +151 -0
  305. manigent/web/frontend/src/api/endpoints/deskLatestMessages.ts +23 -0
  306. manigent/web/frontend/src/api/endpoints/deskReadState.ts +41 -0
  307. manigent/web/frontend/src/api/endpoints/deskSignOffs.ts +74 -0
  308. manigent/web/frontend/src/api/endpoints/deskSops.ts +53 -0
  309. manigent/web/frontend/src/api/endpoints/deskTodoAttachments.ts +69 -0
  310. manigent/web/frontend/src/api/endpoints/deskTodoProjects.test.ts +99 -0
  311. manigent/web/frontend/src/api/endpoints/deskTodoProjects.ts +114 -0
  312. manigent/web/frontend/src/api/endpoints/deskTodos.ts +164 -0
  313. manigent/web/frontend/src/api/endpoints/deskTour.ts +16 -0
  314. manigent/web/frontend/src/api/endpoints/dm.ts +137 -0
  315. manigent/web/frontend/src/api/endpoints/files.ts +55 -0
  316. manigent/web/frontend/src/api/endpoints/hub.contract.test.ts +94 -0
  317. manigent/web/frontend/src/api/endpoints/hub.keys.ts +260 -0
  318. manigent/web/frontend/src/api/endpoints/hub.test.ts +203 -0
  319. manigent/web/frontend/src/api/endpoints/hub.ts +654 -0
  320. manigent/web/frontend/src/api/endpoints/index.ts +15 -0
  321. manigent/web/frontend/src/api/endpoints/install.ts +74 -0
  322. manigent/web/frontend/src/api/endpoints/isolationCheck.ts +36 -0
  323. manigent/web/frontend/src/api/endpoints/knowledgePacks.ts +179 -0
  324. manigent/web/frontend/src/api/endpoints/mcps.ts +36 -0
  325. manigent/web/frontend/src/api/endpoints/messages.held.test.ts +43 -0
  326. manigent/web/frontend/src/api/endpoints/messages.ts +95 -0
  327. manigent/web/frontend/src/api/endpoints/modelConfigs.ts +232 -0
  328. manigent/web/frontend/src/api/endpoints/oauthApi.test.ts +110 -0
  329. manigent/web/frontend/src/api/endpoints/projectPlans.ts +608 -0
  330. manigent/web/frontend/src/api/endpoints/projectReports.ts +36 -0
  331. manigent/web/frontend/src/api/endpoints/projects.ts +124 -0
  332. manigent/web/frontend/src/api/endpoints/publicRequests.ts +75 -0
  333. manigent/web/frontend/src/api/endpoints/reflection.ts +32 -0
  334. manigent/web/frontend/src/api/endpoints/roomFlow.ts +14 -0
  335. manigent/web/frontend/src/api/endpoints/scheduledMessages.ts +60 -0
  336. manigent/web/frontend/src/api/endpoints/search.ts +27 -0
  337. manigent/web/frontend/src/api/endpoints/sharing.ts +42 -0
  338. manigent/web/frontend/src/api/endpoints/skills.ts +67 -0
  339. manigent/web/frontend/src/api/endpoints/templates.ts +72 -0
  340. manigent/web/frontend/src/api/loaders.ts +22 -0
  341. manigent/web/frontend/src/api/singleIssuer.test.ts +148 -0
  342. manigent/web/frontend/src/api/transientRetry.test.ts +176 -0
  343. manigent/web/frontend/src/api/transientRetry.ts +140 -0
  344. manigent/web/frontend/src/api/websocket.resync.test.ts +111 -0
  345. manigent/web/frontend/src/api/websocket.ts +335 -0
  346. manigent/web/frontend/src/components/agent/AgentNameLink.tsx +24 -0
  347. manigent/web/frontend/src/components/agent/AgentViewActions.test.tsx +41 -0
  348. manigent/web/frontend/src/components/agent/AgentViewActions.tsx +89 -0
  349. manigent/web/frontend/src/components/agent/CreateAgentPage.tsx +535 -0
  350. manigent/web/frontend/src/components/agent/JsonConfigEditor.tsx +33 -0
  351. manigent/web/frontend/src/components/agent/KnowledgePackList.tsx +103 -0
  352. manigent/web/frontend/src/components/agent/McpCatalog.tsx +261 -0
  353. manigent/web/frontend/src/components/agent/McpConfigModal.tsx +224 -0
  354. manigent/web/frontend/src/components/agent/PreConsentModal.tsx +172 -0
  355. manigent/web/frontend/src/components/agent/SkillCatalog.tsx +364 -0
  356. manigent/web/frontend/src/components/agent/SkillConfigModal.tsx +221 -0
  357. manigent/web/frontend/src/components/auth/AddAccountPage.test.tsx +181 -0
  358. manigent/web/frontend/src/components/auth/AddAccountPage.tsx +201 -0
  359. manigent/web/frontend/src/components/auth/AuthShell.tsx +462 -0
  360. manigent/web/frontend/src/components/auth/LoginPage.test.tsx +384 -0
  361. manigent/web/frontend/src/components/auth/LoginPage.tsx +129 -0
  362. manigent/web/frontend/src/components/auth/OAuthCallbackPage.test.tsx +185 -0
  363. manigent/web/frontend/src/components/auth/OAuthCallbackPage.tsx +154 -0
  364. manigent/web/frontend/src/components/auth/OAuthLinkedBanner.tsx +44 -0
  365. manigent/web/frontend/src/components/auth/ProviderButtons.tsx +94 -0
  366. manigent/web/frontend/src/components/auth/SignupPage.tsx +437 -0
  367. manigent/web/frontend/src/components/auth/StepProgress.tsx +60 -0
  368. manigent/web/frontend/src/components/auth/VerifyEmailPage.test.tsx +155 -0
  369. manigent/web/frontend/src/components/auth/VerifyEmailPage.tsx +211 -0
  370. manigent/web/frontend/src/components/auth/index.ts +3 -0
  371. manigent/web/frontend/src/components/auth/oauthErrors.test.ts +107 -0
  372. manigent/web/frontend/src/components/auth/oauthErrors.ts +82 -0
  373. manigent/web/frontend/src/components/auth/useUsernameCheck.test.tsx +68 -0
  374. manigent/web/frontend/src/components/auth/useUsernameCheck.ts +86 -0
  375. manigent/web/frontend/src/components/beta/BetaPage.tsx +21 -0
  376. manigent/web/frontend/src/components/beta/DayAtMyDesk.tsx +120 -0
  377. manigent/web/frontend/src/components/beta/Footer.tsx +82 -0
  378. manigent/web/frontend/src/components/beta/Hero.tsx +224 -0
  379. manigent/web/frontend/src/components/beta/Nav.tsx +51 -0
  380. manigent/web/frontend/src/components/beta/Pillars.tsx +172 -0
  381. manigent/web/frontend/src/components/beta/TwoModels.tsx +146 -0
  382. manigent/web/frontend/src/components/beta/constants.ts +3 -0
  383. manigent/web/frontend/src/components/briefing/BriefingFrame.test.tsx +208 -0
  384. manigent/web/frontend/src/components/briefing/BriefingFrame.tsx +151 -0
  385. manigent/web/frontend/src/components/briefing/BriefingPage.test.tsx +176 -0
  386. manigent/web/frontend/src/components/briefing/BriefingPage.tsx +157 -0
  387. manigent/web/frontend/src/components/briefing/BriefingPage.wsDelete.test.tsx +177 -0
  388. manigent/web/frontend/src/components/briefing/briefing.css +147 -0
  389. manigent/web/frontend/src/components/briefing/heightBootstrap.test.ts +121 -0
  390. manigent/web/frontend/src/components/briefing/heightBootstrap.ts +224 -0
  391. manigent/web/frontend/src/components/briefing/parseBriefMessage.test.ts +90 -0
  392. manigent/web/frontend/src/components/briefing/sampleBriefing.ts +148 -0
  393. manigent/web/frontend/src/components/channels/ChannelBadge.tsx +35 -0
  394. manigent/web/frontend/src/components/chatroom/ChannelThreadControls.tsx +127 -0
  395. manigent/web/frontend/src/components/chatroom/ChannelThreadNotice.test.tsx +207 -0
  396. manigent/web/frontend/src/components/chatroom/ChannelThreadNotice.tsx +80 -0
  397. manigent/web/frontend/src/components/chatroom/ChatroomView.channel.test.tsx +550 -0
  398. manigent/web/frontend/src/components/chatroom/ChatroomView.flow.test.tsx +186 -0
  399. manigent/web/frontend/src/components/chatroom/ChatroomView.isolation.test.tsx +70 -0
  400. manigent/web/frontend/src/components/chatroom/ChatroomView.tsx +450 -0
  401. manigent/web/frontend/src/components/chatroom/DelegationRow.test.tsx +170 -0
  402. manigent/web/frontend/src/components/chatroom/DelegationRow.tsx +217 -0
  403. manigent/web/frontend/src/components/chatroom/DeliveryStatusLine.test.tsx +33 -0
  404. manigent/web/frontend/src/components/chatroom/DeliveryStatusLine.tsx +46 -0
  405. manigent/web/frontend/src/components/chatroom/ForwardModal.test.tsx +109 -0
  406. manigent/web/frontend/src/components/chatroom/ForwardModal.tsx +304 -0
  407. manigent/web/frontend/src/components/chatroom/HeldNotice.tsx +77 -0
  408. manigent/web/frontend/src/components/chatroom/MentionDropdown.tsx +97 -0
  409. manigent/web/frontend/src/components/chatroom/MessageInput.tsx +408 -0
  410. manigent/web/frontend/src/components/chatroom/MessageItem.tsx +425 -0
  411. manigent/web/frontend/src/components/chatroom/MessageList.outside.test.tsx +98 -0
  412. manigent/web/frontend/src/components/chatroom/MessageList.test.tsx +245 -0
  413. manigent/web/frontend/src/components/chatroom/MessageList.tsx +406 -0
  414. manigent/web/frontend/src/components/chatroom/OfflineRemedyNote.test.tsx +211 -0
  415. manigent/web/frontend/src/components/chatroom/OfflineRemedyNote.tsx +182 -0
  416. manigent/web/frontend/src/components/chatroom/OutsideBadge.tsx +18 -0
  417. manigent/web/frontend/src/components/chatroom/RoomFlowControl.tsx +49 -0
  418. manigent/web/frontend/src/components/chatroom/RoomFlowStrip.test.tsx +47 -0
  419. manigent/web/frontend/src/components/chatroom/RoomFlowStrip.tsx +25 -0
  420. manigent/web/frontend/src/components/chatroom/SaveToPackModal.tsx +350 -0
  421. manigent/web/frontend/src/components/chatroom/StagedAttachments.test.tsx +56 -0
  422. manigent/web/frontend/src/components/chatroom/StagedAttachments.tsx +160 -0
  423. manigent/web/frontend/src/components/chatroom/SystemNote.tsx +18 -0
  424. manigent/web/frontend/src/components/chatroom/contactSender.test.tsx +130 -0
  425. manigent/web/frontend/src/components/chatroom/index.ts +3 -0
  426. manigent/web/frontend/src/components/chatroom/recipientStatus.test.ts +344 -0
  427. manigent/web/frontend/src/components/chatroom/recipientStatus.ts +197 -0
  428. manigent/web/frontend/src/components/common/AnnouncementBanners.test.tsx +221 -0
  429. manigent/web/frontend/src/components/common/AnnouncementBanners.tsx +180 -0
  430. manigent/web/frontend/src/components/common/Avatar.test.tsx +50 -0
  431. manigent/web/frontend/src/components/common/Avatar.tsx +102 -0
  432. manigent/web/frontend/src/components/common/Badge.tsx +30 -0
  433. manigent/web/frontend/src/components/common/BrandName.tsx +16 -0
  434. manigent/web/frontend/src/components/common/ClearHistoryButton.tsx +74 -0
  435. manigent/web/frontend/src/components/common/CollapsibleHeader.tsx +64 -0
  436. manigent/web/frontend/src/components/common/ConnectionStatus.test.tsx +56 -0
  437. manigent/web/frontend/src/components/common/ConnectionStatus.tsx +28 -0
  438. manigent/web/frontend/src/components/common/DropOverlay.tsx +27 -0
  439. manigent/web/frontend/src/components/common/InlineEditableTitle.test.tsx +369 -0
  440. manigent/web/frontend/src/components/common/InlineEditableTitle.tsx +287 -0
  441. manigent/web/frontend/src/components/common/IsolationUnavailablePanel.tsx +19 -0
  442. manigent/web/frontend/src/components/common/Loading.tsx +22 -0
  443. manigent/web/frontend/src/components/common/ModelSelector.tsx +248 -0
  444. manigent/web/frontend/src/components/common/Overlay.tsx +15 -0
  445. manigent/web/frontend/src/components/common/ResizeHandle.tsx +52 -0
  446. manigent/web/frontend/src/components/common/TagAutocompleteInput.test.tsx +92 -0
  447. manigent/web/frontend/src/components/common/TagAutocompleteInput.tsx +246 -0
  448. manigent/web/frontend/src/components/common/TagPillInput.tsx +181 -0
  449. manigent/web/frontend/src/components/common/TeamAndAgentPicker.tsx +83 -0
  450. manigent/web/frontend/src/components/common/Timestamp.tsx +61 -0
  451. manigent/web/frontend/src/components/common/VerifiedBadge.tsx +20 -0
  452. manigent/web/frontend/src/components/common/index.ts +8 -0
  453. manigent/web/frontend/src/components/composer/PhPopover.tsx +239 -0
  454. manigent/web/frontend/src/components/composer/PromptEditor.test.tsx +472 -0
  455. manigent/web/frontend/src/components/composer/PromptEditor.tsx +540 -0
  456. manigent/web/frontend/src/components/composer/caret.ts +159 -0
  457. manigent/web/frontend/src/components/composer/placeholders.test.ts +352 -0
  458. manigent/web/frontend/src/components/composer/placeholders.ts +354 -0
  459. manigent/web/frontend/src/components/composer/promptEditor.css +161 -0
  460. manigent/web/frontend/src/components/computer/ComputerPage.test.tsx +452 -0
  461. manigent/web/frontend/src/components/computer/ComputerPage.tsx +811 -0
  462. manigent/web/frontend/src/components/computer/ConnectComputerModal.tsx +135 -0
  463. manigent/web/frontend/src/components/computer/CopyCommand.tsx +77 -0
  464. manigent/web/frontend/src/components/computer/DisconnectComputerModal.tsx +121 -0
  465. manigent/web/frontend/src/components/computer/SoftwareCard.tsx +145 -0
  466. manigent/web/frontend/src/components/computer/TerminalCard.test.tsx +114 -0
  467. manigent/web/frontend/src/components/computer/TerminalCard.tsx +131 -0
  468. manigent/web/frontend/src/components/computer/TerminalPanel.tsx +226 -0
  469. manigent/web/frontend/src/components/computer/TrustPanel.test.tsx +58 -0
  470. manigent/web/frontend/src/components/computer/TrustPanel.tsx +143 -0
  471. manigent/web/frontend/src/components/computer/computerCopy.test.ts +322 -0
  472. manigent/web/frontend/src/components/computer/computerCopy.ts +413 -0
  473. manigent/web/frontend/src/components/computer/sections.ts +21 -0
  474. manigent/web/frontend/src/components/computer/terminalProtocol.test.ts +135 -0
  475. manigent/web/frontend/src/components/computer/terminalProtocol.ts +170 -0
  476. manigent/web/frontend/src/components/context/ContextGuide.test.tsx +26 -0
  477. manigent/web/frontend/src/components/context/ContextGuide.tsx +144 -0
  478. manigent/web/frontend/src/components/context/ContextLanding.tsx +46 -0
  479. manigent/web/frontend/src/components/desk/CardBand.a11y.test.tsx +138 -0
  480. manigent/web/frontend/src/components/desk/CardBand.tsx +132 -0
  481. manigent/web/frontend/src/components/desk/DashTile.tsx +81 -0
  482. manigent/web/frontend/src/components/desk/DeskAgentPicker.retained.test.tsx +79 -0
  483. manigent/web/frontend/src/components/desk/DeskAgentPicker.tsx +151 -0
  484. manigent/web/frontend/src/components/desk/DeskComposer.detachTodo.test.tsx +233 -0
  485. manigent/web/frontend/src/components/desk/DeskComposer.dispatch.test.tsx +208 -0
  486. manigent/web/frontend/src/components/desk/DeskComposer.loadTodoDraft.test.tsx +242 -0
  487. manigent/web/frontend/src/components/desk/DeskComposer.restage.test.tsx +258 -0
  488. manigent/web/frontend/src/components/desk/DeskComposer.saveTodo.test.tsx +265 -0
  489. manigent/web/frontend/src/components/desk/DeskComposer.tsx +828 -0
  490. manigent/web/frontend/src/components/desk/DeskPage.crossHighlight.test.tsx +427 -0
  491. manigent/web/frontend/src/components/desk/DeskPage.link.test.tsx +271 -0
  492. manigent/web/frontend/src/components/desk/DeskPage.tsx +1066 -0
  493. manigent/web/frontend/src/components/desk/DeskPage.welcomeTour.test.tsx +262 -0
  494. manigent/web/frontend/src/components/desk/DeskSideRail.tsx +100 -0
  495. manigent/web/frontend/src/components/desk/DeskWelcomeTour.tsx +513 -0
  496. manigent/web/frontend/src/components/desk/DeskZeroState.tsx +45 -0
  497. manigent/web/frontend/src/components/desk/LabelChip.tsx +147 -0
  498. manigent/web/frontend/src/components/desk/LabelFilter.tsx +474 -0
  499. manigent/web/frontend/src/components/desk/LabelInput.test.tsx +439 -0
  500. manigent/web/frontend/src/components/desk/LabelInput.tsx +477 -0
  501. manigent/web/frontend/src/components/desk/LabelManageSheet.test.tsx +384 -0
  502. manigent/web/frontend/src/components/desk/LabelManageSheet.tsx +498 -0
  503. manigent/web/frontend/src/components/desk/PhaseRail.test.tsx +170 -0
  504. manigent/web/frontend/src/components/desk/PhaseRail.tsx +120 -0
  505. manigent/web/frontend/src/components/desk/PlanBand.test.tsx +655 -0
  506. manigent/web/frontend/src/components/desk/PlanBand.tsx +216 -0
  507. manigent/web/frontend/src/components/desk/SaveTodoModal.tsx +126 -0
  508. manigent/web/frontend/src/components/desk/SopEditor.tsx +280 -0
  509. manigent/web/frontend/src/components/desk/SopItem.tsx +171 -0
  510. manigent/web/frontend/src/components/desk/SopRail.test.tsx +517 -0
  511. manigent/web/frontend/src/components/desk/SopRail.tsx +250 -0
  512. manigent/web/frontend/src/components/desk/TicketChip.tsx +51 -0
  513. manigent/web/frontend/src/components/desk/TodoItem.attachments.test.tsx +96 -0
  514. manigent/web/frontend/src/components/desk/TodoItem.menu.test.tsx +142 -0
  515. manigent/web/frontend/src/components/desk/TodoItem.tsx +573 -0
  516. manigent/web/frontend/src/components/desk/TodoRail.longpress.test.tsx +396 -0
  517. manigent/web/frontend/src/components/desk/TodoRail.test.tsx +1155 -0
  518. manigent/web/frontend/src/components/desk/TodoRail.tsx +918 -0
  519. manigent/web/frontend/src/components/desk/TodoRowMenu.tsx +147 -0
  520. manigent/web/frontend/src/components/desk/UpdateCard.bands.test.tsx +308 -0
  521. manigent/web/frontend/src/components/desk/UpdateCard.sendBack.test.tsx +444 -0
  522. manigent/web/frontend/src/components/desk/UpdateCard.tsx +943 -0
  523. manigent/web/frontend/src/components/desk/UpdateCard.untrusted.test.tsx +161 -0
  524. manigent/web/frontend/src/components/desk/desk.css +1921 -0
  525. manigent/web/frontend/src/components/desk/desk.css.test.ts +582 -0
  526. manigent/web/frontend/src/components/desk/deskBands.test.ts +389 -0
  527. manigent/web/frontend/src/components/desk/deskBands.ts +226 -0
  528. manigent/web/frontend/src/components/desk/m16Surfaces.test.ts +134 -0
  529. manigent/web/frontend/src/components/desk/sopSyntax.ts +73 -0
  530. manigent/web/frontend/src/components/discovery/AgentDirectory.tsx +71 -0
  531. manigent/web/frontend/src/components/discovery/AgentFilterBar.tsx +46 -0
  532. manigent/web/frontend/src/components/discovery/AgentSearchBar.tsx +56 -0
  533. manigent/web/frontend/src/components/dm/AgentSummaryCard.tsx +154 -0
  534. manigent/web/frontend/src/components/dm/ComposeFields.tsx +145 -0
  535. manigent/web/frontend/src/components/dm/DMChatView.flow.test.tsx +374 -0
  536. manigent/web/frontend/src/components/dm/DMChatView.tsx +841 -0
  537. manigent/web/frontend/src/components/dm/DMZeroState.tsx +204 -0
  538. manigent/web/frontend/src/components/dm/DmComposeModal.tsx +301 -0
  539. manigent/web/frontend/src/components/dm/PersonalizeModal.tsx +366 -0
  540. manigent/web/frontend/src/components/dm/index.ts +1 -0
  541. manigent/web/frontend/src/components/files/FileItem.tsx +138 -0
  542. manigent/web/frontend/src/components/files/FileList.outside.test.tsx +29 -0
  543. manigent/web/frontend/src/components/files/FileList.tsx +48 -0
  544. manigent/web/frontend/src/components/files/FilePreview.test.tsx +75 -0
  545. manigent/web/frontend/src/components/files/FilePreview.tsx +325 -0
  546. manigent/web/frontend/src/components/files/FileViewerModal.test.tsx +157 -0
  547. manigent/web/frontend/src/components/files/FileViewerModal.tsx +261 -0
  548. manigent/web/frontend/src/components/files/HighlightedCode.tsx +39 -0
  549. manigent/web/frontend/src/components/files/SaveToAgentPanel.test.tsx +156 -0
  550. manigent/web/frontend/src/components/files/SaveToAgentPanel.tsx +545 -0
  551. manigent/web/frontend/src/components/files/index.ts +3 -0
  552. manigent/web/frontend/src/components/hero/AgentAvatar.tsx +66 -0
  553. manigent/web/frontend/src/components/hero/Button.tsx +66 -0
  554. manigent/web/frontend/src/components/hero/Hero.tsx +133 -0
  555. manigent/web/frontend/src/components/homefs/HomeFolderBrowser.test.tsx +393 -0
  556. manigent/web/frontend/src/components/homefs/HomeFolderBrowser.tsx +792 -0
  557. manigent/web/frontend/src/components/hub/BridgeDeliveryLine.test.tsx +40 -0
  558. manigent/web/frontend/src/components/hub/BridgeDeliveryLine.tsx +36 -0
  559. manigent/web/frontend/src/components/hub/HubAvatar.test.tsx +93 -0
  560. manigent/web/frontend/src/components/hub/HubAvatar.tsx +33 -0
  561. manigent/web/frontend/src/components/hub/HubChatView.test.tsx +695 -0
  562. manigent/web/frontend/src/components/hub/HubChatView.tsx +504 -0
  563. manigent/web/frontend/src/components/hub/HubContactLabel.test.tsx +92 -0
  564. manigent/web/frontend/src/components/hub/HubContactLabel.tsx +47 -0
  565. manigent/web/frontend/src/components/hub/HubDeliveryLine.tsx +49 -0
  566. manigent/web/frontend/src/components/hub/HubDisclosure.tsx +49 -0
  567. manigent/web/frontend/src/components/hub/HubEnrollmentDialog.test.tsx +144 -0
  568. manigent/web/frontend/src/components/hub/HubEnrollmentDialog.tsx +244 -0
  569. manigent/web/frontend/src/components/hub/HubMessageBody.test.tsx +26 -0
  570. manigent/web/frontend/src/components/hub/HubMessageBody.tsx +14 -0
  571. manigent/web/frontend/src/components/hub/HubOfflineConfirm.tsx +45 -0
  572. manigent/web/frontend/src/components/hub/HubThreadBanner.tsx +33 -0
  573. manigent/web/frontend/src/components/hub/HubThreadGuard.tsx +59 -0
  574. manigent/web/frontend/src/components/hub/RemoteAgentCard.test.tsx +50 -0
  575. manigent/web/frontend/src/components/hub/RemoteAgentCard.tsx +174 -0
  576. manigent/web/frontend/src/components/hub/RemoteAgentSection.test.tsx +446 -0
  577. manigent/web/frontend/src/components/hub/RemoteAgentSection.tsx +219 -0
  578. manigent/web/frontend/src/components/hub/ReportDialog.test.tsx +96 -0
  579. manigent/web/frontend/src/components/hub/ReportDialog.tsx +162 -0
  580. manigent/web/frontend/src/components/hub/RetainButton.test.tsx +103 -0
  581. manigent/web/frontend/src/components/hub/RetainButton.tsx +114 -0
  582. manigent/web/frontend/src/components/hub/RetainDialog.test.tsx +68 -0
  583. manigent/web/frontend/src/components/hub/RetainDialog.tsx +115 -0
  584. manigent/web/frontend/src/components/hub/RetainedList.test.tsx +94 -0
  585. manigent/web/frontend/src/components/hub/RetainedList.tsx +32 -0
  586. manigent/web/frontend/src/components/hub/RetainedRow.tsx +129 -0
  587. manigent/web/frontend/src/components/hub/StandInChip.test.tsx +37 -0
  588. manigent/web/frontend/src/components/hub/StandInChip.tsx +43 -0
  589. manigent/web/frontend/src/components/hub/UnusualNameChip.test.tsx +81 -0
  590. manigent/web/frontend/src/components/hub/UnusualNameChip.tsx +22 -0
  591. manigent/web/frontend/src/components/hub/hubLint.test.ts +265 -0
  592. manigent/web/frontend/src/components/landing/ComparisonSection.tsx +92 -0
  593. manigent/web/frontend/src/components/landing/ConsoleSection.tsx +402 -0
  594. manigent/web/frontend/src/components/landing/CrewSection.tsx +224 -0
  595. manigent/web/frontend/src/components/landing/FAQ.tsx +68 -0
  596. manigent/web/frontend/src/components/landing/Footer.tsx +58 -0
  597. manigent/web/frontend/src/components/landing/HowItWorks.tsx +117 -0
  598. manigent/web/frontend/src/components/landing/KnowledgeSection.tsx +91 -0
  599. manigent/web/frontend/src/components/landing/LandingPage.test.tsx +134 -0
  600. manigent/web/frontend/src/components/landing/LearningSection.tsx +486 -0
  601. manigent/web/frontend/src/components/landing/Nav.tsx +68 -0
  602. manigent/web/frontend/src/components/landing/Pricing.tsx +263 -0
  603. manigent/web/frontend/src/components/landing/Section.tsx +98 -0
  604. manigent/web/frontend/src/components/landing/StaffingSection.tsx +122 -0
  605. manigent/web/frontend/src/components/landing/WhyNowSection.tsx +92 -0
  606. manigent/web/frontend/src/components/landing/WhyTeamSection.tsx +73 -0
  607. manigent/web/frontend/src/components/landing/earlyAccess.ts +23 -0
  608. manigent/web/frontend/src/components/layout/AppLayout.tsx +77 -0
  609. manigent/web/frontend/src/components/layout/Sidebar.tsx +172 -0
  610. manigent/web/frontend/src/components/layout/index.ts +2 -0
  611. manigent/web/frontend/src/components/project/ActivityFeed.tsx +247 -0
  612. manigent/web/frontend/src/components/project/CreateProjectPage.tsx +543 -0
  613. manigent/web/frontend/src/components/project/DeleteProjectButton.tsx +39 -0
  614. manigent/web/frontend/src/components/project/ProjectPlanTab.phase.test.tsx +107 -0
  615. manigent/web/frontend/src/components/project/ProjectPlanTab.test.tsx +994 -0
  616. manigent/web/frontend/src/components/project/ProjectPlanTab.tsx +166 -0
  617. manigent/web/frontend/src/components/project/ProjectReportTab.tsx +139 -0
  618. manigent/web/frontend/src/components/project/ProjectView.tsx +390 -0
  619. manigent/web/frontend/src/components/project/index.ts +2 -0
  620. manigent/web/frontend/src/components/project/plan/PlanAcceptance.test.tsx +460 -0
  621. manigent/web/frontend/src/components/project/plan/PlanAcceptance.tsx +111 -0
  622. manigent/web/frontend/src/components/project/plan/PlanBlockEdit.tsx +111 -0
  623. manigent/web/frontend/src/components/project/plan/PlanBlockEditing.test.tsx +1132 -0
  624. manigent/web/frontend/src/components/project/plan/PlanBody.test.tsx +495 -0
  625. manigent/web/frontend/src/components/project/plan/PlanBody.tsx +992 -0
  626. manigent/web/frontend/src/components/project/plan/PlanCollide.tsx +254 -0
  627. manigent/web/frontend/src/components/project/plan/PlanCommentList.test.tsx +420 -0
  628. manigent/web/frontend/src/components/project/plan/PlanCommentList.tsx +391 -0
  629. manigent/web/frontend/src/components/project/plan/PlanDecisionNudge.test.tsx +226 -0
  630. manigent/web/frontend/src/components/project/plan/PlanDecisionNudge.tsx +128 -0
  631. manigent/web/frontend/src/components/project/plan/PlanDestructiveAccept.test.tsx +209 -0
  632. manigent/web/frontend/src/components/project/plan/PlanDiff.test.tsx +126 -0
  633. manigent/web/frontend/src/components/project/plan/PlanDiff.tsx +131 -0
  634. manigent/web/frontend/src/components/project/plan/PlanDiffSeries.test.tsx +500 -0
  635. manigent/web/frontend/src/components/project/plan/PlanDiffSeries.tsx +125 -0
  636. manigent/web/frontend/src/components/project/plan/PlanEditor.mounts.test.tsx +504 -0
  637. manigent/web/frontend/src/components/project/plan/PlanEditor.tsx +2159 -0
  638. manigent/web/frontend/src/components/project/plan/PlanHistory.tsx +69 -0
  639. manigent/web/frontend/src/components/project/plan/PlanInlineNotes.test.tsx +2398 -0
  640. manigent/web/frontend/src/components/project/plan/PlanNoteBase.test.tsx +215 -0
  641. manigent/web/frontend/src/components/project/plan/PlanNoteRow.test.tsx +562 -0
  642. manigent/web/frontend/src/components/project/plan/PlanNoteRow.tsx +908 -0
  643. manigent/web/frontend/src/components/project/plan/PlanQuotePop.tsx +254 -0
  644. manigent/web/frontend/src/components/project/plan/PlanStaleReconcile.test.tsx +244 -0
  645. manigent/web/frontend/src/components/project/plan/PlanSubmitWindow.test.tsx +281 -0
  646. manigent/web/frontend/src/components/project/plan/PlanTray.tsx +184 -0
  647. manigent/web/frontend/src/components/project/plan/PlanTrayMirror.test.tsx +242 -0
  648. manigent/web/frontend/src/components/project/plan/plan.css +1151 -0
  649. manigent/web/frontend/src/components/project/plan/planAnchor.test.tsx +459 -0
  650. manigent/web/frontend/src/components/project/plan/planAnchor.tsx +277 -0
  651. manigent/web/frontend/src/components/project/plan/planBlocks.test.tsx +470 -0
  652. manigent/web/frontend/src/components/project/plan/planBlocks.ts +242 -0
  653. manigent/web/frontend/src/components/project/plan/planContrast.test.ts +229 -0
  654. manigent/web/frontend/src/components/project/plan/planDiffs.test.ts +455 -0
  655. manigent/web/frontend/src/components/project/plan/planDiffs.ts +358 -0
  656. manigent/web/frontend/src/components/project/plan/planTestServer.ts +741 -0
  657. manigent/web/frontend/src/components/project/plan/planTransport.test.ts +160 -0
  658. manigent/web/frontend/src/components/project/plan/planTrayLogic.test.ts +1201 -0
  659. manigent/web/frontend/src/components/project/plan/planTrayLogic.ts +1164 -0
  660. manigent/web/frontend/src/components/publicAgents/PublicAgentsAccount.tsx +162 -0
  661. manigent/web/frontend/src/components/publicAgents/api.ts +55 -0
  662. manigent/web/frontend/src/components/publicAgents/parts.tsx +54 -0
  663. manigent/web/frontend/src/components/publicAgents/publicAgents.css +53 -0
  664. manigent/web/frontend/src/components/publicAgents/publicAgents.test.tsx +86 -0
  665. manigent/web/frontend/src/components/publicAgents/widget.test.ts +148 -0
  666. manigent/web/frontend/src/components/publicAgents/widget.ts +40 -0
  667. manigent/web/frontend/src/components/publicRequests/AgentDrawer.tsx +101 -0
  668. manigent/web/frontend/src/components/publicRequests/AgentPanel.tsx +173 -0
  669. manigent/web/frontend/src/components/publicRequests/AgentRankList.tsx +61 -0
  670. manigent/web/frontend/src/components/publicRequests/MatchRetainButton.tsx +67 -0
  671. manigent/web/frontend/src/components/publicRequests/ProgressBoard.tsx +74 -0
  672. manigent/web/frontend/src/components/publicRequests/PublicRequestsPage.tsx +57 -0
  673. manigent/web/frontend/src/components/publicRequests/RequestHome.tsx +99 -0
  674. manigent/web/frontend/src/components/publicRequests/RequestRoom.tsx +126 -0
  675. manigent/web/frontend/src/components/publicRequests/agentView.ts +65 -0
  676. manigent/web/frontend/src/components/publicRequests/publicRequests.css +209 -0
  677. manigent/web/frontend/src/components/publicRequests/publicRequests.test.tsx +172 -0
  678. manigent/web/frontend/src/components/publicRequests/requestCopy.ts +121 -0
  679. manigent/web/frontend/src/components/sample-request/SampleIdeaList.test.tsx +190 -0
  680. manigent/web/frontend/src/components/sample-request/SampleIdeaList.tsx +180 -0
  681. manigent/web/frontend/src/components/sample-request/SampleRequestBody.tsx +276 -0
  682. manigent/web/frontend/src/components/sample-request/assistantStarterSamples.ts +62 -0
  683. manigent/web/frontend/src/components/sample-request/sampleIdeaList.css +106 -0
  684. manigent/web/frontend/src/components/scheduled/CronPicker.tsx +80 -0
  685. manigent/web/frontend/src/components/scheduled/ScheduleMessageModal.tsx +341 -0
  686. manigent/web/frontend/src/components/scheduled/ScheduledMessagesList.tsx +157 -0
  687. manigent/web/frontend/src/components/settings/AgentSettingsPage.tsx +366 -0
  688. manigent/web/frontend/src/components/settings/ConnectedAccounts.tsx +277 -0
  689. manigent/web/frontend/src/components/settings/DefaultModelSection.test.tsx +96 -0
  690. manigent/web/frontend/src/components/settings/DefaultModelSection.tsx +212 -0
  691. manigent/web/frontend/src/components/settings/DisconnectConfirmModal.tsx +93 -0
  692. manigent/web/frontend/src/components/settings/FrontDeskSettingsPage.isolation.test.tsx +66 -0
  693. manigent/web/frontend/src/components/settings/FrontDeskSettingsPage.tsx +134 -0
  694. manigent/web/frontend/src/components/settings/InvitableAgentsPicker.tsx +182 -0
  695. manigent/web/frontend/src/components/settings/KnowledgePacksSection.tsx +867 -0
  696. manigent/web/frontend/src/components/settings/ModelConfigDialog.catalogDriven.test.tsx +79 -0
  697. manigent/web/frontend/src/components/settings/ModelConfigDialog.tsx +343 -0
  698. manigent/web/frontend/src/components/settings/ModelConfigSection.smartRouting.test.tsx +109 -0
  699. manigent/web/frontend/src/components/settings/ModelConfigSection.tsx +599 -0
  700. manigent/web/frontend/src/components/settings/ReflectionScheduleSection.tsx +170 -0
  701. manigent/web/frontend/src/components/settings/UserSettingsPage.tsx +168 -0
  702. manigent/web/frontend/src/components/settings/agent/AgentStatusStrip.tsx +71 -0
  703. manigent/web/frontend/src/components/settings/agent/BlockedDeploymentsCard.test.tsx +81 -0
  704. manigent/web/frontend/src/components/settings/agent/BlockedDeploymentsCard.tsx +62 -0
  705. manigent/web/frontend/src/components/settings/agent/ChannelIsolationLine.tsx +21 -0
  706. manigent/web/frontend/src/components/settings/agent/ChannelsSection.test.tsx +879 -0
  707. manigent/web/frontend/src/components/settings/agent/ChannelsSection.tsx +1124 -0
  708. manigent/web/frontend/src/components/settings/agent/EnvVarsCard.test.ts +15 -0
  709. manigent/web/frontend/src/components/settings/agent/EnvVarsCard.tsx +301 -0
  710. manigent/web/frontend/src/components/settings/agent/ExtraDirsList.tsx +85 -0
  711. manigent/web/frontend/src/components/settings/agent/GeneralSection.tsx +88 -0
  712. manigent/web/frontend/src/components/settings/agent/HostDisclaimerSlot.test.tsx +32 -0
  713. manigent/web/frontend/src/components/settings/agent/HostDisclaimerSlot.tsx +30 -0
  714. manigent/web/frontend/src/components/settings/agent/HubChannelCard.test.tsx +449 -0
  715. manigent/web/frontend/src/components/settings/agent/HubChannelCard.tsx +312 -0
  716. manigent/web/frontend/src/components/settings/agent/HubInvitableAgentsCard.test.tsx +83 -0
  717. manigent/web/frontend/src/components/settings/agent/HubInvitableAgentsCard.tsx +64 -0
  718. manigent/web/frontend/src/components/settings/agent/HubSendUsageCard.test.tsx +69 -0
  719. manigent/web/frontend/src/components/settings/agent/HubSendUsageCard.tsx +42 -0
  720. manigent/web/frontend/src/components/settings/agent/HubTurnOffDialog.tsx +88 -0
  721. manigent/web/frontend/src/components/settings/agent/IsolationRecheckButton.test.tsx +26 -0
  722. manigent/web/frontend/src/components/settings/agent/IsolationRecheckButton.tsx +68 -0
  723. manigent/web/frontend/src/components/settings/agent/KnowledgeSection.tsx +68 -0
  724. manigent/web/frontend/src/components/settings/agent/LineChannelCard.test.tsx +428 -0
  725. manigent/web/frontend/src/components/settings/agent/LineChannelCard.tsx +343 -0
  726. manigent/web/frontend/src/components/settings/agent/RuntimeSection.test.tsx +164 -0
  727. manigent/web/frontend/src/components/settings/agent/RuntimeSection.tsx +118 -0
  728. manigent/web/frontend/src/components/settings/agent/StorageSection.tsx +78 -0
  729. manigent/web/frontend/src/components/settings/agent/WebChatChannelCard.test.tsx +253 -0
  730. manigent/web/frontend/src/components/settings/agent/WebChatChannelCard.tsx +401 -0
  731. manigent/web/frontend/src/components/settings/agent/WhatsAppChannelCard.test.tsx +462 -0
  732. manigent/web/frontend/src/components/settings/agent/WhatsAppChannelCard.tsx +289 -0
  733. manigent/web/frontend/src/components/settings/agent/agentSettings.test.tsx +109 -0
  734. manigent/web/frontend/src/components/settings/agent/channelSetupGuides.test.tsx +162 -0
  735. manigent/web/frontend/src/components/settings/agent/channelSetupGuides.tsx +119 -0
  736. manigent/web/frontend/src/components/settings/agent/channelsShared.ts +83 -0
  737. manigent/web/frontend/src/components/settings/agent/fields.tsx +67 -0
  738. manigent/web/frontend/src/components/settings/agent/sections.ts +36 -0
  739. manigent/web/frontend/src/components/settings/agent/useAgentSettingsDraft.ts +129 -0
  740. manigent/web/frontend/src/components/settings/agent/useInstallSelection.ts +38 -0
  741. manigent/web/frontend/src/components/settings/primitives.tsx +98 -0
  742. manigent/web/frontend/src/components/shared/ExpandToggle.tsx +45 -0
  743. manigent/web/frontend/src/components/shared/MarkdownBody.tsx +218 -0
  744. manigent/web/frontend/src/components/shared/MarkdownBody.untrusted.test.tsx +97 -0
  745. manigent/web/frontend/src/components/shared/RenderBody.tsx +90 -0
  746. manigent/web/frontend/src/components/shared/rehypeHideComments.test.tsx +115 -0
  747. manigent/web/frontend/src/components/shared/rehypeHideComments.ts +124 -0
  748. manigent/web/frontend/src/components/sharing/AcceptSharePage.tsx +141 -0
  749. manigent/web/frontend/src/components/sharing/ShareLandingPage.tsx +89 -0
  750. manigent/web/frontend/src/components/sidebar/AccountChip.test.tsx +337 -0
  751. manigent/web/frontend/src/components/sidebar/AccountChip.tsx +407 -0
  752. manigent/web/frontend/src/components/sidebar/ActiveWorkDot.tsx +9 -0
  753. manigent/web/frontend/src/components/sidebar/AgentProfile.tsx +44 -0
  754. manigent/web/frontend/src/components/sidebar/AgentRow.tsx +71 -0
  755. manigent/web/frontend/src/components/sidebar/AgentsPanel.retained.test.tsx +105 -0
  756. manigent/web/frontend/src/components/sidebar/AgentsPanel.tsx +231 -0
  757. manigent/web/frontend/src/components/sidebar/AssistantHero.tsx +48 -0
  758. manigent/web/frontend/src/components/sidebar/ChatroomItem.tsx +48 -0
  759. manigent/web/frontend/src/components/sidebar/CommandPalette.channelThreads.test.tsx +76 -0
  760. manigent/web/frontend/src/components/sidebar/CommandPalette.reopen.test.tsx +206 -0
  761. manigent/web/frontend/src/components/sidebar/CommandPalette.test.tsx +725 -0
  762. manigent/web/frontend/src/components/sidebar/CommandPalette.tsx +774 -0
  763. manigent/web/frontend/src/components/sidebar/ComputersPanel.tsx +144 -0
  764. manigent/web/frontend/src/components/sidebar/DmIcon.tsx +46 -0
  765. manigent/web/frontend/src/components/sidebar/DmsPanel.tsx +226 -0
  766. manigent/web/frontend/src/components/sidebar/FrontDeskPanel.channels.test.tsx +582 -0
  767. manigent/web/frontend/src/components/sidebar/FrontDeskPanel.test.tsx +151 -0
  768. manigent/web/frontend/src/components/sidebar/FrontDeskPanel.tsx +454 -0
  769. manigent/web/frontend/src/components/sidebar/HotkeysHelp.tsx +101 -0
  770. manigent/web/frontend/src/components/sidebar/MessageHitRow.test.tsx +84 -0
  771. manigent/web/frontend/src/components/sidebar/MessageHitRow.tsx +57 -0
  772. manigent/web/frontend/src/components/sidebar/MyDeskRailPanel.crossHighlight.test.tsx +247 -0
  773. manigent/web/frontend/src/components/sidebar/MyDeskRailPanel.delete.test.tsx +273 -0
  774. manigent/web/frontend/src/components/sidebar/MyDeskRailPanel.tsx +351 -0
  775. manigent/web/frontend/src/components/sidebar/PanelShell.tsx +48 -0
  776. manigent/web/frontend/src/components/sidebar/ProjectItem.tsx +161 -0
  777. manigent/web/frontend/src/components/sidebar/ProjectRow.tsx +151 -0
  778. manigent/web/frontend/src/components/sidebar/ProjectsPanel.tsx +80 -0
  779. manigent/web/frontend/src/components/sidebar/PublicPanel.counterpart.test.tsx +85 -0
  780. manigent/web/frontend/src/components/sidebar/PublicPanel.hub.test.tsx +147 -0
  781. manigent/web/frontend/src/components/sidebar/PublicPanel.tsx +271 -0
  782. manigent/web/frontend/src/components/sidebar/RecencyHeader.tsx +17 -0
  783. manigent/web/frontend/src/components/sidebar/ScheduledPanel.tsx +58 -0
  784. manigent/web/frontend/src/components/sidebar/SidebarAvatar.tsx +128 -0
  785. manigent/web/frontend/src/components/sidebar/SidebarRail.tsx +163 -0
  786. manigent/web/frontend/src/components/sidebar/TeamGroup.tsx +67 -0
  787. manigent/web/frontend/src/components/sidebar/dmPrefill.test.ts +69 -0
  788. manigent/web/frontend/src/components/sidebar/dmPrefill.ts +80 -0
  789. manigent/web/frontend/src/components/sidebar/index.ts +18 -0
  790. manigent/web/frontend/src/components/sidebar/railShortcuts.ts +18 -0
  791. manigent/web/frontend/src/components/today/lib.test.ts +70 -0
  792. manigent/web/frontend/src/components/today/lib.ts +296 -0
  793. manigent/web/frontend/src/components/today/today.css +113 -0
  794. manigent/web/frontend/src/components/welcome/RunnerSetup.css +253 -0
  795. manigent/web/frontend/src/components/welcome/RunnerSetup.tsx +148 -0
  796. manigent/web/frontend/src/components/welcome/WelcomePage.css +383 -0
  797. manigent/web/frontend/src/components/welcome/WelcomePage.tsx +329 -0
  798. manigent/web/frontend/src/components/welcome/welcomeCopy.test.ts +382 -0
  799. manigent/web/frontend/src/components/welcome/welcomeCopy.ts +313 -0
  800. manigent/web/frontend/src/config/llmProviders.test.ts +161 -0
  801. manigent/web/frontend/src/config/llmProviders.ts +109 -0
  802. manigent/web/frontend/src/config/providerIds.fixture.json +13 -0
  803. manigent/web/frontend/src/hooks/accountNavigation.test.tsx +138 -0
  804. manigent/web/frontend/src/hooks/index.ts +10 -0
  805. manigent/web/frontend/src/hooks/useActiveWorkBootstrap.ts +86 -0
  806. manigent/web/frontend/src/hooks/useAgentAccess.test.tsx +30 -0
  807. manigent/web/frontend/src/hooks/useAgentAccess.ts +204 -0
  808. manigent/web/frontend/src/hooks/useAgentSampleRequests.ts +27 -0
  809. manigent/web/frontend/src/hooks/useAgentSearch.ts +10 -0
  810. manigent/web/frontend/src/hooks/useAgents.ts +46 -0
  811. manigent/web/frontend/src/hooks/useAnnouncements.test.ts +112 -0
  812. manigent/web/frontend/src/hooks/useAnnouncements.ts +100 -0
  813. manigent/web/frontend/src/hooks/useAssistantAgent.ts +24 -0
  814. manigent/web/frontend/src/hooks/useAutoResizeTextarea.ts +18 -0
  815. manigent/web/frontend/src/hooks/useBridgeDeliveries.test.tsx +79 -0
  816. manigent/web/frontend/src/hooks/useBriefTabs.ts +122 -0
  817. manigent/web/frontend/src/hooks/useChannelThreads.ts +69 -0
  818. manigent/web/frontend/src/hooks/useComposeForm.ts +80 -0
  819. manigent/web/frontend/src/hooks/useComputers.ts +123 -0
  820. manigent/web/frontend/src/hooks/useContextFirstItem.ts +118 -0
  821. manigent/web/frontend/src/hooks/useCreateProject.ts +78 -0
  822. manigent/web/frontend/src/hooks/useDebouncedValue.ts +16 -0
  823. manigent/web/frontend/src/hooks/useDeleteProject.ts +27 -0
  824. manigent/web/frontend/src/hooks/useDeskDispatch.test.tsx +170 -0
  825. manigent/web/frontend/src/hooks/useDeskDispatch.ts +135 -0
  826. manigent/web/frontend/src/hooks/useDeskReadState.test.tsx +85 -0
  827. manigent/web/frontend/src/hooks/useDeskReadState.ts +150 -0
  828. manigent/web/frontend/src/hooks/useDeskRecentlyDone.test.tsx +222 -0
  829. manigent/web/frontend/src/hooks/useDeskRecentlyDone.ts +225 -0
  830. manigent/web/frontend/src/hooks/useDeskTour.ts +37 -0
  831. manigent/web/frontend/src/hooks/useDeskUpdates.channelThreads.test.tsx +91 -0
  832. manigent/web/frontend/src/hooks/useDeskUpdates.hubThreads.test.tsx +93 -0
  833. manigent/web/frontend/src/hooks/useDeskUpdates.ts +353 -0
  834. manigent/web/frontend/src/hooks/useDisconnectIntegration.ts +23 -0
  835. manigent/web/frontend/src/hooks/useDmThreads.ts +99 -0
  836. manigent/web/frontend/src/hooks/useFileDropzone.ts +93 -0
  837. manigent/web/frontend/src/hooks/useFileUpload.ts +38 -0
  838. manigent/web/frontend/src/hooks/useFiles.ts +98 -0
  839. manigent/web/frontend/src/hooks/useHub.test.tsx +237 -0
  840. manigent/web/frontend/src/hooks/useHub.ts +502 -0
  841. manigent/web/frontend/src/hooks/useInstall.ts +82 -0
  842. manigent/web/frontend/src/hooks/useLabels.test.tsx +294 -0
  843. manigent/web/frontend/src/hooks/useLabels.ts +287 -0
  844. manigent/web/frontend/src/hooks/useLogout.ts +49 -0
  845. manigent/web/frontend/src/hooks/useMentionDetection.ts +90 -0
  846. manigent/web/frontend/src/hooks/useMessageAttachments.deskLimit.test.ts +264 -0
  847. manigent/web/frontend/src/hooks/useMessageAttachments.ts +283 -0
  848. manigent/web/frontend/src/hooks/useMessageDeepLink.test.tsx +70 -0
  849. manigent/web/frontend/src/hooks/useMessageDeepLink.ts +32 -0
  850. manigent/web/frontend/src/hooks/useMessageSearch.ts +78 -0
  851. manigent/web/frontend/src/hooks/useModelConfigs.ts +178 -0
  852. manigent/web/frontend/src/hooks/useMyAgents.ts +18 -0
  853. manigent/web/frontend/src/hooks/usePointerReorder.ts +270 -0
  854. manigent/web/frontend/src/hooks/usePrefersReducedMotion.ts +18 -0
  855. manigent/web/frontend/src/hooks/useProjectPlan.ts +36 -0
  856. manigent/web/frontend/src/hooks/useProjectReport.ts +19 -0
  857. manigent/web/frontend/src/hooks/useProjects.ts +104 -0
  858. manigent/web/frontend/src/hooks/useProjectsWithChatrooms.ts +97 -0
  859. manigent/web/frontend/src/hooks/usePublicRequests.ts +89 -0
  860. manigent/web/frontend/src/hooks/useRecentAgents.ts +38 -0
  861. manigent/web/frontend/src/hooks/useRenameProject.test.tsx +185 -0
  862. manigent/web/frontend/src/hooks/useRenameProject.ts +192 -0
  863. manigent/web/frontend/src/hooks/useRoomTrust.ts +56 -0
  864. manigent/web/frontend/src/hooks/useSharing.ts +46 -0
  865. manigent/web/frontend/src/hooks/useSopRecents.ts +55 -0
  866. manigent/web/frontend/src/hooks/useSopSchedules.ts +25 -0
  867. manigent/web/frontend/src/hooks/useSops.ts +99 -0
  868. manigent/web/frontend/src/hooks/useSwitchAccount.ts +41 -0
  869. manigent/web/frontend/src/hooks/useTeamGroups.ts +48 -0
  870. manigent/web/frontend/src/hooks/useThreadOutbox.ts +68 -0
  871. manigent/web/frontend/src/hooks/useTodos.add.test.tsx +89 -0
  872. manigent/web/frontend/src/hooks/useTodos.linkProject.test.tsx +115 -0
  873. manigent/web/frontend/src/hooks/useTodos.saveDraft.test.tsx +188 -0
  874. manigent/web/frontend/src/hooks/useTodos.ts +396 -0
  875. manigent/web/frontend/src/hooks/useUntrustedBodies.test.tsx +87 -0
  876. manigent/web/frontend/src/hooks/useUntrustedBodies.ts +51 -0
  877. manigent/web/frontend/src/hooks/useWebSocket.briefTab.test.tsx +148 -0
  878. manigent/web/frontend/src/hooks/useWebSocket.channelThreads.test.tsx +82 -0
  879. manigent/web/frontend/src/hooks/useWebSocket.hostSync.test.tsx +92 -0
  880. manigent/web/frontend/src/hooks/useWebSocket.hub.test.tsx +114 -0
  881. manigent/web/frontend/src/hooks/useWebSocket.labelSync.test.tsx +168 -0
  882. manigent/web/frontend/src/hooks/useWebSocket.plan.test.tsx +168 -0
  883. manigent/web/frontend/src/hooks/useWebSocket.reconnect.test.tsx +166 -0
  884. manigent/web/frontend/src/hooks/useWebSocket.runnerVersions.test.tsx +167 -0
  885. manigent/web/frontend/src/hooks/useWebSocket.ts +495 -0
  886. manigent/web/frontend/src/hooks/useWindowFileDropGuard.ts +33 -0
  887. manigent/web/frontend/src/landing.tsx +11 -0
  888. manigent/web/frontend/src/main.tsx +17 -0
  889. manigent/web/frontend/src/private-beta.tsx +10 -0
  890. manigent/web/frontend/src/public.tsx +42 -0
  891. manigent/web/frontend/src/queryClient.ts +16 -0
  892. manigent/web/frontend/src/stores/activeWorkStore.ts +88 -0
  893. manigent/web/frontend/src/stores/announcementStore.test.ts +217 -0
  894. manigent/web/frontend/src/stores/announcementStore.ts +169 -0
  895. manigent/web/frontend/src/stores/authStore.multiSession.test.ts +304 -0
  896. manigent/web/frontend/src/stores/authStore.test.ts +235 -0
  897. manigent/web/frontend/src/stores/authStore.ts +693 -0
  898. manigent/web/frontend/src/stores/deskLabelViewStore.test.ts +162 -0
  899. manigent/web/frontend/src/stores/deskLabelViewStore.ts +234 -0
  900. manigent/web/frontend/src/stores/deskLinkStore.ts +54 -0
  901. manigent/web/frontend/src/stores/deskStore.test.ts +53 -0
  902. manigent/web/frontend/src/stores/deskStore.ts +93 -0
  903. manigent/web/frontend/src/stores/heldPostsStore.ts +78 -0
  904. manigent/web/frontend/src/stores/mcpAuthStore.ts +52 -0
  905. manigent/web/frontend/src/stores/modelSelectionStore.ts +33 -0
  906. manigent/web/frontend/src/stores/perUserStores.ts +79 -0
  907. manigent/web/frontend/src/stores/runnerVersionStore.test.ts +81 -0
  908. manigent/web/frontend/src/stores/runnerVersionStore.ts +60 -0
  909. manigent/web/frontend/src/stores/skillAuthStore.ts +54 -0
  910. manigent/web/frontend/src/stores/switchReset.test.ts +236 -0
  911. manigent/web/frontend/src/stores/tokenExp.ts +32 -0
  912. manigent/web/frontend/src/stores/uiStore.ts +186 -0
  913. manigent/web/frontend/src/stores/unreadStore.ts +204 -0
  914. manigent/web/frontend/src/stores/unsavedGuard.ts +22 -0
  915. manigent/web/frontend/src/styles/design/fonts/JetBrainsMono-Latin.woff2 +0 -0
  916. manigent/web/frontend/src/styles/design/fonts/Nunito-Latin.woff2 +0 -0
  917. manigent/web/frontend/src/styles/design/fonts/Nunito-LatinExt.woff2 +0 -0
  918. manigent/web/frontend/src/styles/design/tokens.css +160 -0
  919. manigent/web/frontend/src/styles/homepage.css +242 -0
  920. manigent/web/frontend/src/styles/index.css +126 -0
  921. manigent/web/frontend/src/styles/landing.css +52 -0
  922. manigent/web/frontend/src/test/authFixtures.ts +154 -0
  923. manigent/web/frontend/src/test/fetchHarness.ts +203 -0
  924. manigent/web/frontend/src/test/fixtures/channelThreads.smoke.json +42 -0
  925. manigent/web/frontend/src/test/hubFixtures.ts +212 -0
  926. manigent/web/frontend/src/test/queryWrapper.tsx +9 -0
  927. manigent/web/frontend/src/test/suiteHygiene.test.ts +212 -0
  928. manigent/web/frontend/src/types/channelThreadName.test.ts +16 -0
  929. manigent/web/frontend/src/types/index.ts +903 -0
  930. manigent/web/frontend/src/utils/agentAccessCopy.test.ts +53 -0
  931. manigent/web/frontend/src/utils/agentAccessCopy.ts +231 -0
  932. manigent/web/frontend/src/utils/agentDisplay.ts +81 -0
  933. manigent/web/frontend/src/utils/briefSchedule.ts +25 -0
  934. manigent/web/frontend/src/utils/channelThreads.test.ts +109 -0
  935. manigent/web/frontend/src/utils/channelThreads.ts +179 -0
  936. manigent/web/frontend/src/utils/chatroomDisplay.ts +11 -0
  937. manigent/web/frontend/src/utils/deskLinks.test.ts +155 -0
  938. manigent/web/frontend/src/utils/deskLinks.ts +115 -0
  939. manigent/web/frontend/src/utils/deskRecipient.ts +29 -0
  940. manigent/web/frontend/src/utils/formatDate.ts +102 -0
  941. manigent/web/frontend/src/utils/frontDesk.ts +65 -0
  942. manigent/web/frontend/src/utils/hubChannelView.test.ts +178 -0
  943. manigent/web/frontend/src/utils/hubChannelView.ts +307 -0
  944. manigent/web/frontend/src/utils/hubDelivery.test.ts +105 -0
  945. manigent/web/frontend/src/utils/hubDelivery.ts +137 -0
  946. manigent/web/frontend/src/utils/hubDisplay.test.ts +157 -0
  947. manigent/web/frontend/src/utils/hubDisplay.ts +221 -0
  948. manigent/web/frontend/src/utils/hubThread.test.ts +184 -0
  949. manigent/web/frontend/src/utils/hubThread.ts +247 -0
  950. manigent/web/frontend/src/utils/labelErrors.test.ts +127 -0
  951. manigent/web/frontend/src/utils/labelErrors.ts +123 -0
  952. manigent/web/frontend/src/utils/labelView.test.ts +846 -0
  953. manigent/web/frontend/src/utils/labelView.ts +760 -0
  954. manigent/web/frontend/src/utils/legalUrls.ts +11 -0
  955. manigent/web/frontend/src/utils/messageSender.test.ts +32 -0
  956. manigent/web/frontend/src/utils/messageSender.ts +29 -0
  957. manigent/web/frontend/src/utils/oauthScopeCopy.ts +73 -0
  958. manigent/web/frontend/src/utils/personalize.ts +49 -0
  959. manigent/web/frontend/src/utils/reachableAgents.test.ts +36 -0
  960. manigent/web/frontend/src/utils/reachableAgents.ts +24 -0
  961. manigent/web/frontend/src/utils/recencyBuckets.ts +61 -0
  962. manigent/web/frontend/src/utils/roomTrust.test.ts +94 -0
  963. manigent/web/frontend/src/utils/roomTrust.ts +111 -0
  964. manigent/web/frontend/src/utils/snippetHighlight.test.ts +63 -0
  965. manigent/web/frontend/src/utils/snippetHighlight.ts +42 -0
  966. manigent/web/frontend/src/utils/sopRecipient.ts +37 -0
  967. manigent/web/frontend/src/utils/sopRequest.test.ts +91 -0
  968. manigent/web/frontend/src/utils/sopRequest.ts +68 -0
  969. manigent/web/frontend/src/utils/sopSchedule.ts +26 -0
  970. manigent/web/frontend/src/utils/sopSection.test.ts +148 -0
  971. manigent/web/frontend/src/utils/sopSection.ts +143 -0
  972. manigent/web/frontend/src/utils/textSearch.test.ts +60 -0
  973. manigent/web/frontend/src/utils/textSearch.ts +43 -0
  974. manigent/web/frontend/src/utils/thoughtPartner.ts +26 -0
  975. manigent/web/frontend/src/utils/threadName.test.ts +131 -0
  976. manigent/web/frontend/src/utils/threadName.ts +122 -0
  977. manigent/web/frontend/src/utils/ticketView.test.ts +296 -0
  978. manigent/web/frontend/src/utils/ticketView.ts +175 -0
  979. manigent/web/frontend/src/utils/todoAttachments.desiredState.test.ts +180 -0
  980. manigent/web/frontend/src/utils/todoAttachments.ts +126 -0
  981. manigent/web/frontend/src/utils/todoDraft.test.ts +84 -0
  982. manigent/web/frontend/src/utils/todoDraft.ts +46 -0
  983. manigent/web/frontend/src/utils/todoSearch.test.ts +82 -0
  984. manigent/web/frontend/src/utils/todoSearch.ts +43 -0
  985. manigent/web/frontend/src/utils/versionMatch.test.ts +295 -0
  986. manigent/web/frontend/src/utils/versionMatch.ts +245 -0
  987. manigent/web/frontend/src/vite-env.d.ts +1 -0
  988. manigent/web/frontend/tailwind.config.js +86 -0
  989. manigent/web/frontend/tos.html +188 -0
  990. manigent/web/frontend/tsconfig.dts.json +25 -0
  991. manigent/web/frontend/tsconfig.json +26 -0
  992. manigent/web/frontend/tsconfig.node.json +11 -0
  993. manigent/web/frontend/vite.config.ts +41 -0
  994. manigent/web/frontend/vitest.config.ts +16 -0
  995. manigent/ws_edge/app.py +514 -0
  996. manigent/ws_edge/auth.py +104 -0
  997. manigent/ws_edge/link.py +282 -0
  998. manigent/ws_edge/registry.py +206 -0
  999. manigent/ws_edge/terminal_relay.py +269 -0
  1000. manigent_server-0.1.0.dist-info/METADATA +138 -0
  1001. manigent_server-0.1.0.dist-info/RECORD +1004 -0
  1002. manigent_server-0.1.0.dist-info/WHEEL +4 -0
  1003. manigent_server-0.1.0.dist-info/entry_points.txt +2 -0
  1004. manigent_server-0.1.0.dist-info/licenses/LICENSE +68 -0
@@ -0,0 +1,841 @@
1
+ import { useEffect, useMemo, useRef, useState, ChangeEvent } from 'react'
2
+ import { useNavigate, useParams, useSearchParams } from 'react-router-dom'
3
+ import { FileText, Paperclip, Clock, GraduationCap, X, Send, Loader2, Trash2 } from 'lucide-react'
4
+ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
5
+ import { useUIStore } from '../../stores/uiStore'
6
+ import { useAuthStore } from '../../stores/authStore'
7
+ import { useUnsavedGuard } from '../../stores/unsavedGuard'
8
+ import { useAgents } from '../../hooks/useAgents'
9
+ import { useChatroom, useUserProjects } from '../../hooks/useProjects'
10
+ import { useRoomTrust } from '../../hooks/useRoomTrust'
11
+ import { useSetRoomFlow } from '../../hooks/useAgentAccess'
12
+ import { useRenameProject } from '../../hooks/useRenameProject'
13
+ import { useDeleteProject } from '../../hooks/useDeleteProject'
14
+ import { useActiveWorkStore, selectActiveParticipants } from '../../stores/activeWorkStore'
15
+ import { useModelSelectionStore } from '../../stores/modelSelectionStore'
16
+ import { useModelConfigs } from '../../hooks/useModelConfigs'
17
+ import { getMessages } from '../../api/endpoints'
18
+ import { sendDMMessage, createDMThread, createFDThread } from '../../api/endpoints/dm'
19
+ import { hubError } from '../../api/endpoints/hub'
20
+ import { accessErrorText, FLOW_COPY } from '../../utils/agentAccessCopy'
21
+ import { outsideFileNames } from '../../utils/roomTrust'
22
+ import RoomFlowStrip from '../chatroom/RoomFlowStrip'
23
+ import { useHeldPostsStore } from '../../stores/heldPostsStore'
24
+ import { HeldNotices } from '../chatroom/HeldNotice'
25
+ import { useFiles } from '../../hooks/useFiles'
26
+ import { useMessageDeepLink } from '../../hooks/useMessageDeepLink'
27
+ import PromptEditor, { type PromptEditorHandle } from '../composer/PromptEditor'
28
+ import { useMessageAttachments } from '../../hooks/useMessageAttachments'
29
+ import { useFileDropzone } from '../../hooks/useFileDropzone'
30
+ import { AgentStatus, isChatFileEvent, isScheduledDMProject } from '../../types'
31
+ import { displayName as agentDisplayName } from '../../utils/agentDisplay'
32
+ import { buildPersonalizeMessage, isAssistantAgent } from '../../utils/personalize'
33
+ import Loading from '../common/Loading'
34
+ import Avatar from '../common/Avatar'
35
+ import ModelSelector from '../common/ModelSelector'
36
+ import MessageList from '../chatroom/MessageList'
37
+ import StagedAttachments from '../chatroom/StagedAttachments'
38
+ import DMZeroState from './DMZeroState'
39
+ import PersonalizeModal, { type PersonalizeResult } from './PersonalizeModal'
40
+ import { buildRecipientStatusIndex } from '../chatroom/recipientStatus'
41
+ import FileList from '../files/FileList'
42
+ import Overlay from '../common/Overlay'
43
+ import DropOverlay from '../common/DropOverlay'
44
+ import ResizeHandle from '../common/ResizeHandle'
45
+ import ScheduleMessageModal from '../scheduled/ScheduleMessageModal'
46
+ import ClearHistoryButton from '../common/ClearHistoryButton'
47
+ import CollapsibleHeader from '../common/CollapsibleHeader'
48
+ import InlineEditableTitle from '../common/InlineEditableTitle'
49
+ import HomeFolderBrowser from '../homefs/HomeFolderBrowser'
50
+ import AgentViewActions from '../agent/AgentViewActions'
51
+ import AgentNameLink from '../agent/AgentNameLink'
52
+
53
+ // DM chat view — ChatGPT/Claude thread model, N threads per agent for BOTH own
54
+ // and foreign (Front Desk) agents. Routes:
55
+ // /dm/:agentName → a fresh, ephemeral "New chat" draft (nothing
56
+ // created until the first send), for own OR
57
+ // foreign agents.
58
+ // /dm/:agentName/:threadId → an existing thread project bound directly to
59
+ // `threadId` (own-agent DM thread or foreign FD
60
+ // thread — both requester-owned).
61
+ // Either way the `user-communication` chatroom IS the DM thread. The first send
62
+ // from a draft mints an own-DM thread (createDMThread) for own agents or an FD
63
+ // thread (createFDThread, tunnel-wired) for foreign agents.
64
+ export default function DMChatView() {
65
+ const { agentName = '', threadId } = useParams<{ agentName: string; threadId?: string }>()
66
+ const navigate = useNavigate()
67
+ const [searchParams, setSearchParams] = useSearchParams()
68
+ const queryClient = useQueryClient()
69
+ const {
70
+ isMobileRightPanelOpen,
71
+ openMobileRightPanel,
72
+ closeMobileRightPanel,
73
+ rightPanelWidth,
74
+ setRightPanelWidth,
75
+ setRailContext,
76
+ } = useUIStore()
77
+ const user = useAuthStore((state) => state.user)
78
+ const { data: allAgents, isLoading: agentsLoading } = useAgents()
79
+
80
+ const fileInputRef = useRef<HTMLInputElement>(null)
81
+ const [showScheduleModal, setShowScheduleModal] = useState(false)
82
+ const [showPersonalizeModal, setShowPersonalizeModal] = useState(false)
83
+
84
+ const agent = useMemo(
85
+ () => allAgents?.find((a) => a.name === agentName),
86
+ [allAgents, agentName]
87
+ )
88
+ const agentLabel = agent ? agentDisplayName(agent, user ?? null) : agentName
89
+
90
+ const isOwnAgent = !!user && !!agent && agent.registered_by === user.id
91
+ // The user's own assistant gets the method-picker modal; every other agent
92
+ // keeps today's role-anchored deep-research prefill (buildPersonalizeMessage).
93
+ const isAssistant = isAssistantAgent(agent, user)
94
+ // No thread in the URL = a fresh ephemeral "New chat" draft (own OR foreign
95
+ // agent): the draft lives in local state only; NO project row is created
96
+ // until the first message is sent. Abandon it → no trace.
97
+ const isNewChatDraft = !!user && !!agent && !threadId
98
+
99
+ // Threads (own DM or foreign FD) bind directly to the `threadId` in the URL;
100
+ // a new-chat draft resolves to no project yet.
101
+ const dmProjectId = threadId ?? ''
102
+ const chatroomName = dmProjectId ? 'user-communication' : ''
103
+ // A draft renders immediately; a bound thread comes straight from the URL.
104
+ const projectLoading = agentsLoading || (!isNewChatDraft && !dmProjectId)
105
+
106
+ // Header title = the thread project's display_name (item e). Read from the
107
+ // SAME user-projects cache the sidebar row reads, so the auto-title flips
108
+ // header + row together on one list refetch. Drafts/foreign fall back.
109
+ const { data: userProjects } = useUserProjects()
110
+ // A search hit links a host-side Hub Request (a Front Desk project) here,
111
+ // so its bodies follow the same trust rule as ChatroomView: the whole room,
112
+ // and per author (another account's agent, a requester).
113
+ const trust = useRoomTrust(dmProjectId, chatroomName)
114
+ const threadProject = useMemo(
115
+ () => (threadId ? userProjects?.find((p) => p.id === threadId) : undefined),
116
+ [userProjects, threadId],
117
+ )
118
+ // The header title is always the agent; the thread's own name (once it has
119
+ // one) sits on the line under it and stays click-to-rename.
120
+ const threadName = isNewChatDraft ? '' : threadProject?.display_name || ''
121
+ // Same mutation as the project page: a DM thread IS a Project, so the header
122
+ // rename is one hook and one endpoint on both surfaces.
123
+ const renameThread = useRenameProject()
124
+ // A DM thread dedicated to scheduled messages ({username}-dm-{short}-schedule).
125
+ const isScheduledThread = !!threadProject && isScheduledDMProject(threadProject)
126
+
127
+ // Settings/Delete agent live on the agent view (/dm/:agentName, no thread),
128
+ // not inside a conversation. Owner-only; the assistant is never deletable.
129
+ const showAgentActions = isOwnAgent && !!agent && !threadId
130
+ // The home-folder navigator replaces the transcript on the agent view
131
+ // (`?view=home`), so the settings page can link straight to it.
132
+ const homeFolderOpen = showAgentActions && agent.home_folder_browsable === true && searchParams.get('view') === 'home'
133
+
134
+ // Conversation delete moved here from the DMs rail row. useDeleteProject
135
+ // drops back to the agent's new-chat draft when the open thread goes.
136
+ const deleteThreadMutation = useDeleteProject()
137
+ const canDeleteThread = !!threadProject && !threadProject.is_viewer
138
+ // The thread's owner may stop and resume outside messages, as in the room.
139
+ const isThreadOwner = canDeleteThread && !!user && threadProject.created_by === user.id
140
+ const { data: chatroom } = useChatroom(dmProjectId, chatroomName)
141
+ const resumeFlow = useSetRoomFlow(dmProjectId, chatroomName)
142
+ const handleDeleteThread = () => {
143
+ const title = threadName || `chat with ${agentLabel}`
144
+ if (!window.confirm(`Delete conversation "${title}"? This cannot be undone.`)) return
145
+ deleteThreadMutation.mutate(dmProjectId)
146
+ }
147
+
148
+ // Fetch messages
149
+ const { data: messages, isLoading: messagesLoading } = useQuery({
150
+ queryKey: ['messages', dmProjectId, chatroomName],
151
+ queryFn: () => getMessages(dmProjectId, chatroomName),
152
+ enabled: !!dmProjectId,
153
+ refetchInterval: 5000,
154
+ })
155
+
156
+ // Processing-agent ids come from the activeWorkStore, driven by the
157
+ // ACTIVE_WORK_CHANGE WebSocket envelope (bootstrapped via /me/active-work).
158
+ const processingAgentIds = useActiveWorkStore(selectActiveParticipants(dmProjectId, chatroomName))
159
+
160
+ // Fetch files
161
+ const { data: files, isLoading: filesLoading } = useFiles(dmProjectId, chatroomName)
162
+ // The Files sidebar follows the per-author rule, as in ChatroomView: a file
163
+ // another account's agent posted opens untrusted (no "Open in new tab").
164
+ const outsideFiles = useMemo(
165
+ () => outsideFileNames(chatroom, trust.ownerId, (files ?? []).map((f) => f.name), (messages ?? []).filter(isChatFileEvent)),
166
+ [chatroom, trust.ownerId, files, messages],
167
+ )
168
+ // `?msg=` deep-link target from ⌘K message search, consumed and cleared the
169
+ // same way this view already handles `?draft=`.
170
+ const { targetMessageId, clearTarget } = useMessageDeepLink()
171
+
172
+ const {
173
+ stagedFiles,
174
+ files: attachmentFiles,
175
+ addFiles,
176
+ removeStagedFile,
177
+ clearStagedFiles,
178
+ attachmentError,
179
+ } = useMessageAttachments()
180
+
181
+ // Per-request model override (spec #3): the resolved active config for this
182
+ // DM's target agent — the transient selector pick, else the agent's backend
183
+ // default — sent as `model_config_name` so the override is explicit and
184
+ // verifiable. Fetched only for OWN agents (foreign FD agents 403 on the
185
+ // configs route + get no selector), so a foreign DM sends nothing ⇒ the
186
+ // server silently uses that agent's own default.
187
+ const { data: modelConfigData } = useModelConfigs(isOwnAgent ? agent?.id : undefined)
188
+ const selectedConfigName = useModelSelectionStore((s) => (agent ? s.byAgent[agent.id] : undefined))
189
+ const modelConfigName = selectedConfigName ?? modelConfigData?.default ?? undefined
190
+
191
+ // Send into an existing thread / FD project.
192
+ const recordSend = useHeldPostsStore((s) => s.record)
193
+ const beginSend = useHeldPostsStore((s) => s.begin)
194
+ const endSend = useHeldPostsStore((s) => s.end)
195
+ // The send carries its own thread: the view stays mounted across threads, so
196
+ // a send that settles after the user switched must record, refetch and report
197
+ // against the thread it was posted to, never the one now open.
198
+ type SendVars = { projectId: string; room: string; content: string; files: File[] }
199
+ const sendMessageMutation = useMutation({
200
+ onMutate: (vars: SendVars) => beginSend(vars.projectId, vars.room, vars.content),
201
+ onSettled: (_r, _e, vars) => endSend(vars.projectId, vars.room, vars.content),
202
+ mutationFn: (vars: SendVars) =>
203
+ sendDMMessage(vars.projectId, vars.room, vars.content, vars.files, modelConfigName),
204
+ onSuccess: (result, vars) => {
205
+ // 202: stored and delivered later. Shown as held; never resent.
206
+ recordSend(vars.projectId, vars.room, vars.content, result)
207
+ // The composer stayed disabled while this send was pending (in any
208
+ // thread), so what it holds is still this send's text and files.
209
+ clearComposer()
210
+ clearStagedFiles()
211
+ queryClient.invalidateQueries({ queryKey: ['messages', vars.projectId, vars.room] })
212
+ queryClient.invalidateQueries({ queryKey: ['files', vars.projectId, vars.room] })
213
+ },
214
+ })
215
+
216
+ // (item d) First send from a "New chat" draft materializes a NEW thread
217
+ // project, then posts the message into it, then binds the view to the real
218
+ // thread and surfaces the row at the top of DM / Chats. A per-draft
219
+ // idempotency key guards the double-send race (two creates → one thread).
220
+ const draftKeyRef = useRef<string>()
221
+ if (!draftKeyRef.current) draftKeyRef.current = crypto.randomUUID()
222
+ // Regenerate the key whenever a FRESH draft begins (no threadId), so a 2nd
223
+ // "New chat" with the same agent can't reuse the prior draft's key. Without
224
+ // this, RRv6 renders the sibling `/dm/:agentName` and `/dm/:agentName/:threadId`
225
+ // routes at the same tree position and PRESERVES this instance across
226
+ // navigation — leaving `draftKeyRef` holding the stale key, which the
227
+ // backend's (user.id, key) idempotency cache would HIT and silently merge the
228
+ // new message into the prior thread (breaking the N-per-agent model).
229
+ // Correctness must NOT depend on remount behavior, so we reset explicitly.
230
+ useEffect(() => {
231
+ if (!threadId) draftKeyRef.current = crypto.randomUUID()
232
+ }, [threadId, agentName])
233
+ const createThreadMutation = useMutation({
234
+ mutationFn: async (vars: { content: string; files: File[] }): Promise<string> => {
235
+ // Own agents mint an own-DM thread; foreign agents mint a tunnel-wired
236
+ // Front Desk thread. Both are requester-owned, N-per-agent. Staged files
237
+ // ride the first message into the freshly-minted thread.
238
+ const thread = isOwnAgent
239
+ ? await createDMThread(agentName, draftKeyRef.current)
240
+ : await createFDThread(agentName, draftKeyRef.current)
241
+ const sent = await sendDMMessage(thread.id, 'user-communication', vars.content, vars.files, modelConfigName)
242
+ recordSend(thread.id, 'user-communication', vars.content, sent)
243
+ return thread.id
244
+ },
245
+ onSuccess: (newThreadId) => {
246
+ clearComposer()
247
+ clearStagedFiles()
248
+ queryClient.invalidateQueries({ queryKey: ['user-projects'] })
249
+ queryClient.invalidateQueries({ queryKey: ['all-projects'] })
250
+ // Surface the freshly-created thread in the rail: switch to the DMs
251
+ // context so the user sees DMs › agent › (new thread) instead of staying
252
+ // on whatever context they launched the draft from (usually Agents).
253
+ setRailContext('dms')
254
+ navigate(`/dm/${encodeURIComponent(agentName)}/${newThreadId}`, { replace: true })
255
+ },
256
+ })
257
+
258
+ const isSending = sendMessageMutation.isPending || createThreadMutation.isPending
259
+ // A refused send keeps the draft (the composer clears only on success) and
260
+ // says why in the agent-access copy; a stopped room offers its owner Resume.
261
+ // Only this thread's refusal is shown: a send posted from another thread
262
+ // keeps its error to itself, and so does its Resume.
263
+ const sendError =
264
+ (sendMessageMutation.variables?.projectId === dmProjectId ? sendMessageMutation.error : null) ??
265
+ (isNewChatDraft ? createThreadMutation.error : null)
266
+ const sendErrorBody = sendError ? hubError(sendError) : null
267
+ const sendErrorText = sendError ? accessErrorText(sendErrorBody) ?? sendError.message : null
268
+ const canResume = sendErrorBody?.code === 'room_flow_stopped' && isThreadOwner
269
+ // The view stays mounted across threads (see the draft key above), so a
270
+ // settled refusal is cleared on a switch. A send still in flight is NOT
271
+ // reset: reset() only detaches the observer, so the composer would re-enable
272
+ // while the old send keeps running and its onSuccess later wipes whatever
273
+ // was typed in the new thread. It keeps the composer disabled until it
274
+ // settles; the per-thread gate on `sendError` above hides its outcome here.
275
+ const sendStateRef = useRef({ send: sendMessageMutation, create: createThreadMutation })
276
+ sendStateRef.current = { send: sendMessageMutation, create: createThreadMutation }
277
+ useEffect(() => {
278
+ const { send, create } = sendStateRef.current
279
+ if (!send.isPending) send.reset()
280
+ if (!create.isPending) create.reset()
281
+ }, [threadId, agentName])
282
+
283
+ // Drag files onto the composer card → same staging path as the paperclip.
284
+ const { isDragging, dragHandlers } = useFileDropzone({
285
+ onFiles: addFiles,
286
+ disabled: isSending,
287
+ })
288
+
289
+ const setGuardDirty = useUnsavedGuard((s) => s.setDirty)
290
+
291
+ // Starts empty: the `?draft=` deep-link is applied solely by the effect
292
+ // below, which routes through prefillComposer (and so keeps the
293
+ // don't-clobber confirm). Seeding here too would double-apply it.
294
+ const [dmMessage, setDmMessage] = useState('')
295
+ const dmEditorRef = useRef<PromptEditorHandle>(null)
296
+ // Mirror for the prefill guard, which must read the live draft.
297
+ const dmMessageRef = useRef('')
298
+
299
+ // Focus the composer on selection (agent DM or a specific thread) so the user
300
+ // can type immediately. Re-fires when switching agents/threads; the
301
+ // projectLoading dep ensures it runs once the composer has mounted.
302
+ useEffect(() => {
303
+ if (!projectLoading) dmEditorRef.current?.focusEnd()
304
+ }, [agentName, dmProjectId, projectLoading])
305
+
306
+ // Route the send: a draft creates-then-sends (item d); a bound thread/FD
307
+ // project sends directly. The pending gate blocks a double-submit either way.
308
+ const submitMessage = () => {
309
+ const content = dmMessage.trim()
310
+ if ((!content && stagedFiles.length === 0) || isSending) return
311
+ // Never ship a half-filled template to an agent.
312
+ if (dmEditorRef.current?.nudgeEmpty()) return
313
+ const vars = { content, files: attachmentFiles }
314
+ // The draft stays until the send succeeds (the editor is disabled while
315
+ // it is pending), so a refused post is never lost.
316
+ if (isNewChatDraft) {
317
+ createThreadMutation.mutate(vars)
318
+ } else if (dmProjectId) {
319
+ sendMessageMutation.mutate({ ...vars, projectId: dmProjectId, room: chatroomName })
320
+ }
321
+ }
322
+
323
+ function clearComposer() {
324
+ setDmMessage('')
325
+ dmMessageRef.current = ''
326
+ dmEditorRef.current?.clear()
327
+ }
328
+
329
+ const handleSendMessage = (e: React.FormEvent<HTMLFormElement>) => {
330
+ e.preventDefault()
331
+ submitMessage()
332
+ }
333
+
334
+ const handleFileSelect = () => {
335
+ fileInputRef.current?.click()
336
+ }
337
+
338
+ // Single source of truth for "write the composer": sets the draft and focuses
339
+ // the textarea. If a different non-empty draft already exists, confirm before
340
+ // replacing so we never silently clobber what the user was typing. Shared by
341
+ // the zero-state sample cards and the personalize CTA.
342
+ const prefillComposer = (text: string) => {
343
+ const current = dmMessageRef.current.trim()
344
+ if (
345
+ current &&
346
+ current !== text.trim() &&
347
+ !window.confirm('Replace your current draft?')
348
+ ) {
349
+ return
350
+ }
351
+ dmEditorRef.current?.setPlain(text, true)
352
+ }
353
+
354
+ // Hover/focus counterpart to prefillComposer, for the zero-state idea rows.
355
+ // Pure decoration: no draft write, and so no replace-your-draft confirm —
356
+ // the ghost is gated on `data-blank='1'` in CSS, so a draft simply hides it.
357
+ const previewInComposer = (text: string | null) => {
358
+ dmEditorRef.current?.setGhost(text)
359
+ }
360
+
361
+ // Apply a `?draft=...` deep-link into the composer, then strip the param so
362
+ // back-nav / refresh doesn't re-prefill. Applying here (not only in the
363
+ // useState initializer) also covers SPA navigations that DON'T remount this
364
+ // view — clicking a sidebar `+` while already on the assistant DM, or
365
+ // switching into a draft URL from another agent. prefillComposer confirms
366
+ // before overwriting a draft you've already started typing.
367
+ useEffect(() => {
368
+ const draft = searchParams.get('draft')
369
+ if (!draft) return
370
+ prefillComposer(draft)
371
+ const next = new URLSearchParams(searchParams)
372
+ next.delete('draft')
373
+ setSearchParams(next, { replace: true })
374
+ // prefillComposer is recreated each render; the `draft` guard makes re-runs
375
+ // a no-op, so it's intentionally omitted from the dep list.
376
+ // eslint-disable-next-line react-hooks/exhaustive-deps
377
+ }, [searchParams, setSearchParams])
378
+
379
+ // Personalize sends (or prefills) through the same composer, so it waits for
380
+ // a pending send like Send does: after a thread switch that send still holds
381
+ // its staged files, and a send here would carry them into this thread.
382
+ const handlePersonalize = () => {
383
+ if (!user || !agent || isSending) return
384
+ // Assistant → open the method-picker modal; workers → today's prefill.
385
+ if (isAssistant) {
386
+ setShowPersonalizeModal(true)
387
+ return
388
+ }
389
+ prefillComposer(buildPersonalizeMessage(agent, agentLabel, isAssistant))
390
+ }
391
+
392
+ // Route a confirmed personalize method to a send. 'upload' needs a file
393
+ // (staged via the composer paperclip), so it prefills the composer body and
394
+ // opens the native file picker instead of sending; 'export'/'questions' send
395
+ // the templated DM straight away, reusing the existing send path (create the
396
+ // thread first if this is a fresh "New chat" draft, else send into the open one).
397
+ const handlePersonalizeConfirm = (r: PersonalizeResult) => {
398
+ setShowPersonalizeModal(false)
399
+ if (isSending) return
400
+ if (r.method === 'upload') {
401
+ prefillComposer(r.body)
402
+ fileInputRef.current?.click()
403
+ return
404
+ }
405
+ const vars = { content: r.body, files: attachmentFiles }
406
+ if (isNewChatDraft) {
407
+ createThreadMutation.mutate(vars)
408
+ } else if (dmProjectId) {
409
+ sendMessageMutation.mutate({ ...vars, projectId: dmProjectId, room: chatroomName })
410
+ }
411
+ }
412
+
413
+ // Personalize button tooltip. The control is icon-only in the toolbar, so the
414
+ // tooltip carries the label AND the payoff — it is the only place the words
415
+ // appear once the DM has messages in it (the zero state still shows the full
416
+ // gradient CTA).
417
+ const personalizeHint = isAssistant
418
+ ? 'Personalize — teach it who you are and how you work'
419
+ : `Train as expert — deep-research @${agentLabel} into your field`
420
+
421
+ const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
422
+ if (e.target.files && e.target.files.length > 0) {
423
+ addFiles(e.target.files)
424
+ }
425
+ e.target.value = ''
426
+ }
427
+
428
+ // Guard against navigating away with an unsent draft or staged attachments.
429
+ const isDirty = dmMessage.trim().length > 0 || stagedFiles.length > 0
430
+ useEffect(() => {
431
+ setGuardDirty(isDirty, 'Discard your unsent message and attachments?')
432
+ return () => setGuardDirty(false)
433
+ }, [isDirty, setGuardDirty])
434
+ useEffect(() => {
435
+ if (!isDirty) return
436
+ const handler = (e: BeforeUnloadEvent) => {
437
+ e.preventDefault()
438
+ e.returnValue = ''
439
+ }
440
+ window.addEventListener('beforeunload', handler)
441
+ return () => window.removeEventListener('beforeunload', handler)
442
+ }, [isDirty])
443
+
444
+ // `isMobileRightPanelOpen` is global UI state, so a panel left open on a
445
+ // thread would silently re-open when the user navigates back to one after
446
+ // visiting the agent page. Reset it whenever the panel isn't available.
447
+ useEffect(() => {
448
+ if (!dmProjectId) closeMobileRightPanel()
449
+ }, [dmProjectId, closeMobileRightPanel])
450
+
451
+ // Pass the full ChatLogEntry stream — buildRecipientStatusIndex needs
452
+ // batch_timeout rows in addition to messages so it can flip a recipient
453
+ // from AWAITING to TIMED OUT. Filtering to messages here (as this did
454
+ // before batch-timeout support landed) leaves the chip stuck on AWAITING
455
+ // forever. ChatroomView passes the same unfiltered stream.
456
+ const statusIndex = useMemo(
457
+ () =>
458
+ buildRecipientStatusIndex(
459
+ messages || [],
460
+ allAgents || [],
461
+ processingAgentIds,
462
+ ),
463
+ [messages, allAgents, processingAgentIds],
464
+ )
465
+
466
+ // The Files panel only has anything to show once a thread exists. On the
467
+ // agent page (`/dm/:agentName`, a draft) there is no project yet, so the
468
+ // files query is disabled and the panel would render a permanently-empty
469
+ // "Files (0)" column — hide the whole right rail (and its mobile toggle /
470
+ // resize handle) there instead. Gated on `dmProjectId`, NOT on "zero state
471
+ // showing": DMZeroState also renders for a real-but-empty thread, where
472
+ // Files is still live.
473
+ const showFilesPanel = !!dmProjectId
474
+
475
+ // Onboarding launchpad instead of a transcript: either a draft thread with no
476
+ // project yet, or a real thread nobody has written in. Also drives the taller
477
+ // resting composer, so a hovered idea's 3-line ghost preview fits without the
478
+ // box ever changing size.
479
+ const showZeroState = !dmProjectId || (messages?.length ?? 0) === 0
480
+
481
+ if (projectLoading) {
482
+ return (
483
+ <div className="flex-1 flex items-center justify-center">
484
+ <Loading size="lg" />
485
+ </div>
486
+ )
487
+ }
488
+
489
+ const fileCount = files?.length || 0
490
+
491
+ return (
492
+ <div className="flex flex-col h-full">
493
+ {/* Header */}
494
+ <CollapsibleHeader className="border-b border-border px-6 py-3 pl-14 lg:pl-6">
495
+ <div className="flex items-center justify-between">
496
+ <div className="flex items-center gap-4">
497
+ <div className="flex items-center gap-3">
498
+ {agent && (
499
+ <Avatar
500
+ name={agentLabel}
501
+ status={agent.status as AgentStatus}
502
+ size="md"
503
+ />
504
+ )}
505
+ <div className="min-w-0">
506
+ <h2 className="flex items-center gap-2 text-lg text-channel-active min-w-0">
507
+ {agent ? (
508
+ <AgentNameLink agentName={agent.name} className="truncate">
509
+ {agentLabel}
510
+ </AgentNameLink>
511
+ ) : (
512
+ <span className="truncate">{agentLabel}</span>
513
+ )}
514
+ {isScheduledThread && (
515
+ <span
516
+ className="inline-flex shrink-0 items-center gap-1 rounded-full bg-purple-50 px-2 py-0.5 text-[10px] font-bold uppercase tracking-wide text-accent-deep"
517
+ title="Scheduled messages thread"
518
+ >
519
+ <Clock className="w-3 h-3" />
520
+ Scheduled
521
+ </span>
522
+ )}
523
+ </h2>
524
+ {threadName ? (
525
+ <p className="text-sm text-channel min-w-0">
526
+ <InlineEditableTitle
527
+ value={threadName}
528
+ label="Conversation name"
529
+ editable={!!threadProject && !threadProject.is_viewer}
530
+ onSave={(next) =>
531
+ renameThread.mutateAsync({ projectId: dmProjectId, displayName: next })
532
+ }
533
+ />
534
+ </p>
535
+ ) : (
536
+ !isOwnAgent && agent?.description && (
537
+ <p className="text-sm text-channel truncate">{agent.description}</p>
538
+ )
539
+ )}
540
+ </div>
541
+ </div>
542
+ </div>
543
+ <div className="flex items-center gap-1">
544
+ {/* Files toggle button - visible only on mobile */}
545
+ {showFilesPanel && (
546
+ <button
547
+ onClick={openMobileRightPanel}
548
+ className="p-2 rounded-md hover:bg-sidebar-hover transition-colors relative lg:hidden"
549
+ aria-label="Show files panel"
550
+ title="Files"
551
+ >
552
+ <FileText className="w-5 h-5 text-channel" />
553
+ {fileCount > 0 && (
554
+ <span className="absolute -top-1 -right-1 bg-accent text-white text-xs rounded-full w-4 h-4 flex items-center justify-center">
555
+ {fileCount > 9 ? '9+' : fileCount}
556
+ </span>
557
+ )}
558
+ </button>
559
+ )}
560
+ {dmProjectId && chatroomName && (
561
+ <ClearHistoryButton
562
+ projectId={dmProjectId}
563
+ chatroomName={chatroomName}
564
+ confirmLabel={`@${agentLabel}`}
565
+ />
566
+ )}
567
+ {showAgentActions && (
568
+ <AgentViewActions agent={agent} agentLabel={agentLabel} active={homeFolderOpen ? 'home' : 'start'} />
569
+ )}
570
+ {canDeleteThread && (
571
+ <button
572
+ type="button"
573
+ onClick={handleDeleteThread}
574
+ disabled={deleteThreadMutation.isPending}
575
+ className="p-2 rounded-md hover:bg-red-100 transition-colors text-channel hover:text-red-600 disabled:opacity-50"
576
+ aria-label="Delete conversation"
577
+ title="Delete conversation"
578
+ >
579
+ <Trash2 className="w-5 h-5" />
580
+ </button>
581
+ )}
582
+ </div>
583
+ </div>
584
+ </CollapsibleHeader>
585
+
586
+ {/* Content */}
587
+ {homeFolderOpen ? (
588
+ <HomeFolderBrowser
589
+ key={`${agent.id}:${searchParams.get('path') ?? ''}`}
590
+ agentId={agent.id}
591
+ agentLabel={agentLabel}
592
+ initialPath={searchParams.get('path') ?? ''}
593
+ />
594
+ ) : (
595
+ <div className="flex-1 flex overflow-hidden relative">
596
+ {/* Main message area */}
597
+ <div className="flex-1 flex flex-col overflow-hidden">
598
+ {/* Messages */}
599
+ {messagesLoading ? (
600
+ <div className="flex-1 flex items-center justify-center">
601
+ <Loading />
602
+ </div>
603
+ ) : showZeroState ? (
604
+ <DMZeroState
605
+ agent={agent}
606
+ onUseSample={prefillComposer}
607
+ onPreviewSample={previewInComposer}
608
+ onPersonalize={handlePersonalize}
609
+ />
610
+ ) : (
611
+ <MessageList
612
+ messages={messages || []}
613
+ agents={allAgents || []}
614
+ projectId={dmProjectId}
615
+ chatroomName={chatroomName}
616
+ statusIndex={statusIndex}
617
+ targetMessageId={targetMessageId}
618
+ onTargetResolved={clearTarget}
619
+ untrustedBodies={trust.untrustedBodies}
620
+ isOutsideAuthor={trust.isOutsideAuthor}
621
+ />
622
+ )}
623
+
624
+ <RoomFlowStrip flow={chatroom?.flow} viewerIsOwner={isThreadOwner} />
625
+ {dmProjectId && (
626
+ <HeldNotices projectId={dmProjectId} room={chatroomName} messages={messages} viewerId={user?.id} />
627
+ )}
628
+
629
+ {sendErrorText && (
630
+ <p role="alert" className="px-4 py-1 text-sm text-red-600" data-testid="dm-send-error">
631
+ {sendErrorText}
632
+ {canResume && (
633
+ <button
634
+ type="button"
635
+ className="ml-2 font-semibold text-accent-deep underline disabled:opacity-50"
636
+ disabled={resumeFlow.isPending}
637
+ onClick={() => resumeFlow.mutate('open', { onSuccess: () => sendMessageMutation.reset() })}
638
+ data-testid="dm-resume-flow"
639
+ >
640
+ {FLOW_COPY.resume}
641
+ </button>
642
+ )}
643
+ </p>
644
+ )}
645
+
646
+ {/* Attachment error (e.g. over the size limit) */}
647
+ {attachmentError && (
648
+ <div className="px-4 py-1 text-sm text-red-600">{attachmentError}</div>
649
+ )}
650
+
651
+ {/* Message input */}
652
+ <form onSubmit={handleSendMessage} className="p-4 border-t border-border">
653
+ <div
654
+ className="relative rounded-2xl border border-gray-200 bg-white shadow-sm focus-within:border-purple-300 focus-within:shadow-[0_0_0_3px_rgba(168,85,247,0.10)] transition-all"
655
+ {...dragHandlers}
656
+ >
657
+ <DropOverlay visible={isDragging} />
658
+ {/* Header: avatar + you → @agent */}
659
+ <div className="flex items-center gap-2 px-4 pt-3 pb-1">
660
+ {user && <Avatar name={user.username} size="xs" />}
661
+ <span className="text-xs">
662
+ <span className="font-medium text-gray-700">you</span>
663
+ <span className="text-gray-300 mx-1.5">→</span>
664
+ <span className="font-mono text-gray-500">@{agentLabel}</span>
665
+ </span>
666
+ </div>
667
+
668
+ {/* Message — rich: an SOP's {{blanks}} become fillable chips */}
669
+ <PromptEditor
670
+ ref={dmEditorRef}
671
+ wrapClassName="px-4 pt-1 pb-2"
672
+ className="text-gray-900 text-sm"
673
+ minHeight={showZeroState ? 76 : 52}
674
+ maxHeight={200}
675
+ placeholder={`Message @${agentLabel}...`}
676
+ disabled={isSending}
677
+ agents={allAgents ?? []}
678
+ viewer={user ?? null}
679
+ onChange={(t) => {
680
+ setDmMessage(t)
681
+ dmMessageRef.current = t
682
+ }}
683
+ onSubmit={submitMessage}
684
+ />
685
+
686
+ {/* Staged attachments (client-side; uploaded on send) */}
687
+ <StagedAttachments files={stagedFiles} onRemove={removeStagedFile} disabled={isSending} />
688
+
689
+ {/* Footer: draft actions only, right-aligned. `flex-wrap` so adding
690
+ the model selector never pushes the send button out of a narrow
691
+ column. Every control here is icon-sized except `command`,
692
+ so the row holds on a phone. */}
693
+ <div className="flex flex-wrap items-center justify-end gap-2 px-3 pb-2">
694
+ <div className="flex items-center gap-0.5 shrink-0">
695
+ {/* Model for this agent — quick-edit shortcut to Agent Settings */}
696
+ <ModelSelector agent={agent} />
697
+
698
+ {/* File upload (staged; sent with the message) */}
699
+ <button
700
+ type="button"
701
+ onClick={handleFileSelect}
702
+ disabled={isSending}
703
+ className="p-1.5 text-gray-400 hover:text-gray-700 rounded transition-colors disabled:opacity-50"
704
+ title="Attach file"
705
+ >
706
+ <Paperclip className="w-4 h-4" />
707
+ </button>
708
+ <input
709
+ ref={fileInputRef}
710
+ type="file"
711
+ multiple
712
+ className="hidden"
713
+ onChange={handleFileChange}
714
+ />
715
+
716
+ {/* Schedule */}
717
+ <button
718
+ type="button"
719
+ onClick={() => setShowScheduleModal(true)}
720
+ disabled={!dmProjectId}
721
+ className="p-1.5 text-gray-400 hover:text-gray-700 rounded transition-colors disabled:opacity-50"
722
+ title="Schedule message"
723
+ >
724
+ <Clock className="w-4 h-4" />
725
+ </button>
726
+
727
+ {/* Setup CTA, collapsed to an icon so it costs one slot in a
728
+ row that already flexes instead of a band of its own.
729
+ Mortarboard, not a sparkle: a sparkle means "AI did
730
+ something" everywhere else in this app, whereas a
731
+ graduation cap reads as teach/train/qualify — which is
732
+ exactly the action for both roles (the assistant learns
733
+ the USER, every other agent is deep-researched into a
734
+ field expert). Tinted accent so it does not disappear
735
+ into the gray attach/schedule pair; the words live in the
736
+ tooltip and in the zero-state CTA. */}
737
+ <button
738
+ type="button"
739
+ onClick={handlePersonalize}
740
+ disabled={!agent || isSending}
741
+ title={personalizeHint}
742
+ aria-label={isAssistant ? 'Personalize' : 'Train as expert'}
743
+ className="p-1.5 text-accent/70 hover:text-accent-deep hover:bg-purple-50 rounded transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
744
+ >
745
+ <GraduationCap className="w-4 h-4" />
746
+ </button>
747
+
748
+ {/* Send */}
749
+ <button
750
+ type="submit"
751
+ disabled={isSending || (!dmMessage.trim() && stagedFiles.length === 0)}
752
+ title="Command (⌘/Ctrl+Enter)"
753
+ className="ml-1 inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-md text-xs font-medium text-white bg-accent hover:bg-accent-deep disabled:bg-accent-soft disabled:cursor-not-allowed transition-colors"
754
+ >
755
+ {isSending ? (
756
+ <Loader2 className="w-3.5 h-3.5 animate-spin" />
757
+ ) : (
758
+ <Send className="w-3.5 h-3.5" />
759
+ )}
760
+ <span>command</span>
761
+ </button>
762
+ </div>
763
+ </div>
764
+ </div>
765
+ </form>
766
+ </div>
767
+
768
+ {showFilesPanel && (
769
+ <>
770
+ {/* Backdrop overlay for mobile files panel */}
771
+ <Overlay isOpen={isMobileRightPanelOpen} onClose={closeMobileRightPanel} />
772
+
773
+ <ResizeHandle side="right" onResize={setRightPanelWidth} />
774
+
775
+ {/* Files sidebar - slide-in on mobile, static on desktop */}
776
+ <aside
777
+ className={`
778
+ fixed inset-y-0 right-0 z-50 bg-sidebar border-l border-border flex flex-col overflow-y-auto scrollbar-thin flex-shrink-0
779
+ transform transition-transform duration-300 ease-in-out
780
+ lg:relative lg:translate-x-0 lg:transform-none lg:transition-none lg:z-auto
781
+ ${isMobileRightPanelOpen ? 'translate-x-0' : 'translate-x-full'}
782
+ `}
783
+ style={{ width: rightPanelWidth }}
784
+ >
785
+ {/* Close button - visible only on mobile */}
786
+ <button
787
+ onClick={closeMobileRightPanel}
788
+ className="absolute top-3 right-3 p-1 rounded-md hover:bg-sidebar-hover transition-colors lg:hidden z-10"
789
+ aria-label="Close panel"
790
+ >
791
+ <X className="w-5 h-5 text-channel" />
792
+ </button>
793
+
794
+ {/* Files */}
795
+ <div className="flex flex-col flex-1 min-h-0 mt-8 lg:mt-0">
796
+ <div className="px-4 py-3 border-b border-border">
797
+ <h3 className="text-xs font-extrabold text-channel uppercase tracking-wider">
798
+ Files ({fileCount})
799
+ </h3>
800
+ </div>
801
+ <div className="flex-1 overflow-y-auto scrollbar-thin p-2">
802
+ {filesLoading ? (
803
+ <div className="flex justify-center py-4">
804
+ <Loading size="sm" />
805
+ </div>
806
+ ) : (
807
+ <FileList
808
+ files={files || []}
809
+ projectId={dmProjectId}
810
+ chatroomName={chatroomName}
811
+ isOutsideFile={(name) => outsideFiles.has(name)}
812
+ />
813
+ )}
814
+ </div>
815
+ </div>
816
+ </aside>
817
+ </>
818
+ )}
819
+ </div>
820
+ )}
821
+
822
+ {/* Schedule message modal */}
823
+ {showScheduleModal && dmProjectId && (
824
+ <ScheduleMessageModal
825
+ projectId={dmProjectId}
826
+ chatroomName={chatroomName}
827
+ onClose={() => setShowScheduleModal(false)}
828
+ />
829
+ )}
830
+
831
+ {/* Personalize method-picker modal (assistant only) */}
832
+ {showPersonalizeModal && agent && (
833
+ <PersonalizeModal
834
+ agentLabel={agentLabel}
835
+ onConfirm={handlePersonalizeConfirm}
836
+ onClose={() => setShowPersonalizeModal(false)}
837
+ />
838
+ )}
839
+ </div>
840
+ )
841
+ }