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
manigent/server/app.py ADDED
@@ -0,0 +1,807 @@
1
+ # SPDX-License-Identifier: BUSL-1.1
2
+ """
3
+ manigent/server/app.py
4
+ FastAPI application factory.
5
+
6
+ This module creates the FastAPI app and registers all route modules.
7
+ Business logic has been extracted to:
8
+ - routes/ - HTTP and WebSocket route handlers
9
+ - services/ - Shared services and context
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import asyncio
14
+ import logging
15
+ import os
16
+ from pathlib import Path
17
+ from typing import Mapping, Optional
18
+
19
+ from fastapi import FastAPI
20
+ from fastapi.middleware.cors import CORSMiddleware
21
+ from fastapi.responses import FileResponse, RedirectResponse
22
+
23
+ from manigent.models.work_tracker import WorkTracker
24
+ from manigent.models.managed_job import ManagedJobStore
25
+ from manigent.models.user import User
26
+ from .ws_hub import WSHub
27
+ from .edge_hub import EdgeWSHub
28
+ from manigent.server.agent_capabilities import AgentCapabilityRegistry
29
+ from manigent.server.signup_policy import load_signup_policy, warn_if_exposed
30
+ from manigent.server.config import public_app_url
31
+ from manigent.server.isolation_gate import HeldWorkStore, IsolationGate, IsolationHeaderMiddleware
32
+ from manigent.server.isolation_notice import IsolationNotice
33
+ from manigent.server.coordinator_rule import ForeignCoordinator, compose_guards, coordinator_guard
34
+ from manigent.server.owner_isolation import OwnerIsolationService, OwnerIsolationStore
35
+ from manigent.server.serving_only import ServingOnlyMiddleware
36
+ from manigent.server.turn_tokens import TurnGrantStore, TurnTokenMiddleware, TurnTokenService
37
+ from manigent.server.routes.owner_isolation import create_owner_isolation_router
38
+ from manigent.server.routes.turn_tokens import create_turn_tokens_router
39
+ from manigent.server.hub.retain import migrate_local_retains
40
+ from manigent.server.requester_key_migration import (
41
+ migrate_hub_thread_marks, migrate_owner_coordinators, migrate_requester_keys, migrate_scoped_turn_projects,
42
+ )
43
+ from .auth import JWT_SECRET, AuthService
44
+ from .idempotency import IdempotencyMiddleware, IdempotencyStore
45
+ from .managed_job_events import restore_active_jobs
46
+ from .timeout_checker import BatchTimeoutChecker
47
+ from .message_scheduler import MessageScheduler
48
+ from .reflection_scheduler import ReflectionScheduler
49
+ from manigent.models.context import ModelContext
50
+ from manigent.models.project_report import backfill_report_published_at
51
+ from manigent.models.scheduled_message import ScheduledMessageStore
52
+ from manigent.models.reflection_schedule import ReflectionScheduleStore
53
+ from .reflection_completion_subscriber import ReflectionCompletionSubscriber
54
+ from .tunnel_subscriber import TunnelSubscriber
55
+ from .hub.room_bridge import RoomBridgeSubscriber
56
+ from .chat_search_index import ChatSearchIndex, ChatSearchIndexSubscriber
57
+ from manigent.utils.notification_center import NotificationCenter
58
+ from manigent.sync.runloop_manager import ChangelogRunloopManager
59
+ from .context import ServerContext
60
+ from .config import cors_allow_origins
61
+ from .routes.agents import create_agents_router
62
+ from .routes.public_agents import create_public_agents_router
63
+ from .routes.agent_env import create_agent_env_router
64
+ from .routes.isolation_check import create_isolation_check_router
65
+ from .routes.agent_fs import create_agent_fs_router
66
+ from .routes.auth import create_auth_router
67
+ from .routes.projects import create_projects_router
68
+ from .routes.chatrooms import create_chatrooms_router
69
+ from .routes.files import create_files_router
70
+ from .routes.messages import create_messages_router
71
+ from .routes.changelog import create_changelog_router
72
+ from .inspection import build_outside_ingress
73
+ from .room_flow import RoomFlowSwitch
74
+ from .routes.websocket import create_websocket_router
75
+ from .routes.announcements import create_announcements_router
76
+ from .routes.scheduled_messages import create_scheduled_messages_router
77
+ from .routes.managed_jobs import create_managed_jobs_router
78
+ from .routes.reflection import create_reflection_router
79
+ from .routes.model_defaults import create_model_defaults_router
80
+ from .routes.sharing import create_sharing_router
81
+ from .routes.skills import create_skills_router
82
+ from .routes.knowledge_packs import create_knowledge_packs_router
83
+ from .routes.brief_tabs import (
84
+ BriefBodyLimitMiddleware,
85
+ create_brief_tabs_router,
86
+ )
87
+ from .routes.hosts import create_hosts_router
88
+ from .routes.install import create_install_router
89
+ from .routes.desk_todos import create_desk_todos_router
90
+ from .routes.desk_sops import create_desk_sops_router
91
+ from .routes.desk_labels import create_desk_labels_router
92
+ from .routes.desk_read_state import create_desk_read_state_router
93
+ from .routes.desk_tour import create_desk_tour_router
94
+ from .routes.desk_sign_off import create_desk_sign_off_router
95
+ from .routes.desk_latest_messages import create_desk_latest_messages_router
96
+ from .routes.project_reports import create_project_reports_router
97
+ from .routes.project_plans import create_project_plans_router
98
+ from .routes.mcps import create_mcps_router
99
+ from .routes.oauth import create_oauth_router
100
+ from .routes.oauth_login import create_oauth_login_router
101
+ from .routes.templates import create_templates_router
102
+ from .routes.inbox import create_inbox_router
103
+ from manigent.ws_edge.terminal_relay import TerminalRelay
104
+ from .home_fs_relay import HomeFsRelay
105
+ from .socket_events import SocketEvents
106
+ from .routes.search import create_search_router
107
+ from .routes.channels import create_channels_router
108
+ from .routes.hub import create_hub_router, hub_error_response
109
+ from .routes.hub_channels import create_hub_channels_router
110
+ from .routes.public_requests import create_public_requests_router
111
+ from .hub.browser import HubError
112
+ from .routes.webchat import create_webchat_router
113
+ from .channels.adapter import ChannelAdapter
114
+ from .channels.gateway import GatewayOptions, build_channel_gateway
115
+ from .hub.runtime import HubRuntime, HubRuntimeOptions
116
+ from .channels.store import ChannelStore
117
+ from .skill_registry import SkillRegistry
118
+ from .mcp_registry import McpRegistry
119
+ from .oauth_state import OAuthStateStore
120
+ from .oauth_login.handoff import LoginHandoffStore
121
+ from .oauth_login.cli_state import CliOAuthStateStore
122
+
123
+ logger = logging.getLogger("manigent.server")
124
+
125
+
126
+ def _serve_spa_file(base_dir: Path, path: str, fallback: Path) -> FileResponse:
127
+ """Serve a real static file under ``base_dir`` for an SPA catch-all route,
128
+ falling back to the SPA entry (``fallback``) for client-side routing.
129
+
130
+ ``path`` comes straight from a ``{path:path}`` URL segment, so it is
131
+ untrusted: a URL-encoded ``..`` would otherwise let ``base_dir / path``
132
+ escape the served directory and read arbitrary files the server process can
133
+ reach. We resolve the candidate and confirm it stays within ``base_dir``
134
+ before serving it; anything that escapes (or isn't a real file) falls back
135
+ to the SPA entry.
136
+ """
137
+ base_resolved = base_dir.resolve()
138
+ try:
139
+ candidate = (base_dir / path).resolve()
140
+ candidate.relative_to(base_resolved) # ValueError if it escapes base_dir
141
+ except ValueError:
142
+ return FileResponse(fallback)
143
+ if candidate.is_file():
144
+ return FileResponse(candidate)
145
+ return FileResponse(fallback)
146
+
147
+
148
+ def create_app(
149
+ data_dir: Path,
150
+ batch_timeout: int = 1800,
151
+ skills_dir: Path | None = None,
152
+ mcps_dir: Path | None = None,
153
+ agent_pool_dir: Path | None = None,
154
+ announcements_path: Path | None = None,
155
+ channel_env: Optional[Mapping[str, str]] = None,
156
+ channel_adapters: Optional[Mapping[str, ChannelAdapter]] = None,
157
+ channel_options: Optional[GatewayOptions] = None,
158
+ ws_mode: Optional[str] = None,
159
+ edge_link_url: Optional[str] = None,
160
+ edge_link_secret: Optional[str] = None,
161
+ hub_options: Optional[HubRuntimeOptions] = None,
162
+ ) -> FastAPI:
163
+ """Create and configure the FastAPI application.
164
+
165
+ Args:
166
+ data_dir: Base directory for all server data
167
+ batch_timeout: Batch timeout in seconds (default: 1800)
168
+ skills_dir: Directory containing skills registry (optional)
169
+ mcps_dir: Directory containing MCP servers registry (optional)
170
+ agent_pool_dir: A manigent-agents checkout: the agent catalog (optional)
171
+ announcements_path: Path to announcements.json (optional; defaults to
172
+ the repo-root file resolved by manigent/server/announcements.py)
173
+ channel_env: Environment the channel kill switch, channel settings and
174
+ hub settings are read from (default ``os.environ``; tests pass a dict).
175
+ channel_adapters: Channel name -> adapter. No real provider ships yet;
176
+ tests pass a fake one.
177
+ channel_options: Gateway clock, burst window, crash hooks (tests).
178
+ hub_options: The hub runtime's injection points: the socket's
179
+ connect, the reclaim's HTTP transport, the registration poll
180
+ (tests; production uses the defaults).
181
+ ws_mode: ``inprocess`` (default; this process holds the sockets) or
182
+ ``edge`` (the websocket edge holds them and this process dials it).
183
+ Defaults to ``$MANIGENT_WS_MODE``.
184
+ edge_link_url / edge_link_secret: where to dial the edge and the
185
+ shared secret, in edge mode. Default to
186
+ ``$MANIGENT_EDGE_LINK_URL`` / ``$MANIGENT_EDGE_LINK_SECRET``.
187
+
188
+ Returns:
189
+ Configured FastAPI application
190
+
191
+ Raises:
192
+ HubConfigError: ``MANIGENT_HUB_MODE`` is not ``off`` and the hub
193
+ settings are invalid (the message names each setting at fault).
194
+ The server must not start; a broken CHANNEL configuration, by
195
+ contrast, only keeps the channel gateway off.
196
+ """
197
+ data_dir.mkdir(parents=True, exist_ok=True)
198
+
199
+ # Create shared ModelContext for file and message I/O
200
+ # This is the server-wide context used by UnifiedChangelog
201
+ model_ctx = ModelContext(base_dir=data_dir, notification_center=NotificationCenter())
202
+
203
+ # Initialize services
204
+ ws_mode = (ws_mode or os.environ.get("MANIGENT_WS_MODE") or "inprocess").strip().lower()
205
+ if ws_mode not in ("inprocess", "edge"):
206
+ raise RuntimeError(f"MANIGENT_WS_MODE must be 'inprocess' or 'edge', not {ws_mode!r}")
207
+ if ws_mode == "edge":
208
+ link_url = edge_link_url or os.environ.get("MANIGENT_EDGE_LINK_URL") or "ws://127.0.0.1:8091/link"
209
+ link_secret = edge_link_secret or os.environ.get("MANIGENT_EDGE_LINK_SECRET")
210
+ if not link_secret:
211
+ raise RuntimeError("MANIGENT_WS_MODE=edge needs MANIGENT_EDGE_LINK_SECRET")
212
+ if "MANIGENT_JWT_SECRET" not in os.environ:
213
+ # The edge checks user tokens itself; with a per-process random
214
+ # secret no browser could ever connect.
215
+ logger.warning("MANIGENT_WS_MODE=edge without MANIGENT_JWT_SECRET: browsers cannot connect")
216
+ ws_hub: WSHub = EdgeWSHub(link_url, link_secret, data_dir=data_dir, model_ctx=model_ctx)
217
+ else:
218
+ ws_hub = WSHub(data_dir=data_dir, model_ctx=model_ctx)
219
+
220
+ # Bridge WorkTracker state transitions to a WebSocket push so the frontend
221
+ # sidebar's active-work indicators and in-room typing indicators both read
222
+ # from the same signal (no polling).
223
+ from manigent.models.project import Project
224
+
225
+ async def _on_work_change(
226
+ project_id: str, chatroom_name: str, active_participants: list[str]
227
+ ) -> None:
228
+ project = Project.get(project_id, model_ctx)
229
+ if project is None:
230
+ return
231
+ await ws_hub.broadcast_active_work_change(
232
+ project, chatroom_name, active_participants
233
+ )
234
+
235
+ work_tracker = WorkTracker(on_change=_on_work_change)
236
+ managed_job_store = ManagedJobStore(data_dir)
237
+
238
+ # Initialize auth service
239
+ auth = AuthService(model_ctx)
240
+
241
+ # Create runloop manager for per-project changelog processing
242
+ reflection_completion_subscriber = ReflectionCompletionSubscriber(model_ctx)
243
+ reflection_completion_subscriber.bind_ws_hub(ws_hub)
244
+ # TunnelSubscriber needs a back-reference to the runloop manager so it can
245
+ # append mirrored entries onto the other end of a binding. Construct it
246
+ # first (without the manager), then bind after the manager exists.
247
+ tunnel_subscriber = TunnelSubscriber(model_ctx)
248
+ # The room bridge: relays addressed workroom messages to retained hub
249
+ # agents (server/hub/room_bridge.py). Bound to the context below.
250
+ room_bridge_subscriber = RoomBridgeSubscriber()
251
+ # Derived FTS5 chat-message index. Registered immediately AFTER the
252
+ # subscriber that writes CHATS.ndjson, so it indexes a row that is already
253
+ # durable rather than racing the write.
254
+ chat_search_index = ChatSearchIndex(model_ctx)
255
+ chat_search_subscriber = ChatSearchIndexSubscriber(chat_search_index, model_ctx)
256
+ runloop_manager = ChangelogRunloopManager(
257
+ runloop_factory=lambda pid, pname, cid: (
258
+ model_ctx.changelog_dir(pid, pname),
259
+ [
260
+ model_ctx.changelog_subscriber(pid, pname),
261
+ chat_search_subscriber,
262
+ reflection_completion_subscriber,
263
+ tunnel_subscriber,
264
+ room_bridge_subscriber,
265
+ ],
266
+ ),
267
+ )
268
+ tunnel_subscriber.bind_runloop_manager(runloop_manager)
269
+ tunnel_subscriber.bind_ws_hub(ws_hub)
270
+ tunnel_subscriber.bind_work_tracker(work_tracker, batch_timeout)
271
+
272
+ # Create timeout checker for batch completion enforcement
273
+ timeout_checker = BatchTimeoutChecker(
274
+ work_tracker=work_tracker,
275
+ runloop_manager=runloop_manager,
276
+ ws_hub=ws_hub,
277
+ model_ctx=model_ctx,
278
+ batch_timeout=batch_timeout,
279
+ )
280
+ timeout_checker.bind_managed_job_store(managed_job_store)
281
+
282
+ # Create scheduled message store and scheduler
283
+ scheduled_message_store = ScheduledMessageStore(model_ctx)
284
+ message_scheduler = MessageScheduler(
285
+ store=scheduled_message_store,
286
+ runloop_manager=runloop_manager,
287
+ ws_hub=ws_hub,
288
+ model_ctx=model_ctx,
289
+ work_tracker=work_tracker,
290
+ batch_timeout=batch_timeout,
291
+ )
292
+
293
+ # Create reflection schedule store and scheduler
294
+ reflection_schedule_store = ReflectionScheduleStore(model_ctx)
295
+ reflection_scheduler = ReflectionScheduler(
296
+ store=reflection_schedule_store,
297
+ runloop_manager=runloop_manager,
298
+ ws_hub=ws_hub,
299
+ model_ctx=model_ctx,
300
+ )
301
+
302
+ # Who may sign up. A bad value stops boot here, like a bad hub config.
303
+ signup_policy = load_signup_policy()
304
+ warn_if_exposed(signup_policy, public_app_url())
305
+
306
+ # In-memory state store for the MCP OAuth relay flow
307
+ oauth_state_store = OAuthStateStore()
308
+
309
+ # In-memory single-use store for OAuth-login exchange handoff codes
310
+ login_handoff_store = LoginHandoffStore()
311
+
312
+ # In-memory single-use store for CLI OAuth pending states + PKCE bindings
313
+ cli_oauth_state_store = CliOAuthStateStore()
314
+
315
+ # Create server context
316
+ ctx = ServerContext(
317
+ model_ctx=model_ctx,
318
+ ws_hub=ws_hub,
319
+ work_tracker=work_tracker,
320
+ auth=auth,
321
+ runloop_manager=runloop_manager,
322
+ timeout_checker=timeout_checker,
323
+ scheduled_message_store=scheduled_message_store,
324
+ message_scheduler=message_scheduler,
325
+ reflection_schedule_store=reflection_schedule_store,
326
+ reflection_scheduler=reflection_scheduler,
327
+ managed_job_store=managed_job_store,
328
+ oauth_state_store=oauth_state_store,
329
+ login_handoff_store=login_handoff_store,
330
+ cli_oauth_state_store=cli_oauth_state_store,
331
+ chat_search_index=chat_search_index,
332
+ # In edge mode terminal sessions live in the edge, next to both sockets.
333
+ terminal_relay=(
334
+ TerminalRelay(ws_hub, model_ctx.participants_dir, JWT_SECRET)
335
+ if ws_mode == "inprocess" else None
336
+ ),
337
+ home_fs_relay=HomeFsRelay(ws_hub, model_ctx.participants_dir),
338
+ batch_timeout=batch_timeout,
339
+ skills_dir=skills_dir,
340
+ mcps_dir=mcps_dir,
341
+ agent_pool_dir=agent_pool_dir,
342
+ announcements_path=announcements_path,
343
+ signup_policy=signup_policy,
344
+ )
345
+
346
+ ctx.socket_events = SocketEvents(ctx)
347
+ turn_token_service = TurnTokenService(
348
+ TurnGrantStore(data_dir / "isolation" / "turn_grants.sqlite3"), JWT_SECRET,
349
+ )
350
+ ctx.isolation_gate = IsolationGate(
351
+ model_ctx,
352
+ AgentCapabilityRegistry(ws_hub),
353
+ turn_token_service,
354
+ HeldWorkStore(data_dir / "isolation" / "held_work.sqlite3"),
355
+ JWT_SECRET,
356
+ )
357
+ ctx.isolation_gate.bind(ctx)
358
+ # Held because the agent cannot isolate: tell its owner and the requester.
359
+ ctx.isolation_gate.notice = IsolationNotice(ctx)
360
+ ctx.owner_isolation = OwnerIsolationService(
361
+ model_ctx, ws_hub, OwnerIsolationStore(data_dir / "isolation" / "owner_isolation.sqlite3"),
362
+ )
363
+ ctx.owner_isolation.capabilities = ctx.isolation_gate.capabilities
364
+ ctx.owner_isolation.load_enabled()
365
+ # Every outside message passes the inspection hook before it is stored;
366
+ # the append guard refuses one that did not (server/inspection.py).
367
+ ctx.outside_ingress = build_outside_ingress(
368
+ data_dir, model_ctx, env=channel_env if channel_env is not None else os.environ,
369
+ )
370
+ ctx.outside_ingress.bind(ctx)
371
+ ctx.room_flow = RoomFlowSwitch(ctx)
372
+ # Plus the own-coordinator rule (plan-owner-isolation section 4): no
373
+ # append may make a stand-in or another account's agent a coordinator.
374
+ runloop_manager.set_append_guard(compose_guards(ctx.outside_ingress.guard, coordinator_guard(model_ctx)))
375
+ ws_hub.isolation_gate = ctx.isolation_gate
376
+ if isinstance(ws_hub, EdgeWSHub):
377
+ ws_hub.bind(ctx)
378
+
379
+ # Channel gateway. The store opens either way; the gateway exists when the
380
+ # channel kill switch is on and its configuration is valid, when the hub is
381
+ # on, or while open hub rows remain to be swept (build_channel_gateway).
382
+ # Raises only HubConfigError, which must stop the server.
383
+ ctx.channel_store = ChannelStore(data_dir)
384
+ ctx.channel_gateway = build_channel_gateway(
385
+ ctx, ctx.channel_store, env=channel_env,
386
+ adapters=channel_adapters, options=channel_options,
387
+ )
388
+ # The hub runtime rides on the gateway (it exists whenever the hub is
389
+ # configured, or open hub rows remain); in mode off it builds no client.
390
+ if ctx.channel_gateway is not None:
391
+ ctx.hub_runtime = HubRuntime(ctx, ctx.channel_gateway, options=hub_options)
392
+
393
+ # TunnelSubscriber's detect-and-route path needs the full ServerContext to
394
+ # call `ensure_fd_routing_for_foreign_agents`. Bind after the context is
395
+ # constructed (chicken-and-egg with runloop_manager handled above).
396
+ tunnel_subscriber.bind_server_context(ctx)
397
+ room_bridge_subscriber.bind_server_context(ctx)
398
+ ctx.room_bridge_subscriber = room_bridge_subscriber
399
+
400
+ # What re-delivers a held outside message when its room reopens: each
401
+ # path's own append (server/inspection.py release_held).
402
+ from .inspection import OutsidePath
403
+
404
+ ingress = ctx.outside_ingress
405
+ ingress.register_deliverer(OutsidePath.CROSS_ACCOUNT_RELAY, tunnel_subscriber.deliver_held)
406
+ ingress.register_deliverer(OutsidePath.FRONT_DESK_REQUESTER, tunnel_subscriber.deliver_held)
407
+ # ...and what tells the sender side when one expires instead (expire_held).
408
+ ingress.register_closer(OutsidePath.CROSS_ACCOUNT_RELAY, tunnel_subscriber.close_held)
409
+ ingress.register_closer(OutsidePath.FRONT_DESK_REQUESTER, tunnel_subscriber.close_held)
410
+ # ...and what a block on release does beyond the audit and room note:
411
+ # the path's own live-block effects (release_held).
412
+ ingress.register_blocker(OutsidePath.CROSS_ACCOUNT_RELAY, tunnel_subscriber.block_held)
413
+ ingress.register_blocker(OutsidePath.FRONT_DESK_REQUESTER, tunnel_subscriber.block_held)
414
+ if ctx.channel_gateway is not None:
415
+ ingress.register_deliverer(OutsidePath.CHANNEL_INBOUND, ctx.channel_gateway.deliver_held)
416
+ ingress.register_deliverer(OutsidePath.HUB_INBOUND, ctx.channel_gateway.deliver_held)
417
+ ingress.register_blocker(OutsidePath.CHANNEL_INBOUND, ctx.channel_gateway.block_held)
418
+ ingress.register_blocker(OutsidePath.HUB_INBOUND, ctx.channel_gateway.block_held)
419
+ if ctx.hub_runtime is not None:
420
+ ingress.register_deliverer(OutsidePath.HUB_REPLY_DM, ctx.hub_runtime.mirror.deliver_held_reply)
421
+ ingress.register_deliverer(OutsidePath.HUB_REPLY_BRIDGE, ctx.hub_runtime.bridge.deliver_reply)
422
+ ingress.register_deliverer(OutsidePath.BRIDGE_OUTBOUND, ctx.hub_runtime.bridge.send_relay)
423
+ ingress.register_closer(OutsidePath.BRIDGE_OUTBOUND, ctx.hub_runtime.bridge.close_held_relay)
424
+ ingress.register_blocker(OutsidePath.HUB_REPLY_DM, ctx.hub_runtime.mirror.block_held_reply)
425
+ ingress.register_blocker(OutsidePath.HUB_REPLY_BRIDGE, ctx.hub_runtime.bridge.block_reply)
426
+ ingress.register_blocker(OutsidePath.BRIDGE_OUTBOUND, ctx.hub_runtime.bridge.block_held_relay)
427
+ from .routes.messages import FD_REQUESTER_POST, deliver_held_fd_requester_post
428
+
429
+ ingress.register_deliverer(
430
+ FD_REQUESTER_POST, lambda replay, ticket: deliver_held_fd_requester_post(ctx, replay, ticket),
431
+ )
432
+
433
+ # A direct post was answered "delivered on reopen": when it is blocked
434
+ # or expires instead, the requester's room (the one it was posted into)
435
+ # is told. Never quotes the message.
436
+ async def _tell_fd_requester(replay, tail: str) -> None:
437
+ await ingress.post_note(replay["project_id"], replay["chatroom"],
438
+ f"A message from {replay.get('author_name') or 'the requester'} {tail}")
439
+
440
+ ingress.register_blocker(
441
+ FD_REQUESTER_POST, lambda replay: _tell_fd_requester(replay, "was blocked; it was not delivered."),
442
+ )
443
+ ingress.register_closer(
444
+ FD_REQUESTER_POST,
445
+ lambda replay: _tell_fd_requester(replay, "was held for review and expired; it was not delivered."),
446
+ )
447
+
448
+ # Create skill registry (if skills_dir provided)
449
+ skill_registry: SkillRegistry | None = None
450
+ if skills_dir and skills_dir.exists():
451
+ skill_registry = SkillRegistry(skills_dir)
452
+ logger.info(f"Skill registry loaded from {skills_dir}")
453
+
454
+ # Create MCP registry (if mcps_dir provided)
455
+ mcp_registry: McpRegistry | None = None
456
+ if mcps_dir and mcps_dir.exists():
457
+ mcp_registry = McpRegistry(mcps_dir)
458
+ logger.info(f"MCP registry loaded from {mcps_dir}")
459
+
460
+ # Create FastAPI app
461
+ app = FastAPI(title="Manigent", version="0.1.0")
462
+ # The context behind every route; tests reach the channel gateway through it.
463
+ app.state.server_ctx = ctx
464
+
465
+ # Answers a retried write from the record of its first attempt. Added
466
+ # BEFORE CORS so CORS stays outermost and decorates replays too.
467
+ idempotency_store = IdempotencyStore(data_dir / "idempotency")
468
+ app.add_middleware(IdempotencyMiddleware, store=idempotency_store)
469
+
470
+ # CORS middleware — explicit allowlist (MANIGENT_CORS_ORIGINS +
471
+ # MANIGENT_APP_URL), env-configurable. Falls back to ["*"] only when
472
+ # nothing is configured (dev/test).
473
+ cors_origins = cors_allow_origins()
474
+ if cors_origins == ["*"]:
475
+ logger.info("CORS: no allowlist configured, allowing all origins (dev)")
476
+ else:
477
+ logger.info(f"CORS allowlist: {cors_origins}")
478
+ app.add_middleware(
479
+ CORSMiddleware,
480
+ allow_origins=cors_origins,
481
+ allow_credentials=True,
482
+ allow_methods=["*"],
483
+ allow_headers=["*"],
484
+ expose_headers=["*"],
485
+ )
486
+
487
+ # Rejects an oversized PUT /me/brief/tabs/{slug} on Content-Length
488
+ # BEFORE FastAPI buffers the body — the in-handler check runs after
489
+ # that buffering and so is a status code, not a mitigation. Scoped to
490
+ # that one path; every other request passes straight through.
491
+ app.add_middleware(BriefBodyLimitMiddleware)
492
+
493
+ # A turn token (a scoped turn's credential) reaches only the read routes
494
+ # of its grant's projects; anything else is answered turn_scope [403]
495
+ # before a route runs (server/turn_tokens.py).
496
+ app.add_middleware(
497
+ TurnTokenMiddleware,
498
+ service_getter=lambda: ctx.isolation_gate.turn_tokens if ctx.isolation_gate else None,
499
+ )
500
+
501
+ # Records X-Manigent-Isolation for the isolation gate's read check.
502
+ app.add_middleware(IsolationHeaderMiddleware)
503
+ # An owner-isolated agent's own token reaches only the serving-only
504
+ # allowlist (plan-owner-isolation 5d).
505
+ app.add_middleware(ServingOnlyMiddleware, ctx_getter=lambda: ctx)
506
+
507
+ # Register route modules
508
+ app.include_router(create_auth_router(ctx))
509
+ app.include_router(create_agents_router(ctx))
510
+ app.include_router(create_turn_tokens_router(ctx))
511
+ app.include_router(create_owner_isolation_router(ctx))
512
+ app.include_router(create_agent_env_router(ctx))
513
+ app.include_router(create_isolation_check_router(ctx))
514
+ app.include_router(create_agent_fs_router(ctx))
515
+ app.include_router(create_projects_router(ctx))
516
+ app.include_router(create_chatrooms_router(ctx))
517
+ app.include_router(create_files_router(ctx))
518
+ app.include_router(create_messages_router(ctx))
519
+ app.include_router(create_changelog_router(ctx))
520
+ if ws_mode == "inprocess":
521
+ app.include_router(create_websocket_router(ctx))
522
+
523
+ @app.get("/healthz/ready", include_in_schema=False)
524
+ async def healthz_ready():
525
+ """200 once this process can serve sockets' traffic: always in
526
+ in-process mode, only while the edge link is up in edge mode."""
527
+ from fastapi.responses import JSONResponse
528
+ if isinstance(ws_hub, EdgeWSHub):
529
+ up = ws_hub.ready
530
+ return JSONResponse(
531
+ {"ws_mode": ws_mode, "edge_link": "up" if up else "down"},
532
+ status_code=200 if up else 503,
533
+ )
534
+ return {"ws_mode": ws_mode, "edge_link": "n/a"}
535
+ app.include_router(create_announcements_router(ctx))
536
+ app.include_router(create_scheduled_messages_router(ctx))
537
+ app.include_router(create_managed_jobs_router(ctx))
538
+ app.include_router(create_reflection_router(ctx))
539
+ app.include_router(create_model_defaults_router(ctx))
540
+ app.include_router(create_sharing_router(ctx))
541
+ app.include_router(create_knowledge_packs_router(ctx))
542
+ app.include_router(create_brief_tabs_router(ctx))
543
+ app.include_router(create_hosts_router(ctx))
544
+ app.include_router(create_install_router(ctx))
545
+ app.include_router(create_desk_todos_router(ctx))
546
+ app.include_router(create_desk_sops_router(ctx))
547
+ app.include_router(create_desk_labels_router(ctx))
548
+ app.include_router(create_desk_read_state_router(ctx))
549
+ app.include_router(create_desk_tour_router(ctx))
550
+ app.include_router(create_desk_sign_off_router(ctx))
551
+ app.include_router(create_desk_latest_messages_router(ctx))
552
+ app.include_router(create_project_reports_router(ctx))
553
+ app.include_router(create_project_plans_router(ctx))
554
+ app.include_router(create_inbox_router(ctx))
555
+ app.include_router(create_search_router(ctx))
556
+ app.include_router(create_channels_router(ctx))
557
+ app.include_router(create_hub_router(ctx))
558
+ app.include_router(create_hub_channels_router(ctx))
559
+ app.include_router(create_public_requests_router(ctx))
560
+ app.add_exception_handler(HubError, hub_error_response)
561
+
562
+ async def foreign_coordinator_response(_request, exc):
563
+ from fastapi.responses import JSONResponse
564
+
565
+ from manigent.server.coordinator_rule import CODE, MESSAGE
566
+ logger.warning("foreign_coordinator: %s", exc)
567
+ return JSONResponse(status_code=403, content={"detail": {"code": CODE, "message": MESSAGE}})
568
+
569
+ app.add_exception_handler(ForeignCoordinator, foreign_coordinator_response)
570
+ app.include_router(create_webchat_router(ctx))
571
+ app.include_router(create_public_agents_router(
572
+ ctx, Path(__file__).parent.parent / "web" / "frontend" / "dist" / "public.html",
573
+ ))
574
+ app.include_router(create_oauth_router(ctx))
575
+ # OAuth invite-login (Google/GitHub) — mounted only when the four namespaced
576
+ # provider creds + MANIGENT_APP_URL are configured. Fail-fast from_env()
577
+ # raises when unset; we degrade to "feature off" rather than crash startup,
578
+ # mirroring the optional skill/mcp routers above.
579
+ try:
580
+ app.include_router(create_oauth_login_router(ctx))
581
+ logger.info("OAuth invite-login routes mounted (/auth/oauth/*)")
582
+ except RuntimeError as e:
583
+ logger.warning(f"OAuth invite-login not configured, routes not mounted: {e}")
584
+ if skill_registry:
585
+ app.include_router(create_skills_router(ctx, skill_registry))
586
+ if mcp_registry:
587
+ app.include_router(create_mcps_router(ctx, mcp_registry))
588
+ # The agent catalog: always routed, empty without a pool directory.
589
+ pool_dir = agent_pool_dir if agent_pool_dir and agent_pool_dir.exists() else None
590
+ app.include_router(create_templates_router(ctx, pool_dir))
591
+ if pool_dir:
592
+ logger.info(f"Agent pool loaded from {pool_dir}")
593
+
594
+ # Serve frontend static files
595
+ frontend_dist = Path(__file__).parent.parent / "web" / "frontend" / "dist"
596
+
597
+ if frontend_dist.exists():
598
+ logger.info(f"Frontend served from {frontend_dist}")
599
+
600
+ # Serve static assets at /app/assets/* (matches Vite build output)
601
+ @app.get("/app/assets/{file_path:path}", include_in_schema=False)
602
+ async def serve_static(file_path: str):
603
+ """Serve static assets (JS, CSS, etc.)."""
604
+ asset_file = frontend_dist / "assets" / file_path
605
+ if asset_file.exists() and asset_file.is_file():
606
+ return FileResponse(asset_file)
607
+ return FileResponse(frontend_dist / "index.html", status_code=404)
608
+
609
+ # Serve landing page at root
610
+ @app.get("/", include_in_schema=False)
611
+ async def serve_root():
612
+ landing_file = frontend_dist / "landing.html"
613
+ if landing_file.exists():
614
+ return FileResponse(landing_file)
615
+ return RedirectResponse(url="/app")
616
+
617
+ # Serve TOS and Privacy pages
618
+ @app.get("/tos", include_in_schema=False)
619
+ async def serve_tos():
620
+ return FileResponse(frontend_dist / "tos.html")
621
+
622
+ @app.get("/privacy", include_in_schema=False)
623
+ async def serve_privacy():
624
+ return FileResponse(frontend_dist / "privacy.html")
625
+
626
+ # The hub operator terms (`manigent server hub register --accept-tos`).
627
+ @app.get("/hub/terms", include_in_schema=False)
628
+ async def serve_hub_terms():
629
+ return FileResponse(frontend_dist / "hub-terms.html")
630
+
631
+ @app.get("/private-beta-announcement", include_in_schema=False)
632
+ async def serve_private_beta_announcement():
633
+ return FileResponse(frontend_dist / "private-beta-announcement.html")
634
+
635
+ # Serve brand images for landing page
636
+ @app.get("/brand-hero.png", include_in_schema=False)
637
+ async def serve_brand_hero():
638
+ return FileResponse(frontend_dist / "brand-hero.png")
639
+
640
+ @app.get("/brand-hero-banner.png", include_in_schema=False)
641
+ async def serve_brand_hero_banner():
642
+ return FileResponse(frontend_dist / "brand-hero-banner.png")
643
+
644
+ @app.get("/icon.png", include_in_schema=False)
645
+ async def serve_icon():
646
+ return FileResponse(frontend_dist / "icon.png")
647
+
648
+ # Icons at the bare root. The HTML entries reference these through Vite's
649
+ # base ('/app/…'), so these routes are the fallback for the
650
+ # requests that never pass through our HTML: a bookmark/scraper hitting
651
+ # /favicon.svg, or iOS asking for /apple-touch-icon.png on "Add to Home
652
+ # Screen". Without them those paths fall to the 404 JSON handler.
653
+ @app.get("/favicon.png", include_in_schema=False)
654
+ async def serve_favicon():
655
+ return FileResponse(frontend_dist / "favicon.png")
656
+
657
+ @app.get("/favicon.svg", include_in_schema=False)
658
+ async def serve_favicon_svg():
659
+ return FileResponse(frontend_dist / "favicon.svg")
660
+
661
+ @app.get("/apple-touch-icon.png", include_in_schema=False)
662
+ async def serve_apple_touch_icon():
663
+ return FileResponse(frontend_dist / "apple-touch-icon.png")
664
+
665
+ # Serve landing page assets (CSS/JS built by Vite for the landing entry).
666
+ @app.get("/assets/{file_path:path}", include_in_schema=False)
667
+ async def serve_landing_assets(file_path: str):
668
+ asset_file = frontend_dist / "assets" / file_path
669
+ if asset_file.exists() and asset_file.is_file():
670
+ return FileResponse(asset_file)
671
+ return FileResponse(frontend_dist / "index.html", status_code=404)
672
+
673
+ # SPA base route
674
+ @app.get("/app", include_in_schema=False)
675
+ async def serve_app():
676
+ """Serve SPA at /app."""
677
+ return FileResponse(frontend_dist / "index.html")
678
+
679
+ # SPA catch-all - serves static files if they exist, otherwise index.html for SPA routing
680
+ @app.get("/app/{path:path}", include_in_schema=False)
681
+ async def serve_spa(path: str):
682
+ """Serve static files or SPA for /app/* routes."""
683
+ return _serve_spa_file(frontend_dist, path, frontend_dist / "index.html")
684
+ else:
685
+ @app.get("/", include_in_schema=False)
686
+ async def serve_root_fallback():
687
+ return {"message": "Manigent API", "frontend": "Not built. Run: cd manigent/web/frontend && npm run build"}
688
+
689
+ logger.warning(f"Frontend not found at {frontend_dist}. Run: cd manigent/web/frontend && npm run build")
690
+
691
+ background_tasks: list[asyncio.Task] = []
692
+
693
+ async def _sweep_idempotency_hourly() -> None:
694
+ while True:
695
+ try:
696
+ removed = await asyncio.to_thread(idempotency_store.sweep)
697
+ if removed:
698
+ logger.info(f"Swept {removed} expired idempotency hour dir(s)")
699
+ except Exception:
700
+ logger.warning("Idempotency sweep failed", exc_info=True)
701
+ await asyncio.sleep(3600)
702
+
703
+ # Startup event
704
+ @app.on_event("startup")
705
+ async def startup():
706
+ await User.initialize(model_ctx)
707
+ if isinstance(ws_hub, EdgeWSHub):
708
+ # Before the port binds: the snapshot settles every agent's status
709
+ # first, so the first request already sees the right one.
710
+ await ws_hub.start()
711
+ # One-shot idempotent reconcile of report_published_at against report.json
712
+ # for every project, so the denormalized field is correct from first
713
+ # deploy (projects with a pre-existing report predate the meta key). Only
714
+ # writes on a real delta, so re-running on every boot is cheap.
715
+ stamped = backfill_report_published_at(model_ctx)
716
+ if stamped:
717
+ logger.info(f"Backfilled report_published_at for {stamped} project(s)")
718
+ # One-time passes (server/requester_key_migration.py), each under its
719
+ # own guard so one failing never skips the others; each runs again at
720
+ # the next start. A failed scoped-turn pass fails closed: a project it
721
+ # had not keyed yet is still scoped by models/project.scope_key.
722
+ for migrate in (
723
+ # First: projects a scoped turn created keep their scope once
724
+ # remote_content stops isolating (plan-owner-isolation section 3).
725
+ migrate_scoped_turn_projects,
726
+ # Requester ends coordinated by a stand-in or another account's
727
+ # agent are reassigned to their owner (plan-owner-isolation 4).
728
+ migrate_owner_coordinators,
729
+ # Existing host conversations get their requester_key, so they
730
+ # are requester-scoped like new ones.
731
+ migrate_requester_keys,
732
+ migrate_hub_thread_marks,
733
+ # Same-server agents users already talk to are retained, so they
734
+ # stay in Cmd-K and the agents' rosters (server/hub/retain.py).
735
+ migrate_local_retains,
736
+ ):
737
+ try:
738
+ await migrate(ctx, data_dir / "isolation")
739
+ except Exception:
740
+ logger.exception("%s failed; it will run again at next start", migrate.__name__)
741
+ # Managed jobs outlive the in-memory WorkTracker: rebuild their open
742
+ # requests before the checker's first pass, so a job whose process
743
+ # died while the server was down is reported as stalled.
744
+ try:
745
+ await restore_active_jobs(
746
+ managed_job_store, work_tracker, default_timeout=ctx.batch_timeout,
747
+ )
748
+ except Exception:
749
+ logger.exception("Managed job restore failed")
750
+ await timeout_checker.start()
751
+ background_tasks.append(asyncio.create_task(_sweep_idempotency_hourly()))
752
+ # Held outside messages past their ceiling go, with their closing notes.
753
+ background_tasks.append(asyncio.create_task(ctx.outside_ingress.run_expiry_sweep()))
754
+ # Work held for an agent that cannot isolate: closed at its ceiling,
755
+ # and the owner reminded at most daily.
756
+ background_tasks.append(asyncio.create_task(ctx.isolation_gate.notice.run_sweep()))
757
+ await message_scheduler.start()
758
+ await reflection_scheduler.start()
759
+ # Schema + FTS5 probe is synchronous and cheap; the reconcile that
760
+ # backfills existing history (and repairs any drift) runs as a
761
+ # background task so it never blocks boot. The endpoint answers while
762
+ # it runs, with `indexing: true`.
763
+ chat_search_index.open()
764
+ if chat_search_index.available:
765
+ asyncio.create_task(chat_search_index.reconcile_all())
766
+ if ctx.channel_gateway is not None:
767
+ try:
768
+ await ctx.channel_gateway.start()
769
+ except Exception as exc: # noqa: BLE001 — never stop the server booting
770
+ logger.error(
771
+ "Channel gateway OFF: unexpected %s during startup",
772
+ type(exc).__name__,
773
+ )
774
+ ctx.channel_gateway = None
775
+ ctx.hub_runtime = None
776
+ if ctx.hub_runtime is not None:
777
+ # After the gateway: reopen paused work, purge withdrawn hub
778
+ # keys, then (registered and mode not off) the first connect.
779
+ try:
780
+ await ctx.hub_runtime.start()
781
+ except Exception as exc: # noqa: BLE001 — never stop the server booting
782
+ logger.error("Hub runtime OFF: unexpected %s during startup", type(exc).__name__)
783
+ ctx.hub_runtime = None
784
+ logger.info(f"Server started with data_dir={data_dir}")
785
+
786
+ # Shutdown event
787
+ @app.on_event("shutdown")
788
+ async def shutdown():
789
+ for task in background_tasks:
790
+ task.cancel()
791
+ await reflection_scheduler.stop()
792
+ await message_scheduler.stop()
793
+ await timeout_checker.stop()
794
+ if ctx.hub_runtime is not None:
795
+ await ctx.hub_runtime.stop()
796
+ if ctx.channel_gateway is not None:
797
+ await ctx.channel_gateway.stop()
798
+ await ctx.socket_events.close()
799
+ if isinstance(ws_hub, EdgeWSHub):
800
+ await ws_hub.stop()
801
+ await runloop_manager.shutdown()
802
+ chat_search_index.close()
803
+ if ctx.channel_store is not None:
804
+ ctx.channel_store.close()
805
+ logger.info("Server shutdown complete")
806
+
807
+ return app