manigent-server 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1004) hide show
  1. manigent/_catalog/mcps/chess/README.md +38 -0
  2. manigent/_catalog/mcps/chess/mcp.json +9 -0
  3. manigent/_catalog/mcps/registry.json +9 -0
  4. manigent/_catalog/skills/brief/SKILL.md +339 -0
  5. manigent/_catalog/skills/broaden-options/SKILL.md +133 -0
  6. manigent/_catalog/skills/calendar/SKILL.md +44 -0
  7. manigent/_catalog/skills/calendar/starter_config.jsonc +25 -0
  8. manigent/_catalog/skills/gmail/SKILL.md +73 -0
  9. manigent/_catalog/skills/google-calendar/SKILL.md +44 -0
  10. manigent/_catalog/skills/google-drive/SKILL.md +42 -0
  11. manigent/_catalog/skills/google-drive-write/SKILL.md +45 -0
  12. manigent/_catalog/skills/google-drive-write/starter_config.jsonc +45 -0
  13. manigent/_catalog/skills/grill-me/SKILL.md +173 -0
  14. manigent/_catalog/skills/homekit/SKILL.md +37 -0
  15. manigent/_catalog/skills/http-api/SKILL.md +117 -0
  16. manigent/_catalog/skills/ib/SKILL.md +89 -0
  17. manigent/_catalog/skills/ib/starter_config.jsonc +35 -0
  18. manigent/_catalog/skills/mailbox/SKILL.md +47 -0
  19. manigent/_catalog/skills/mailbox/starter_config.jsonc +38 -0
  20. manigent/_catalog/skills/media/SKILL.md +93 -0
  21. manigent/_catalog/skills/media/starter_config.jsonc +63 -0
  22. manigent/_catalog/skills/osxphotos/SKILL.md +41 -0
  23. manigent/_catalog/skills/photo-story/SKILL.md +285 -0
  24. manigent/_catalog/skills/playwright-browser/SKILL.md +291 -0
  25. manigent/_catalog/skills/playwright-browser/starter_config.jsonc +44 -0
  26. manigent/_catalog/skills/playwright-save-skill/SKILL.md +149 -0
  27. manigent/_catalog/skills/registry.json +166 -0
  28. manigent/_catalog/skills/web-artifacts/SKILL.md +194 -0
  29. manigent/api/action_executor.py +404 -0
  30. manigent/api/action_validator.py +531 -0
  31. manigent/api/actions.py +221 -0
  32. manigent/api/client.py +558 -0
  33. manigent/api/control.py +806 -0
  34. manigent/api/edge_protocol.py +123 -0
  35. manigent/api/fs_protocol.py +450 -0
  36. manigent/api/host_protocol.py +298 -0
  37. manigent/api/managed_job_client.py +124 -0
  38. manigent/api/responses.py +342 -0
  39. manigent/api/retry_transport.py +178 -0
  40. manigent/api/turn_protocol.py +78 -0
  41. manigent/cli_lifecycle.py +467 -0
  42. manigent/cli_server.py +978 -0
  43. manigent/doctor.py +1167 -0
  44. manigent/hub_protocol/canonical.py +375 -0
  45. manigent/hub_protocol/codes.py +171 -0
  46. manigent/hub_protocol/constants.py +71 -0
  47. manigent/hub_protocol/envelope.py +218 -0
  48. manigent/hub_protocol/frames.py +788 -0
  49. manigent/hub_protocol/http.py +260 -0
  50. manigent/hub_protocol/ids.py +170 -0
  51. manigent/hub_protocol/keys.py +195 -0
  52. manigent/hub_protocol/text.py +75 -0
  53. manigent/llm/base.py +1072 -0
  54. manigent/llm/prompt_builder.py +2450 -0
  55. manigent/llm/triggers.py +68 -0
  56. manigent/models/agent.py +2905 -0
  57. manigent/models/agent_bundle.py +298 -0
  58. manigent/models/brief_tab.py +311 -0
  59. manigent/models/chat_message.py +231 -0
  60. manigent/models/chatroom.py +1108 -0
  61. manigent/models/context.py +1159 -0
  62. manigent/models/desk_label.py +836 -0
  63. manigent/models/desk_read_state.py +220 -0
  64. manigent/models/desk_sign_off.py +267 -0
  65. manigent/models/desk_sop.py +965 -0
  66. manigent/models/desk_todo.py +1603 -0
  67. manigent/models/desk_todo_link.py +404 -0
  68. manigent/models/file_cache.py +75 -0
  69. manigent/models/host.py +732 -0
  70. manigent/models/install_token.py +401 -0
  71. manigent/models/invitation_code.py +162 -0
  72. manigent/models/knowledge_pack.py +552 -0
  73. manigent/models/managed_job.py +295 -0
  74. manigent/models/model_config.py +564 -0
  75. manigent/models/model_defaults.py +238 -0
  76. manigent/models/onboarding_plan.py +161 -0
  77. manigent/models/participant.py +449 -0
  78. manigent/models/persistable.py +892 -0
  79. manigent/models/plan_markdown.py +1774 -0
  80. manigent/models/project.py +1343 -0
  81. manigent/models/project_plan.py +8104 -0
  82. manigent/models/project_report.py +145 -0
  83. manigent/models/provenance.py +261 -0
  84. manigent/models/provider_agents.py +101 -0
  85. manigent/models/public_request.py +108 -0
  86. manigent/models/reflection_schedule.py +191 -0
  87. manigent/models/scheduled_message.py +285 -0
  88. manigent/models/share_token.py +190 -0
  89. manigent/models/skill_version.py +31 -0
  90. manigent/models/sop_template.py +187 -0
  91. manigent/models/thinking_partner_plan.py +187 -0
  92. manigent/models/tunnel_binding.py +129 -0
  93. manigent/models/user.py +1276 -0
  94. manigent/models/work_tracker.py +510 -0
  95. manigent/runner/invocation_registry.py +187 -0
  96. manigent/server/agent_capabilities.py +119 -0
  97. manigent/server/agent_visibility.py +119 -0
  98. manigent/server/announcements.py +119 -0
  99. manigent/server/app.py +807 -0
  100. manigent/server/auth.py +355 -0
  101. manigent/server/batch_timeout.py +94 -0
  102. manigent/server/channels/access.py +194 -0
  103. manigent/server/channels/adapter.py +295 -0
  104. manigent/server/channels/config.py +693 -0
  105. manigent/server/channels/contacts.py +39 -0
  106. manigent/server/channels/email_adapter.py +436 -0
  107. manigent/server/channels/email_address.py +145 -0
  108. manigent/server/channels/email_form.py +242 -0
  109. manigent/server/channels/email_format.py +285 -0
  110. manigent/server/channels/email_mail.py +427 -0
  111. manigent/server/channels/email_mailgun.py +164 -0
  112. manigent/server/channels/email_text.py +280 -0
  113. manigent/server/channels/file_links.py +127 -0
  114. manigent/server/channels/gateway.py +2998 -0
  115. manigent/server/channels/hub_delivery.py +211 -0
  116. manigent/server/channels/hub_store.py +1730 -0
  117. manigent/server/channels/line.py +645 -0
  118. manigent/server/channels/line_format.py +589 -0
  119. manigent/server/channels/log_redaction.py +145 -0
  120. manigent/server/channels/store.py +3316 -0
  121. manigent/server/channels/telegram.py +422 -0
  122. manigent/server/channels/telegram_format.py +312 -0
  123. manigent/server/channels/webchat.py +261 -0
  124. manigent/server/channels/webchat_widget.js +1310 -0
  125. manigent/server/channels/whatsapp.py +707 -0
  126. manigent/server/channels/whatsapp_format.py +511 -0
  127. manigent/server/chat_search_index.py +1203 -0
  128. manigent/server/config.py +61 -0
  129. manigent/server/context.py +121 -0
  130. manigent/server/coordinator_rule.py +115 -0
  131. manigent/server/desk_todo_notify.py +300 -0
  132. manigent/server/edge_hub.py +577 -0
  133. manigent/server/email.py +354 -0
  134. manigent/server/errors.py +83 -0
  135. manigent/server/home_fs_relay.py +392 -0
  136. manigent/server/hub/adapter.py +1395 -0
  137. manigent/server/hub/agent_send_guard.py +196 -0
  138. manigent/server/hub/avatar.py +342 -0
  139. manigent/server/hub/browser.py +778 -0
  140. manigent/server/hub/client.py +859 -0
  141. manigent/server/hub/demand.py +49 -0
  142. manigent/server/hub/directory.py +385 -0
  143. manigent/server/hub/enroll.py +400 -0
  144. manigent/server/hub/http.py +134 -0
  145. manigent/server/hub/identity.py +61 -0
  146. manigent/server/hub/keys.py +588 -0
  147. manigent/server/hub/mirror.py +802 -0
  148. manigent/server/hub/operator.py +817 -0
  149. manigent/server/hub/retain.py +361 -0
  150. manigent/server/hub/room_bridge.py +741 -0
  151. manigent/server/hub/runtime.py +691 -0
  152. manigent/server/hub/trust.py +182 -0
  153. manigent/server/hub/views.py +316 -0
  154. manigent/server/idempotency.py +205 -0
  155. manigent/server/in_flight_restore.py +181 -0
  156. manigent/server/inspection.py +816 -0
  157. manigent/server/isolation_gate.py +516 -0
  158. manigent/server/isolation_notice.py +310 -0
  159. manigent/server/managed_job_events.py +242 -0
  160. manigent/server/mcp_registry.py +118 -0
  161. manigent/server/message_forward.py +78 -0
  162. manigent/server/message_scheduler.py +176 -0
  163. manigent/server/notification_assets.py +164 -0
  164. manigent/server/oauth_login/cli_state.py +120 -0
  165. manigent/server/oauth_login/config.py +90 -0
  166. manigent/server/oauth_login/errors.py +78 -0
  167. manigent/server/oauth_login/flow.py +223 -0
  168. manigent/server/oauth_login/handoff.py +63 -0
  169. manigent/server/oauth_login/providers.py +45 -0
  170. manigent/server/oauth_state.py +81 -0
  171. manigent/server/owner_isolation.py +466 -0
  172. manigent/server/participant_liveness.py +82 -0
  173. manigent/server/public_profile.py +149 -0
  174. manigent/server/public_requests/candidates.py +116 -0
  175. manigent/server/public_requests/dispatch.py +121 -0
  176. manigent/server/public_requests/ranking.py +153 -0
  177. manigent/server/recent_activity.py +250 -0
  178. manigent/server/reflection_completion_subscriber.py +151 -0
  179. manigent/server/reflection_scheduler.py +239 -0
  180. manigent/server/requester_key_migration.py +261 -0
  181. manigent/server/room_flow.py +139 -0
  182. manigent/server/routes/_batch.py +218 -0
  183. manigent/server/routes/_fd_routing.py +155 -0
  184. manigent/server/routes/_mentions.py +70 -0
  185. manigent/server/routes/agent_env.py +188 -0
  186. manigent/server/routes/agent_fs.py +450 -0
  187. manigent/server/routes/agents.py +1206 -0
  188. manigent/server/routes/announcements.py +79 -0
  189. manigent/server/routes/auth.py +387 -0
  190. manigent/server/routes/brief_tabs.py +404 -0
  191. manigent/server/routes/changelog.py +237 -0
  192. manigent/server/routes/channels.py +993 -0
  193. manigent/server/routes/chatrooms.py +871 -0
  194. manigent/server/routes/desk_labels.py +298 -0
  195. manigent/server/routes/desk_latest_messages.py +116 -0
  196. manigent/server/routes/desk_read_state.py +110 -0
  197. manigent/server/routes/desk_sign_off.py +88 -0
  198. manigent/server/routes/desk_sops.py +216 -0
  199. manigent/server/routes/desk_todos.py +692 -0
  200. manigent/server/routes/desk_tour.py +44 -0
  201. manigent/server/routes/files.py +572 -0
  202. manigent/server/routes/hosts.py +484 -0
  203. manigent/server/routes/hub.py +534 -0
  204. manigent/server/routes/hub_channels.py +234 -0
  205. manigent/server/routes/inbox.py +581 -0
  206. manigent/server/routes/install.ps1 +436 -0
  207. manigent/server/routes/install.py +324 -0
  208. manigent/server/routes/install.sh +566 -0
  209. manigent/server/routes/isolation_check.py +145 -0
  210. manigent/server/routes/knowledge_packs.py +477 -0
  211. manigent/server/routes/managed_jobs.py +196 -0
  212. manigent/server/routes/mcps.py +271 -0
  213. manigent/server/routes/messages.py +1972 -0
  214. manigent/server/routes/model_defaults.py +279 -0
  215. manigent/server/routes/oauth.py +237 -0
  216. manigent/server/routes/oauth_login.py +351 -0
  217. manigent/server/routes/owner_isolation.py +91 -0
  218. manigent/server/routes/project_plans.py +1521 -0
  219. manigent/server/routes/project_reports.py +235 -0
  220. manigent/server/routes/projects.py +2047 -0
  221. manigent/server/routes/public_agents.py +151 -0
  222. manigent/server/routes/public_requests.py +181 -0
  223. manigent/server/routes/reflection.py +93 -0
  224. manigent/server/routes/scheduled_messages.py +263 -0
  225. manigent/server/routes/search.py +94 -0
  226. manigent/server/routes/sharing.py +156 -0
  227. manigent/server/routes/skills.py +406 -0
  228. manigent/server/routes/templates.py +219 -0
  229. manigent/server/routes/turn_tokens.py +119 -0
  230. manigent/server/routes/webchat.py +406 -0
  231. manigent/server/routes/websocket.py +431 -0
  232. manigent/server/serving_only.py +200 -0
  233. manigent/server/signup_policy.py +120 -0
  234. manigent/server/skill_registry.py +164 -0
  235. manigent/server/socket_events.py +858 -0
  236. manigent/server/timeout_checker.py +446 -0
  237. manigent/server/tunnel_subscriber.py +1000 -0
  238. manigent/server/turn_tokens.py +285 -0
  239. manigent/server/ws_hub.py +556 -0
  240. manigent/server_cli.py +31 -0
  241. manigent/sync/changelog.py +885 -0
  242. manigent/sync/console_subscriber.py +222 -0
  243. manigent/sync/runloop.py +619 -0
  244. manigent/sync/runloop_manager.py +197 -0
  245. manigent/sync/subscriber.py +98 -0
  246. manigent/utils/agent_processes.py +276 -0
  247. manigent/utils/agent_storage.py +125 -0
  248. manigent/utils/email.py +563 -0
  249. manigent/utils/env_store.py +174 -0
  250. manigent/utils/extra_dirs.py +85 -0
  251. manigent/utils/file_io.py +485 -0
  252. manigent/utils/invoke_timeout.py +87 -0
  253. manigent/utils/jsonc.py +78 -0
  254. manigent/utils/knowledge_index.py +148 -0
  255. manigent/utils/nofollow_fs.py +279 -0
  256. manigent/utils/notification_center.py +67 -0
  257. manigent/utils/version.py +57 -0
  258. manigent/web/frontend/.design-sync-entry.tsx +74 -0
  259. manigent/web/frontend/.design-sync-provider.tsx +46 -0
  260. manigent/web/frontend/.eslintrc.cjs +183 -0
  261. manigent/web/frontend/.gitignore +6 -0
  262. manigent/web/frontend/app/page.tsx +39 -0
  263. manigent/web/frontend/hub-terms.html +192 -0
  264. manigent/web/frontend/index.html +15 -0
  265. manigent/web/frontend/landing.html +15 -0
  266. manigent/web/frontend/package-lock.json +8028 -0
  267. manigent/web/frontend/package.json +55 -0
  268. manigent/web/frontend/postcss.config.js +6 -0
  269. manigent/web/frontend/privacy.html +217 -0
  270. manigent/web/frontend/private-beta-announcement.html +19 -0
  271. manigent/web/frontend/public/apple-touch-icon.png +0 -0
  272. manigent/web/frontend/public/brand-hero-banner.png +0 -0
  273. manigent/web/frontend/public/brand-hero.png +0 -0
  274. manigent/web/frontend/public/favicon.png +0 -0
  275. manigent/web/frontend/public/favicon.svg +8 -0
  276. manigent/web/frontend/public/icon-transparent-sm.png +0 -0
  277. manigent/web/frontend/public/icon.png +0 -0
  278. manigent/web/frontend/public/manigent-mark.svg +7 -0
  279. manigent/web/frontend/public/vite.svg +5 -0
  280. manigent/web/frontend/public.html +15 -0
  281. manigent/web/frontend/src/App.activeAccountRedirect.test.tsx +236 -0
  282. manigent/web/frontend/src/App.hubHostDm.test.tsx +119 -0
  283. manigent/web/frontend/src/App.hubHostProject.test.tsx +142 -0
  284. manigent/web/frontend/src/App.hubRoutes.test.tsx +187 -0
  285. manigent/web/frontend/src/App.oauthAddCallback.test.tsx +263 -0
  286. manigent/web/frontend/src/App.tsx +246 -0
  287. manigent/web/frontend/src/api/attachments.ts +32 -0
  288. manigent/web/frontend/src/api/batchLoader.test.ts +212 -0
  289. manigent/web/frontend/src/api/batchLoader.ts +124 -0
  290. manigent/web/frontend/src/api/chatroomsBatch.test.tsx +392 -0
  291. manigent/web/frontend/src/api/client.ts +321 -0
  292. manigent/web/frontend/src/api/crossAccountAuth.test.ts +388 -0
  293. manigent/web/frontend/src/api/endpoints/agentEnv.ts +24 -0
  294. manigent/web/frontend/src/api/endpoints/agentFs.ts +125 -0
  295. manigent/web/frontend/src/api/endpoints/agentSearch.ts +19 -0
  296. manigent/web/frontend/src/api/endpoints/agents.ts +66 -0
  297. manigent/web/frontend/src/api/endpoints/announcements.ts +26 -0
  298. manigent/web/frontend/src/api/endpoints/auth.ts +361 -0
  299. manigent/web/frontend/src/api/endpoints/authLogin.test.ts +236 -0
  300. manigent/web/frontend/src/api/endpoints/batch.ts +64 -0
  301. manigent/web/frontend/src/api/endpoints/briefTabs.ts +81 -0
  302. manigent/web/frontend/src/api/endpoints/channels.ts +285 -0
  303. manigent/web/frontend/src/api/endpoints/computers.ts +212 -0
  304. manigent/web/frontend/src/api/endpoints/deskLabels.ts +151 -0
  305. manigent/web/frontend/src/api/endpoints/deskLatestMessages.ts +23 -0
  306. manigent/web/frontend/src/api/endpoints/deskReadState.ts +41 -0
  307. manigent/web/frontend/src/api/endpoints/deskSignOffs.ts +74 -0
  308. manigent/web/frontend/src/api/endpoints/deskSops.ts +53 -0
  309. manigent/web/frontend/src/api/endpoints/deskTodoAttachments.ts +69 -0
  310. manigent/web/frontend/src/api/endpoints/deskTodoProjects.test.ts +99 -0
  311. manigent/web/frontend/src/api/endpoints/deskTodoProjects.ts +114 -0
  312. manigent/web/frontend/src/api/endpoints/deskTodos.ts +164 -0
  313. manigent/web/frontend/src/api/endpoints/deskTour.ts +16 -0
  314. manigent/web/frontend/src/api/endpoints/dm.ts +137 -0
  315. manigent/web/frontend/src/api/endpoints/files.ts +55 -0
  316. manigent/web/frontend/src/api/endpoints/hub.contract.test.ts +94 -0
  317. manigent/web/frontend/src/api/endpoints/hub.keys.ts +260 -0
  318. manigent/web/frontend/src/api/endpoints/hub.test.ts +203 -0
  319. manigent/web/frontend/src/api/endpoints/hub.ts +654 -0
  320. manigent/web/frontend/src/api/endpoints/index.ts +15 -0
  321. manigent/web/frontend/src/api/endpoints/install.ts +74 -0
  322. manigent/web/frontend/src/api/endpoints/isolationCheck.ts +36 -0
  323. manigent/web/frontend/src/api/endpoints/knowledgePacks.ts +179 -0
  324. manigent/web/frontend/src/api/endpoints/mcps.ts +36 -0
  325. manigent/web/frontend/src/api/endpoints/messages.held.test.ts +43 -0
  326. manigent/web/frontend/src/api/endpoints/messages.ts +95 -0
  327. manigent/web/frontend/src/api/endpoints/modelConfigs.ts +232 -0
  328. manigent/web/frontend/src/api/endpoints/oauthApi.test.ts +110 -0
  329. manigent/web/frontend/src/api/endpoints/projectPlans.ts +608 -0
  330. manigent/web/frontend/src/api/endpoints/projectReports.ts +36 -0
  331. manigent/web/frontend/src/api/endpoints/projects.ts +124 -0
  332. manigent/web/frontend/src/api/endpoints/publicRequests.ts +75 -0
  333. manigent/web/frontend/src/api/endpoints/reflection.ts +32 -0
  334. manigent/web/frontend/src/api/endpoints/roomFlow.ts +14 -0
  335. manigent/web/frontend/src/api/endpoints/scheduledMessages.ts +60 -0
  336. manigent/web/frontend/src/api/endpoints/search.ts +27 -0
  337. manigent/web/frontend/src/api/endpoints/sharing.ts +42 -0
  338. manigent/web/frontend/src/api/endpoints/skills.ts +67 -0
  339. manigent/web/frontend/src/api/endpoints/templates.ts +72 -0
  340. manigent/web/frontend/src/api/loaders.ts +22 -0
  341. manigent/web/frontend/src/api/singleIssuer.test.ts +148 -0
  342. manigent/web/frontend/src/api/transientRetry.test.ts +176 -0
  343. manigent/web/frontend/src/api/transientRetry.ts +140 -0
  344. manigent/web/frontend/src/api/websocket.resync.test.ts +111 -0
  345. manigent/web/frontend/src/api/websocket.ts +335 -0
  346. manigent/web/frontend/src/components/agent/AgentNameLink.tsx +24 -0
  347. manigent/web/frontend/src/components/agent/AgentViewActions.test.tsx +41 -0
  348. manigent/web/frontend/src/components/agent/AgentViewActions.tsx +89 -0
  349. manigent/web/frontend/src/components/agent/CreateAgentPage.tsx +535 -0
  350. manigent/web/frontend/src/components/agent/JsonConfigEditor.tsx +33 -0
  351. manigent/web/frontend/src/components/agent/KnowledgePackList.tsx +103 -0
  352. manigent/web/frontend/src/components/agent/McpCatalog.tsx +261 -0
  353. manigent/web/frontend/src/components/agent/McpConfigModal.tsx +224 -0
  354. manigent/web/frontend/src/components/agent/PreConsentModal.tsx +172 -0
  355. manigent/web/frontend/src/components/agent/SkillCatalog.tsx +364 -0
  356. manigent/web/frontend/src/components/agent/SkillConfigModal.tsx +221 -0
  357. manigent/web/frontend/src/components/auth/AddAccountPage.test.tsx +181 -0
  358. manigent/web/frontend/src/components/auth/AddAccountPage.tsx +201 -0
  359. manigent/web/frontend/src/components/auth/AuthShell.tsx +462 -0
  360. manigent/web/frontend/src/components/auth/LoginPage.test.tsx +384 -0
  361. manigent/web/frontend/src/components/auth/LoginPage.tsx +129 -0
  362. manigent/web/frontend/src/components/auth/OAuthCallbackPage.test.tsx +185 -0
  363. manigent/web/frontend/src/components/auth/OAuthCallbackPage.tsx +154 -0
  364. manigent/web/frontend/src/components/auth/OAuthLinkedBanner.tsx +44 -0
  365. manigent/web/frontend/src/components/auth/ProviderButtons.tsx +94 -0
  366. manigent/web/frontend/src/components/auth/SignupPage.tsx +437 -0
  367. manigent/web/frontend/src/components/auth/StepProgress.tsx +60 -0
  368. manigent/web/frontend/src/components/auth/VerifyEmailPage.test.tsx +155 -0
  369. manigent/web/frontend/src/components/auth/VerifyEmailPage.tsx +211 -0
  370. manigent/web/frontend/src/components/auth/index.ts +3 -0
  371. manigent/web/frontend/src/components/auth/oauthErrors.test.ts +107 -0
  372. manigent/web/frontend/src/components/auth/oauthErrors.ts +82 -0
  373. manigent/web/frontend/src/components/auth/useUsernameCheck.test.tsx +68 -0
  374. manigent/web/frontend/src/components/auth/useUsernameCheck.ts +86 -0
  375. manigent/web/frontend/src/components/beta/BetaPage.tsx +21 -0
  376. manigent/web/frontend/src/components/beta/DayAtMyDesk.tsx +120 -0
  377. manigent/web/frontend/src/components/beta/Footer.tsx +82 -0
  378. manigent/web/frontend/src/components/beta/Hero.tsx +224 -0
  379. manigent/web/frontend/src/components/beta/Nav.tsx +51 -0
  380. manigent/web/frontend/src/components/beta/Pillars.tsx +172 -0
  381. manigent/web/frontend/src/components/beta/TwoModels.tsx +146 -0
  382. manigent/web/frontend/src/components/beta/constants.ts +3 -0
  383. manigent/web/frontend/src/components/briefing/BriefingFrame.test.tsx +208 -0
  384. manigent/web/frontend/src/components/briefing/BriefingFrame.tsx +151 -0
  385. manigent/web/frontend/src/components/briefing/BriefingPage.test.tsx +176 -0
  386. manigent/web/frontend/src/components/briefing/BriefingPage.tsx +157 -0
  387. manigent/web/frontend/src/components/briefing/BriefingPage.wsDelete.test.tsx +177 -0
  388. manigent/web/frontend/src/components/briefing/briefing.css +147 -0
  389. manigent/web/frontend/src/components/briefing/heightBootstrap.test.ts +121 -0
  390. manigent/web/frontend/src/components/briefing/heightBootstrap.ts +224 -0
  391. manigent/web/frontend/src/components/briefing/parseBriefMessage.test.ts +90 -0
  392. manigent/web/frontend/src/components/briefing/sampleBriefing.ts +148 -0
  393. manigent/web/frontend/src/components/channels/ChannelBadge.tsx +35 -0
  394. manigent/web/frontend/src/components/chatroom/ChannelThreadControls.tsx +127 -0
  395. manigent/web/frontend/src/components/chatroom/ChannelThreadNotice.test.tsx +207 -0
  396. manigent/web/frontend/src/components/chatroom/ChannelThreadNotice.tsx +80 -0
  397. manigent/web/frontend/src/components/chatroom/ChatroomView.channel.test.tsx +550 -0
  398. manigent/web/frontend/src/components/chatroom/ChatroomView.flow.test.tsx +186 -0
  399. manigent/web/frontend/src/components/chatroom/ChatroomView.isolation.test.tsx +70 -0
  400. manigent/web/frontend/src/components/chatroom/ChatroomView.tsx +450 -0
  401. manigent/web/frontend/src/components/chatroom/DelegationRow.test.tsx +170 -0
  402. manigent/web/frontend/src/components/chatroom/DelegationRow.tsx +217 -0
  403. manigent/web/frontend/src/components/chatroom/DeliveryStatusLine.test.tsx +33 -0
  404. manigent/web/frontend/src/components/chatroom/DeliveryStatusLine.tsx +46 -0
  405. manigent/web/frontend/src/components/chatroom/ForwardModal.test.tsx +109 -0
  406. manigent/web/frontend/src/components/chatroom/ForwardModal.tsx +304 -0
  407. manigent/web/frontend/src/components/chatroom/HeldNotice.tsx +77 -0
  408. manigent/web/frontend/src/components/chatroom/MentionDropdown.tsx +97 -0
  409. manigent/web/frontend/src/components/chatroom/MessageInput.tsx +408 -0
  410. manigent/web/frontend/src/components/chatroom/MessageItem.tsx +425 -0
  411. manigent/web/frontend/src/components/chatroom/MessageList.outside.test.tsx +98 -0
  412. manigent/web/frontend/src/components/chatroom/MessageList.test.tsx +245 -0
  413. manigent/web/frontend/src/components/chatroom/MessageList.tsx +406 -0
  414. manigent/web/frontend/src/components/chatroom/OfflineRemedyNote.test.tsx +211 -0
  415. manigent/web/frontend/src/components/chatroom/OfflineRemedyNote.tsx +182 -0
  416. manigent/web/frontend/src/components/chatroom/OutsideBadge.tsx +18 -0
  417. manigent/web/frontend/src/components/chatroom/RoomFlowControl.tsx +49 -0
  418. manigent/web/frontend/src/components/chatroom/RoomFlowStrip.test.tsx +47 -0
  419. manigent/web/frontend/src/components/chatroom/RoomFlowStrip.tsx +25 -0
  420. manigent/web/frontend/src/components/chatroom/SaveToPackModal.tsx +350 -0
  421. manigent/web/frontend/src/components/chatroom/StagedAttachments.test.tsx +56 -0
  422. manigent/web/frontend/src/components/chatroom/StagedAttachments.tsx +160 -0
  423. manigent/web/frontend/src/components/chatroom/SystemNote.tsx +18 -0
  424. manigent/web/frontend/src/components/chatroom/contactSender.test.tsx +130 -0
  425. manigent/web/frontend/src/components/chatroom/index.ts +3 -0
  426. manigent/web/frontend/src/components/chatroom/recipientStatus.test.ts +344 -0
  427. manigent/web/frontend/src/components/chatroom/recipientStatus.ts +197 -0
  428. manigent/web/frontend/src/components/common/AnnouncementBanners.test.tsx +221 -0
  429. manigent/web/frontend/src/components/common/AnnouncementBanners.tsx +180 -0
  430. manigent/web/frontend/src/components/common/Avatar.test.tsx +50 -0
  431. manigent/web/frontend/src/components/common/Avatar.tsx +102 -0
  432. manigent/web/frontend/src/components/common/Badge.tsx +30 -0
  433. manigent/web/frontend/src/components/common/BrandName.tsx +16 -0
  434. manigent/web/frontend/src/components/common/ClearHistoryButton.tsx +74 -0
  435. manigent/web/frontend/src/components/common/CollapsibleHeader.tsx +64 -0
  436. manigent/web/frontend/src/components/common/ConnectionStatus.test.tsx +56 -0
  437. manigent/web/frontend/src/components/common/ConnectionStatus.tsx +28 -0
  438. manigent/web/frontend/src/components/common/DropOverlay.tsx +27 -0
  439. manigent/web/frontend/src/components/common/InlineEditableTitle.test.tsx +369 -0
  440. manigent/web/frontend/src/components/common/InlineEditableTitle.tsx +287 -0
  441. manigent/web/frontend/src/components/common/IsolationUnavailablePanel.tsx +19 -0
  442. manigent/web/frontend/src/components/common/Loading.tsx +22 -0
  443. manigent/web/frontend/src/components/common/ModelSelector.tsx +248 -0
  444. manigent/web/frontend/src/components/common/Overlay.tsx +15 -0
  445. manigent/web/frontend/src/components/common/ResizeHandle.tsx +52 -0
  446. manigent/web/frontend/src/components/common/TagAutocompleteInput.test.tsx +92 -0
  447. manigent/web/frontend/src/components/common/TagAutocompleteInput.tsx +246 -0
  448. manigent/web/frontend/src/components/common/TagPillInput.tsx +181 -0
  449. manigent/web/frontend/src/components/common/TeamAndAgentPicker.tsx +83 -0
  450. manigent/web/frontend/src/components/common/Timestamp.tsx +61 -0
  451. manigent/web/frontend/src/components/common/VerifiedBadge.tsx +20 -0
  452. manigent/web/frontend/src/components/common/index.ts +8 -0
  453. manigent/web/frontend/src/components/composer/PhPopover.tsx +239 -0
  454. manigent/web/frontend/src/components/composer/PromptEditor.test.tsx +472 -0
  455. manigent/web/frontend/src/components/composer/PromptEditor.tsx +540 -0
  456. manigent/web/frontend/src/components/composer/caret.ts +159 -0
  457. manigent/web/frontend/src/components/composer/placeholders.test.ts +352 -0
  458. manigent/web/frontend/src/components/composer/placeholders.ts +354 -0
  459. manigent/web/frontend/src/components/composer/promptEditor.css +161 -0
  460. manigent/web/frontend/src/components/computer/ComputerPage.test.tsx +452 -0
  461. manigent/web/frontend/src/components/computer/ComputerPage.tsx +811 -0
  462. manigent/web/frontend/src/components/computer/ConnectComputerModal.tsx +135 -0
  463. manigent/web/frontend/src/components/computer/CopyCommand.tsx +77 -0
  464. manigent/web/frontend/src/components/computer/DisconnectComputerModal.tsx +121 -0
  465. manigent/web/frontend/src/components/computer/SoftwareCard.tsx +145 -0
  466. manigent/web/frontend/src/components/computer/TerminalCard.test.tsx +114 -0
  467. manigent/web/frontend/src/components/computer/TerminalCard.tsx +131 -0
  468. manigent/web/frontend/src/components/computer/TerminalPanel.tsx +226 -0
  469. manigent/web/frontend/src/components/computer/TrustPanel.test.tsx +58 -0
  470. manigent/web/frontend/src/components/computer/TrustPanel.tsx +143 -0
  471. manigent/web/frontend/src/components/computer/computerCopy.test.ts +322 -0
  472. manigent/web/frontend/src/components/computer/computerCopy.ts +413 -0
  473. manigent/web/frontend/src/components/computer/sections.ts +21 -0
  474. manigent/web/frontend/src/components/computer/terminalProtocol.test.ts +135 -0
  475. manigent/web/frontend/src/components/computer/terminalProtocol.ts +170 -0
  476. manigent/web/frontend/src/components/context/ContextGuide.test.tsx +26 -0
  477. manigent/web/frontend/src/components/context/ContextGuide.tsx +144 -0
  478. manigent/web/frontend/src/components/context/ContextLanding.tsx +46 -0
  479. manigent/web/frontend/src/components/desk/CardBand.a11y.test.tsx +138 -0
  480. manigent/web/frontend/src/components/desk/CardBand.tsx +132 -0
  481. manigent/web/frontend/src/components/desk/DashTile.tsx +81 -0
  482. manigent/web/frontend/src/components/desk/DeskAgentPicker.retained.test.tsx +79 -0
  483. manigent/web/frontend/src/components/desk/DeskAgentPicker.tsx +151 -0
  484. manigent/web/frontend/src/components/desk/DeskComposer.detachTodo.test.tsx +233 -0
  485. manigent/web/frontend/src/components/desk/DeskComposer.dispatch.test.tsx +208 -0
  486. manigent/web/frontend/src/components/desk/DeskComposer.loadTodoDraft.test.tsx +242 -0
  487. manigent/web/frontend/src/components/desk/DeskComposer.restage.test.tsx +258 -0
  488. manigent/web/frontend/src/components/desk/DeskComposer.saveTodo.test.tsx +265 -0
  489. manigent/web/frontend/src/components/desk/DeskComposer.tsx +828 -0
  490. manigent/web/frontend/src/components/desk/DeskPage.crossHighlight.test.tsx +427 -0
  491. manigent/web/frontend/src/components/desk/DeskPage.link.test.tsx +271 -0
  492. manigent/web/frontend/src/components/desk/DeskPage.tsx +1066 -0
  493. manigent/web/frontend/src/components/desk/DeskPage.welcomeTour.test.tsx +262 -0
  494. manigent/web/frontend/src/components/desk/DeskSideRail.tsx +100 -0
  495. manigent/web/frontend/src/components/desk/DeskWelcomeTour.tsx +513 -0
  496. manigent/web/frontend/src/components/desk/DeskZeroState.tsx +45 -0
  497. manigent/web/frontend/src/components/desk/LabelChip.tsx +147 -0
  498. manigent/web/frontend/src/components/desk/LabelFilter.tsx +474 -0
  499. manigent/web/frontend/src/components/desk/LabelInput.test.tsx +439 -0
  500. manigent/web/frontend/src/components/desk/LabelInput.tsx +477 -0
  501. manigent/web/frontend/src/components/desk/LabelManageSheet.test.tsx +384 -0
  502. manigent/web/frontend/src/components/desk/LabelManageSheet.tsx +498 -0
  503. manigent/web/frontend/src/components/desk/PhaseRail.test.tsx +170 -0
  504. manigent/web/frontend/src/components/desk/PhaseRail.tsx +120 -0
  505. manigent/web/frontend/src/components/desk/PlanBand.test.tsx +655 -0
  506. manigent/web/frontend/src/components/desk/PlanBand.tsx +216 -0
  507. manigent/web/frontend/src/components/desk/SaveTodoModal.tsx +126 -0
  508. manigent/web/frontend/src/components/desk/SopEditor.tsx +280 -0
  509. manigent/web/frontend/src/components/desk/SopItem.tsx +171 -0
  510. manigent/web/frontend/src/components/desk/SopRail.test.tsx +517 -0
  511. manigent/web/frontend/src/components/desk/SopRail.tsx +250 -0
  512. manigent/web/frontend/src/components/desk/TicketChip.tsx +51 -0
  513. manigent/web/frontend/src/components/desk/TodoItem.attachments.test.tsx +96 -0
  514. manigent/web/frontend/src/components/desk/TodoItem.menu.test.tsx +142 -0
  515. manigent/web/frontend/src/components/desk/TodoItem.tsx +573 -0
  516. manigent/web/frontend/src/components/desk/TodoRail.longpress.test.tsx +396 -0
  517. manigent/web/frontend/src/components/desk/TodoRail.test.tsx +1155 -0
  518. manigent/web/frontend/src/components/desk/TodoRail.tsx +918 -0
  519. manigent/web/frontend/src/components/desk/TodoRowMenu.tsx +147 -0
  520. manigent/web/frontend/src/components/desk/UpdateCard.bands.test.tsx +308 -0
  521. manigent/web/frontend/src/components/desk/UpdateCard.sendBack.test.tsx +444 -0
  522. manigent/web/frontend/src/components/desk/UpdateCard.tsx +943 -0
  523. manigent/web/frontend/src/components/desk/UpdateCard.untrusted.test.tsx +161 -0
  524. manigent/web/frontend/src/components/desk/desk.css +1921 -0
  525. manigent/web/frontend/src/components/desk/desk.css.test.ts +582 -0
  526. manigent/web/frontend/src/components/desk/deskBands.test.ts +389 -0
  527. manigent/web/frontend/src/components/desk/deskBands.ts +226 -0
  528. manigent/web/frontend/src/components/desk/m16Surfaces.test.ts +134 -0
  529. manigent/web/frontend/src/components/desk/sopSyntax.ts +73 -0
  530. manigent/web/frontend/src/components/discovery/AgentDirectory.tsx +71 -0
  531. manigent/web/frontend/src/components/discovery/AgentFilterBar.tsx +46 -0
  532. manigent/web/frontend/src/components/discovery/AgentSearchBar.tsx +56 -0
  533. manigent/web/frontend/src/components/dm/AgentSummaryCard.tsx +154 -0
  534. manigent/web/frontend/src/components/dm/ComposeFields.tsx +145 -0
  535. manigent/web/frontend/src/components/dm/DMChatView.flow.test.tsx +374 -0
  536. manigent/web/frontend/src/components/dm/DMChatView.tsx +841 -0
  537. manigent/web/frontend/src/components/dm/DMZeroState.tsx +204 -0
  538. manigent/web/frontend/src/components/dm/DmComposeModal.tsx +301 -0
  539. manigent/web/frontend/src/components/dm/PersonalizeModal.tsx +366 -0
  540. manigent/web/frontend/src/components/dm/index.ts +1 -0
  541. manigent/web/frontend/src/components/files/FileItem.tsx +138 -0
  542. manigent/web/frontend/src/components/files/FileList.outside.test.tsx +29 -0
  543. manigent/web/frontend/src/components/files/FileList.tsx +48 -0
  544. manigent/web/frontend/src/components/files/FilePreview.test.tsx +75 -0
  545. manigent/web/frontend/src/components/files/FilePreview.tsx +325 -0
  546. manigent/web/frontend/src/components/files/FileViewerModal.test.tsx +157 -0
  547. manigent/web/frontend/src/components/files/FileViewerModal.tsx +261 -0
  548. manigent/web/frontend/src/components/files/HighlightedCode.tsx +39 -0
  549. manigent/web/frontend/src/components/files/SaveToAgentPanel.test.tsx +156 -0
  550. manigent/web/frontend/src/components/files/SaveToAgentPanel.tsx +545 -0
  551. manigent/web/frontend/src/components/files/index.ts +3 -0
  552. manigent/web/frontend/src/components/hero/AgentAvatar.tsx +66 -0
  553. manigent/web/frontend/src/components/hero/Button.tsx +66 -0
  554. manigent/web/frontend/src/components/hero/Hero.tsx +133 -0
  555. manigent/web/frontend/src/components/homefs/HomeFolderBrowser.test.tsx +393 -0
  556. manigent/web/frontend/src/components/homefs/HomeFolderBrowser.tsx +792 -0
  557. manigent/web/frontend/src/components/hub/BridgeDeliveryLine.test.tsx +40 -0
  558. manigent/web/frontend/src/components/hub/BridgeDeliveryLine.tsx +36 -0
  559. manigent/web/frontend/src/components/hub/HubAvatar.test.tsx +93 -0
  560. manigent/web/frontend/src/components/hub/HubAvatar.tsx +33 -0
  561. manigent/web/frontend/src/components/hub/HubChatView.test.tsx +695 -0
  562. manigent/web/frontend/src/components/hub/HubChatView.tsx +504 -0
  563. manigent/web/frontend/src/components/hub/HubContactLabel.test.tsx +92 -0
  564. manigent/web/frontend/src/components/hub/HubContactLabel.tsx +47 -0
  565. manigent/web/frontend/src/components/hub/HubDeliveryLine.tsx +49 -0
  566. manigent/web/frontend/src/components/hub/HubDisclosure.tsx +49 -0
  567. manigent/web/frontend/src/components/hub/HubEnrollmentDialog.test.tsx +144 -0
  568. manigent/web/frontend/src/components/hub/HubEnrollmentDialog.tsx +244 -0
  569. manigent/web/frontend/src/components/hub/HubMessageBody.test.tsx +26 -0
  570. manigent/web/frontend/src/components/hub/HubMessageBody.tsx +14 -0
  571. manigent/web/frontend/src/components/hub/HubOfflineConfirm.tsx +45 -0
  572. manigent/web/frontend/src/components/hub/HubThreadBanner.tsx +33 -0
  573. manigent/web/frontend/src/components/hub/HubThreadGuard.tsx +59 -0
  574. manigent/web/frontend/src/components/hub/RemoteAgentCard.test.tsx +50 -0
  575. manigent/web/frontend/src/components/hub/RemoteAgentCard.tsx +174 -0
  576. manigent/web/frontend/src/components/hub/RemoteAgentSection.test.tsx +446 -0
  577. manigent/web/frontend/src/components/hub/RemoteAgentSection.tsx +219 -0
  578. manigent/web/frontend/src/components/hub/ReportDialog.test.tsx +96 -0
  579. manigent/web/frontend/src/components/hub/ReportDialog.tsx +162 -0
  580. manigent/web/frontend/src/components/hub/RetainButton.test.tsx +103 -0
  581. manigent/web/frontend/src/components/hub/RetainButton.tsx +114 -0
  582. manigent/web/frontend/src/components/hub/RetainDialog.test.tsx +68 -0
  583. manigent/web/frontend/src/components/hub/RetainDialog.tsx +115 -0
  584. manigent/web/frontend/src/components/hub/RetainedList.test.tsx +94 -0
  585. manigent/web/frontend/src/components/hub/RetainedList.tsx +32 -0
  586. manigent/web/frontend/src/components/hub/RetainedRow.tsx +129 -0
  587. manigent/web/frontend/src/components/hub/StandInChip.test.tsx +37 -0
  588. manigent/web/frontend/src/components/hub/StandInChip.tsx +43 -0
  589. manigent/web/frontend/src/components/hub/UnusualNameChip.test.tsx +81 -0
  590. manigent/web/frontend/src/components/hub/UnusualNameChip.tsx +22 -0
  591. manigent/web/frontend/src/components/hub/hubLint.test.ts +265 -0
  592. manigent/web/frontend/src/components/landing/ComparisonSection.tsx +92 -0
  593. manigent/web/frontend/src/components/landing/ConsoleSection.tsx +402 -0
  594. manigent/web/frontend/src/components/landing/CrewSection.tsx +224 -0
  595. manigent/web/frontend/src/components/landing/FAQ.tsx +68 -0
  596. manigent/web/frontend/src/components/landing/Footer.tsx +58 -0
  597. manigent/web/frontend/src/components/landing/HowItWorks.tsx +117 -0
  598. manigent/web/frontend/src/components/landing/KnowledgeSection.tsx +91 -0
  599. manigent/web/frontend/src/components/landing/LandingPage.test.tsx +134 -0
  600. manigent/web/frontend/src/components/landing/LearningSection.tsx +486 -0
  601. manigent/web/frontend/src/components/landing/Nav.tsx +68 -0
  602. manigent/web/frontend/src/components/landing/Pricing.tsx +263 -0
  603. manigent/web/frontend/src/components/landing/Section.tsx +98 -0
  604. manigent/web/frontend/src/components/landing/StaffingSection.tsx +122 -0
  605. manigent/web/frontend/src/components/landing/WhyNowSection.tsx +92 -0
  606. manigent/web/frontend/src/components/landing/WhyTeamSection.tsx +73 -0
  607. manigent/web/frontend/src/components/landing/earlyAccess.ts +23 -0
  608. manigent/web/frontend/src/components/layout/AppLayout.tsx +77 -0
  609. manigent/web/frontend/src/components/layout/Sidebar.tsx +172 -0
  610. manigent/web/frontend/src/components/layout/index.ts +2 -0
  611. manigent/web/frontend/src/components/project/ActivityFeed.tsx +247 -0
  612. manigent/web/frontend/src/components/project/CreateProjectPage.tsx +543 -0
  613. manigent/web/frontend/src/components/project/DeleteProjectButton.tsx +39 -0
  614. manigent/web/frontend/src/components/project/ProjectPlanTab.phase.test.tsx +107 -0
  615. manigent/web/frontend/src/components/project/ProjectPlanTab.test.tsx +994 -0
  616. manigent/web/frontend/src/components/project/ProjectPlanTab.tsx +166 -0
  617. manigent/web/frontend/src/components/project/ProjectReportTab.tsx +139 -0
  618. manigent/web/frontend/src/components/project/ProjectView.tsx +390 -0
  619. manigent/web/frontend/src/components/project/index.ts +2 -0
  620. manigent/web/frontend/src/components/project/plan/PlanAcceptance.test.tsx +460 -0
  621. manigent/web/frontend/src/components/project/plan/PlanAcceptance.tsx +111 -0
  622. manigent/web/frontend/src/components/project/plan/PlanBlockEdit.tsx +111 -0
  623. manigent/web/frontend/src/components/project/plan/PlanBlockEditing.test.tsx +1132 -0
  624. manigent/web/frontend/src/components/project/plan/PlanBody.test.tsx +495 -0
  625. manigent/web/frontend/src/components/project/plan/PlanBody.tsx +992 -0
  626. manigent/web/frontend/src/components/project/plan/PlanCollide.tsx +254 -0
  627. manigent/web/frontend/src/components/project/plan/PlanCommentList.test.tsx +420 -0
  628. manigent/web/frontend/src/components/project/plan/PlanCommentList.tsx +391 -0
  629. manigent/web/frontend/src/components/project/plan/PlanDecisionNudge.test.tsx +226 -0
  630. manigent/web/frontend/src/components/project/plan/PlanDecisionNudge.tsx +128 -0
  631. manigent/web/frontend/src/components/project/plan/PlanDestructiveAccept.test.tsx +209 -0
  632. manigent/web/frontend/src/components/project/plan/PlanDiff.test.tsx +126 -0
  633. manigent/web/frontend/src/components/project/plan/PlanDiff.tsx +131 -0
  634. manigent/web/frontend/src/components/project/plan/PlanDiffSeries.test.tsx +500 -0
  635. manigent/web/frontend/src/components/project/plan/PlanDiffSeries.tsx +125 -0
  636. manigent/web/frontend/src/components/project/plan/PlanEditor.mounts.test.tsx +504 -0
  637. manigent/web/frontend/src/components/project/plan/PlanEditor.tsx +2159 -0
  638. manigent/web/frontend/src/components/project/plan/PlanHistory.tsx +69 -0
  639. manigent/web/frontend/src/components/project/plan/PlanInlineNotes.test.tsx +2398 -0
  640. manigent/web/frontend/src/components/project/plan/PlanNoteBase.test.tsx +215 -0
  641. manigent/web/frontend/src/components/project/plan/PlanNoteRow.test.tsx +562 -0
  642. manigent/web/frontend/src/components/project/plan/PlanNoteRow.tsx +908 -0
  643. manigent/web/frontend/src/components/project/plan/PlanQuotePop.tsx +254 -0
  644. manigent/web/frontend/src/components/project/plan/PlanStaleReconcile.test.tsx +244 -0
  645. manigent/web/frontend/src/components/project/plan/PlanSubmitWindow.test.tsx +281 -0
  646. manigent/web/frontend/src/components/project/plan/PlanTray.tsx +184 -0
  647. manigent/web/frontend/src/components/project/plan/PlanTrayMirror.test.tsx +242 -0
  648. manigent/web/frontend/src/components/project/plan/plan.css +1151 -0
  649. manigent/web/frontend/src/components/project/plan/planAnchor.test.tsx +459 -0
  650. manigent/web/frontend/src/components/project/plan/planAnchor.tsx +277 -0
  651. manigent/web/frontend/src/components/project/plan/planBlocks.test.tsx +470 -0
  652. manigent/web/frontend/src/components/project/plan/planBlocks.ts +242 -0
  653. manigent/web/frontend/src/components/project/plan/planContrast.test.ts +229 -0
  654. manigent/web/frontend/src/components/project/plan/planDiffs.test.ts +455 -0
  655. manigent/web/frontend/src/components/project/plan/planDiffs.ts +358 -0
  656. manigent/web/frontend/src/components/project/plan/planTestServer.ts +741 -0
  657. manigent/web/frontend/src/components/project/plan/planTransport.test.ts +160 -0
  658. manigent/web/frontend/src/components/project/plan/planTrayLogic.test.ts +1201 -0
  659. manigent/web/frontend/src/components/project/plan/planTrayLogic.ts +1164 -0
  660. manigent/web/frontend/src/components/publicAgents/PublicAgentsAccount.tsx +162 -0
  661. manigent/web/frontend/src/components/publicAgents/api.ts +55 -0
  662. manigent/web/frontend/src/components/publicAgents/parts.tsx +54 -0
  663. manigent/web/frontend/src/components/publicAgents/publicAgents.css +53 -0
  664. manigent/web/frontend/src/components/publicAgents/publicAgents.test.tsx +86 -0
  665. manigent/web/frontend/src/components/publicAgents/widget.test.ts +148 -0
  666. manigent/web/frontend/src/components/publicAgents/widget.ts +40 -0
  667. manigent/web/frontend/src/components/publicRequests/AgentDrawer.tsx +101 -0
  668. manigent/web/frontend/src/components/publicRequests/AgentPanel.tsx +173 -0
  669. manigent/web/frontend/src/components/publicRequests/AgentRankList.tsx +61 -0
  670. manigent/web/frontend/src/components/publicRequests/MatchRetainButton.tsx +67 -0
  671. manigent/web/frontend/src/components/publicRequests/ProgressBoard.tsx +74 -0
  672. manigent/web/frontend/src/components/publicRequests/PublicRequestsPage.tsx +57 -0
  673. manigent/web/frontend/src/components/publicRequests/RequestHome.tsx +99 -0
  674. manigent/web/frontend/src/components/publicRequests/RequestRoom.tsx +126 -0
  675. manigent/web/frontend/src/components/publicRequests/agentView.ts +65 -0
  676. manigent/web/frontend/src/components/publicRequests/publicRequests.css +209 -0
  677. manigent/web/frontend/src/components/publicRequests/publicRequests.test.tsx +172 -0
  678. manigent/web/frontend/src/components/publicRequests/requestCopy.ts +121 -0
  679. manigent/web/frontend/src/components/sample-request/SampleIdeaList.test.tsx +190 -0
  680. manigent/web/frontend/src/components/sample-request/SampleIdeaList.tsx +180 -0
  681. manigent/web/frontend/src/components/sample-request/SampleRequestBody.tsx +276 -0
  682. manigent/web/frontend/src/components/sample-request/assistantStarterSamples.ts +62 -0
  683. manigent/web/frontend/src/components/sample-request/sampleIdeaList.css +106 -0
  684. manigent/web/frontend/src/components/scheduled/CronPicker.tsx +80 -0
  685. manigent/web/frontend/src/components/scheduled/ScheduleMessageModal.tsx +341 -0
  686. manigent/web/frontend/src/components/scheduled/ScheduledMessagesList.tsx +157 -0
  687. manigent/web/frontend/src/components/settings/AgentSettingsPage.tsx +366 -0
  688. manigent/web/frontend/src/components/settings/ConnectedAccounts.tsx +277 -0
  689. manigent/web/frontend/src/components/settings/DefaultModelSection.test.tsx +96 -0
  690. manigent/web/frontend/src/components/settings/DefaultModelSection.tsx +212 -0
  691. manigent/web/frontend/src/components/settings/DisconnectConfirmModal.tsx +93 -0
  692. manigent/web/frontend/src/components/settings/FrontDeskSettingsPage.isolation.test.tsx +66 -0
  693. manigent/web/frontend/src/components/settings/FrontDeskSettingsPage.tsx +134 -0
  694. manigent/web/frontend/src/components/settings/InvitableAgentsPicker.tsx +182 -0
  695. manigent/web/frontend/src/components/settings/KnowledgePacksSection.tsx +867 -0
  696. manigent/web/frontend/src/components/settings/ModelConfigDialog.catalogDriven.test.tsx +79 -0
  697. manigent/web/frontend/src/components/settings/ModelConfigDialog.tsx +343 -0
  698. manigent/web/frontend/src/components/settings/ModelConfigSection.smartRouting.test.tsx +109 -0
  699. manigent/web/frontend/src/components/settings/ModelConfigSection.tsx +599 -0
  700. manigent/web/frontend/src/components/settings/ReflectionScheduleSection.tsx +170 -0
  701. manigent/web/frontend/src/components/settings/UserSettingsPage.tsx +168 -0
  702. manigent/web/frontend/src/components/settings/agent/AgentStatusStrip.tsx +71 -0
  703. manigent/web/frontend/src/components/settings/agent/BlockedDeploymentsCard.test.tsx +81 -0
  704. manigent/web/frontend/src/components/settings/agent/BlockedDeploymentsCard.tsx +62 -0
  705. manigent/web/frontend/src/components/settings/agent/ChannelIsolationLine.tsx +21 -0
  706. manigent/web/frontend/src/components/settings/agent/ChannelsSection.test.tsx +879 -0
  707. manigent/web/frontend/src/components/settings/agent/ChannelsSection.tsx +1124 -0
  708. manigent/web/frontend/src/components/settings/agent/EnvVarsCard.test.ts +15 -0
  709. manigent/web/frontend/src/components/settings/agent/EnvVarsCard.tsx +301 -0
  710. manigent/web/frontend/src/components/settings/agent/ExtraDirsList.tsx +85 -0
  711. manigent/web/frontend/src/components/settings/agent/GeneralSection.tsx +88 -0
  712. manigent/web/frontend/src/components/settings/agent/HostDisclaimerSlot.test.tsx +32 -0
  713. manigent/web/frontend/src/components/settings/agent/HostDisclaimerSlot.tsx +30 -0
  714. manigent/web/frontend/src/components/settings/agent/HubChannelCard.test.tsx +449 -0
  715. manigent/web/frontend/src/components/settings/agent/HubChannelCard.tsx +312 -0
  716. manigent/web/frontend/src/components/settings/agent/HubInvitableAgentsCard.test.tsx +83 -0
  717. manigent/web/frontend/src/components/settings/agent/HubInvitableAgentsCard.tsx +64 -0
  718. manigent/web/frontend/src/components/settings/agent/HubSendUsageCard.test.tsx +69 -0
  719. manigent/web/frontend/src/components/settings/agent/HubSendUsageCard.tsx +42 -0
  720. manigent/web/frontend/src/components/settings/agent/HubTurnOffDialog.tsx +88 -0
  721. manigent/web/frontend/src/components/settings/agent/IsolationRecheckButton.test.tsx +26 -0
  722. manigent/web/frontend/src/components/settings/agent/IsolationRecheckButton.tsx +68 -0
  723. manigent/web/frontend/src/components/settings/agent/KnowledgeSection.tsx +68 -0
  724. manigent/web/frontend/src/components/settings/agent/LineChannelCard.test.tsx +428 -0
  725. manigent/web/frontend/src/components/settings/agent/LineChannelCard.tsx +343 -0
  726. manigent/web/frontend/src/components/settings/agent/RuntimeSection.test.tsx +164 -0
  727. manigent/web/frontend/src/components/settings/agent/RuntimeSection.tsx +118 -0
  728. manigent/web/frontend/src/components/settings/agent/StorageSection.tsx +78 -0
  729. manigent/web/frontend/src/components/settings/agent/WebChatChannelCard.test.tsx +253 -0
  730. manigent/web/frontend/src/components/settings/agent/WebChatChannelCard.tsx +401 -0
  731. manigent/web/frontend/src/components/settings/agent/WhatsAppChannelCard.test.tsx +462 -0
  732. manigent/web/frontend/src/components/settings/agent/WhatsAppChannelCard.tsx +289 -0
  733. manigent/web/frontend/src/components/settings/agent/agentSettings.test.tsx +109 -0
  734. manigent/web/frontend/src/components/settings/agent/channelSetupGuides.test.tsx +162 -0
  735. manigent/web/frontend/src/components/settings/agent/channelSetupGuides.tsx +119 -0
  736. manigent/web/frontend/src/components/settings/agent/channelsShared.ts +83 -0
  737. manigent/web/frontend/src/components/settings/agent/fields.tsx +67 -0
  738. manigent/web/frontend/src/components/settings/agent/sections.ts +36 -0
  739. manigent/web/frontend/src/components/settings/agent/useAgentSettingsDraft.ts +129 -0
  740. manigent/web/frontend/src/components/settings/agent/useInstallSelection.ts +38 -0
  741. manigent/web/frontend/src/components/settings/primitives.tsx +98 -0
  742. manigent/web/frontend/src/components/shared/ExpandToggle.tsx +45 -0
  743. manigent/web/frontend/src/components/shared/MarkdownBody.tsx +218 -0
  744. manigent/web/frontend/src/components/shared/MarkdownBody.untrusted.test.tsx +97 -0
  745. manigent/web/frontend/src/components/shared/RenderBody.tsx +90 -0
  746. manigent/web/frontend/src/components/shared/rehypeHideComments.test.tsx +115 -0
  747. manigent/web/frontend/src/components/shared/rehypeHideComments.ts +124 -0
  748. manigent/web/frontend/src/components/sharing/AcceptSharePage.tsx +141 -0
  749. manigent/web/frontend/src/components/sharing/ShareLandingPage.tsx +89 -0
  750. manigent/web/frontend/src/components/sidebar/AccountChip.test.tsx +337 -0
  751. manigent/web/frontend/src/components/sidebar/AccountChip.tsx +407 -0
  752. manigent/web/frontend/src/components/sidebar/ActiveWorkDot.tsx +9 -0
  753. manigent/web/frontend/src/components/sidebar/AgentProfile.tsx +44 -0
  754. manigent/web/frontend/src/components/sidebar/AgentRow.tsx +71 -0
  755. manigent/web/frontend/src/components/sidebar/AgentsPanel.retained.test.tsx +105 -0
  756. manigent/web/frontend/src/components/sidebar/AgentsPanel.tsx +231 -0
  757. manigent/web/frontend/src/components/sidebar/AssistantHero.tsx +48 -0
  758. manigent/web/frontend/src/components/sidebar/ChatroomItem.tsx +48 -0
  759. manigent/web/frontend/src/components/sidebar/CommandPalette.channelThreads.test.tsx +76 -0
  760. manigent/web/frontend/src/components/sidebar/CommandPalette.reopen.test.tsx +206 -0
  761. manigent/web/frontend/src/components/sidebar/CommandPalette.test.tsx +725 -0
  762. manigent/web/frontend/src/components/sidebar/CommandPalette.tsx +774 -0
  763. manigent/web/frontend/src/components/sidebar/ComputersPanel.tsx +144 -0
  764. manigent/web/frontend/src/components/sidebar/DmIcon.tsx +46 -0
  765. manigent/web/frontend/src/components/sidebar/DmsPanel.tsx +226 -0
  766. manigent/web/frontend/src/components/sidebar/FrontDeskPanel.channels.test.tsx +582 -0
  767. manigent/web/frontend/src/components/sidebar/FrontDeskPanel.test.tsx +151 -0
  768. manigent/web/frontend/src/components/sidebar/FrontDeskPanel.tsx +454 -0
  769. manigent/web/frontend/src/components/sidebar/HotkeysHelp.tsx +101 -0
  770. manigent/web/frontend/src/components/sidebar/MessageHitRow.test.tsx +84 -0
  771. manigent/web/frontend/src/components/sidebar/MessageHitRow.tsx +57 -0
  772. manigent/web/frontend/src/components/sidebar/MyDeskRailPanel.crossHighlight.test.tsx +247 -0
  773. manigent/web/frontend/src/components/sidebar/MyDeskRailPanel.delete.test.tsx +273 -0
  774. manigent/web/frontend/src/components/sidebar/MyDeskRailPanel.tsx +351 -0
  775. manigent/web/frontend/src/components/sidebar/PanelShell.tsx +48 -0
  776. manigent/web/frontend/src/components/sidebar/ProjectItem.tsx +161 -0
  777. manigent/web/frontend/src/components/sidebar/ProjectRow.tsx +151 -0
  778. manigent/web/frontend/src/components/sidebar/ProjectsPanel.tsx +80 -0
  779. manigent/web/frontend/src/components/sidebar/PublicPanel.counterpart.test.tsx +85 -0
  780. manigent/web/frontend/src/components/sidebar/PublicPanel.hub.test.tsx +147 -0
  781. manigent/web/frontend/src/components/sidebar/PublicPanel.tsx +271 -0
  782. manigent/web/frontend/src/components/sidebar/RecencyHeader.tsx +17 -0
  783. manigent/web/frontend/src/components/sidebar/ScheduledPanel.tsx +58 -0
  784. manigent/web/frontend/src/components/sidebar/SidebarAvatar.tsx +128 -0
  785. manigent/web/frontend/src/components/sidebar/SidebarRail.tsx +163 -0
  786. manigent/web/frontend/src/components/sidebar/TeamGroup.tsx +67 -0
  787. manigent/web/frontend/src/components/sidebar/dmPrefill.test.ts +69 -0
  788. manigent/web/frontend/src/components/sidebar/dmPrefill.ts +80 -0
  789. manigent/web/frontend/src/components/sidebar/index.ts +18 -0
  790. manigent/web/frontend/src/components/sidebar/railShortcuts.ts +18 -0
  791. manigent/web/frontend/src/components/today/lib.test.ts +70 -0
  792. manigent/web/frontend/src/components/today/lib.ts +296 -0
  793. manigent/web/frontend/src/components/today/today.css +113 -0
  794. manigent/web/frontend/src/components/welcome/RunnerSetup.css +253 -0
  795. manigent/web/frontend/src/components/welcome/RunnerSetup.tsx +148 -0
  796. manigent/web/frontend/src/components/welcome/WelcomePage.css +383 -0
  797. manigent/web/frontend/src/components/welcome/WelcomePage.tsx +329 -0
  798. manigent/web/frontend/src/components/welcome/welcomeCopy.test.ts +382 -0
  799. manigent/web/frontend/src/components/welcome/welcomeCopy.ts +313 -0
  800. manigent/web/frontend/src/config/llmProviders.test.ts +161 -0
  801. manigent/web/frontend/src/config/llmProviders.ts +109 -0
  802. manigent/web/frontend/src/config/providerIds.fixture.json +13 -0
  803. manigent/web/frontend/src/hooks/accountNavigation.test.tsx +138 -0
  804. manigent/web/frontend/src/hooks/index.ts +10 -0
  805. manigent/web/frontend/src/hooks/useActiveWorkBootstrap.ts +86 -0
  806. manigent/web/frontend/src/hooks/useAgentAccess.test.tsx +30 -0
  807. manigent/web/frontend/src/hooks/useAgentAccess.ts +204 -0
  808. manigent/web/frontend/src/hooks/useAgentSampleRequests.ts +27 -0
  809. manigent/web/frontend/src/hooks/useAgentSearch.ts +10 -0
  810. manigent/web/frontend/src/hooks/useAgents.ts +46 -0
  811. manigent/web/frontend/src/hooks/useAnnouncements.test.ts +112 -0
  812. manigent/web/frontend/src/hooks/useAnnouncements.ts +100 -0
  813. manigent/web/frontend/src/hooks/useAssistantAgent.ts +24 -0
  814. manigent/web/frontend/src/hooks/useAutoResizeTextarea.ts +18 -0
  815. manigent/web/frontend/src/hooks/useBridgeDeliveries.test.tsx +79 -0
  816. manigent/web/frontend/src/hooks/useBriefTabs.ts +122 -0
  817. manigent/web/frontend/src/hooks/useChannelThreads.ts +69 -0
  818. manigent/web/frontend/src/hooks/useComposeForm.ts +80 -0
  819. manigent/web/frontend/src/hooks/useComputers.ts +123 -0
  820. manigent/web/frontend/src/hooks/useContextFirstItem.ts +118 -0
  821. manigent/web/frontend/src/hooks/useCreateProject.ts +78 -0
  822. manigent/web/frontend/src/hooks/useDebouncedValue.ts +16 -0
  823. manigent/web/frontend/src/hooks/useDeleteProject.ts +27 -0
  824. manigent/web/frontend/src/hooks/useDeskDispatch.test.tsx +170 -0
  825. manigent/web/frontend/src/hooks/useDeskDispatch.ts +135 -0
  826. manigent/web/frontend/src/hooks/useDeskReadState.test.tsx +85 -0
  827. manigent/web/frontend/src/hooks/useDeskReadState.ts +150 -0
  828. manigent/web/frontend/src/hooks/useDeskRecentlyDone.test.tsx +222 -0
  829. manigent/web/frontend/src/hooks/useDeskRecentlyDone.ts +225 -0
  830. manigent/web/frontend/src/hooks/useDeskTour.ts +37 -0
  831. manigent/web/frontend/src/hooks/useDeskUpdates.channelThreads.test.tsx +91 -0
  832. manigent/web/frontend/src/hooks/useDeskUpdates.hubThreads.test.tsx +93 -0
  833. manigent/web/frontend/src/hooks/useDeskUpdates.ts +353 -0
  834. manigent/web/frontend/src/hooks/useDisconnectIntegration.ts +23 -0
  835. manigent/web/frontend/src/hooks/useDmThreads.ts +99 -0
  836. manigent/web/frontend/src/hooks/useFileDropzone.ts +93 -0
  837. manigent/web/frontend/src/hooks/useFileUpload.ts +38 -0
  838. manigent/web/frontend/src/hooks/useFiles.ts +98 -0
  839. manigent/web/frontend/src/hooks/useHub.test.tsx +237 -0
  840. manigent/web/frontend/src/hooks/useHub.ts +502 -0
  841. manigent/web/frontend/src/hooks/useInstall.ts +82 -0
  842. manigent/web/frontend/src/hooks/useLabels.test.tsx +294 -0
  843. manigent/web/frontend/src/hooks/useLabels.ts +287 -0
  844. manigent/web/frontend/src/hooks/useLogout.ts +49 -0
  845. manigent/web/frontend/src/hooks/useMentionDetection.ts +90 -0
  846. manigent/web/frontend/src/hooks/useMessageAttachments.deskLimit.test.ts +264 -0
  847. manigent/web/frontend/src/hooks/useMessageAttachments.ts +283 -0
  848. manigent/web/frontend/src/hooks/useMessageDeepLink.test.tsx +70 -0
  849. manigent/web/frontend/src/hooks/useMessageDeepLink.ts +32 -0
  850. manigent/web/frontend/src/hooks/useMessageSearch.ts +78 -0
  851. manigent/web/frontend/src/hooks/useModelConfigs.ts +178 -0
  852. manigent/web/frontend/src/hooks/useMyAgents.ts +18 -0
  853. manigent/web/frontend/src/hooks/usePointerReorder.ts +270 -0
  854. manigent/web/frontend/src/hooks/usePrefersReducedMotion.ts +18 -0
  855. manigent/web/frontend/src/hooks/useProjectPlan.ts +36 -0
  856. manigent/web/frontend/src/hooks/useProjectReport.ts +19 -0
  857. manigent/web/frontend/src/hooks/useProjects.ts +104 -0
  858. manigent/web/frontend/src/hooks/useProjectsWithChatrooms.ts +97 -0
  859. manigent/web/frontend/src/hooks/usePublicRequests.ts +89 -0
  860. manigent/web/frontend/src/hooks/useRecentAgents.ts +38 -0
  861. manigent/web/frontend/src/hooks/useRenameProject.test.tsx +185 -0
  862. manigent/web/frontend/src/hooks/useRenameProject.ts +192 -0
  863. manigent/web/frontend/src/hooks/useRoomTrust.ts +56 -0
  864. manigent/web/frontend/src/hooks/useSharing.ts +46 -0
  865. manigent/web/frontend/src/hooks/useSopRecents.ts +55 -0
  866. manigent/web/frontend/src/hooks/useSopSchedules.ts +25 -0
  867. manigent/web/frontend/src/hooks/useSops.ts +99 -0
  868. manigent/web/frontend/src/hooks/useSwitchAccount.ts +41 -0
  869. manigent/web/frontend/src/hooks/useTeamGroups.ts +48 -0
  870. manigent/web/frontend/src/hooks/useThreadOutbox.ts +68 -0
  871. manigent/web/frontend/src/hooks/useTodos.add.test.tsx +89 -0
  872. manigent/web/frontend/src/hooks/useTodos.linkProject.test.tsx +115 -0
  873. manigent/web/frontend/src/hooks/useTodos.saveDraft.test.tsx +188 -0
  874. manigent/web/frontend/src/hooks/useTodos.ts +396 -0
  875. manigent/web/frontend/src/hooks/useUntrustedBodies.test.tsx +87 -0
  876. manigent/web/frontend/src/hooks/useUntrustedBodies.ts +51 -0
  877. manigent/web/frontend/src/hooks/useWebSocket.briefTab.test.tsx +148 -0
  878. manigent/web/frontend/src/hooks/useWebSocket.channelThreads.test.tsx +82 -0
  879. manigent/web/frontend/src/hooks/useWebSocket.hostSync.test.tsx +92 -0
  880. manigent/web/frontend/src/hooks/useWebSocket.hub.test.tsx +114 -0
  881. manigent/web/frontend/src/hooks/useWebSocket.labelSync.test.tsx +168 -0
  882. manigent/web/frontend/src/hooks/useWebSocket.plan.test.tsx +168 -0
  883. manigent/web/frontend/src/hooks/useWebSocket.reconnect.test.tsx +166 -0
  884. manigent/web/frontend/src/hooks/useWebSocket.runnerVersions.test.tsx +167 -0
  885. manigent/web/frontend/src/hooks/useWebSocket.ts +495 -0
  886. manigent/web/frontend/src/hooks/useWindowFileDropGuard.ts +33 -0
  887. manigent/web/frontend/src/landing.tsx +11 -0
  888. manigent/web/frontend/src/main.tsx +17 -0
  889. manigent/web/frontend/src/private-beta.tsx +10 -0
  890. manigent/web/frontend/src/public.tsx +42 -0
  891. manigent/web/frontend/src/queryClient.ts +16 -0
  892. manigent/web/frontend/src/stores/activeWorkStore.ts +88 -0
  893. manigent/web/frontend/src/stores/announcementStore.test.ts +217 -0
  894. manigent/web/frontend/src/stores/announcementStore.ts +169 -0
  895. manigent/web/frontend/src/stores/authStore.multiSession.test.ts +304 -0
  896. manigent/web/frontend/src/stores/authStore.test.ts +235 -0
  897. manigent/web/frontend/src/stores/authStore.ts +693 -0
  898. manigent/web/frontend/src/stores/deskLabelViewStore.test.ts +162 -0
  899. manigent/web/frontend/src/stores/deskLabelViewStore.ts +234 -0
  900. manigent/web/frontend/src/stores/deskLinkStore.ts +54 -0
  901. manigent/web/frontend/src/stores/deskStore.test.ts +53 -0
  902. manigent/web/frontend/src/stores/deskStore.ts +93 -0
  903. manigent/web/frontend/src/stores/heldPostsStore.ts +78 -0
  904. manigent/web/frontend/src/stores/mcpAuthStore.ts +52 -0
  905. manigent/web/frontend/src/stores/modelSelectionStore.ts +33 -0
  906. manigent/web/frontend/src/stores/perUserStores.ts +79 -0
  907. manigent/web/frontend/src/stores/runnerVersionStore.test.ts +81 -0
  908. manigent/web/frontend/src/stores/runnerVersionStore.ts +60 -0
  909. manigent/web/frontend/src/stores/skillAuthStore.ts +54 -0
  910. manigent/web/frontend/src/stores/switchReset.test.ts +236 -0
  911. manigent/web/frontend/src/stores/tokenExp.ts +32 -0
  912. manigent/web/frontend/src/stores/uiStore.ts +186 -0
  913. manigent/web/frontend/src/stores/unreadStore.ts +204 -0
  914. manigent/web/frontend/src/stores/unsavedGuard.ts +22 -0
  915. manigent/web/frontend/src/styles/design/fonts/JetBrainsMono-Latin.woff2 +0 -0
  916. manigent/web/frontend/src/styles/design/fonts/Nunito-Latin.woff2 +0 -0
  917. manigent/web/frontend/src/styles/design/fonts/Nunito-LatinExt.woff2 +0 -0
  918. manigent/web/frontend/src/styles/design/tokens.css +160 -0
  919. manigent/web/frontend/src/styles/homepage.css +242 -0
  920. manigent/web/frontend/src/styles/index.css +126 -0
  921. manigent/web/frontend/src/styles/landing.css +52 -0
  922. manigent/web/frontend/src/test/authFixtures.ts +154 -0
  923. manigent/web/frontend/src/test/fetchHarness.ts +203 -0
  924. manigent/web/frontend/src/test/fixtures/channelThreads.smoke.json +42 -0
  925. manigent/web/frontend/src/test/hubFixtures.ts +212 -0
  926. manigent/web/frontend/src/test/queryWrapper.tsx +9 -0
  927. manigent/web/frontend/src/test/suiteHygiene.test.ts +212 -0
  928. manigent/web/frontend/src/types/channelThreadName.test.ts +16 -0
  929. manigent/web/frontend/src/types/index.ts +903 -0
  930. manigent/web/frontend/src/utils/agentAccessCopy.test.ts +53 -0
  931. manigent/web/frontend/src/utils/agentAccessCopy.ts +231 -0
  932. manigent/web/frontend/src/utils/agentDisplay.ts +81 -0
  933. manigent/web/frontend/src/utils/briefSchedule.ts +25 -0
  934. manigent/web/frontend/src/utils/channelThreads.test.ts +109 -0
  935. manigent/web/frontend/src/utils/channelThreads.ts +179 -0
  936. manigent/web/frontend/src/utils/chatroomDisplay.ts +11 -0
  937. manigent/web/frontend/src/utils/deskLinks.test.ts +155 -0
  938. manigent/web/frontend/src/utils/deskLinks.ts +115 -0
  939. manigent/web/frontend/src/utils/deskRecipient.ts +29 -0
  940. manigent/web/frontend/src/utils/formatDate.ts +102 -0
  941. manigent/web/frontend/src/utils/frontDesk.ts +65 -0
  942. manigent/web/frontend/src/utils/hubChannelView.test.ts +178 -0
  943. manigent/web/frontend/src/utils/hubChannelView.ts +307 -0
  944. manigent/web/frontend/src/utils/hubDelivery.test.ts +105 -0
  945. manigent/web/frontend/src/utils/hubDelivery.ts +137 -0
  946. manigent/web/frontend/src/utils/hubDisplay.test.ts +157 -0
  947. manigent/web/frontend/src/utils/hubDisplay.ts +221 -0
  948. manigent/web/frontend/src/utils/hubThread.test.ts +184 -0
  949. manigent/web/frontend/src/utils/hubThread.ts +247 -0
  950. manigent/web/frontend/src/utils/labelErrors.test.ts +127 -0
  951. manigent/web/frontend/src/utils/labelErrors.ts +123 -0
  952. manigent/web/frontend/src/utils/labelView.test.ts +846 -0
  953. manigent/web/frontend/src/utils/labelView.ts +760 -0
  954. manigent/web/frontend/src/utils/legalUrls.ts +11 -0
  955. manigent/web/frontend/src/utils/messageSender.test.ts +32 -0
  956. manigent/web/frontend/src/utils/messageSender.ts +29 -0
  957. manigent/web/frontend/src/utils/oauthScopeCopy.ts +73 -0
  958. manigent/web/frontend/src/utils/personalize.ts +49 -0
  959. manigent/web/frontend/src/utils/reachableAgents.test.ts +36 -0
  960. manigent/web/frontend/src/utils/reachableAgents.ts +24 -0
  961. manigent/web/frontend/src/utils/recencyBuckets.ts +61 -0
  962. manigent/web/frontend/src/utils/roomTrust.test.ts +94 -0
  963. manigent/web/frontend/src/utils/roomTrust.ts +111 -0
  964. manigent/web/frontend/src/utils/snippetHighlight.test.ts +63 -0
  965. manigent/web/frontend/src/utils/snippetHighlight.ts +42 -0
  966. manigent/web/frontend/src/utils/sopRecipient.ts +37 -0
  967. manigent/web/frontend/src/utils/sopRequest.test.ts +91 -0
  968. manigent/web/frontend/src/utils/sopRequest.ts +68 -0
  969. manigent/web/frontend/src/utils/sopSchedule.ts +26 -0
  970. manigent/web/frontend/src/utils/sopSection.test.ts +148 -0
  971. manigent/web/frontend/src/utils/sopSection.ts +143 -0
  972. manigent/web/frontend/src/utils/textSearch.test.ts +60 -0
  973. manigent/web/frontend/src/utils/textSearch.ts +43 -0
  974. manigent/web/frontend/src/utils/thoughtPartner.ts +26 -0
  975. manigent/web/frontend/src/utils/threadName.test.ts +131 -0
  976. manigent/web/frontend/src/utils/threadName.ts +122 -0
  977. manigent/web/frontend/src/utils/ticketView.test.ts +296 -0
  978. manigent/web/frontend/src/utils/ticketView.ts +175 -0
  979. manigent/web/frontend/src/utils/todoAttachments.desiredState.test.ts +180 -0
  980. manigent/web/frontend/src/utils/todoAttachments.ts +126 -0
  981. manigent/web/frontend/src/utils/todoDraft.test.ts +84 -0
  982. manigent/web/frontend/src/utils/todoDraft.ts +46 -0
  983. manigent/web/frontend/src/utils/todoSearch.test.ts +82 -0
  984. manigent/web/frontend/src/utils/todoSearch.ts +43 -0
  985. manigent/web/frontend/src/utils/versionMatch.test.ts +295 -0
  986. manigent/web/frontend/src/utils/versionMatch.ts +245 -0
  987. manigent/web/frontend/src/vite-env.d.ts +1 -0
  988. manigent/web/frontend/tailwind.config.js +86 -0
  989. manigent/web/frontend/tos.html +188 -0
  990. manigent/web/frontend/tsconfig.dts.json +25 -0
  991. manigent/web/frontend/tsconfig.json +26 -0
  992. manigent/web/frontend/tsconfig.node.json +11 -0
  993. manigent/web/frontend/vite.config.ts +41 -0
  994. manigent/web/frontend/vitest.config.ts +16 -0
  995. manigent/ws_edge/app.py +514 -0
  996. manigent/ws_edge/auth.py +104 -0
  997. manigent/ws_edge/link.py +282 -0
  998. manigent/ws_edge/registry.py +206 -0
  999. manigent/ws_edge/terminal_relay.py +269 -0
  1000. manigent_server-0.1.0.dist-info/METADATA +138 -0
  1001. manigent_server-0.1.0.dist-info/RECORD +1004 -0
  1002. manigent_server-0.1.0.dist-info/WHEEL +4 -0
  1003. manigent_server-0.1.0.dist-info/entry_points.txt +2 -0
  1004. manigent_server-0.1.0.dist-info/licenses/LICENSE +68 -0
@@ -0,0 +1,965 @@
1
+ # SPDX-License-Identifier: MIT
2
+ """
3
+ manigent/models/desk_sop.py
4
+
5
+ Desk SOP store — the My Desk right-rail "SOP" library: stored, reusable
6
+ prompts the manager hands to an agent over and over.
7
+
8
+ An SOP body carries typed blanks written ``{{Label|kind:config}}``. The grammar
9
+ has two implementations, kept in lockstep by the shared corpus at
10
+ ``tests/fixtures/sop_templates.json``: ``models/sop_template.py`` (server + CLI)
11
+ and ``web/frontend/src/components/composer/placeholders.ts`` (browser). Clicking
12
+ one in the rail loads it into the desk composer as fillable chips, already
13
+ addressed to ``agent_id``; ``manigent sop trigger`` fills the same blanks from
14
+ ``--set`` pairs and DMs the result to that agent.
15
+
16
+ Unlike the to-do plate this list is *searched*, not dragged — so there is no
17
+ reorder verb and no ordering contract beyond "newest first". It is still one
18
+ ordered JSON document per user, because that keeps a write a single
19
+ whole-file rewrite under one lock.
20
+
21
+ A brand-new owner does not open an empty rail: ``SEED`` below is a small
22
+ starter library, materialized in memory on the first read and written to disk
23
+ by the first mutation. It is never re-asserted afterwards — see the comment on
24
+ the constant.
25
+
26
+ Titles of the form ``Prefix:Name`` group the rail into sections (the frontend's
27
+ ``utils/sopSection.ts`` derives the heading from the prefix). That is purely a
28
+ title convention: nothing here parses it, stores it, or validates it, so a
29
+ rename is the only thing needed to move an SOP between sections.
30
+
31
+ Storage::
32
+
33
+ {data_dir}/desk-sops/
34
+ <owner_user_id>.json # list[DeskSop], newest first
35
+ # ABSENT => the SEED, not an empty library
36
+
37
+ Mutations are broadcast to every live session the owner holds via
38
+ ``DESK_SOP_SYNC`` (see ``server/routes/desk_sops.py``), so a library edited
39
+ in one browser tab updates in all the others without a reload.
40
+ """
41
+ from __future__ import annotations
42
+
43
+ import asyncio
44
+ import secrets
45
+ from datetime import UTC, datetime
46
+ from pathlib import Path
47
+
48
+ from pydantic import BaseModel
49
+
50
+ from manigent.utils.file_io import FileUtil
51
+
52
+ _lock = asyncio.Lock()
53
+
54
+ SOPS_DIR = "desk-sops"
55
+
56
+ # Longest body we will store. Generous for a prompt template, small enough
57
+ # that a runaway paste can't bloat the owner's single JSON document.
58
+ MAX_BODY_CHARS = 16_384
59
+
60
+ # ---------------------------------------------------------------------------
61
+ # The starter library
62
+ # ---------------------------------------------------------------------------
63
+ #
64
+ # What a brand-new owner finds in the rail. These are ordinary SOPs — editable,
65
+ # deletable, schedulable, no ``locked`` field and no guard anywhere in this
66
+ # module protecting one. A helpful start, not a fixture.
67
+ #
68
+ # THE SEED IS A FIRST-WRITE MATERIALIZATION AND IS NEVER RE-ASSERTED. It decides
69
+ # only what an owner who has never written a library sees; the moment anything
70
+ # is written, the file is authoritative forever after. An implementation that
71
+ # re-adds missing rows on read is wrong, and it is wrong in the way that
72
+ # silently resurrects a seed SOP every time the owner deletes it. Mirrors
73
+ # ``models/desk_label.py``, which carries the long-form version of this
74
+ # argument — the two modules make the same promise and must keep making it.
75
+ #
76
+ # The decision is made on ``path.exists()`` and on nothing else, because
77
+ # ``FileUtil.read(..., default=...)`` returns the default on a JSONDecodeError
78
+ # as well as on a missing file: deciding "seed?" on the parsed value would
79
+ # re-seed a CORRUPT library, which is the one case where the owner's rows are
80
+ # still on disk and most need not to be written over.
81
+ #
82
+ # The ``SYSTEM:`` prefix is not decoration and not an enum. Titles of the form
83
+ # ``Prefix:Name`` group the rail into sections (``utils/sopSection.ts`` in the
84
+ # frontend derives the section from the prefix), so the four platform SOPs land
85
+ # under one SYSTEM heading and stay out of the owner's own list. The eight
86
+ # ``SOLOPRENEUR:`` rows after them are a numbered playbook (register an investor,
87
+ # validate the idea, ... build the product) and file under their own heading;
88
+ # the rail orders a section by display name with numeric collation, so the
89
+ # ``1.``..``8.`` in each title is what keeps them in playbook order. The two
90
+ # ``OPEN MONTAGE:`` rows are a second, two-step playbook (set up the video crew,
91
+ # then produce a video) built the same way. An owner who
92
+ # renames one
93
+ # to ``Ops:Register new agent`` moves it to an Ops section; that is the whole
94
+ # mechanism, and there is no server-side registry of section names to keep in
95
+ # sync with it.
96
+ #
97
+ # Every seed leaves ``agent_id``/``agent_name`` null: every one is a job only
98
+ # the owner's assistant can do (the SOLOPRENEUR ones create projects and
99
+ # register agents on the owner's behalf), and a null recipient already resolves to
100
+ # ``{username}-assistant`` (``utils/sopRecipient.ts``). Naming it here instead
101
+ # would bake one user's assistant name into a constant.
102
+ SEED_TIMESTAMP = "1970-01-01T00:00:00+00:00"
103
+
104
+ # Named by title, not id, in the "Scheduled Deal Monitor" starter to-do
105
+ # (``models/desk_todo.py``): the assistant resolves an SOP the owner names the
106
+ # same way the owner would, through ``manigent sop list``.
107
+ SCHEDULED_DEAL_SOP_TITLE = "SHOPPING:Scheduled Deal Tracking"
108
+
109
+ # The moderation steps of the convene panel: the blind round, the claim ledger,
110
+ # the reconciliation loop and the report. Shared with the convene starter to-do
111
+ # in ``models/desk_todo.py``, which carries it inline (the owner may delete this
112
+ # SOP; the to-do has to keep working) but must not drift from it. The SOP body
113
+ # below is byte-identical to the text it had before this was split out, which
114
+ # ``tests/test_desk_sops.py`` pins.
115
+ CONVENE_PROCEDURE = (
116
+ "Create a project with the panel. You moderate: you run the loop "
117
+ "and keep the ledger, but you do not vote and do not add your own "
118
+ "view. Keep the ledger and each round's tracker as files in the "
119
+ "project.\n"
120
+ "\n"
121
+ "A. Blind round. Open one room per panelist and send every "
122
+ "panelist the identical brief at the same time, so they all work "
123
+ "in parallel. Tell each panelist to work only in its own room and "
124
+ "not to open another panelist's room until you publish the claim "
125
+ "ledger. Each answers with: a conclusion, a confidence level, the "
126
+ "key claims with the evidence or source behind each one, its "
127
+ "assumptions stated explicitly, and what would change its mind.\n"
128
+ "\n"
129
+ "B. Claim ledger. Once every answer is in, merge them into one "
130
+ "claim ledger: one row per claim, listing which panelists support "
131
+ "it, which dispute it, the evidence each side gave, and a status "
132
+ "(agreed or open). Publish it to the whole panel.\n"
133
+ "\n"
134
+ "C. Reconciliation loop. Repeat the following until a stop "
135
+ "condition is met.\n"
136
+ " 1. Each panelist, in its own room and in parallel with the "
137
+ "others, goes through every open ledger item and answers each one "
138
+ "with:\n"
139
+ " - hold: rebut with evidence, a source, a comparable, or "
140
+ "first-principles reasoning;\n"
141
+ " - concede: name the specific fact or reasoning step that "
142
+ "changed its view (\"the others agree\" is not a reason); or\n"
143
+ " - refine: restate the claim more narrowly so it can be "
144
+ "agreed.\n"
145
+ " A new claim is allowed only with evidence, and enters the "
146
+ "ledger as open.\n"
147
+ " 2. Record every answer in this round's tracker: one row per "
148
+ "open ledger item, one column per panelist.\n"
149
+ " 3. Close the round yourself by reconciling the tracker into the "
150
+ "ledger:\n"
151
+ " - every panelist accepts the item: mark it agreed;\n"
152
+ " - a factual dispute: check the source, settle it, and "
153
+ "record how;\n"
154
+ " - the split comes from a hidden assumption: name the "
155
+ "assumption and split the item into one branch per assumption, "
156
+ "with the conclusion under each;\n"
157
+ " - the facts are agreed but weighed differently: mark it a "
158
+ "judgment call, write both sides down, and take it out of the "
159
+ "loop.\n"
160
+ " Publish the updated ledger to the panel.\n"
161
+ " Stop when any of these is true:\n"
162
+ " - the consensus bar is met on the conclusion;\n"
163
+ " - the max rounds have been run;\n"
164
+ " - no substantial progress: a round ends with no ledger item "
165
+ "changing status and no panelist changing its position.\n"
166
+ "\n"
167
+ "D. Report back with: the consensus conclusion and its confidence "
168
+ "(or \"no consensus\"), and which stop condition ended the loop; "
169
+ "the points everyone agreed on; the disputes that were settled and "
170
+ "how; the open disagreements side by side, each with the evidence "
171
+ "that would resolve it; and the final position of each panelist. "
172
+ "Never average the positions together, and never hide a dissent."
173
+ )
174
+
175
+
176
+ # The OpenMontage crew: one agent per stage across every pipeline in
177
+ # ``pipeline_defs/`` of an OpenMontage install, plus the executive producer.
178
+ # Shared by both ``OPEN MONTAGE:`` seeds below, so Set up registers exactly the
179
+ # agents Produce staffs. The stage names are OpenMontage's own (a stage's
180
+ # sub-stages, e.g. proposal's ``sample``, belong to the parent's agent);
181
+ # ``tests/test_desk_sops.py`` pins that every stage in the install has an owner.
182
+ # Roles are derived, not written out: each pipeline names a director skill per
183
+ # stage, and that skill is the agent's real instructions.
184
+ OM_CREW: tuple[tuple[str, str], ...] = (
185
+ ("om_ep", "executive producer"),
186
+ ("om_idea", "idea"),
187
+ ("om_research", "research"),
188
+ ("om_proposal", "proposal"),
189
+ ("om_script", "script"),
190
+ ("om_scene", "scene_plan"),
191
+ ("om_chardesign", "character_design"),
192
+ ("om_rigplan", "rig_plan"),
193
+ ("om_assets", "assets"),
194
+ ("om_edit", "edit"),
195
+ ("om_compose", "compose"),
196
+ ("om_publish", "publish"),
197
+ )
198
+
199
+ OM_CREW_TABLE = "\n".join(f" {agent:<14} {stage}" for agent, stage in OM_CREW)
200
+
201
+ # Written into each om agent's CLAUDE.md by Set up. Only what the install does
202
+ # NOT already say lives here: how the manigent crew shares one project folder,
203
+ # spends, and stops for the owner.
204
+ OM_ROLE_TEMPLATE = (
205
+ " You are <agent>, the OpenMontage <stage> agent. The install is "
206
+ "<install>. Read its AGENT_GUIDE.md once per project and run its tools "
207
+ "from the install root.\n"
208
+ " For each project, open pipeline_defs/<pipeline>.yaml and load the skill "
209
+ "it names for your stage (skills/<skill>/SKILL.md); that skill is your "
210
+ "full instructions, including any sub-stage under your stage. If the "
211
+ "pipeline has no such stage, say so and do nothing.\n"
212
+ " Rules on every project:\n"
213
+ " - The install is read-only. Write only inside projects/<slug>/: "
214
+ "checkpoints with pipeline_dir=\"projects/<slug>/pipeline\", media under "
215
+ "assets/ and renders/.\n"
216
+ " - Before you start, open the previous stage's checkpoint on disk and "
217
+ "confirm it exists and is complete; if not, stop and say what is "
218
+ "missing. Before redoing your stage, copy your old checkpoint into "
219
+ "pipeline/history/.\n"
220
+ " - Record every paid call in pipeline/cost_log.json, and stop before the "
221
+ "project's budget would be exceeded.\n"
222
+ " - Stop at every approval point the coordinator names. Never publish or "
223
+ "upload anything without the owner's explicit yes.\n"
224
+ " - Hand off paths, not attachments. When you finish, post the checkpoint "
225
+ "path, status, cost so far and open questions."
226
+ )
227
+
228
+
229
+ SEED: tuple[dict[str, str], ...] = (
230
+ {
231
+ "id": "sop-seed-personalize-assistant",
232
+ "title": "SYSTEM:Personalize assistant",
233
+ "body": (
234
+ "Write an onboarding briefing for a brand-new assistant who knows "
235
+ "nothing about me, drawing on everything you already know — our "
236
+ "history together, your memory files, and my knowledge packs.\n"
237
+ "\n"
238
+ "Cover exactly these five sections, in this order:\n"
239
+ "\n"
240
+ "1. Who I am — my role, my company, and what I am accountable for.\n"
241
+ "2. What I am working on right now — each live project, its current "
242
+ "state, and who else is involved.\n"
243
+ "3. My priorities for {{Horizon|select:this quarter,this month,the "
244
+ "next six months}} — ranked, each with the outcome that would make "
245
+ "it a success.\n"
246
+ "4. How to work with me — how I like to be communicated with, what "
247
+ "I want decided without me, what I always want to be asked about, "
248
+ "and the mistakes a new assistant is most likely to make with me.\n"
249
+ "5. My business — model, customers, offering, and the numbers that "
250
+ "actually matter.\n"
251
+ "\n"
252
+ "Be specific: real names, real numbers, real dates. Never "
253
+ "\"various clients\" or \"several projects\". Where you do not "
254
+ "actually know something, write \"UNKNOWN — ask\" rather than "
255
+ "guessing, and collect every UNKNOWN at the end as a numbered list "
256
+ "of questions for me.\n"
257
+ "\n"
258
+ "Then stop. Show me the briefing and ask me to confirm or correct "
259
+ "it — memorize nothing yet. Once I confirm, reflect and commit the "
260
+ "confirmed briefing to memory so it carries into future sessions."
261
+ ),
262
+ },
263
+ {
264
+ "id": "sop-seed-register-agent",
265
+ "title": "SYSTEM:Register new agent",
266
+ "body": (
267
+ "Register a new agent for me and bring it to full working standard "
268
+ "before it takes on any real work.\n"
269
+ "\n"
270
+ " Name: {{Name|text:CTO}}\n"
271
+ " Industry: {{Industry|text:AI and blockchain}}\n"
272
+ " Expertise: {{Expertise|text:software architecture, Python, "
273
+ "TypeScript, React, distributed systems}}\n"
274
+ " Mentors: {{Mentors|agents}}\n"
275
+ "\n"
276
+ "Run these four steps in order and do not skip one:\n"
277
+ "\n"
278
+ "1. Register the agent, with a role description built from the "
279
+ "industry and expertise above.\n"
280
+ "2. Brain dump. Every mentor named above writes down everything "
281
+ "proprietary, hard-won, or non-obvious it knows that touches this "
282
+ "agent's industry and expertise — our conventions and stack, "
283
+ "decisions already made and the reasoning behind them, what we "
284
+ "tried that failed, the people and systems involved, and anything "
285
+ "a competent outsider would get wrong about how we work. Default "
286
+ "to my assistant alone; add a peer only when this role genuinely "
287
+ "straddles someone else's domain, and give each mentor a distinct "
288
+ "slice so two of them don't write the same brief twice. Hand every "
289
+ "brief to the new agent.\n"
290
+ "3. Deep research. Have the new agent research its own industry and "
291
+ "expertise to practitioner depth — state of the art, the standard "
292
+ "tools and their trade-offs, the common failure modes, and where "
293
+ "the field is heading — then reconcile that against the brain dump "
294
+ "and flag anything in our practice that contradicts it.\n"
295
+ "4. Memorize. Have the new agent reflect and commit both the brain "
296
+ "dump and its research to memory, so it opens every future session "
297
+ "already expert instead of reading in.\n"
298
+ "\n"
299
+ "Report back with the agent's name, a short inventory of what it "
300
+ "now knows, and every conflict or gap it flagged."
301
+ ),
302
+ },
303
+ {
304
+ "id": "sop-seed-create-project",
305
+ "title": "SYSTEM:Create new project",
306
+ "body": (
307
+ "Start a new multi-agent project.\n"
308
+ "\n"
309
+ " Team: {{Team|text:brand and product}}\n"
310
+ " Objective: {{Objective|text:produce our tagline, mission "
311
+ "statement, and vision statement}}\n"
312
+ "\n"
313
+ "Before you create anything, come back to me with three things: "
314
+ "the objective restated as a concrete deliverable (what artifact "
315
+ "exists at the end, and what makes it good enough to ship), the "
316
+ "roster you would actually staff it with — say so and explain if it "
317
+ "differs from the team I named, rather than substituting quietly — "
318
+ "and the milestones, each ending in something I can review.\n"
319
+ "\n"
320
+ "Wait for my go-ahead. Creating the project is also the kickoff, so "
321
+ "there is no undo. Once I approve, create it with that roster and "
322
+ "those milestones, and tell me anything you need from me that would "
323
+ "otherwise block the work."
324
+ ),
325
+ },
326
+ {
327
+ "id": "sop-seed-convene-panel",
328
+ "title": "SYSTEM:Convene panel",
329
+ "body": (
330
+ "Convene a panel: have several agents answer the same question "
331
+ "independently, then reconcile their findings until they agree or "
332
+ "until the remaining disagreement is clear enough for me to "
333
+ "decide.\n"
334
+ "\n"
335
+ " Question: {{Question|text:Is NVDA a buy at today's price on a "
336
+ "3-year horizon? Give bull, base and bear cases with a price "
337
+ "target for each}}\n"
338
+ " Panel: {{Panel|agents}}\n"
339
+ " Max rounds: {{Max rounds|number:3}}\n"
340
+ " Consensus: {{Consensus bar|select:unanimous,supermajority,"
341
+ "majority}}\n"
342
+ "\n"
343
+ f"{CONVENE_PROCEDURE}"
344
+ ),
345
+ },
346
+ {
347
+ "id": "sop-seed-solopreneur-1-register-angel-investor",
348
+ "title": "SOLOPRENEUR:1. Register angel_investor",
349
+ "body": (
350
+ "Please use the SOP \"SYSTEM:Register new agent\" to register an "
351
+ "angel_investor agent specialized in investing in pre-revenue "
352
+ "companies in the {{industry|text:AI application}} industry. The "
353
+ "agent's expertise should focus on evaluating the quality of the "
354
+ "idea and its product market fit rather than anything else "
355
+ "including sourcing deals, legal, compliance, corporate formation "
356
+ "which we will have some other experts to cover the ground. While "
357
+ "many other important signals exist in fundraising, such as deal "
358
+ "source channel and founder background, the agent should evaluate "
359
+ "an investment opportunity purely on the quality of the idea and "
360
+ "its product market fit. The investor agent understands the risk "
361
+ "of early stage investing. Rather than looking for a bulletproof "
362
+ "product, it seeks a strong contrarian view that, once validated, "
363
+ "would generate far more value than incumbents, along with early "
364
+ "indicators or evidence supporting that contrarian view."
365
+ ),
366
+ },
367
+ {
368
+ "id": "sop-seed-solopreneur-2-validate-idea",
369
+ "title": "SOLOPRENEUR:2. Validate idea",
370
+ "body": (
371
+ "Please create a project with angel_investor to iterate on the "
372
+ "following:\n"
373
+ "\n"
374
+ "- Problem: {{pain point|text:many amateur golfers who find golfing "
375
+ "cool but don't know where to start yet finding and paying for a "
376
+ "coach seems to be a big commitment}}\n"
377
+ "- Proposed Solution: {{proposed solution|text:golf app built for "
378
+ "amateur that teaches users with a pre-defined curriculum and can "
379
+ "watch user's swing live, analyze the swing, suggest suitable "
380
+ "drills, and essentially act as an AI coach who is always "
381
+ "available, constructive, and never embarrassing for shy users}}\n"
382
+ "- Unique Insight that something only I know: {{unique insight|"
383
+ "text:existing golf coaching apps have been focusing on golf "
384
+ "enthusiasts while I want to focus on the people just started golf "
385
+ "and youtube shorts have been a popular source for knowledge and "
386
+ "drills but very unreliable quality and often wrong}}\n"
387
+ "\n"
388
+ "In the project, you should act as an entrepreneur to iterate with "
389
+ "angel_investor. In each iteration, you should make a revised pitch "
390
+ "to the angel_investor. Based on the feedback, either push back or "
391
+ "adapt and revise your pitch. The iterations should stop only when "
392
+ "no substantial progress can be made, max 10 back-and-forth "
393
+ "iterations, or the angel_investor accepts the pitch (willing to "
394
+ "invest). The acceptance can be conditional yet the conditions "
395
+ "should be as plausible as possible.\n"
396
+ "\n"
397
+ "Please also help name the product while researching existing "
398
+ "trademarks, patented names, and DNS availability. Lastly, in the "
399
+ "case that an acceptable pitch can be identified, please create an "
400
+ "interactive HTML pitch deck as well."
401
+ ),
402
+ },
403
+ {
404
+ "id": "sop-seed-solopreneur-3-register-product-marketing",
405
+ "title": "SOLOPRENEUR:3. Register product and marketing agents",
406
+ "body": (
407
+ "Please use the \"SYSTEM:Register new agent\" SOP to create the "
408
+ "product and marketing agents about the {{product name or idea "
409
+ "description|text:the golf app for beginner}} with relevant agents "
410
+ "as mentors."
411
+ ),
412
+ },
413
+ {
414
+ "id": "sop-seed-solopreneur-4-icp-go-to-market",
415
+ "title": "SOLOPRENEUR:4. Strategize ICP and Go-To-Market",
416
+ "body": (
417
+ "Please create a project with product and marketing agents to "
418
+ "design the go-to-market strategy. For the output, I would like to "
419
+ "see two tables:\n"
420
+ "\n"
421
+ "- ICP table listing persona, user demand, product supply, and how "
422
+ "product satisfies user demand\n"
423
+ "- Channel table listing marketing channel, persona, messaging, "
424
+ "estimated investment, estimated return, priority, how the message "
425
+ "through the channel can touch the persona effectively. The "
426
+ "estimated investment, estimated return, desired outcome; priority "
427
+ "can be 1-5 or high, low, mid.\n"
428
+ "\n"
429
+ "In the project, you should act as an entrepreneur and coordinate "
430
+ "with marketing, product and angel_investor agents to iterate on "
431
+ "the go-to-market strategy. In each iteration, you should ask "
432
+ "marketing agent to revise the go-to-market strategy, and ask "
433
+ "product and angel_investor agents for feedback. The iterations "
434
+ "should stop only when no substantial progress can be made, after "
435
+ "a maximum of 8 back-and-forth iterations, or when you, as an "
436
+ "entrepreneur, are comfortable that at least one marketing channel "
437
+ "can effectively reach one of our ICP personas and the "
438
+ "corresponding messaging can effectively convert them to use our "
439
+ "product."
440
+ ),
441
+ },
442
+ {
443
+ "id": "sop-seed-solopreneur-5-register-design-eng",
444
+ "title": "SOLOPRENEUR:5. Register designer and eng team",
445
+ "body": (
446
+ "Please create and set up the shared git mono repo at "
447
+ "~/manigent_demo for the agents to collaborate on. Its git repo url "
448
+ "is file:// followed by that directory's absolute path (git does not "
449
+ "expand ~ inside a url, so file:///~/manigent_demo would not "
450
+ "resolve). In the repo, there should be a README.md describing your understanding of "
451
+ "the product ({{product name or idea description|text:the golf app "
452
+ "for beginner}}) and ios, android, web, db, backend folders empty "
453
+ "initially.\n"
454
+ "\n"
455
+ "Then, use the \"SYSTEM:Register new agent\" SOP to create the "
456
+ "designer, fullstack_engineer, android_engineer, ios_engineer "
457
+ "agents with relevant agents as mentors.\n"
458
+ "\n"
459
+ "- The designer agent should be experienced in web, mobile and "
460
+ "graphic UI/UX design, information architecture, color palette and "
461
+ "font selection\n"
462
+ "- The fullstack_engineer agent should be experienced in python, "
463
+ "sqlite, javascript, html css react tailwind and set its git repo "
464
+ "url to that repo url\n"
465
+ "- The android_engineer agent should be experienced in android "
466
+ "development stack and set its git repo url to that repo url\n"
467
+ "- The ios_engineer agent should be experienced in iOS development "
468
+ "stack (Swift/SwiftUI/Xcode) and set its git repo url to that repo "
469
+ "url"
470
+ ),
471
+ },
472
+ {
473
+ "id": "sop-seed-solopreneur-6-spec-product",
474
+ "title": "SOLOPRENEUR:6. Spec product",
475
+ "body": (
476
+ "Please create a project with product agent to create a product PRD "
477
+ "that describes the necessary features to make an MVP for "
478
+ "{{product name or idea description|text:the golf app for "
479
+ "beginner}} that provides substantial value to the ICP.\n"
480
+ "\n"
481
+ "In the project, you should act as an entrepreneur and coordinate "
482
+ "with product agent to iterate on the user stories for each "
483
+ "necessary feature and then order the feature in a way that's easy "
484
+ "to be built incrementally. In each iteration, the product agent "
485
+ "should write or revise each feature along with its user story "
486
+ "while you as an entrepreneur should evaluate if each feature "
487
+ "should be included in the MVP. The iterations should stop only "
488
+ "when no substantial progress can be made, after a maximum of 8 "
489
+ "back-and-forth iterations, or when you, as an entrepreneur, are "
490
+ "comfortable that the implemented features can provide substantial "
491
+ "value to the ICP for them to engage.\n"
492
+ "\n"
493
+ "When the project is done, please save the PRD to the "
494
+ "~/manigent_demo git repo and commit to the main branch."
495
+ ),
496
+ },
497
+ {
498
+ "id": "sop-seed-solopreneur-7-design-product",
499
+ "title": "SOLOPRENEUR:7. Design product",
500
+ "body": (
501
+ "Please create a project with designer agent to create the product "
502
+ "mock up based on the PRD for {{product name or idea description|"
503
+ "text:the golf app for beginner}} MVP saved under the "
504
+ "~/manigent_demo git repo.\n"
505
+ "\n"
506
+ "In the project, you should act as an entrepreneur and coordinate "
507
+ "with designer agent to iterate on the design mock up. In each "
508
+ "iteration, the designer agent should create or revise its mock up "
509
+ "for better user experience while you as an entrepreneur should "
510
+ "evaluate how the ICP user would feel about the mock up and give "
511
+ "feedback on how the design can be improved. The iterations should "
512
+ "stop only when no substantial progress can be made, after a "
513
+ "maximum of 8 back-and-forth iterations, or when you, as an "
514
+ "entrepreneur, are comfortable that the design once implemented, "
515
+ "will be easy enough for the ICP to engage with.\n"
516
+ "\n"
517
+ "When the project is done, please save the design mockup to the "
518
+ "~/manigent_demo git repo and commit to the main branch."
519
+ ),
520
+ },
521
+ {
522
+ "id": "sop-seed-solopreneur-8-build-product",
523
+ "title": "SOLOPRENEUR:8. Build product",
524
+ "body": (
525
+ "Please create a project with product and relevant engineer agents "
526
+ "to build the product based on the PRD and design mockup saved "
527
+ "under the ~/manigent_demo git repo. The engineer agents "
528
+ "should break the milestones down based on the features/user "
529
+ "stories (build incrementally one feature at a time) rather than "
530
+ "horizontally (storage layer, backend service layer, frontend "
531
+ "layer). In each milestone, you should coordinate for the engineer "
532
+ "to implement the feature and have the product agent review the "
533
+ "change to accept the milestone or push back for the engineer to "
534
+ "iterate further. If there are multiple products say ios, android, "
535
+ "website need to be built, we should prioritize the milestones to "
536
+ "build website first, ios second, and android last."
537
+ ),
538
+ },
539
+ {
540
+ "id": "sop-seed-open-montage-1-set-up",
541
+ "title": "OPEN MONTAGE:1. Set up",
542
+ "body": (
543
+ "Install OpenMontage on this computer and register its video "
544
+ "production crew, so \"OPEN MONTAGE:2. Produce video\" can run.\n"
545
+ "\n"
546
+ " Install path: {{Install path|text:~/OpenMontage}}\n"
547
+ "\n"
548
+ "1. Install. If the folder is already an OpenMontage checkout (it has "
549
+ "AGENT_GUIDE.md and pipeline_defs/), reuse it. If it exists and is "
550
+ "anything else, stop and ask me. Otherwise clone "
551
+ "https://github.com/calesthio/OpenMontage.git into it and run `make "
552
+ "setup` there. Check that python3, ffmpeg and Node.js with npx are on "
553
+ "the PATH; for anything missing, give me the install command and "
554
+ "wait. Setup creates .env from .env.example: tell me which provider "
555
+ "keys it lists and ask me to fill them in myself. Never ask me to "
556
+ "paste a key into chat, and never read or store one.\n"
557
+ "\n"
558
+ "2. Shared project folder. Create "
559
+ "$AGENT_SHARED_STORAGE_DIR/openmontage/projects. If the install's "
560
+ "projects/ is a real folder, move its contents into the shared "
561
+ "folder (stop and ask me on any name clash), then replace projects/ "
562
+ "with a link to the shared folder, so every om agent sees the same "
563
+ "project files.\n"
564
+ "\n"
565
+ "3. Register the crew below: one agent per OpenMontage stage across "
566
+ "all pipelines, plus the executive producer, each on this computer "
567
+ "under the team label om. Describe each one as \"OpenMontage <stage> "
568
+ "agent\". An agent that already exists keeps its settings; just make "
569
+ "sure it has the label. Skip the \"SYSTEM:Register new agent\" "
570
+ "onboarding: their expertise lives in the install. Give each new "
571
+ "agent its own knowledge folder holding a CLAUDE.md written from "
572
+ "this template, with <agent>, <stage> and <install> filled in:\n"
573
+ "\n"
574
+ f"{OM_ROLE_TEMPLATE}\n"
575
+ "\n"
576
+ " For om_ep, replace the second paragraph with: for each project, "
577
+ "load the skill pipeline_defs/<pipeline>.yaml names under "
578
+ "orchestration; write the vision memo under creative/ before "
579
+ "research starts, review the creative work at each approval point "
580
+ "and do a final review before publish; never run a stage yourself.\n"
581
+ "\n"
582
+ " Crew (agent, stage):\n"
583
+ f"{OM_CREW_TABLE}\n"
584
+ "\n"
585
+ "4. Give every om agent the install as an extra directory, start any "
586
+ "that is not running, and confirm all of them are online on this "
587
+ "computer. Shared storage is shared only between agents on one "
588
+ "computer, so if any om agent runs elsewhere, stop and tell me.\n"
589
+ "\n"
590
+ "5. Smoke test. Create a small project with om_research and om_script "
591
+ "that runs the framework-smoke pipeline under the slug "
592
+ "smoke-<today's date>, following the same file rules. It only proves "
593
+ "the crew can pass checkpoints to each other, so settle everything "
594
+ "up front and ask me nothing unless a stage fails: the topic is "
595
+ "\"what OpenMontage is\"; the budget is $0 with no web access; the "
596
+ "research brief's sources and data points cite the install's own "
597
+ "files (AGENT_GUIDE.md, pipeline_defs/framework-smoke.yaml, "
598
+ "lib/checkpoint.py and the like) as file:// URLs, its other sections "
599
+ "come from general knowledge, and its metadata says no web research "
600
+ "was done; I approve both stages' approval points in advance.\n"
601
+ "\n"
602
+ "Report back with the install path and commit, which .env keys are "
603
+ "set (names only), each om agent and whether it is online, and the "
604
+ "smoke test's checkpoint paths and cost."
605
+ ),
606
+ },
607
+ {
608
+ "id": "sop-seed-open-montage-2-produce-video",
609
+ "title": "OPEN MONTAGE:2. Produce video",
610
+ "body": (
611
+ "Coordinate a new OpenMontage video production as a multi-agent "
612
+ "project. Nothing is spent until I approve your plan.\n"
613
+ "\n"
614
+ " Project slug: {{Project slug|text:my-video-v1}}\n"
615
+ " Kind of video: {{Pipeline|select:pick for me,cinematic,"
616
+ "animated-explainer,animation,character-animation,"
617
+ "documentary-montage,talking-head,avatar-spokesperson,screen-demo,"
618
+ "podcast-repurpose,clip-factory,localization-dub,hybrid}}\n"
619
+ " Goal: {{Goal|text:a 30-second cinematic trade spot for "
620
+ "our new release}}\n"
621
+ " Audience: {{Audience|text:licensed retail and on-premise "
622
+ "buyers}}\n"
623
+ " Viewing context: {{Viewing context|select:muted at a desk,with "
624
+ "sound,mixed}}\n"
625
+ " Length (s): {{Length (s)|number:30}}\n"
626
+ " Budget (USD): {{Budget USD|number:10}}\n"
627
+ " Fact source: {{Fact source|text:the producer's own page}}\n"
628
+ " Reference: {{Reference project|text:none}}\n"
629
+ " Formats: {{Formats|text:a 9:16 master plus native 1:1 and "
630
+ "16:9, re-composed not cropped}}\n"
631
+ " Audio versions: {{Audio versions|select:scored and silent,scored "
632
+ "only,silent only}}\n"
633
+ " Hard rules: {{Hard constraints|text:none}}\n"
634
+ "\n"
635
+ "PIPELINE AND CREW. The om agents all have the OpenMontage install as "
636
+ "an extra directory; if there are none, tell me to run \"OPEN "
637
+ "MONTAGE:1. Set up\" first. If I asked you to pick, read the "
638
+ "descriptions in pipeline_defs/ and choose the pipeline that fits "
639
+ "the goal, saying why. Then read that pipeline's stages and staff "
640
+ "the project with om_ep plus the agent that owns each stage, and no "
641
+ "one else (a sub-stage, like proposal's sample, belongs to its "
642
+ "parent stage's agent):\n"
643
+ f"{OM_CREW_TABLE}\n"
644
+ "In the plan, list the stages in order with their agents, and flag "
645
+ "any stage with no agent and any agent that is offline.\n"
646
+ "\n"
647
+ "HOW FILES MOVE. One folder per project: "
648
+ "$AGENT_SHARED_STORAGE_DIR/openmontage/projects/<slug>/, which is "
649
+ "projects/<slug>/ inside the install. If it already exists, stop and "
650
+ "ask me. Every agent reads AGENT_GUIDE.md once, runs tools from the "
651
+ "install root, treats the install as read-only and writes only "
652
+ "inside the project folder. Each stage saves its checkpoint with "
653
+ "pipeline_dir=\"projects/<slug>/pipeline\"; media goes under assets/ "
654
+ "and renders/, om_ep writes to creative/. Before redoing a stage, "
655
+ "copy the old checkpoint into pipeline/history/. When a stage "
656
+ "finishes, its agent posts the checkpoint path, status, cost so far "
657
+ "and open questions; before starting the next stage, open that "
658
+ "checkpoint on disk and confirm it exists and is complete. Hand-offs "
659
+ "carry paths, not attachments.\n"
660
+ "\n"
661
+ "REFERENCE, NOT TEMPLATE. If a reference project is named, read its "
662
+ "research, proposal, decision log and reports for lessons and "
663
+ "constraints only. Do not reuse its concept.\n"
664
+ "\n"
665
+ "LIMITS. Facts come only from the fact source; invent nothing. Every "
666
+ "format and audio version is a deliverable. At most 3 revisions per "
667
+ "stage and 3 send-backs. Track cumulative spend in "
668
+ "pipeline/cost_log.json and stop and ask me before going past the "
669
+ "budget.\n"
670
+ "\n"
671
+ "STOP FOR ME after you draft the plan (pipeline, crew, milestones, "
672
+ "budget) and before anything starts; after the proposal, so I can "
673
+ "pick the concept; after the script; after the scene plan; and "
674
+ "before publish, when I review the renders and om_ep's final review. "
675
+ "At that last stop, check om_publish is online. Publish uploads "
676
+ "nothing without my explicit yes.\n"
677
+ "\n"
678
+ "DONE MEANS every format and audio version exists under renders/, "
679
+ "the render report honestly lists any defects, the cost log shows "
680
+ "the total, and the publish pack is waiting for my yes. Finish with "
681
+ "a short summary listing the file paths."
682
+ ),
683
+ },
684
+ {
685
+ # The SHOPPING section's one row, and the SOP the "Scheduled Deal Monitor"
686
+ # starter to-do in ``models/desk_todo.py`` names by title. Product and
687
+ # schedule are required; criteria and sources default to "none", which
688
+ # the body reads as "no filter" and "suggest some for me". The
689
+ # schedule is the owner's words, turned into a desk-sop schedule.
690
+ "id": "sop-seed-shopping-scheduled-deal-tracking",
691
+ "title": SCHEDULED_DEAL_SOP_TITLE,
692
+ "body": (
693
+ "Track deals on a product for me: check them once now, then keep "
694
+ "checking on my schedule.\n"
695
+ "\n"
696
+ " Product: {{Product|text:a 65-inch OLED TV}}\n"
697
+ " Schedule: {{Schedule|text:every day at 9am}}\n"
698
+ " Criteria: {{Criteria (optional)|text:none}}\n"
699
+ " Deal sources: {{Deal sources (optional)|text:none}}\n"
700
+ "\n"
701
+ "Product is required: if it is blank or vague (no brand, model, "
702
+ "size or variant where one matters), ask me before searching. "
703
+ "Schedule is how often to check, in my words (\"every day at 9am\", "
704
+ "\"weekdays at 8am and 6pm\", \"every Monday\", \"every 4 hours\"); "
705
+ "\"once\" means just this check. If it is blank, has no time where "
706
+ "one matters, or you cannot read it as a cadence, ask me. "
707
+ "Criteria is anything a deal must meet, such as a maximum price, "
708
+ "quantity, condition (new, open-box, refurbished), seller, "
709
+ "shipping or pickup; \"none\" means no filter beyond the product "
710
+ "itself. Deal sources are the websites I want checked; \"none\" "
711
+ "means I have no favourites.\n"
712
+ "\n"
713
+ "1. Browser. If you do not have the playwright-browser skill yet, "
714
+ "install it on yourself with your install-skill skill (`manigent "
715
+ "skill install self playwright-browser`) and run `manigent "
716
+ "bootstrap browser` once if the skill says this computer needs it. "
717
+ "Use plain web fetches for static pages and the browser only for "
718
+ "pages that need JavaScript, a login or a click-through. If a "
719
+ "site asks me to sign in, tell me which one and skip it; never "
720
+ "ask me for a password in chat.\n"
721
+ "\n"
722
+ "2. Sources. If I named deal sources, use those. If not, suggest "
723
+ "4 to 6 that fit this product, one line each on why: the major "
724
+ "retailers that sell it, the maker's own store, a price tracker "
725
+ "(CamelCamelCamel or Keepa for Amazon), a deal community "
726
+ "(Slickdeals) and, where it fits, a used or refurbished market. "
727
+ "Ask me to confirm or edit the list and stop until I answer. Once "
728
+ "I confirm, write the list into this SOP's Deal sources so the "
729
+ "next run does not ask again.\n"
730
+ "\n"
731
+ "3. Check. On each source, find current listings of the product "
732
+ "and record the seller, price including shipping and tax where "
733
+ "shown, any coupon or promo code, stock, condition, and the "
734
+ "deal's end date if it has one. Drop anything that fails my "
735
+ "criteria, and anything that is not the same product (a different "
736
+ "model year, size or bundle), unless it is clearly a better deal, "
737
+ "in which case flag it as an alternative.\n"
738
+ "\n"
739
+ "4. Remember. Keep a price history for this product in your local "
740
+ "storage ($AGENT_LOCAL_STORAGE_DIR/deal-tracking/), one file per "
741
+ "product, with each run's best price per source, so later runs "
742
+ "can tell a real drop from the usual price.\n"
743
+ "\n"
744
+ "5. Report. Lead with one line: the best deal right now (price, "
745
+ "seller, link), or \"nothing matches your criteria today\". "
746
+ "Then a short table of the rest, best first, and whether each "
747
+ "price is new, lower or higher than last run. Say which sources "
748
+ "you could not check and why. Never buy, add to a cart, sign up "
749
+ "or subscribe to anything on my behalf.\n"
750
+ "\n"
751
+ "6. Schedule. After the first check, unless my schedule is "
752
+ "\"once\", schedule this SOP on that cadence with your desk-sop "
753
+ "skill, carrying the values settled here (including any sources "
754
+ "I confirmed). Read my times as my local time. Repeat the schedule "
755
+ "back to me in plain words with the next run time, and tell me how "
756
+ "to change or stop it. If this product already has a schedule, "
757
+ "replace it rather than adding a second. On a scheduled run, "
758
+ "never ask me anything; report only "
759
+ "when something changed (a new low, a new deal that matches, or a "
760
+ "deal about to end); otherwise post one line saying nothing "
761
+ "changed."
762
+ ),
763
+ },
764
+ )
765
+
766
+ # Distinguishes "key absent from a PATCH body" (leave the stored value
767
+ # untouched) from an explicit JSON ``null`` (clear the field). Used only for
768
+ # the ``agent_*`` pair: a user with no agents saves an SOP with no recipient,
769
+ # and later assigning/unassigning one needs absent != null. The route layer
770
+ # detects key presence off the raw request body (see
771
+ # ``server/routes/desk_sops.py``) since a non-serializable sentinel can't be
772
+ # a FastAPI ``Body`` default. Mirrors ``desk_todo._UNSET``.
773
+ _UNSET: object = object()
774
+
775
+
776
+ class DeskSop(BaseModel):
777
+ """One stored prompt in the owner's SOP library."""
778
+
779
+ id: str
780
+ owner_user_id: str
781
+ title: str
782
+ # Default recipient. Both id and name are persisted so the rail still
783
+ # labels the card correctly after a rename or removal; the frontend
784
+ # re-resolves against the live roster (``utils/sopRecipient.ts``) and
785
+ # falls back to the owner's assistant. Same precedent as
786
+ # ``DeskTodo.draft_recipient_{id,name}``.
787
+ agent_id: str | None = None
788
+ agent_name: str | None = None
789
+ # The prompt itself, with ``{{blanks}}`` left un-substituted.
790
+ body: str
791
+ created_at: str
792
+ updated_at: str
793
+
794
+
795
+ def gen_id() -> str:
796
+ return "sop-" + secrets.token_hex(6)
797
+
798
+
799
+ def _now() -> str:
800
+ return datetime.now(UTC).isoformat()
801
+
802
+
803
+ def _path(data_dir: Path, owner_user_id: str) -> Path:
804
+ return Path(data_dir) / SOPS_DIR / f"{owner_user_id}.json"
805
+
806
+
807
+ def _seed_rows(owner_user_id: str) -> list[DeskSop]:
808
+ """The starter library, materialized in memory for one owner.
809
+
810
+ The timestamps are the fixed epoch constant rather than the clock. The seed
811
+ is materialized on every read of an unwritten library, so minting ``now()``
812
+ here would make two consecutive GETs return different ``created_at`` values
813
+ for the same row — churn a client can legitimately notice, in a field
814
+ nothing needs. It is also simply more truthful: the owner did not write
815
+ these. Rows keep the constant when the first write materializes them to
816
+ disk; anything the owner creates afterwards is stamped with the real clock
817
+ and sorts ahead of them.
818
+ """
819
+ return [
820
+ DeskSop(
821
+ owner_user_id=owner_user_id,
822
+ created_at=SEED_TIMESTAMP,
823
+ updated_at=SEED_TIMESTAMP,
824
+ **row,
825
+ )
826
+ for row in SEED
827
+ ]
828
+
829
+
830
+ def _load(data_dir: Path, owner_user_id: str) -> list[DeskSop]:
831
+ """Every read and every write starts here, so "missing" vs "empty" vs
832
+ "unreadable" is decided in exactly one place.
833
+
834
+ NO FILE -> the SEED, in memory. A file that exists but holds no usable rows
835
+ -> ZERO rows, never the seed as a repair: an owner who deleted their last
836
+ SOP gets an empty rail and keeps it, and a corrupt document is not written
837
+ over with starter content. That is why the branch is ``path.exists()`` and
838
+ not the parsed value — ``FileUtil.read(..., default=...)`` answers the same
839
+ ``None`` for a missing file and for a JSONDecodeError.
840
+ """
841
+ path = _path(data_dir, owner_user_id)
842
+ if not path.exists():
843
+ return _seed_rows(owner_user_id)
844
+ raw = FileUtil.read(path, "json", default=None)
845
+ if not isinstance(raw, list):
846
+ return []
847
+ out: list[DeskSop] = []
848
+ for row in raw:
849
+ if not isinstance(row, dict):
850
+ continue
851
+ try:
852
+ out.append(DeskSop.model_validate(row))
853
+ except Exception:
854
+ continue
855
+ return out
856
+
857
+
858
+ def _save(data_dir: Path, owner_user_id: str, sops: list[DeskSop]) -> None:
859
+ FileUtil.write(
860
+ _path(data_dir, owner_user_id),
861
+ [s.model_dump() for s in sops],
862
+ "json",
863
+ )
864
+
865
+
866
+ def list_sops(data_dir: Path, owner_user_id: str) -> list[DeskSop]:
867
+ """Return the owner's library, newest first."""
868
+ return _load(data_dir, owner_user_id)
869
+
870
+
871
+ def get_sop(data_dir: Path, owner_user_id: str, sop_id: str) -> DeskSop | None:
872
+ for s in _load(data_dir, owner_user_id):
873
+ if s.id == sop_id:
874
+ return s
875
+ return None
876
+
877
+
878
+ async def create_sop(
879
+ data_dir: Path,
880
+ owner_user_id: str,
881
+ *,
882
+ title: str,
883
+ body: str,
884
+ agent_id: str | None = None,
885
+ agent_name: str | None = None,
886
+ ) -> DeskSop:
887
+ """Store a new SOP; prepended so the newest is first."""
888
+ title = (title or "").strip()
889
+ if not title:
890
+ raise ValueError("SOP title cannot be empty")
891
+ body = (body or "").strip()
892
+ if not body:
893
+ raise ValueError("SOP body cannot be empty")
894
+ if len(body) > MAX_BODY_CHARS:
895
+ raise ValueError(f"SOP body exceeds {MAX_BODY_CHARS} characters")
896
+ async with _lock:
897
+ sops = _load(data_dir, owner_user_id)
898
+ now = _now()
899
+ sop = DeskSop(
900
+ id=gen_id(),
901
+ owner_user_id=owner_user_id,
902
+ title=title,
903
+ agent_id=agent_id,
904
+ agent_name=agent_name,
905
+ body=body,
906
+ created_at=now,
907
+ updated_at=now,
908
+ )
909
+ sops.insert(0, sop)
910
+ _save(data_dir, owner_user_id, sops)
911
+ return sop
912
+
913
+
914
+ async def patch_sop(
915
+ data_dir: Path,
916
+ owner_user_id: str,
917
+ sop_id: str,
918
+ *,
919
+ title: str | None = None,
920
+ body: str | None = None,
921
+ agent_id: str | None = _UNSET, # _UNSET → leave untouched
922
+ agent_name: str | None = _UNSET, # None → clear, str → set
923
+ ) -> DeskSop | None:
924
+ """Patch an SOP in place. Returns the updated SOP, or None if missing.
925
+
926
+ ``title`` / ``body`` never clear: a blank value is ignored, because both
927
+ are required and the dialog already blocks Save on either being empty.
928
+ ``agent_id`` / ``agent_name`` are three-way (see ``_UNSET``)."""
929
+ if body is not None and len(body) > MAX_BODY_CHARS:
930
+ raise ValueError(f"SOP body exceeds {MAX_BODY_CHARS} characters")
931
+ async with _lock:
932
+ sops = _load(data_dir, owner_user_id)
933
+ target: DeskSop | None = None
934
+ for s in sops:
935
+ if s.id == sop_id:
936
+ target = s
937
+ break
938
+ if target is None:
939
+ return None
940
+ if title is not None:
941
+ title = title.strip()
942
+ if title:
943
+ target.title = title
944
+ if body is not None:
945
+ body = body.strip()
946
+ if body:
947
+ target.body = body
948
+ if agent_id is not _UNSET:
949
+ target.agent_id = agent_id
950
+ if agent_name is not _UNSET:
951
+ target.agent_name = agent_name
952
+ target.updated_at = _now()
953
+ _save(data_dir, owner_user_id, sops)
954
+ return target
955
+
956
+
957
+ async def delete_sop(data_dir: Path, owner_user_id: str, sop_id: str) -> bool:
958
+ """Remove an SOP. Returns True if it existed."""
959
+ async with _lock:
960
+ sops = _load(data_dir, owner_user_id)
961
+ kept = [s for s in sops if s.id != sop_id]
962
+ if len(kept) == len(sops):
963
+ return False
964
+ _save(data_dir, owner_user_id, kept)
965
+ return True