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.
- manigent/_catalog/mcps/chess/README.md +38 -0
- manigent/_catalog/mcps/chess/mcp.json +9 -0
- manigent/_catalog/mcps/registry.json +9 -0
- manigent/_catalog/skills/brief/SKILL.md +339 -0
- manigent/_catalog/skills/broaden-options/SKILL.md +133 -0
- manigent/_catalog/skills/calendar/SKILL.md +44 -0
- manigent/_catalog/skills/calendar/starter_config.jsonc +25 -0
- manigent/_catalog/skills/gmail/SKILL.md +73 -0
- manigent/_catalog/skills/google-calendar/SKILL.md +44 -0
- manigent/_catalog/skills/google-drive/SKILL.md +42 -0
- manigent/_catalog/skills/google-drive-write/SKILL.md +45 -0
- manigent/_catalog/skills/google-drive-write/starter_config.jsonc +45 -0
- manigent/_catalog/skills/grill-me/SKILL.md +173 -0
- manigent/_catalog/skills/homekit/SKILL.md +37 -0
- manigent/_catalog/skills/http-api/SKILL.md +117 -0
- manigent/_catalog/skills/ib/SKILL.md +89 -0
- manigent/_catalog/skills/ib/starter_config.jsonc +35 -0
- manigent/_catalog/skills/mailbox/SKILL.md +47 -0
- manigent/_catalog/skills/mailbox/starter_config.jsonc +38 -0
- manigent/_catalog/skills/media/SKILL.md +93 -0
- manigent/_catalog/skills/media/starter_config.jsonc +63 -0
- manigent/_catalog/skills/osxphotos/SKILL.md +41 -0
- manigent/_catalog/skills/photo-story/SKILL.md +285 -0
- manigent/_catalog/skills/playwright-browser/SKILL.md +291 -0
- manigent/_catalog/skills/playwright-browser/starter_config.jsonc +44 -0
- manigent/_catalog/skills/playwright-save-skill/SKILL.md +149 -0
- manigent/_catalog/skills/registry.json +166 -0
- manigent/_catalog/skills/web-artifacts/SKILL.md +194 -0
- manigent/api/action_executor.py +404 -0
- manigent/api/action_validator.py +531 -0
- manigent/api/actions.py +221 -0
- manigent/api/client.py +558 -0
- manigent/api/control.py +806 -0
- manigent/api/edge_protocol.py +123 -0
- manigent/api/fs_protocol.py +450 -0
- manigent/api/host_protocol.py +298 -0
- manigent/api/managed_job_client.py +124 -0
- manigent/api/responses.py +342 -0
- manigent/api/retry_transport.py +178 -0
- manigent/api/turn_protocol.py +78 -0
- manigent/cli_lifecycle.py +467 -0
- manigent/cli_server.py +978 -0
- manigent/doctor.py +1167 -0
- manigent/hub_protocol/canonical.py +375 -0
- manigent/hub_protocol/codes.py +171 -0
- manigent/hub_protocol/constants.py +71 -0
- manigent/hub_protocol/envelope.py +218 -0
- manigent/hub_protocol/frames.py +788 -0
- manigent/hub_protocol/http.py +260 -0
- manigent/hub_protocol/ids.py +170 -0
- manigent/hub_protocol/keys.py +195 -0
- manigent/hub_protocol/text.py +75 -0
- manigent/llm/base.py +1072 -0
- manigent/llm/prompt_builder.py +2450 -0
- manigent/llm/triggers.py +68 -0
- manigent/models/agent.py +2905 -0
- manigent/models/agent_bundle.py +298 -0
- manigent/models/brief_tab.py +311 -0
- manigent/models/chat_message.py +231 -0
- manigent/models/chatroom.py +1108 -0
- manigent/models/context.py +1159 -0
- manigent/models/desk_label.py +836 -0
- manigent/models/desk_read_state.py +220 -0
- manigent/models/desk_sign_off.py +267 -0
- manigent/models/desk_sop.py +965 -0
- manigent/models/desk_todo.py +1603 -0
- manigent/models/desk_todo_link.py +404 -0
- manigent/models/file_cache.py +75 -0
- manigent/models/host.py +732 -0
- manigent/models/install_token.py +401 -0
- manigent/models/invitation_code.py +162 -0
- manigent/models/knowledge_pack.py +552 -0
- manigent/models/managed_job.py +295 -0
- manigent/models/model_config.py +564 -0
- manigent/models/model_defaults.py +238 -0
- manigent/models/onboarding_plan.py +161 -0
- manigent/models/participant.py +449 -0
- manigent/models/persistable.py +892 -0
- manigent/models/plan_markdown.py +1774 -0
- manigent/models/project.py +1343 -0
- manigent/models/project_plan.py +8104 -0
- manigent/models/project_report.py +145 -0
- manigent/models/provenance.py +261 -0
- manigent/models/provider_agents.py +101 -0
- manigent/models/public_request.py +108 -0
- manigent/models/reflection_schedule.py +191 -0
- manigent/models/scheduled_message.py +285 -0
- manigent/models/share_token.py +190 -0
- manigent/models/skill_version.py +31 -0
- manigent/models/sop_template.py +187 -0
- manigent/models/thinking_partner_plan.py +187 -0
- manigent/models/tunnel_binding.py +129 -0
- manigent/models/user.py +1276 -0
- manigent/models/work_tracker.py +510 -0
- manigent/runner/invocation_registry.py +187 -0
- manigent/server/agent_capabilities.py +119 -0
- manigent/server/agent_visibility.py +119 -0
- manigent/server/announcements.py +119 -0
- manigent/server/app.py +807 -0
- manigent/server/auth.py +355 -0
- manigent/server/batch_timeout.py +94 -0
- manigent/server/channels/access.py +194 -0
- manigent/server/channels/adapter.py +295 -0
- manigent/server/channels/config.py +693 -0
- manigent/server/channels/contacts.py +39 -0
- manigent/server/channels/email_adapter.py +436 -0
- manigent/server/channels/email_address.py +145 -0
- manigent/server/channels/email_form.py +242 -0
- manigent/server/channels/email_format.py +285 -0
- manigent/server/channels/email_mail.py +427 -0
- manigent/server/channels/email_mailgun.py +164 -0
- manigent/server/channels/email_text.py +280 -0
- manigent/server/channels/file_links.py +127 -0
- manigent/server/channels/gateway.py +2998 -0
- manigent/server/channels/hub_delivery.py +211 -0
- manigent/server/channels/hub_store.py +1730 -0
- manigent/server/channels/line.py +645 -0
- manigent/server/channels/line_format.py +589 -0
- manigent/server/channels/log_redaction.py +145 -0
- manigent/server/channels/store.py +3316 -0
- manigent/server/channels/telegram.py +422 -0
- manigent/server/channels/telegram_format.py +312 -0
- manigent/server/channels/webchat.py +261 -0
- manigent/server/channels/webchat_widget.js +1310 -0
- manigent/server/channels/whatsapp.py +707 -0
- manigent/server/channels/whatsapp_format.py +511 -0
- manigent/server/chat_search_index.py +1203 -0
- manigent/server/config.py +61 -0
- manigent/server/context.py +121 -0
- manigent/server/coordinator_rule.py +115 -0
- manigent/server/desk_todo_notify.py +300 -0
- manigent/server/edge_hub.py +577 -0
- manigent/server/email.py +354 -0
- manigent/server/errors.py +83 -0
- manigent/server/home_fs_relay.py +392 -0
- manigent/server/hub/adapter.py +1395 -0
- manigent/server/hub/agent_send_guard.py +196 -0
- manigent/server/hub/avatar.py +342 -0
- manigent/server/hub/browser.py +778 -0
- manigent/server/hub/client.py +859 -0
- manigent/server/hub/demand.py +49 -0
- manigent/server/hub/directory.py +385 -0
- manigent/server/hub/enroll.py +400 -0
- manigent/server/hub/http.py +134 -0
- manigent/server/hub/identity.py +61 -0
- manigent/server/hub/keys.py +588 -0
- manigent/server/hub/mirror.py +802 -0
- manigent/server/hub/operator.py +817 -0
- manigent/server/hub/retain.py +361 -0
- manigent/server/hub/room_bridge.py +741 -0
- manigent/server/hub/runtime.py +691 -0
- manigent/server/hub/trust.py +182 -0
- manigent/server/hub/views.py +316 -0
- manigent/server/idempotency.py +205 -0
- manigent/server/in_flight_restore.py +181 -0
- manigent/server/inspection.py +816 -0
- manigent/server/isolation_gate.py +516 -0
- manigent/server/isolation_notice.py +310 -0
- manigent/server/managed_job_events.py +242 -0
- manigent/server/mcp_registry.py +118 -0
- manigent/server/message_forward.py +78 -0
- manigent/server/message_scheduler.py +176 -0
- manigent/server/notification_assets.py +164 -0
- manigent/server/oauth_login/cli_state.py +120 -0
- manigent/server/oauth_login/config.py +90 -0
- manigent/server/oauth_login/errors.py +78 -0
- manigent/server/oauth_login/flow.py +223 -0
- manigent/server/oauth_login/handoff.py +63 -0
- manigent/server/oauth_login/providers.py +45 -0
- manigent/server/oauth_state.py +81 -0
- manigent/server/owner_isolation.py +466 -0
- manigent/server/participant_liveness.py +82 -0
- manigent/server/public_profile.py +149 -0
- manigent/server/public_requests/candidates.py +116 -0
- manigent/server/public_requests/dispatch.py +121 -0
- manigent/server/public_requests/ranking.py +153 -0
- manigent/server/recent_activity.py +250 -0
- manigent/server/reflection_completion_subscriber.py +151 -0
- manigent/server/reflection_scheduler.py +239 -0
- manigent/server/requester_key_migration.py +261 -0
- manigent/server/room_flow.py +139 -0
- manigent/server/routes/_batch.py +218 -0
- manigent/server/routes/_fd_routing.py +155 -0
- manigent/server/routes/_mentions.py +70 -0
- manigent/server/routes/agent_env.py +188 -0
- manigent/server/routes/agent_fs.py +450 -0
- manigent/server/routes/agents.py +1206 -0
- manigent/server/routes/announcements.py +79 -0
- manigent/server/routes/auth.py +387 -0
- manigent/server/routes/brief_tabs.py +404 -0
- manigent/server/routes/changelog.py +237 -0
- manigent/server/routes/channels.py +993 -0
- manigent/server/routes/chatrooms.py +871 -0
- manigent/server/routes/desk_labels.py +298 -0
- manigent/server/routes/desk_latest_messages.py +116 -0
- manigent/server/routes/desk_read_state.py +110 -0
- manigent/server/routes/desk_sign_off.py +88 -0
- manigent/server/routes/desk_sops.py +216 -0
- manigent/server/routes/desk_todos.py +692 -0
- manigent/server/routes/desk_tour.py +44 -0
- manigent/server/routes/files.py +572 -0
- manigent/server/routes/hosts.py +484 -0
- manigent/server/routes/hub.py +534 -0
- manigent/server/routes/hub_channels.py +234 -0
- manigent/server/routes/inbox.py +581 -0
- manigent/server/routes/install.ps1 +436 -0
- manigent/server/routes/install.py +324 -0
- manigent/server/routes/install.sh +566 -0
- manigent/server/routes/isolation_check.py +145 -0
- manigent/server/routes/knowledge_packs.py +477 -0
- manigent/server/routes/managed_jobs.py +196 -0
- manigent/server/routes/mcps.py +271 -0
- manigent/server/routes/messages.py +1972 -0
- manigent/server/routes/model_defaults.py +279 -0
- manigent/server/routes/oauth.py +237 -0
- manigent/server/routes/oauth_login.py +351 -0
- manigent/server/routes/owner_isolation.py +91 -0
- manigent/server/routes/project_plans.py +1521 -0
- manigent/server/routes/project_reports.py +235 -0
- manigent/server/routes/projects.py +2047 -0
- manigent/server/routes/public_agents.py +151 -0
- manigent/server/routes/public_requests.py +181 -0
- manigent/server/routes/reflection.py +93 -0
- manigent/server/routes/scheduled_messages.py +263 -0
- manigent/server/routes/search.py +94 -0
- manigent/server/routes/sharing.py +156 -0
- manigent/server/routes/skills.py +406 -0
- manigent/server/routes/templates.py +219 -0
- manigent/server/routes/turn_tokens.py +119 -0
- manigent/server/routes/webchat.py +406 -0
- manigent/server/routes/websocket.py +431 -0
- manigent/server/serving_only.py +200 -0
- manigent/server/signup_policy.py +120 -0
- manigent/server/skill_registry.py +164 -0
- manigent/server/socket_events.py +858 -0
- manigent/server/timeout_checker.py +446 -0
- manigent/server/tunnel_subscriber.py +1000 -0
- manigent/server/turn_tokens.py +285 -0
- manigent/server/ws_hub.py +556 -0
- manigent/server_cli.py +31 -0
- manigent/sync/changelog.py +885 -0
- manigent/sync/console_subscriber.py +222 -0
- manigent/sync/runloop.py +619 -0
- manigent/sync/runloop_manager.py +197 -0
- manigent/sync/subscriber.py +98 -0
- manigent/utils/agent_processes.py +276 -0
- manigent/utils/agent_storage.py +125 -0
- manigent/utils/email.py +563 -0
- manigent/utils/env_store.py +174 -0
- manigent/utils/extra_dirs.py +85 -0
- manigent/utils/file_io.py +485 -0
- manigent/utils/invoke_timeout.py +87 -0
- manigent/utils/jsonc.py +78 -0
- manigent/utils/knowledge_index.py +148 -0
- manigent/utils/nofollow_fs.py +279 -0
- manigent/utils/notification_center.py +67 -0
- manigent/utils/version.py +57 -0
- manigent/web/frontend/.design-sync-entry.tsx +74 -0
- manigent/web/frontend/.design-sync-provider.tsx +46 -0
- manigent/web/frontend/.eslintrc.cjs +183 -0
- manigent/web/frontend/.gitignore +6 -0
- manigent/web/frontend/app/page.tsx +39 -0
- manigent/web/frontend/hub-terms.html +192 -0
- manigent/web/frontend/index.html +15 -0
- manigent/web/frontend/landing.html +15 -0
- manigent/web/frontend/package-lock.json +8028 -0
- manigent/web/frontend/package.json +55 -0
- manigent/web/frontend/postcss.config.js +6 -0
- manigent/web/frontend/privacy.html +217 -0
- manigent/web/frontend/private-beta-announcement.html +19 -0
- manigent/web/frontend/public/apple-touch-icon.png +0 -0
- manigent/web/frontend/public/brand-hero-banner.png +0 -0
- manigent/web/frontend/public/brand-hero.png +0 -0
- manigent/web/frontend/public/favicon.png +0 -0
- manigent/web/frontend/public/favicon.svg +8 -0
- manigent/web/frontend/public/icon-transparent-sm.png +0 -0
- manigent/web/frontend/public/icon.png +0 -0
- manigent/web/frontend/public/manigent-mark.svg +7 -0
- manigent/web/frontend/public/vite.svg +5 -0
- manigent/web/frontend/public.html +15 -0
- manigent/web/frontend/src/App.activeAccountRedirect.test.tsx +236 -0
- manigent/web/frontend/src/App.hubHostDm.test.tsx +119 -0
- manigent/web/frontend/src/App.hubHostProject.test.tsx +142 -0
- manigent/web/frontend/src/App.hubRoutes.test.tsx +187 -0
- manigent/web/frontend/src/App.oauthAddCallback.test.tsx +263 -0
- manigent/web/frontend/src/App.tsx +246 -0
- manigent/web/frontend/src/api/attachments.ts +32 -0
- manigent/web/frontend/src/api/batchLoader.test.ts +212 -0
- manigent/web/frontend/src/api/batchLoader.ts +124 -0
- manigent/web/frontend/src/api/chatroomsBatch.test.tsx +392 -0
- manigent/web/frontend/src/api/client.ts +321 -0
- manigent/web/frontend/src/api/crossAccountAuth.test.ts +388 -0
- manigent/web/frontend/src/api/endpoints/agentEnv.ts +24 -0
- manigent/web/frontend/src/api/endpoints/agentFs.ts +125 -0
- manigent/web/frontend/src/api/endpoints/agentSearch.ts +19 -0
- manigent/web/frontend/src/api/endpoints/agents.ts +66 -0
- manigent/web/frontend/src/api/endpoints/announcements.ts +26 -0
- manigent/web/frontend/src/api/endpoints/auth.ts +361 -0
- manigent/web/frontend/src/api/endpoints/authLogin.test.ts +236 -0
- manigent/web/frontend/src/api/endpoints/batch.ts +64 -0
- manigent/web/frontend/src/api/endpoints/briefTabs.ts +81 -0
- manigent/web/frontend/src/api/endpoints/channels.ts +285 -0
- manigent/web/frontend/src/api/endpoints/computers.ts +212 -0
- manigent/web/frontend/src/api/endpoints/deskLabels.ts +151 -0
- manigent/web/frontend/src/api/endpoints/deskLatestMessages.ts +23 -0
- manigent/web/frontend/src/api/endpoints/deskReadState.ts +41 -0
- manigent/web/frontend/src/api/endpoints/deskSignOffs.ts +74 -0
- manigent/web/frontend/src/api/endpoints/deskSops.ts +53 -0
- manigent/web/frontend/src/api/endpoints/deskTodoAttachments.ts +69 -0
- manigent/web/frontend/src/api/endpoints/deskTodoProjects.test.ts +99 -0
- manigent/web/frontend/src/api/endpoints/deskTodoProjects.ts +114 -0
- manigent/web/frontend/src/api/endpoints/deskTodos.ts +164 -0
- manigent/web/frontend/src/api/endpoints/deskTour.ts +16 -0
- manigent/web/frontend/src/api/endpoints/dm.ts +137 -0
- manigent/web/frontend/src/api/endpoints/files.ts +55 -0
- manigent/web/frontend/src/api/endpoints/hub.contract.test.ts +94 -0
- manigent/web/frontend/src/api/endpoints/hub.keys.ts +260 -0
- manigent/web/frontend/src/api/endpoints/hub.test.ts +203 -0
- manigent/web/frontend/src/api/endpoints/hub.ts +654 -0
- manigent/web/frontend/src/api/endpoints/index.ts +15 -0
- manigent/web/frontend/src/api/endpoints/install.ts +74 -0
- manigent/web/frontend/src/api/endpoints/isolationCheck.ts +36 -0
- manigent/web/frontend/src/api/endpoints/knowledgePacks.ts +179 -0
- manigent/web/frontend/src/api/endpoints/mcps.ts +36 -0
- manigent/web/frontend/src/api/endpoints/messages.held.test.ts +43 -0
- manigent/web/frontend/src/api/endpoints/messages.ts +95 -0
- manigent/web/frontend/src/api/endpoints/modelConfigs.ts +232 -0
- manigent/web/frontend/src/api/endpoints/oauthApi.test.ts +110 -0
- manigent/web/frontend/src/api/endpoints/projectPlans.ts +608 -0
- manigent/web/frontend/src/api/endpoints/projectReports.ts +36 -0
- manigent/web/frontend/src/api/endpoints/projects.ts +124 -0
- manigent/web/frontend/src/api/endpoints/publicRequests.ts +75 -0
- manigent/web/frontend/src/api/endpoints/reflection.ts +32 -0
- manigent/web/frontend/src/api/endpoints/roomFlow.ts +14 -0
- manigent/web/frontend/src/api/endpoints/scheduledMessages.ts +60 -0
- manigent/web/frontend/src/api/endpoints/search.ts +27 -0
- manigent/web/frontend/src/api/endpoints/sharing.ts +42 -0
- manigent/web/frontend/src/api/endpoints/skills.ts +67 -0
- manigent/web/frontend/src/api/endpoints/templates.ts +72 -0
- manigent/web/frontend/src/api/loaders.ts +22 -0
- manigent/web/frontend/src/api/singleIssuer.test.ts +148 -0
- manigent/web/frontend/src/api/transientRetry.test.ts +176 -0
- manigent/web/frontend/src/api/transientRetry.ts +140 -0
- manigent/web/frontend/src/api/websocket.resync.test.ts +111 -0
- manigent/web/frontend/src/api/websocket.ts +335 -0
- manigent/web/frontend/src/components/agent/AgentNameLink.tsx +24 -0
- manigent/web/frontend/src/components/agent/AgentViewActions.test.tsx +41 -0
- manigent/web/frontend/src/components/agent/AgentViewActions.tsx +89 -0
- manigent/web/frontend/src/components/agent/CreateAgentPage.tsx +535 -0
- manigent/web/frontend/src/components/agent/JsonConfigEditor.tsx +33 -0
- manigent/web/frontend/src/components/agent/KnowledgePackList.tsx +103 -0
- manigent/web/frontend/src/components/agent/McpCatalog.tsx +261 -0
- manigent/web/frontend/src/components/agent/McpConfigModal.tsx +224 -0
- manigent/web/frontend/src/components/agent/PreConsentModal.tsx +172 -0
- manigent/web/frontend/src/components/agent/SkillCatalog.tsx +364 -0
- manigent/web/frontend/src/components/agent/SkillConfigModal.tsx +221 -0
- manigent/web/frontend/src/components/auth/AddAccountPage.test.tsx +181 -0
- manigent/web/frontend/src/components/auth/AddAccountPage.tsx +201 -0
- manigent/web/frontend/src/components/auth/AuthShell.tsx +462 -0
- manigent/web/frontend/src/components/auth/LoginPage.test.tsx +384 -0
- manigent/web/frontend/src/components/auth/LoginPage.tsx +129 -0
- manigent/web/frontend/src/components/auth/OAuthCallbackPage.test.tsx +185 -0
- manigent/web/frontend/src/components/auth/OAuthCallbackPage.tsx +154 -0
- manigent/web/frontend/src/components/auth/OAuthLinkedBanner.tsx +44 -0
- manigent/web/frontend/src/components/auth/ProviderButtons.tsx +94 -0
- manigent/web/frontend/src/components/auth/SignupPage.tsx +437 -0
- manigent/web/frontend/src/components/auth/StepProgress.tsx +60 -0
- manigent/web/frontend/src/components/auth/VerifyEmailPage.test.tsx +155 -0
- manigent/web/frontend/src/components/auth/VerifyEmailPage.tsx +211 -0
- manigent/web/frontend/src/components/auth/index.ts +3 -0
- manigent/web/frontend/src/components/auth/oauthErrors.test.ts +107 -0
- manigent/web/frontend/src/components/auth/oauthErrors.ts +82 -0
- manigent/web/frontend/src/components/auth/useUsernameCheck.test.tsx +68 -0
- manigent/web/frontend/src/components/auth/useUsernameCheck.ts +86 -0
- manigent/web/frontend/src/components/beta/BetaPage.tsx +21 -0
- manigent/web/frontend/src/components/beta/DayAtMyDesk.tsx +120 -0
- manigent/web/frontend/src/components/beta/Footer.tsx +82 -0
- manigent/web/frontend/src/components/beta/Hero.tsx +224 -0
- manigent/web/frontend/src/components/beta/Nav.tsx +51 -0
- manigent/web/frontend/src/components/beta/Pillars.tsx +172 -0
- manigent/web/frontend/src/components/beta/TwoModels.tsx +146 -0
- manigent/web/frontend/src/components/beta/constants.ts +3 -0
- manigent/web/frontend/src/components/briefing/BriefingFrame.test.tsx +208 -0
- manigent/web/frontend/src/components/briefing/BriefingFrame.tsx +151 -0
- manigent/web/frontend/src/components/briefing/BriefingPage.test.tsx +176 -0
- manigent/web/frontend/src/components/briefing/BriefingPage.tsx +157 -0
- manigent/web/frontend/src/components/briefing/BriefingPage.wsDelete.test.tsx +177 -0
- manigent/web/frontend/src/components/briefing/briefing.css +147 -0
- manigent/web/frontend/src/components/briefing/heightBootstrap.test.ts +121 -0
- manigent/web/frontend/src/components/briefing/heightBootstrap.ts +224 -0
- manigent/web/frontend/src/components/briefing/parseBriefMessage.test.ts +90 -0
- manigent/web/frontend/src/components/briefing/sampleBriefing.ts +148 -0
- manigent/web/frontend/src/components/channels/ChannelBadge.tsx +35 -0
- manigent/web/frontend/src/components/chatroom/ChannelThreadControls.tsx +127 -0
- manigent/web/frontend/src/components/chatroom/ChannelThreadNotice.test.tsx +207 -0
- manigent/web/frontend/src/components/chatroom/ChannelThreadNotice.tsx +80 -0
- manigent/web/frontend/src/components/chatroom/ChatroomView.channel.test.tsx +550 -0
- manigent/web/frontend/src/components/chatroom/ChatroomView.flow.test.tsx +186 -0
- manigent/web/frontend/src/components/chatroom/ChatroomView.isolation.test.tsx +70 -0
- manigent/web/frontend/src/components/chatroom/ChatroomView.tsx +450 -0
- manigent/web/frontend/src/components/chatroom/DelegationRow.test.tsx +170 -0
- manigent/web/frontend/src/components/chatroom/DelegationRow.tsx +217 -0
- manigent/web/frontend/src/components/chatroom/DeliveryStatusLine.test.tsx +33 -0
- manigent/web/frontend/src/components/chatroom/DeliveryStatusLine.tsx +46 -0
- manigent/web/frontend/src/components/chatroom/ForwardModal.test.tsx +109 -0
- manigent/web/frontend/src/components/chatroom/ForwardModal.tsx +304 -0
- manigent/web/frontend/src/components/chatroom/HeldNotice.tsx +77 -0
- manigent/web/frontend/src/components/chatroom/MentionDropdown.tsx +97 -0
- manigent/web/frontend/src/components/chatroom/MessageInput.tsx +408 -0
- manigent/web/frontend/src/components/chatroom/MessageItem.tsx +425 -0
- manigent/web/frontend/src/components/chatroom/MessageList.outside.test.tsx +98 -0
- manigent/web/frontend/src/components/chatroom/MessageList.test.tsx +245 -0
- manigent/web/frontend/src/components/chatroom/MessageList.tsx +406 -0
- manigent/web/frontend/src/components/chatroom/OfflineRemedyNote.test.tsx +211 -0
- manigent/web/frontend/src/components/chatroom/OfflineRemedyNote.tsx +182 -0
- manigent/web/frontend/src/components/chatroom/OutsideBadge.tsx +18 -0
- manigent/web/frontend/src/components/chatroom/RoomFlowControl.tsx +49 -0
- manigent/web/frontend/src/components/chatroom/RoomFlowStrip.test.tsx +47 -0
- manigent/web/frontend/src/components/chatroom/RoomFlowStrip.tsx +25 -0
- manigent/web/frontend/src/components/chatroom/SaveToPackModal.tsx +350 -0
- manigent/web/frontend/src/components/chatroom/StagedAttachments.test.tsx +56 -0
- manigent/web/frontend/src/components/chatroom/StagedAttachments.tsx +160 -0
- manigent/web/frontend/src/components/chatroom/SystemNote.tsx +18 -0
- manigent/web/frontend/src/components/chatroom/contactSender.test.tsx +130 -0
- manigent/web/frontend/src/components/chatroom/index.ts +3 -0
- manigent/web/frontend/src/components/chatroom/recipientStatus.test.ts +344 -0
- manigent/web/frontend/src/components/chatroom/recipientStatus.ts +197 -0
- manigent/web/frontend/src/components/common/AnnouncementBanners.test.tsx +221 -0
- manigent/web/frontend/src/components/common/AnnouncementBanners.tsx +180 -0
- manigent/web/frontend/src/components/common/Avatar.test.tsx +50 -0
- manigent/web/frontend/src/components/common/Avatar.tsx +102 -0
- manigent/web/frontend/src/components/common/Badge.tsx +30 -0
- manigent/web/frontend/src/components/common/BrandName.tsx +16 -0
- manigent/web/frontend/src/components/common/ClearHistoryButton.tsx +74 -0
- manigent/web/frontend/src/components/common/CollapsibleHeader.tsx +64 -0
- manigent/web/frontend/src/components/common/ConnectionStatus.test.tsx +56 -0
- manigent/web/frontend/src/components/common/ConnectionStatus.tsx +28 -0
- manigent/web/frontend/src/components/common/DropOverlay.tsx +27 -0
- manigent/web/frontend/src/components/common/InlineEditableTitle.test.tsx +369 -0
- manigent/web/frontend/src/components/common/InlineEditableTitle.tsx +287 -0
- manigent/web/frontend/src/components/common/IsolationUnavailablePanel.tsx +19 -0
- manigent/web/frontend/src/components/common/Loading.tsx +22 -0
- manigent/web/frontend/src/components/common/ModelSelector.tsx +248 -0
- manigent/web/frontend/src/components/common/Overlay.tsx +15 -0
- manigent/web/frontend/src/components/common/ResizeHandle.tsx +52 -0
- manigent/web/frontend/src/components/common/TagAutocompleteInput.test.tsx +92 -0
- manigent/web/frontend/src/components/common/TagAutocompleteInput.tsx +246 -0
- manigent/web/frontend/src/components/common/TagPillInput.tsx +181 -0
- manigent/web/frontend/src/components/common/TeamAndAgentPicker.tsx +83 -0
- manigent/web/frontend/src/components/common/Timestamp.tsx +61 -0
- manigent/web/frontend/src/components/common/VerifiedBadge.tsx +20 -0
- manigent/web/frontend/src/components/common/index.ts +8 -0
- manigent/web/frontend/src/components/composer/PhPopover.tsx +239 -0
- manigent/web/frontend/src/components/composer/PromptEditor.test.tsx +472 -0
- manigent/web/frontend/src/components/composer/PromptEditor.tsx +540 -0
- manigent/web/frontend/src/components/composer/caret.ts +159 -0
- manigent/web/frontend/src/components/composer/placeholders.test.ts +352 -0
- manigent/web/frontend/src/components/composer/placeholders.ts +354 -0
- manigent/web/frontend/src/components/composer/promptEditor.css +161 -0
- manigent/web/frontend/src/components/computer/ComputerPage.test.tsx +452 -0
- manigent/web/frontend/src/components/computer/ComputerPage.tsx +811 -0
- manigent/web/frontend/src/components/computer/ConnectComputerModal.tsx +135 -0
- manigent/web/frontend/src/components/computer/CopyCommand.tsx +77 -0
- manigent/web/frontend/src/components/computer/DisconnectComputerModal.tsx +121 -0
- manigent/web/frontend/src/components/computer/SoftwareCard.tsx +145 -0
- manigent/web/frontend/src/components/computer/TerminalCard.test.tsx +114 -0
- manigent/web/frontend/src/components/computer/TerminalCard.tsx +131 -0
- manigent/web/frontend/src/components/computer/TerminalPanel.tsx +226 -0
- manigent/web/frontend/src/components/computer/TrustPanel.test.tsx +58 -0
- manigent/web/frontend/src/components/computer/TrustPanel.tsx +143 -0
- manigent/web/frontend/src/components/computer/computerCopy.test.ts +322 -0
- manigent/web/frontend/src/components/computer/computerCopy.ts +413 -0
- manigent/web/frontend/src/components/computer/sections.ts +21 -0
- manigent/web/frontend/src/components/computer/terminalProtocol.test.ts +135 -0
- manigent/web/frontend/src/components/computer/terminalProtocol.ts +170 -0
- manigent/web/frontend/src/components/context/ContextGuide.test.tsx +26 -0
- manigent/web/frontend/src/components/context/ContextGuide.tsx +144 -0
- manigent/web/frontend/src/components/context/ContextLanding.tsx +46 -0
- manigent/web/frontend/src/components/desk/CardBand.a11y.test.tsx +138 -0
- manigent/web/frontend/src/components/desk/CardBand.tsx +132 -0
- manigent/web/frontend/src/components/desk/DashTile.tsx +81 -0
- manigent/web/frontend/src/components/desk/DeskAgentPicker.retained.test.tsx +79 -0
- manigent/web/frontend/src/components/desk/DeskAgentPicker.tsx +151 -0
- manigent/web/frontend/src/components/desk/DeskComposer.detachTodo.test.tsx +233 -0
- manigent/web/frontend/src/components/desk/DeskComposer.dispatch.test.tsx +208 -0
- manigent/web/frontend/src/components/desk/DeskComposer.loadTodoDraft.test.tsx +242 -0
- manigent/web/frontend/src/components/desk/DeskComposer.restage.test.tsx +258 -0
- manigent/web/frontend/src/components/desk/DeskComposer.saveTodo.test.tsx +265 -0
- manigent/web/frontend/src/components/desk/DeskComposer.tsx +828 -0
- manigent/web/frontend/src/components/desk/DeskPage.crossHighlight.test.tsx +427 -0
- manigent/web/frontend/src/components/desk/DeskPage.link.test.tsx +271 -0
- manigent/web/frontend/src/components/desk/DeskPage.tsx +1066 -0
- manigent/web/frontend/src/components/desk/DeskPage.welcomeTour.test.tsx +262 -0
- manigent/web/frontend/src/components/desk/DeskSideRail.tsx +100 -0
- manigent/web/frontend/src/components/desk/DeskWelcomeTour.tsx +513 -0
- manigent/web/frontend/src/components/desk/DeskZeroState.tsx +45 -0
- manigent/web/frontend/src/components/desk/LabelChip.tsx +147 -0
- manigent/web/frontend/src/components/desk/LabelFilter.tsx +474 -0
- manigent/web/frontend/src/components/desk/LabelInput.test.tsx +439 -0
- manigent/web/frontend/src/components/desk/LabelInput.tsx +477 -0
- manigent/web/frontend/src/components/desk/LabelManageSheet.test.tsx +384 -0
- manigent/web/frontend/src/components/desk/LabelManageSheet.tsx +498 -0
- manigent/web/frontend/src/components/desk/PhaseRail.test.tsx +170 -0
- manigent/web/frontend/src/components/desk/PhaseRail.tsx +120 -0
- manigent/web/frontend/src/components/desk/PlanBand.test.tsx +655 -0
- manigent/web/frontend/src/components/desk/PlanBand.tsx +216 -0
- manigent/web/frontend/src/components/desk/SaveTodoModal.tsx +126 -0
- manigent/web/frontend/src/components/desk/SopEditor.tsx +280 -0
- manigent/web/frontend/src/components/desk/SopItem.tsx +171 -0
- manigent/web/frontend/src/components/desk/SopRail.test.tsx +517 -0
- manigent/web/frontend/src/components/desk/SopRail.tsx +250 -0
- manigent/web/frontend/src/components/desk/TicketChip.tsx +51 -0
- manigent/web/frontend/src/components/desk/TodoItem.attachments.test.tsx +96 -0
- manigent/web/frontend/src/components/desk/TodoItem.menu.test.tsx +142 -0
- manigent/web/frontend/src/components/desk/TodoItem.tsx +573 -0
- manigent/web/frontend/src/components/desk/TodoRail.longpress.test.tsx +396 -0
- manigent/web/frontend/src/components/desk/TodoRail.test.tsx +1155 -0
- manigent/web/frontend/src/components/desk/TodoRail.tsx +918 -0
- manigent/web/frontend/src/components/desk/TodoRowMenu.tsx +147 -0
- manigent/web/frontend/src/components/desk/UpdateCard.bands.test.tsx +308 -0
- manigent/web/frontend/src/components/desk/UpdateCard.sendBack.test.tsx +444 -0
- manigent/web/frontend/src/components/desk/UpdateCard.tsx +943 -0
- manigent/web/frontend/src/components/desk/UpdateCard.untrusted.test.tsx +161 -0
- manigent/web/frontend/src/components/desk/desk.css +1921 -0
- manigent/web/frontend/src/components/desk/desk.css.test.ts +582 -0
- manigent/web/frontend/src/components/desk/deskBands.test.ts +389 -0
- manigent/web/frontend/src/components/desk/deskBands.ts +226 -0
- manigent/web/frontend/src/components/desk/m16Surfaces.test.ts +134 -0
- manigent/web/frontend/src/components/desk/sopSyntax.ts +73 -0
- manigent/web/frontend/src/components/discovery/AgentDirectory.tsx +71 -0
- manigent/web/frontend/src/components/discovery/AgentFilterBar.tsx +46 -0
- manigent/web/frontend/src/components/discovery/AgentSearchBar.tsx +56 -0
- manigent/web/frontend/src/components/dm/AgentSummaryCard.tsx +154 -0
- manigent/web/frontend/src/components/dm/ComposeFields.tsx +145 -0
- manigent/web/frontend/src/components/dm/DMChatView.flow.test.tsx +374 -0
- manigent/web/frontend/src/components/dm/DMChatView.tsx +841 -0
- manigent/web/frontend/src/components/dm/DMZeroState.tsx +204 -0
- manigent/web/frontend/src/components/dm/DmComposeModal.tsx +301 -0
- manigent/web/frontend/src/components/dm/PersonalizeModal.tsx +366 -0
- manigent/web/frontend/src/components/dm/index.ts +1 -0
- manigent/web/frontend/src/components/files/FileItem.tsx +138 -0
- manigent/web/frontend/src/components/files/FileList.outside.test.tsx +29 -0
- manigent/web/frontend/src/components/files/FileList.tsx +48 -0
- manigent/web/frontend/src/components/files/FilePreview.test.tsx +75 -0
- manigent/web/frontend/src/components/files/FilePreview.tsx +325 -0
- manigent/web/frontend/src/components/files/FileViewerModal.test.tsx +157 -0
- manigent/web/frontend/src/components/files/FileViewerModal.tsx +261 -0
- manigent/web/frontend/src/components/files/HighlightedCode.tsx +39 -0
- manigent/web/frontend/src/components/files/SaveToAgentPanel.test.tsx +156 -0
- manigent/web/frontend/src/components/files/SaveToAgentPanel.tsx +545 -0
- manigent/web/frontend/src/components/files/index.ts +3 -0
- manigent/web/frontend/src/components/hero/AgentAvatar.tsx +66 -0
- manigent/web/frontend/src/components/hero/Button.tsx +66 -0
- manigent/web/frontend/src/components/hero/Hero.tsx +133 -0
- manigent/web/frontend/src/components/homefs/HomeFolderBrowser.test.tsx +393 -0
- manigent/web/frontend/src/components/homefs/HomeFolderBrowser.tsx +792 -0
- manigent/web/frontend/src/components/hub/BridgeDeliveryLine.test.tsx +40 -0
- manigent/web/frontend/src/components/hub/BridgeDeliveryLine.tsx +36 -0
- manigent/web/frontend/src/components/hub/HubAvatar.test.tsx +93 -0
- manigent/web/frontend/src/components/hub/HubAvatar.tsx +33 -0
- manigent/web/frontend/src/components/hub/HubChatView.test.tsx +695 -0
- manigent/web/frontend/src/components/hub/HubChatView.tsx +504 -0
- manigent/web/frontend/src/components/hub/HubContactLabel.test.tsx +92 -0
- manigent/web/frontend/src/components/hub/HubContactLabel.tsx +47 -0
- manigent/web/frontend/src/components/hub/HubDeliveryLine.tsx +49 -0
- manigent/web/frontend/src/components/hub/HubDisclosure.tsx +49 -0
- manigent/web/frontend/src/components/hub/HubEnrollmentDialog.test.tsx +144 -0
- manigent/web/frontend/src/components/hub/HubEnrollmentDialog.tsx +244 -0
- manigent/web/frontend/src/components/hub/HubMessageBody.test.tsx +26 -0
- manigent/web/frontend/src/components/hub/HubMessageBody.tsx +14 -0
- manigent/web/frontend/src/components/hub/HubOfflineConfirm.tsx +45 -0
- manigent/web/frontend/src/components/hub/HubThreadBanner.tsx +33 -0
- manigent/web/frontend/src/components/hub/HubThreadGuard.tsx +59 -0
- manigent/web/frontend/src/components/hub/RemoteAgentCard.test.tsx +50 -0
- manigent/web/frontend/src/components/hub/RemoteAgentCard.tsx +174 -0
- manigent/web/frontend/src/components/hub/RemoteAgentSection.test.tsx +446 -0
- manigent/web/frontend/src/components/hub/RemoteAgentSection.tsx +219 -0
- manigent/web/frontend/src/components/hub/ReportDialog.test.tsx +96 -0
- manigent/web/frontend/src/components/hub/ReportDialog.tsx +162 -0
- manigent/web/frontend/src/components/hub/RetainButton.test.tsx +103 -0
- manigent/web/frontend/src/components/hub/RetainButton.tsx +114 -0
- manigent/web/frontend/src/components/hub/RetainDialog.test.tsx +68 -0
- manigent/web/frontend/src/components/hub/RetainDialog.tsx +115 -0
- manigent/web/frontend/src/components/hub/RetainedList.test.tsx +94 -0
- manigent/web/frontend/src/components/hub/RetainedList.tsx +32 -0
- manigent/web/frontend/src/components/hub/RetainedRow.tsx +129 -0
- manigent/web/frontend/src/components/hub/StandInChip.test.tsx +37 -0
- manigent/web/frontend/src/components/hub/StandInChip.tsx +43 -0
- manigent/web/frontend/src/components/hub/UnusualNameChip.test.tsx +81 -0
- manigent/web/frontend/src/components/hub/UnusualNameChip.tsx +22 -0
- manigent/web/frontend/src/components/hub/hubLint.test.ts +265 -0
- manigent/web/frontend/src/components/landing/ComparisonSection.tsx +92 -0
- manigent/web/frontend/src/components/landing/ConsoleSection.tsx +402 -0
- manigent/web/frontend/src/components/landing/CrewSection.tsx +224 -0
- manigent/web/frontend/src/components/landing/FAQ.tsx +68 -0
- manigent/web/frontend/src/components/landing/Footer.tsx +58 -0
- manigent/web/frontend/src/components/landing/HowItWorks.tsx +117 -0
- manigent/web/frontend/src/components/landing/KnowledgeSection.tsx +91 -0
- manigent/web/frontend/src/components/landing/LandingPage.test.tsx +134 -0
- manigent/web/frontend/src/components/landing/LearningSection.tsx +486 -0
- manigent/web/frontend/src/components/landing/Nav.tsx +68 -0
- manigent/web/frontend/src/components/landing/Pricing.tsx +263 -0
- manigent/web/frontend/src/components/landing/Section.tsx +98 -0
- manigent/web/frontend/src/components/landing/StaffingSection.tsx +122 -0
- manigent/web/frontend/src/components/landing/WhyNowSection.tsx +92 -0
- manigent/web/frontend/src/components/landing/WhyTeamSection.tsx +73 -0
- manigent/web/frontend/src/components/landing/earlyAccess.ts +23 -0
- manigent/web/frontend/src/components/layout/AppLayout.tsx +77 -0
- manigent/web/frontend/src/components/layout/Sidebar.tsx +172 -0
- manigent/web/frontend/src/components/layout/index.ts +2 -0
- manigent/web/frontend/src/components/project/ActivityFeed.tsx +247 -0
- manigent/web/frontend/src/components/project/CreateProjectPage.tsx +543 -0
- manigent/web/frontend/src/components/project/DeleteProjectButton.tsx +39 -0
- manigent/web/frontend/src/components/project/ProjectPlanTab.phase.test.tsx +107 -0
- manigent/web/frontend/src/components/project/ProjectPlanTab.test.tsx +994 -0
- manigent/web/frontend/src/components/project/ProjectPlanTab.tsx +166 -0
- manigent/web/frontend/src/components/project/ProjectReportTab.tsx +139 -0
- manigent/web/frontend/src/components/project/ProjectView.tsx +390 -0
- manigent/web/frontend/src/components/project/index.ts +2 -0
- manigent/web/frontend/src/components/project/plan/PlanAcceptance.test.tsx +460 -0
- manigent/web/frontend/src/components/project/plan/PlanAcceptance.tsx +111 -0
- manigent/web/frontend/src/components/project/plan/PlanBlockEdit.tsx +111 -0
- manigent/web/frontend/src/components/project/plan/PlanBlockEditing.test.tsx +1132 -0
- manigent/web/frontend/src/components/project/plan/PlanBody.test.tsx +495 -0
- manigent/web/frontend/src/components/project/plan/PlanBody.tsx +992 -0
- manigent/web/frontend/src/components/project/plan/PlanCollide.tsx +254 -0
- manigent/web/frontend/src/components/project/plan/PlanCommentList.test.tsx +420 -0
- manigent/web/frontend/src/components/project/plan/PlanCommentList.tsx +391 -0
- manigent/web/frontend/src/components/project/plan/PlanDecisionNudge.test.tsx +226 -0
- manigent/web/frontend/src/components/project/plan/PlanDecisionNudge.tsx +128 -0
- manigent/web/frontend/src/components/project/plan/PlanDestructiveAccept.test.tsx +209 -0
- manigent/web/frontend/src/components/project/plan/PlanDiff.test.tsx +126 -0
- manigent/web/frontend/src/components/project/plan/PlanDiff.tsx +131 -0
- manigent/web/frontend/src/components/project/plan/PlanDiffSeries.test.tsx +500 -0
- manigent/web/frontend/src/components/project/plan/PlanDiffSeries.tsx +125 -0
- manigent/web/frontend/src/components/project/plan/PlanEditor.mounts.test.tsx +504 -0
- manigent/web/frontend/src/components/project/plan/PlanEditor.tsx +2159 -0
- manigent/web/frontend/src/components/project/plan/PlanHistory.tsx +69 -0
- manigent/web/frontend/src/components/project/plan/PlanInlineNotes.test.tsx +2398 -0
- manigent/web/frontend/src/components/project/plan/PlanNoteBase.test.tsx +215 -0
- manigent/web/frontend/src/components/project/plan/PlanNoteRow.test.tsx +562 -0
- manigent/web/frontend/src/components/project/plan/PlanNoteRow.tsx +908 -0
- manigent/web/frontend/src/components/project/plan/PlanQuotePop.tsx +254 -0
- manigent/web/frontend/src/components/project/plan/PlanStaleReconcile.test.tsx +244 -0
- manigent/web/frontend/src/components/project/plan/PlanSubmitWindow.test.tsx +281 -0
- manigent/web/frontend/src/components/project/plan/PlanTray.tsx +184 -0
- manigent/web/frontend/src/components/project/plan/PlanTrayMirror.test.tsx +242 -0
- manigent/web/frontend/src/components/project/plan/plan.css +1151 -0
- manigent/web/frontend/src/components/project/plan/planAnchor.test.tsx +459 -0
- manigent/web/frontend/src/components/project/plan/planAnchor.tsx +277 -0
- manigent/web/frontend/src/components/project/plan/planBlocks.test.tsx +470 -0
- manigent/web/frontend/src/components/project/plan/planBlocks.ts +242 -0
- manigent/web/frontend/src/components/project/plan/planContrast.test.ts +229 -0
- manigent/web/frontend/src/components/project/plan/planDiffs.test.ts +455 -0
- manigent/web/frontend/src/components/project/plan/planDiffs.ts +358 -0
- manigent/web/frontend/src/components/project/plan/planTestServer.ts +741 -0
- manigent/web/frontend/src/components/project/plan/planTransport.test.ts +160 -0
- manigent/web/frontend/src/components/project/plan/planTrayLogic.test.ts +1201 -0
- manigent/web/frontend/src/components/project/plan/planTrayLogic.ts +1164 -0
- manigent/web/frontend/src/components/publicAgents/PublicAgentsAccount.tsx +162 -0
- manigent/web/frontend/src/components/publicAgents/api.ts +55 -0
- manigent/web/frontend/src/components/publicAgents/parts.tsx +54 -0
- manigent/web/frontend/src/components/publicAgents/publicAgents.css +53 -0
- manigent/web/frontend/src/components/publicAgents/publicAgents.test.tsx +86 -0
- manigent/web/frontend/src/components/publicAgents/widget.test.ts +148 -0
- manigent/web/frontend/src/components/publicAgents/widget.ts +40 -0
- manigent/web/frontend/src/components/publicRequests/AgentDrawer.tsx +101 -0
- manigent/web/frontend/src/components/publicRequests/AgentPanel.tsx +173 -0
- manigent/web/frontend/src/components/publicRequests/AgentRankList.tsx +61 -0
- manigent/web/frontend/src/components/publicRequests/MatchRetainButton.tsx +67 -0
- manigent/web/frontend/src/components/publicRequests/ProgressBoard.tsx +74 -0
- manigent/web/frontend/src/components/publicRequests/PublicRequestsPage.tsx +57 -0
- manigent/web/frontend/src/components/publicRequests/RequestHome.tsx +99 -0
- manigent/web/frontend/src/components/publicRequests/RequestRoom.tsx +126 -0
- manigent/web/frontend/src/components/publicRequests/agentView.ts +65 -0
- manigent/web/frontend/src/components/publicRequests/publicRequests.css +209 -0
- manigent/web/frontend/src/components/publicRequests/publicRequests.test.tsx +172 -0
- manigent/web/frontend/src/components/publicRequests/requestCopy.ts +121 -0
- manigent/web/frontend/src/components/sample-request/SampleIdeaList.test.tsx +190 -0
- manigent/web/frontend/src/components/sample-request/SampleIdeaList.tsx +180 -0
- manigent/web/frontend/src/components/sample-request/SampleRequestBody.tsx +276 -0
- manigent/web/frontend/src/components/sample-request/assistantStarterSamples.ts +62 -0
- manigent/web/frontend/src/components/sample-request/sampleIdeaList.css +106 -0
- manigent/web/frontend/src/components/scheduled/CronPicker.tsx +80 -0
- manigent/web/frontend/src/components/scheduled/ScheduleMessageModal.tsx +341 -0
- manigent/web/frontend/src/components/scheduled/ScheduledMessagesList.tsx +157 -0
- manigent/web/frontend/src/components/settings/AgentSettingsPage.tsx +366 -0
- manigent/web/frontend/src/components/settings/ConnectedAccounts.tsx +277 -0
- manigent/web/frontend/src/components/settings/DefaultModelSection.test.tsx +96 -0
- manigent/web/frontend/src/components/settings/DefaultModelSection.tsx +212 -0
- manigent/web/frontend/src/components/settings/DisconnectConfirmModal.tsx +93 -0
- manigent/web/frontend/src/components/settings/FrontDeskSettingsPage.isolation.test.tsx +66 -0
- manigent/web/frontend/src/components/settings/FrontDeskSettingsPage.tsx +134 -0
- manigent/web/frontend/src/components/settings/InvitableAgentsPicker.tsx +182 -0
- manigent/web/frontend/src/components/settings/KnowledgePacksSection.tsx +867 -0
- manigent/web/frontend/src/components/settings/ModelConfigDialog.catalogDriven.test.tsx +79 -0
- manigent/web/frontend/src/components/settings/ModelConfigDialog.tsx +343 -0
- manigent/web/frontend/src/components/settings/ModelConfigSection.smartRouting.test.tsx +109 -0
- manigent/web/frontend/src/components/settings/ModelConfigSection.tsx +599 -0
- manigent/web/frontend/src/components/settings/ReflectionScheduleSection.tsx +170 -0
- manigent/web/frontend/src/components/settings/UserSettingsPage.tsx +168 -0
- manigent/web/frontend/src/components/settings/agent/AgentStatusStrip.tsx +71 -0
- manigent/web/frontend/src/components/settings/agent/BlockedDeploymentsCard.test.tsx +81 -0
- manigent/web/frontend/src/components/settings/agent/BlockedDeploymentsCard.tsx +62 -0
- manigent/web/frontend/src/components/settings/agent/ChannelIsolationLine.tsx +21 -0
- manigent/web/frontend/src/components/settings/agent/ChannelsSection.test.tsx +879 -0
- manigent/web/frontend/src/components/settings/agent/ChannelsSection.tsx +1124 -0
- manigent/web/frontend/src/components/settings/agent/EnvVarsCard.test.ts +15 -0
- manigent/web/frontend/src/components/settings/agent/EnvVarsCard.tsx +301 -0
- manigent/web/frontend/src/components/settings/agent/ExtraDirsList.tsx +85 -0
- manigent/web/frontend/src/components/settings/agent/GeneralSection.tsx +88 -0
- manigent/web/frontend/src/components/settings/agent/HostDisclaimerSlot.test.tsx +32 -0
- manigent/web/frontend/src/components/settings/agent/HostDisclaimerSlot.tsx +30 -0
- manigent/web/frontend/src/components/settings/agent/HubChannelCard.test.tsx +449 -0
- manigent/web/frontend/src/components/settings/agent/HubChannelCard.tsx +312 -0
- manigent/web/frontend/src/components/settings/agent/HubInvitableAgentsCard.test.tsx +83 -0
- manigent/web/frontend/src/components/settings/agent/HubInvitableAgentsCard.tsx +64 -0
- manigent/web/frontend/src/components/settings/agent/HubSendUsageCard.test.tsx +69 -0
- manigent/web/frontend/src/components/settings/agent/HubSendUsageCard.tsx +42 -0
- manigent/web/frontend/src/components/settings/agent/HubTurnOffDialog.tsx +88 -0
- manigent/web/frontend/src/components/settings/agent/IsolationRecheckButton.test.tsx +26 -0
- manigent/web/frontend/src/components/settings/agent/IsolationRecheckButton.tsx +68 -0
- manigent/web/frontend/src/components/settings/agent/KnowledgeSection.tsx +68 -0
- manigent/web/frontend/src/components/settings/agent/LineChannelCard.test.tsx +428 -0
- manigent/web/frontend/src/components/settings/agent/LineChannelCard.tsx +343 -0
- manigent/web/frontend/src/components/settings/agent/RuntimeSection.test.tsx +164 -0
- manigent/web/frontend/src/components/settings/agent/RuntimeSection.tsx +118 -0
- manigent/web/frontend/src/components/settings/agent/StorageSection.tsx +78 -0
- manigent/web/frontend/src/components/settings/agent/WebChatChannelCard.test.tsx +253 -0
- manigent/web/frontend/src/components/settings/agent/WebChatChannelCard.tsx +401 -0
- manigent/web/frontend/src/components/settings/agent/WhatsAppChannelCard.test.tsx +462 -0
- manigent/web/frontend/src/components/settings/agent/WhatsAppChannelCard.tsx +289 -0
- manigent/web/frontend/src/components/settings/agent/agentSettings.test.tsx +109 -0
- manigent/web/frontend/src/components/settings/agent/channelSetupGuides.test.tsx +162 -0
- manigent/web/frontend/src/components/settings/agent/channelSetupGuides.tsx +119 -0
- manigent/web/frontend/src/components/settings/agent/channelsShared.ts +83 -0
- manigent/web/frontend/src/components/settings/agent/fields.tsx +67 -0
- manigent/web/frontend/src/components/settings/agent/sections.ts +36 -0
- manigent/web/frontend/src/components/settings/agent/useAgentSettingsDraft.ts +129 -0
- manigent/web/frontend/src/components/settings/agent/useInstallSelection.ts +38 -0
- manigent/web/frontend/src/components/settings/primitives.tsx +98 -0
- manigent/web/frontend/src/components/shared/ExpandToggle.tsx +45 -0
- manigent/web/frontend/src/components/shared/MarkdownBody.tsx +218 -0
- manigent/web/frontend/src/components/shared/MarkdownBody.untrusted.test.tsx +97 -0
- manigent/web/frontend/src/components/shared/RenderBody.tsx +90 -0
- manigent/web/frontend/src/components/shared/rehypeHideComments.test.tsx +115 -0
- manigent/web/frontend/src/components/shared/rehypeHideComments.ts +124 -0
- manigent/web/frontend/src/components/sharing/AcceptSharePage.tsx +141 -0
- manigent/web/frontend/src/components/sharing/ShareLandingPage.tsx +89 -0
- manigent/web/frontend/src/components/sidebar/AccountChip.test.tsx +337 -0
- manigent/web/frontend/src/components/sidebar/AccountChip.tsx +407 -0
- manigent/web/frontend/src/components/sidebar/ActiveWorkDot.tsx +9 -0
- manigent/web/frontend/src/components/sidebar/AgentProfile.tsx +44 -0
- manigent/web/frontend/src/components/sidebar/AgentRow.tsx +71 -0
- manigent/web/frontend/src/components/sidebar/AgentsPanel.retained.test.tsx +105 -0
- manigent/web/frontend/src/components/sidebar/AgentsPanel.tsx +231 -0
- manigent/web/frontend/src/components/sidebar/AssistantHero.tsx +48 -0
- manigent/web/frontend/src/components/sidebar/ChatroomItem.tsx +48 -0
- manigent/web/frontend/src/components/sidebar/CommandPalette.channelThreads.test.tsx +76 -0
- manigent/web/frontend/src/components/sidebar/CommandPalette.reopen.test.tsx +206 -0
- manigent/web/frontend/src/components/sidebar/CommandPalette.test.tsx +725 -0
- manigent/web/frontend/src/components/sidebar/CommandPalette.tsx +774 -0
- manigent/web/frontend/src/components/sidebar/ComputersPanel.tsx +144 -0
- manigent/web/frontend/src/components/sidebar/DmIcon.tsx +46 -0
- manigent/web/frontend/src/components/sidebar/DmsPanel.tsx +226 -0
- manigent/web/frontend/src/components/sidebar/FrontDeskPanel.channels.test.tsx +582 -0
- manigent/web/frontend/src/components/sidebar/FrontDeskPanel.test.tsx +151 -0
- manigent/web/frontend/src/components/sidebar/FrontDeskPanel.tsx +454 -0
- manigent/web/frontend/src/components/sidebar/HotkeysHelp.tsx +101 -0
- manigent/web/frontend/src/components/sidebar/MessageHitRow.test.tsx +84 -0
- manigent/web/frontend/src/components/sidebar/MessageHitRow.tsx +57 -0
- manigent/web/frontend/src/components/sidebar/MyDeskRailPanel.crossHighlight.test.tsx +247 -0
- manigent/web/frontend/src/components/sidebar/MyDeskRailPanel.delete.test.tsx +273 -0
- manigent/web/frontend/src/components/sidebar/MyDeskRailPanel.tsx +351 -0
- manigent/web/frontend/src/components/sidebar/PanelShell.tsx +48 -0
- manigent/web/frontend/src/components/sidebar/ProjectItem.tsx +161 -0
- manigent/web/frontend/src/components/sidebar/ProjectRow.tsx +151 -0
- manigent/web/frontend/src/components/sidebar/ProjectsPanel.tsx +80 -0
- manigent/web/frontend/src/components/sidebar/PublicPanel.counterpart.test.tsx +85 -0
- manigent/web/frontend/src/components/sidebar/PublicPanel.hub.test.tsx +147 -0
- manigent/web/frontend/src/components/sidebar/PublicPanel.tsx +271 -0
- manigent/web/frontend/src/components/sidebar/RecencyHeader.tsx +17 -0
- manigent/web/frontend/src/components/sidebar/ScheduledPanel.tsx +58 -0
- manigent/web/frontend/src/components/sidebar/SidebarAvatar.tsx +128 -0
- manigent/web/frontend/src/components/sidebar/SidebarRail.tsx +163 -0
- manigent/web/frontend/src/components/sidebar/TeamGroup.tsx +67 -0
- manigent/web/frontend/src/components/sidebar/dmPrefill.test.ts +69 -0
- manigent/web/frontend/src/components/sidebar/dmPrefill.ts +80 -0
- manigent/web/frontend/src/components/sidebar/index.ts +18 -0
- manigent/web/frontend/src/components/sidebar/railShortcuts.ts +18 -0
- manigent/web/frontend/src/components/today/lib.test.ts +70 -0
- manigent/web/frontend/src/components/today/lib.ts +296 -0
- manigent/web/frontend/src/components/today/today.css +113 -0
- manigent/web/frontend/src/components/welcome/RunnerSetup.css +253 -0
- manigent/web/frontend/src/components/welcome/RunnerSetup.tsx +148 -0
- manigent/web/frontend/src/components/welcome/WelcomePage.css +383 -0
- manigent/web/frontend/src/components/welcome/WelcomePage.tsx +329 -0
- manigent/web/frontend/src/components/welcome/welcomeCopy.test.ts +382 -0
- manigent/web/frontend/src/components/welcome/welcomeCopy.ts +313 -0
- manigent/web/frontend/src/config/llmProviders.test.ts +161 -0
- manigent/web/frontend/src/config/llmProviders.ts +109 -0
- manigent/web/frontend/src/config/providerIds.fixture.json +13 -0
- manigent/web/frontend/src/hooks/accountNavigation.test.tsx +138 -0
- manigent/web/frontend/src/hooks/index.ts +10 -0
- manigent/web/frontend/src/hooks/useActiveWorkBootstrap.ts +86 -0
- manigent/web/frontend/src/hooks/useAgentAccess.test.tsx +30 -0
- manigent/web/frontend/src/hooks/useAgentAccess.ts +204 -0
- manigent/web/frontend/src/hooks/useAgentSampleRequests.ts +27 -0
- manigent/web/frontend/src/hooks/useAgentSearch.ts +10 -0
- manigent/web/frontend/src/hooks/useAgents.ts +46 -0
- manigent/web/frontend/src/hooks/useAnnouncements.test.ts +112 -0
- manigent/web/frontend/src/hooks/useAnnouncements.ts +100 -0
- manigent/web/frontend/src/hooks/useAssistantAgent.ts +24 -0
- manigent/web/frontend/src/hooks/useAutoResizeTextarea.ts +18 -0
- manigent/web/frontend/src/hooks/useBridgeDeliveries.test.tsx +79 -0
- manigent/web/frontend/src/hooks/useBriefTabs.ts +122 -0
- manigent/web/frontend/src/hooks/useChannelThreads.ts +69 -0
- manigent/web/frontend/src/hooks/useComposeForm.ts +80 -0
- manigent/web/frontend/src/hooks/useComputers.ts +123 -0
- manigent/web/frontend/src/hooks/useContextFirstItem.ts +118 -0
- manigent/web/frontend/src/hooks/useCreateProject.ts +78 -0
- manigent/web/frontend/src/hooks/useDebouncedValue.ts +16 -0
- manigent/web/frontend/src/hooks/useDeleteProject.ts +27 -0
- manigent/web/frontend/src/hooks/useDeskDispatch.test.tsx +170 -0
- manigent/web/frontend/src/hooks/useDeskDispatch.ts +135 -0
- manigent/web/frontend/src/hooks/useDeskReadState.test.tsx +85 -0
- manigent/web/frontend/src/hooks/useDeskReadState.ts +150 -0
- manigent/web/frontend/src/hooks/useDeskRecentlyDone.test.tsx +222 -0
- manigent/web/frontend/src/hooks/useDeskRecentlyDone.ts +225 -0
- manigent/web/frontend/src/hooks/useDeskTour.ts +37 -0
- manigent/web/frontend/src/hooks/useDeskUpdates.channelThreads.test.tsx +91 -0
- manigent/web/frontend/src/hooks/useDeskUpdates.hubThreads.test.tsx +93 -0
- manigent/web/frontend/src/hooks/useDeskUpdates.ts +353 -0
- manigent/web/frontend/src/hooks/useDisconnectIntegration.ts +23 -0
- manigent/web/frontend/src/hooks/useDmThreads.ts +99 -0
- manigent/web/frontend/src/hooks/useFileDropzone.ts +93 -0
- manigent/web/frontend/src/hooks/useFileUpload.ts +38 -0
- manigent/web/frontend/src/hooks/useFiles.ts +98 -0
- manigent/web/frontend/src/hooks/useHub.test.tsx +237 -0
- manigent/web/frontend/src/hooks/useHub.ts +502 -0
- manigent/web/frontend/src/hooks/useInstall.ts +82 -0
- manigent/web/frontend/src/hooks/useLabels.test.tsx +294 -0
- manigent/web/frontend/src/hooks/useLabels.ts +287 -0
- manigent/web/frontend/src/hooks/useLogout.ts +49 -0
- manigent/web/frontend/src/hooks/useMentionDetection.ts +90 -0
- manigent/web/frontend/src/hooks/useMessageAttachments.deskLimit.test.ts +264 -0
- manigent/web/frontend/src/hooks/useMessageAttachments.ts +283 -0
- manigent/web/frontend/src/hooks/useMessageDeepLink.test.tsx +70 -0
- manigent/web/frontend/src/hooks/useMessageDeepLink.ts +32 -0
- manigent/web/frontend/src/hooks/useMessageSearch.ts +78 -0
- manigent/web/frontend/src/hooks/useModelConfigs.ts +178 -0
- manigent/web/frontend/src/hooks/useMyAgents.ts +18 -0
- manigent/web/frontend/src/hooks/usePointerReorder.ts +270 -0
- manigent/web/frontend/src/hooks/usePrefersReducedMotion.ts +18 -0
- manigent/web/frontend/src/hooks/useProjectPlan.ts +36 -0
- manigent/web/frontend/src/hooks/useProjectReport.ts +19 -0
- manigent/web/frontend/src/hooks/useProjects.ts +104 -0
- manigent/web/frontend/src/hooks/useProjectsWithChatrooms.ts +97 -0
- manigent/web/frontend/src/hooks/usePublicRequests.ts +89 -0
- manigent/web/frontend/src/hooks/useRecentAgents.ts +38 -0
- manigent/web/frontend/src/hooks/useRenameProject.test.tsx +185 -0
- manigent/web/frontend/src/hooks/useRenameProject.ts +192 -0
- manigent/web/frontend/src/hooks/useRoomTrust.ts +56 -0
- manigent/web/frontend/src/hooks/useSharing.ts +46 -0
- manigent/web/frontend/src/hooks/useSopRecents.ts +55 -0
- manigent/web/frontend/src/hooks/useSopSchedules.ts +25 -0
- manigent/web/frontend/src/hooks/useSops.ts +99 -0
- manigent/web/frontend/src/hooks/useSwitchAccount.ts +41 -0
- manigent/web/frontend/src/hooks/useTeamGroups.ts +48 -0
- manigent/web/frontend/src/hooks/useThreadOutbox.ts +68 -0
- manigent/web/frontend/src/hooks/useTodos.add.test.tsx +89 -0
- manigent/web/frontend/src/hooks/useTodos.linkProject.test.tsx +115 -0
- manigent/web/frontend/src/hooks/useTodos.saveDraft.test.tsx +188 -0
- manigent/web/frontend/src/hooks/useTodos.ts +396 -0
- manigent/web/frontend/src/hooks/useUntrustedBodies.test.tsx +87 -0
- manigent/web/frontend/src/hooks/useUntrustedBodies.ts +51 -0
- manigent/web/frontend/src/hooks/useWebSocket.briefTab.test.tsx +148 -0
- manigent/web/frontend/src/hooks/useWebSocket.channelThreads.test.tsx +82 -0
- manigent/web/frontend/src/hooks/useWebSocket.hostSync.test.tsx +92 -0
- manigent/web/frontend/src/hooks/useWebSocket.hub.test.tsx +114 -0
- manigent/web/frontend/src/hooks/useWebSocket.labelSync.test.tsx +168 -0
- manigent/web/frontend/src/hooks/useWebSocket.plan.test.tsx +168 -0
- manigent/web/frontend/src/hooks/useWebSocket.reconnect.test.tsx +166 -0
- manigent/web/frontend/src/hooks/useWebSocket.runnerVersions.test.tsx +167 -0
- manigent/web/frontend/src/hooks/useWebSocket.ts +495 -0
- manigent/web/frontend/src/hooks/useWindowFileDropGuard.ts +33 -0
- manigent/web/frontend/src/landing.tsx +11 -0
- manigent/web/frontend/src/main.tsx +17 -0
- manigent/web/frontend/src/private-beta.tsx +10 -0
- manigent/web/frontend/src/public.tsx +42 -0
- manigent/web/frontend/src/queryClient.ts +16 -0
- manigent/web/frontend/src/stores/activeWorkStore.ts +88 -0
- manigent/web/frontend/src/stores/announcementStore.test.ts +217 -0
- manigent/web/frontend/src/stores/announcementStore.ts +169 -0
- manigent/web/frontend/src/stores/authStore.multiSession.test.ts +304 -0
- manigent/web/frontend/src/stores/authStore.test.ts +235 -0
- manigent/web/frontend/src/stores/authStore.ts +693 -0
- manigent/web/frontend/src/stores/deskLabelViewStore.test.ts +162 -0
- manigent/web/frontend/src/stores/deskLabelViewStore.ts +234 -0
- manigent/web/frontend/src/stores/deskLinkStore.ts +54 -0
- manigent/web/frontend/src/stores/deskStore.test.ts +53 -0
- manigent/web/frontend/src/stores/deskStore.ts +93 -0
- manigent/web/frontend/src/stores/heldPostsStore.ts +78 -0
- manigent/web/frontend/src/stores/mcpAuthStore.ts +52 -0
- manigent/web/frontend/src/stores/modelSelectionStore.ts +33 -0
- manigent/web/frontend/src/stores/perUserStores.ts +79 -0
- manigent/web/frontend/src/stores/runnerVersionStore.test.ts +81 -0
- manigent/web/frontend/src/stores/runnerVersionStore.ts +60 -0
- manigent/web/frontend/src/stores/skillAuthStore.ts +54 -0
- manigent/web/frontend/src/stores/switchReset.test.ts +236 -0
- manigent/web/frontend/src/stores/tokenExp.ts +32 -0
- manigent/web/frontend/src/stores/uiStore.ts +186 -0
- manigent/web/frontend/src/stores/unreadStore.ts +204 -0
- manigent/web/frontend/src/stores/unsavedGuard.ts +22 -0
- manigent/web/frontend/src/styles/design/fonts/JetBrainsMono-Latin.woff2 +0 -0
- manigent/web/frontend/src/styles/design/fonts/Nunito-Latin.woff2 +0 -0
- manigent/web/frontend/src/styles/design/fonts/Nunito-LatinExt.woff2 +0 -0
- manigent/web/frontend/src/styles/design/tokens.css +160 -0
- manigent/web/frontend/src/styles/homepage.css +242 -0
- manigent/web/frontend/src/styles/index.css +126 -0
- manigent/web/frontend/src/styles/landing.css +52 -0
- manigent/web/frontend/src/test/authFixtures.ts +154 -0
- manigent/web/frontend/src/test/fetchHarness.ts +203 -0
- manigent/web/frontend/src/test/fixtures/channelThreads.smoke.json +42 -0
- manigent/web/frontend/src/test/hubFixtures.ts +212 -0
- manigent/web/frontend/src/test/queryWrapper.tsx +9 -0
- manigent/web/frontend/src/test/suiteHygiene.test.ts +212 -0
- manigent/web/frontend/src/types/channelThreadName.test.ts +16 -0
- manigent/web/frontend/src/types/index.ts +903 -0
- manigent/web/frontend/src/utils/agentAccessCopy.test.ts +53 -0
- manigent/web/frontend/src/utils/agentAccessCopy.ts +231 -0
- manigent/web/frontend/src/utils/agentDisplay.ts +81 -0
- manigent/web/frontend/src/utils/briefSchedule.ts +25 -0
- manigent/web/frontend/src/utils/channelThreads.test.ts +109 -0
- manigent/web/frontend/src/utils/channelThreads.ts +179 -0
- manigent/web/frontend/src/utils/chatroomDisplay.ts +11 -0
- manigent/web/frontend/src/utils/deskLinks.test.ts +155 -0
- manigent/web/frontend/src/utils/deskLinks.ts +115 -0
- manigent/web/frontend/src/utils/deskRecipient.ts +29 -0
- manigent/web/frontend/src/utils/formatDate.ts +102 -0
- manigent/web/frontend/src/utils/frontDesk.ts +65 -0
- manigent/web/frontend/src/utils/hubChannelView.test.ts +178 -0
- manigent/web/frontend/src/utils/hubChannelView.ts +307 -0
- manigent/web/frontend/src/utils/hubDelivery.test.ts +105 -0
- manigent/web/frontend/src/utils/hubDelivery.ts +137 -0
- manigent/web/frontend/src/utils/hubDisplay.test.ts +157 -0
- manigent/web/frontend/src/utils/hubDisplay.ts +221 -0
- manigent/web/frontend/src/utils/hubThread.test.ts +184 -0
- manigent/web/frontend/src/utils/hubThread.ts +247 -0
- manigent/web/frontend/src/utils/labelErrors.test.ts +127 -0
- manigent/web/frontend/src/utils/labelErrors.ts +123 -0
- manigent/web/frontend/src/utils/labelView.test.ts +846 -0
- manigent/web/frontend/src/utils/labelView.ts +760 -0
- manigent/web/frontend/src/utils/legalUrls.ts +11 -0
- manigent/web/frontend/src/utils/messageSender.test.ts +32 -0
- manigent/web/frontend/src/utils/messageSender.ts +29 -0
- manigent/web/frontend/src/utils/oauthScopeCopy.ts +73 -0
- manigent/web/frontend/src/utils/personalize.ts +49 -0
- manigent/web/frontend/src/utils/reachableAgents.test.ts +36 -0
- manigent/web/frontend/src/utils/reachableAgents.ts +24 -0
- manigent/web/frontend/src/utils/recencyBuckets.ts +61 -0
- manigent/web/frontend/src/utils/roomTrust.test.ts +94 -0
- manigent/web/frontend/src/utils/roomTrust.ts +111 -0
- manigent/web/frontend/src/utils/snippetHighlight.test.ts +63 -0
- manigent/web/frontend/src/utils/snippetHighlight.ts +42 -0
- manigent/web/frontend/src/utils/sopRecipient.ts +37 -0
- manigent/web/frontend/src/utils/sopRequest.test.ts +91 -0
- manigent/web/frontend/src/utils/sopRequest.ts +68 -0
- manigent/web/frontend/src/utils/sopSchedule.ts +26 -0
- manigent/web/frontend/src/utils/sopSection.test.ts +148 -0
- manigent/web/frontend/src/utils/sopSection.ts +143 -0
- manigent/web/frontend/src/utils/textSearch.test.ts +60 -0
- manigent/web/frontend/src/utils/textSearch.ts +43 -0
- manigent/web/frontend/src/utils/thoughtPartner.ts +26 -0
- manigent/web/frontend/src/utils/threadName.test.ts +131 -0
- manigent/web/frontend/src/utils/threadName.ts +122 -0
- manigent/web/frontend/src/utils/ticketView.test.ts +296 -0
- manigent/web/frontend/src/utils/ticketView.ts +175 -0
- manigent/web/frontend/src/utils/todoAttachments.desiredState.test.ts +180 -0
- manigent/web/frontend/src/utils/todoAttachments.ts +126 -0
- manigent/web/frontend/src/utils/todoDraft.test.ts +84 -0
- manigent/web/frontend/src/utils/todoDraft.ts +46 -0
- manigent/web/frontend/src/utils/todoSearch.test.ts +82 -0
- manigent/web/frontend/src/utils/todoSearch.ts +43 -0
- manigent/web/frontend/src/utils/versionMatch.test.ts +295 -0
- manigent/web/frontend/src/utils/versionMatch.ts +245 -0
- manigent/web/frontend/src/vite-env.d.ts +1 -0
- manigent/web/frontend/tailwind.config.js +86 -0
- manigent/web/frontend/tos.html +188 -0
- manigent/web/frontend/tsconfig.dts.json +25 -0
- manigent/web/frontend/tsconfig.json +26 -0
- manigent/web/frontend/tsconfig.node.json +11 -0
- manigent/web/frontend/vite.config.ts +41 -0
- manigent/web/frontend/vitest.config.ts +16 -0
- manigent/ws_edge/app.py +514 -0
- manigent/ws_edge/auth.py +104 -0
- manigent/ws_edge/link.py +282 -0
- manigent/ws_edge/registry.py +206 -0
- manigent/ws_edge/terminal_relay.py +269 -0
- manigent_server-0.1.0.dist-info/METADATA +138 -0
- manigent_server-0.1.0.dist-info/RECORD +1004 -0
- manigent_server-0.1.0.dist-info/WHEEL +4 -0
- manigent_server-0.1.0.dist-info/entry_points.txt +2 -0
- manigent_server-0.1.0.dist-info/licenses/LICENSE +68 -0
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { createElement, type ReactNode } from 'react'
|
|
3
|
+
import { cleanup, fireEvent, render, screen, waitFor, within } from '@testing-library/react'
|
|
4
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
5
|
+
import type { PlanNote, PlanSection } from '../../../api/endpoints/projectPlans'
|
|
6
|
+
import { FakePlanServer, routeTo } from './planTestServer'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* THE SERIES, AND THE STACK, DRIVEN THROUGH THE REAL EDITOR.
|
|
10
|
+
*
|
|
11
|
+
* The thing being fixed is a SEQUENCE, not a render: two proposals on one
|
|
12
|
+
* section used to draw as two independent cards, each with a small, clean,
|
|
13
|
+
* plausible-looking diff, and nothing on screen said they were mutually
|
|
14
|
+
* exclusive until the user clicked Accept on the second and a modal appeared.
|
|
15
|
+
* The claim of this change is that the reveal moves EARLIER and that both
|
|
16
|
+
* changes can now land — neither of which a component mounted in isolation can
|
|
17
|
+
* demonstrate, because both depend on the tray moving between renders.
|
|
18
|
+
*
|
|
19
|
+
* `PlanDiff` is stubbed as a `<pre>` of the raw unified diff: `diff2html` is not
|
|
20
|
+
* under test, and the diff TEXT is exactly what these assertions are about.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const routes = { current: null as ReturnType<typeof routeTo> | null }
|
|
24
|
+
|
|
25
|
+
vi.mock('../../../api/client', async () => {
|
|
26
|
+
const actual = await vi.importActual<typeof import('../../../api/client')>('../../../api/client')
|
|
27
|
+
return {
|
|
28
|
+
...actual,
|
|
29
|
+
get: (path: string) => routes.current!.get(path),
|
|
30
|
+
post: (path: string, body?: unknown) => routes.current!.post(path, body),
|
|
31
|
+
put: (path: string, body?: unknown) => routes.current!.put(path, body),
|
|
32
|
+
del: (path: string) => routes.current!.del(path),
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
vi.mock('./PlanDiff', () => ({
|
|
37
|
+
PlanDiff: ({ text }: { text: string }) =>
|
|
38
|
+
createElement('pre', { 'data-testid': 'plan-diff' }, text),
|
|
39
|
+
}))
|
|
40
|
+
|
|
41
|
+
const { PlanEditor } = await import('./PlanEditor')
|
|
42
|
+
|
|
43
|
+
const PID = 'p-1'
|
|
44
|
+
|
|
45
|
+
/* A section with FOUR independently editable lines, because that is what makes
|
|
46
|
+
* two proposals compose. On a one-line section every proposal collides with
|
|
47
|
+
* every other and the stack has nothing to prove. */
|
|
48
|
+
const MILESTONES = [
|
|
49
|
+
'## Milestones',
|
|
50
|
+
'',
|
|
51
|
+
'- [ ] **M1** — spec',
|
|
52
|
+
'- [ ] **M2** — build',
|
|
53
|
+
'- [ ] **M3** — polish',
|
|
54
|
+
'- [ ] **M4** — ship',
|
|
55
|
+
'',
|
|
56
|
+
].join('\n')
|
|
57
|
+
const BODY = ['# Project Plan: demo', '', MILESTONES].join('\n')
|
|
58
|
+
|
|
59
|
+
const SECTIONS: PlanSection[] = [
|
|
60
|
+
{ id: 'milestones', heading: 'Milestones', depth: 2, boxes: [0, 4], char_start: 0, char_end: 0 },
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
/** @backend ticks M1. */
|
|
64
|
+
const BACKEND_TEXT = MILESTONES.replace('- [ ] **M1** — spec', '- [x] **M1** — spec (done)')
|
|
65
|
+
/** @frontend ticks M4 — a different line, three away, so the fold fits. */
|
|
66
|
+
const FRONTEND_TEXT = MILESTONES.replace('- [ ] **M4** — ship', '- [x] **M4** — ship (done)')
|
|
67
|
+
/** @devops rewrites M1 — the SAME line @backend ticked, so the fold refuses. */
|
|
68
|
+
const DEVOPS_TEXT = MILESTONES.replace('- [ ] **M1** — spec', '- [ ] **M1** — spec and scope')
|
|
69
|
+
|
|
70
|
+
function note(over: Partial<PlanNote>): PlanNote {
|
|
71
|
+
return {
|
|
72
|
+
id: 'n-1',
|
|
73
|
+
section: 'milestones',
|
|
74
|
+
to: 'user',
|
|
75
|
+
by: 'backend',
|
|
76
|
+
at: 't',
|
|
77
|
+
status: 'open',
|
|
78
|
+
kind: 'proposal',
|
|
79
|
+
layer: 'spec',
|
|
80
|
+
comment: '',
|
|
81
|
+
proposal: BACKEND_TEXT,
|
|
82
|
+
base_section: MILESTONES,
|
|
83
|
+
quote: '',
|
|
84
|
+
reply_to: '',
|
|
85
|
+
round: '',
|
|
86
|
+
conflict: false,
|
|
87
|
+
resolved_by: '',
|
|
88
|
+
resolved_at: '',
|
|
89
|
+
resolution: '',
|
|
90
|
+
revision: 1,
|
|
91
|
+
has_proposal: true,
|
|
92
|
+
proposes_delete: false,
|
|
93
|
+
bootstrap: false,
|
|
94
|
+
sent: false,
|
|
95
|
+
replies: [],
|
|
96
|
+
section_missing: false,
|
|
97
|
+
section_new: false,
|
|
98
|
+
section_changed: false,
|
|
99
|
+
display_diff: '',
|
|
100
|
+
...over,
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let server: FakePlanServer
|
|
105
|
+
let qc: QueryClient
|
|
106
|
+
/** Every `GET` the editor makes, counted — the "no request" claim below is the
|
|
107
|
+
* whole reason the series is generated in the browser, so it is asserted
|
|
108
|
+
* rather than asserted-about. */
|
|
109
|
+
let gets = 0
|
|
110
|
+
|
|
111
|
+
const wrapper = ({ children }: { children: ReactNode }) =>
|
|
112
|
+
createElement(QueryClientProvider, { client: qc }, children)
|
|
113
|
+
|
|
114
|
+
beforeEach(() => {
|
|
115
|
+
server = new FakePlanServer(BODY, SECTIONS)
|
|
116
|
+
const real = routeTo(server, PID)
|
|
117
|
+
gets = 0
|
|
118
|
+
routes.current = {
|
|
119
|
+
...real,
|
|
120
|
+
get: (path: string) => {
|
|
121
|
+
gets += 1
|
|
122
|
+
return real.get(path)
|
|
123
|
+
},
|
|
124
|
+
}
|
|
125
|
+
qc = new QueryClient({ defaultOptions: { queries: { retry: false, gcTime: 0 } } })
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
afterEach(() => {
|
|
129
|
+
cleanup()
|
|
130
|
+
qc.clear()
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
const card = async (id: string) => {
|
|
134
|
+
const acts = await screen.findByTestId(`plan-note-acts-${id}`)
|
|
135
|
+
return acts.closest('.plan-note') as HTMLElement
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const accept = async (id: string) =>
|
|
139
|
+
fireEvent.click(
|
|
140
|
+
within(await screen.findByTestId(`plan-note-acts-${id}`)).getByRole('button', {
|
|
141
|
+
name: 'Accept',
|
|
142
|
+
}),
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
async function withTwoProposals(second = FRONTEND_TEXT) {
|
|
146
|
+
server.notes.push(
|
|
147
|
+
note({ id: 'n1', by: 'backend', proposal: BACKEND_TEXT }),
|
|
148
|
+
note({ id: 'n2', by: 'frontend', proposal: second }),
|
|
149
|
+
)
|
|
150
|
+
render(createElement(PlanEditor, { projectId: PID, density: 'full' }), { wrapper })
|
|
151
|
+
await screen.findByTestId('plan-body')
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
describe('the reveal moves earlier — a card names its rival before any click', () => {
|
|
155
|
+
/**
|
|
156
|
+
* THE DEFECT THIS CHANGE IS ABOUT. Two proposals used to render as two cards
|
|
157
|
+
* with no cross-talk at all: the only aggregate on the surface was
|
|
158
|
+
* `openNotesOn`, a count that treats a comment and a proposal alike. That a
|
|
159
|
+
* proposal is a whole-section replacement — and therefore that these two
|
|
160
|
+
* cannot both be staged — was invisible until Accept was clicked.
|
|
161
|
+
*/
|
|
162
|
+
it('says who else has proposed here, on both cards, with nothing staged', async () => {
|
|
163
|
+
await withTwoProposals()
|
|
164
|
+
expect((await card('n1')).textContent).toContain('@frontend has also proposed a change')
|
|
165
|
+
expect((await card('n2')).textContent).toContain('@backend has also proposed a change')
|
|
166
|
+
expect(server.draft).toHaveLength(0)
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
/** THE CONSEQUENCE IS ONE CLICK AWAY AND NOT ON SCREEN BY DEFAULT. Three
|
|
170
|
+
* proposals on one section would otherwise stack six diffs in a note row, so
|
|
171
|
+
* the rival steps sit behind a disclosure — named in words, not counted. */
|
|
172
|
+
it('keeps the rival diff behind a disclosure until it is opened', async () => {
|
|
173
|
+
await withTwoProposals()
|
|
174
|
+
const first = await card('n1')
|
|
175
|
+
expect(within(first).getAllByTestId('plan-diff')).toHaveLength(1)
|
|
176
|
+
|
|
177
|
+
fireEvent.click(within(first).getByTestId('plan-diff-series-toggle'))
|
|
178
|
+
|
|
179
|
+
const diffs = within(first).getAllByTestId('plan-diff')
|
|
180
|
+
expect(diffs).toHaveLength(2)
|
|
181
|
+
// @frontend's tick, added — and @backend's own, taken away. THAT is the
|
|
182
|
+
// fact the two independent cards hid.
|
|
183
|
+
expect(diffs[1].textContent).toContain('+- [x] **M4** — ship (done)')
|
|
184
|
+
expect(diffs[1].textContent).toContain('-- [x] **M1** — spec (done)')
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
/** A LONE PROPOSAL IS UNTOUCHED, which is the compatibility promise: one
|
|
188
|
+
* step renders bare, with no disclosure and no summary line. */
|
|
189
|
+
it('adds nothing at all to a lone proposal', async () => {
|
|
190
|
+
server.notes.push(note({ id: 'n1', by: 'backend', proposal: BACKEND_TEXT }))
|
|
191
|
+
render(createElement(PlanEditor, { projectId: PID, density: 'full' }), { wrapper })
|
|
192
|
+
await screen.findByTestId('plan-body')
|
|
193
|
+
const only = await card('n1')
|
|
194
|
+
expect(within(only).getAllByTestId('plan-diff')).toHaveLength(1)
|
|
195
|
+
expect(within(only).queryByTestId('plan-diff-series-toggle')).toBeNull()
|
|
196
|
+
})
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
describe("accepting one re-heads the others, with no request", () => {
|
|
200
|
+
/**
|
|
201
|
+
* THE REASON THE SERIES IS GENERATED IN THE BROWSER. Accepting writes ZERO
|
|
202
|
+
* bytes — it stages a tray row — so the SERVER still believes the section
|
|
203
|
+
* reads as it did, and `section_changed` is `false` on every note. A
|
|
204
|
+
* server-generated series would keep drawing @frontend's proposal against the
|
|
205
|
+
* old text. The tray's text is the head here, so the card re-draws on the
|
|
206
|
+
* next render.
|
|
207
|
+
*/
|
|
208
|
+
it("diffs the second proposal against the first's staged text", async () => {
|
|
209
|
+
await withTwoProposals()
|
|
210
|
+
const before = gets
|
|
211
|
+
await accept('n1')
|
|
212
|
+
await screen.findByTestId('plan-tray')
|
|
213
|
+
|
|
214
|
+
const second = await card('n2')
|
|
215
|
+
await waitFor(() =>
|
|
216
|
+
expect(within(second).getByTestId('plan-diff-series-toggle').textContent).toContain(
|
|
217
|
+
'This section has moved',
|
|
218
|
+
),
|
|
219
|
+
)
|
|
220
|
+
fireEvent.click(within(second).getByTestId('plan-diff-series-toggle'))
|
|
221
|
+
const diffs = within(second).getAllByTestId('plan-diff')
|
|
222
|
+
// Read against what the tray now holds: taking @frontend's alone would undo
|
|
223
|
+
// @backend's tick.
|
|
224
|
+
expect(diffs[1].textContent).toContain('-- [x] **M1** — spec (done)')
|
|
225
|
+
expect(diffs[1].textContent).toContain('+- [x] **M4** — ship (done)')
|
|
226
|
+
// The server was not asked anything to produce that.
|
|
227
|
+
expect(gets).toBe(before)
|
|
228
|
+
})
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
describe('Keep both — a stack of two proposals on one section', () => {
|
|
232
|
+
/**
|
|
233
|
+
* THE ASK, END TO END: accept @backend's, read @frontend's against it, and
|
|
234
|
+
* take that too, so BOTH land. ONE row LANDS, carrying both ticks —
|
|
235
|
+
* `_collapse_text_rows` keeps the LAST text row per section and `apply_edits`
|
|
236
|
+
* splices its text verbatim, so nothing about the write path is softened to
|
|
237
|
+
* make this work.
|
|
238
|
+
*
|
|
239
|
+
* THE WINNER IS THE SAME ROW ON BOTH BRANCHES, WHICH IS WHY THIS RUNS TWICE.
|
|
240
|
+
* `records_folds` selects what happens to the row that LOST the section — a
|
|
241
|
+
* dismissal on one branch, a live row carrying one boolean on the other — and
|
|
242
|
+
* it must not touch the text that lands. Reading the LAST text row rather
|
|
243
|
+
* than the only one is what makes that claim testable instead of assumed.
|
|
244
|
+
*/
|
|
245
|
+
it.each([false, true])('stages a row carrying both changes (records_folds=%s)', async (recordsFolds) => {
|
|
246
|
+
server.recordsFolds = recordsFolds
|
|
247
|
+
await withTwoProposals()
|
|
248
|
+
await accept('n1')
|
|
249
|
+
await screen.findByTestId('plan-tray')
|
|
250
|
+
await accept('n2')
|
|
251
|
+
|
|
252
|
+
const collide = await screen.findByRole('group', { name: 'Two versions of milestones' })
|
|
253
|
+
fireEvent.click(within(collide).getByRole('button', { name: 'Keep both' }))
|
|
254
|
+
|
|
255
|
+
await waitFor(() => expect(server.draft.filter((r) => r.kind === 'accept')).toHaveLength(recordsFolds ? 2 : 1))
|
|
256
|
+
const accepts = server.draft.filter((r) => r.kind === 'accept')
|
|
257
|
+
const winner = accepts[accepts.length - 1]
|
|
258
|
+
expect(winner.note_id).toBe('n2')
|
|
259
|
+
expect(winner.text).toContain('- [x] **M1** — spec (done)')
|
|
260
|
+
expect(winner.text).toContain('- [x] **M4** — ship (done)')
|
|
261
|
+
// Untouched lines are untouched, and the section keeps its shape.
|
|
262
|
+
expect(winner.text).toContain('- [ ] **M2** — build')
|
|
263
|
+
expect(winner.text).toBe(
|
|
264
|
+
MILESTONES.replace('- [ ] **M1** — spec', '- [x] **M1** — spec (done)').replace(
|
|
265
|
+
'- [ ] **M4** — ship',
|
|
266
|
+
'- [x] **M4** — ship (done)',
|
|
267
|
+
),
|
|
268
|
+
)
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* WHAT THE FOLDED-AWAY AUTHOR IS TOLD WHEN THE SERVER CANNOT SAY IT, AND WHY
|
|
273
|
+
* IT IS A DISMISSAL THERE.
|
|
274
|
+
*
|
|
275
|
+
* A second `accept` row on one section is what the server collapses away and
|
|
276
|
+
* then force-closes `rejected` with "superseded by @{by}'s proposal on the
|
|
277
|
+
* same section" — false about a proposal whose lines are in the document. A
|
|
278
|
+
* `dismiss` row is not a text row, so it is never collapsed, and `_close_note`
|
|
279
|
+
* stores this sentence on `note.resolution`.
|
|
280
|
+
*
|
|
281
|
+
* IT DID NOT "DELIVER IT", AND SAYING SO WAS THE OTHER HALF OF THE BUG. This
|
|
282
|
+
* comment used to claim `_close_note` delivered the sentence to the agent. It
|
|
283
|
+
* did not: the reason was stored and no surface in the repo read the field
|
|
284
|
+
* back out, so the folded-away author was told nothing at all — the same was
|
|
285
|
+
* true of a plain reject's comment and an `ask`'s question. Delivery arrived
|
|
286
|
+
* with the batch-message change that shipped beside the fold record, so the
|
|
287
|
+
* claim is true NOW and was false when it was written.
|
|
288
|
+
*/
|
|
289
|
+
it("tells the folded-away author the truth in the user's own sentence, on a server that does not record folds", async () => {
|
|
290
|
+
server.recordsFolds = false
|
|
291
|
+
await withTwoProposals()
|
|
292
|
+
await accept('n1')
|
|
293
|
+
await screen.findByTestId('plan-tray')
|
|
294
|
+
await accept('n2')
|
|
295
|
+
const collide = await screen.findByRole('group', { name: 'Two versions of milestones' })
|
|
296
|
+
fireEvent.click(within(collide).getByRole('button', { name: 'Keep both' }))
|
|
297
|
+
|
|
298
|
+
await waitFor(() => expect(server.draft).toHaveLength(2))
|
|
299
|
+
const closed = server.draft.find((r) => r.note_id === 'n1')!
|
|
300
|
+
expect(closed.kind).toBe('dismiss')
|
|
301
|
+
expect(closed.comment).toContain("Folded into @frontend's change")
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* THE RECORD, ARRIVING BACK FROM A SUBMIT — which is the only way to prove
|
|
306
|
+
* it. The tray assertion above says what the client SENT; this says what the
|
|
307
|
+
* server MADE of it, through a fake that now collapses text rows and runs the
|
|
308
|
+
* superseded loop as the real one does. A hand-stuffed `status: 'folded'` on
|
|
309
|
+
* a fixture would prove that the chip renders a string, not that a fold ever
|
|
310
|
+
* produces one.
|
|
311
|
+
*
|
|
312
|
+
* NOTHING THE CLIENT WROTE IS IN THE ANSWER. The client sent one boolean on
|
|
313
|
+
* the losing row; the winner's name in the sentence is the server's, derived
|
|
314
|
+
* from its own collapse.
|
|
315
|
+
*/
|
|
316
|
+
it('records the fold as the sixth status, with the reason the server wrote', async () => {
|
|
317
|
+
await withTwoProposals()
|
|
318
|
+
await accept('n1')
|
|
319
|
+
await screen.findByTestId('plan-tray')
|
|
320
|
+
await accept('n2')
|
|
321
|
+
const collide = await screen.findByRole('group', { name: 'Two versions of milestones' })
|
|
322
|
+
fireEvent.click(within(collide).getByRole('button', { name: 'Keep both' }))
|
|
323
|
+
|
|
324
|
+
// TWO text rows reach the wire, loser first, and the bit rides on the loser
|
|
325
|
+
// alone. No dismissal, no sentence, no author name from this side.
|
|
326
|
+
await waitFor(() => expect(server.draft).toHaveLength(2))
|
|
327
|
+
expect(server.draft.map((r) => r.kind)).toEqual(['accept', 'accept'])
|
|
328
|
+
expect(server.draft[0].note_id).toBe('n1')
|
|
329
|
+
expect(server.draft[0].folded).toBe(true)
|
|
330
|
+
expect(server.draft[1].folded).toBeUndefined()
|
|
331
|
+
expect(JSON.stringify(server.draft)).not.toContain('folded_by')
|
|
332
|
+
|
|
333
|
+
fireEvent.click(await screen.findByRole('button', { name: /^Send review/ }))
|
|
334
|
+
|
|
335
|
+
await waitFor(() => expect(server.draft).toHaveLength(0))
|
|
336
|
+
const folded = server.notes.find((n) => n.id === 'n1')!
|
|
337
|
+
expect(folded.status).toBe('folded')
|
|
338
|
+
expect(folded.resolution).toBe(
|
|
339
|
+
"folded into @frontend's change on the same section — your text is in the section that landed",
|
|
340
|
+
)
|
|
341
|
+
// The winner landed, and BOTH sets of lines are in the document.
|
|
342
|
+
expect(server.notes.find((n) => n.id === 'n2')!.status).toBe('applied')
|
|
343
|
+
expect(folded.status).not.toBe('rejected')
|
|
344
|
+
expect(folded.status).not.toBe('dismissed')
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
/** THE COST IS STATED WHERE THE DECISION IS MADE, and the sentence is now one
|
|
348
|
+
* that is true whichever server is on the other end — which is why it is
|
|
349
|
+
* asserted in both flag positions rather than one. It names NO status word:
|
|
350
|
+
* `dismissed` would be false against a server that records folds, `folded`
|
|
351
|
+
* false against one that does not, and "closed carrying a reason that says
|
|
352
|
+
* their text was folded into the section that landed" is true of both. That
|
|
353
|
+
* is what keeps the capability flag out of this component entirely. */
|
|
354
|
+
it.each([false, true])(
|
|
355
|
+
'says on the control that the folded-away text landed (records_folds=%s)',
|
|
356
|
+
async (recordsFolds) => {
|
|
357
|
+
server.recordsFolds = recordsFolds
|
|
358
|
+
await withTwoProposals()
|
|
359
|
+
await accept('n1')
|
|
360
|
+
await screen.findByTestId('plan-tray')
|
|
361
|
+
await accept('n2')
|
|
362
|
+
const collide = await screen.findByRole('group', { name: 'Two versions of milestones' })
|
|
363
|
+
const cost = within(collide).getByTestId('plan-collide-stack-cost')
|
|
364
|
+
expect(cost.textContent).toContain('both edits land in one write')
|
|
365
|
+
expect(cost.textContent).toContain('folded into the section that landed')
|
|
366
|
+
expect(cost.textContent).toContain('not that it was dropped')
|
|
367
|
+
// The retired claim is gone, and nothing replaced it with a status word
|
|
368
|
+
// that only one of the two servers would make true.
|
|
369
|
+
expect(cost.textContent).not.toContain('no way to record')
|
|
370
|
+
expect(cost.textContent).not.toContain('as dismissed')
|
|
371
|
+
},
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* IT DEGRADES RATHER THAN GUESSES. @devops rewrites the same line @backend
|
|
376
|
+
* ticked, so there is no correct automatic answer and the button is not
|
|
377
|
+
* offered — which is exactly the case the pick-one control has always been
|
|
378
|
+
* for. An absent button with no explanation is indistinguishable from a
|
|
379
|
+
* feature that does not exist, so the control says why.
|
|
380
|
+
*
|
|
381
|
+
* RUN IN BOTH FLAG POSITIONS TO SAY THAT THE FLAG HAS NOTHING TO DO WITH IT.
|
|
382
|
+
* Whether two proposals COMPOSE is a question about diffs; whether the fold
|
|
383
|
+
* can be RECORDED is a question about the server. A capability flag that
|
|
384
|
+
* started deciding which button appears would be answering the first question
|
|
385
|
+
* with the second.
|
|
386
|
+
*/
|
|
387
|
+
it.each([false, true])(
|
|
388
|
+
'withholds `Keep both` when the two proposals touch the same line (records_folds=%s)',
|
|
389
|
+
async (recordsFolds) => {
|
|
390
|
+
server.recordsFolds = recordsFolds
|
|
391
|
+
await withTwoProposals(DEVOPS_TEXT)
|
|
392
|
+
await accept('n1')
|
|
393
|
+
await screen.findByTestId('plan-tray')
|
|
394
|
+
await accept('n2')
|
|
395
|
+
|
|
396
|
+
const collide = await screen.findByRole('group', { name: 'Two versions of milestones' })
|
|
397
|
+
expect(within(collide).queryByRole('button', { name: 'Keep both' })).toBeNull()
|
|
398
|
+
expect(within(collide).getByTestId('plan-collide-stack-refused').textContent).toContain(
|
|
399
|
+
'change the same lines',
|
|
400
|
+
)
|
|
401
|
+
// And the three original choices are all still there.
|
|
402
|
+
expect(within(collide).getByRole('button', { name: "Keep @backend's" })).toBeTruthy()
|
|
403
|
+
expect(within(collide).getByRole('button', { name: 'Write my own' })).toBeTruthy()
|
|
404
|
+
expect(within(collide).getByRole('button', { name: "Take @frontend's" })).toBeTruthy()
|
|
405
|
+
},
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
/** `Take @{new}'s` STILL DISCARDS, and the sentence that says so is still
|
|
409
|
+
* there. Adding an outcome must not quietly retire one. */
|
|
410
|
+
it('leaves the pick-one outcome exactly as it was', async () => {
|
|
411
|
+
await withTwoProposals()
|
|
412
|
+
await accept('n1')
|
|
413
|
+
await screen.findByTestId('plan-tray')
|
|
414
|
+
await accept('n2')
|
|
415
|
+
const collide = await screen.findByRole('group', { name: 'Two versions of milestones' })
|
|
416
|
+
expect(collide.textContent).toContain(
|
|
417
|
+
'the discarded proposal is closed as rejected with a reason — never as applied',
|
|
418
|
+
)
|
|
419
|
+
fireEvent.click(within(collide).getByRole('button', { name: "Take @frontend's" }))
|
|
420
|
+
// Two accept rows, the loser first — the server collapses to the last.
|
|
421
|
+
await waitFor(() => expect(server.draft.filter((r) => r.kind === 'accept')).toHaveLength(2))
|
|
422
|
+
})
|
|
423
|
+
})
|
|
424
|
+
|
|
425
|
+
describe('the go-note may not be folded away', () => {
|
|
426
|
+
/**
|
|
427
|
+
* THE ASSERTION IS THE SAME; THE REASON FOR IT HAS CHANGED, AND THE OLD ONE
|
|
428
|
+
* WOULD NOW ARGUE THE GUARD AWAY.
|
|
429
|
+
*
|
|
430
|
+
* It used to read: a fold DISMISSES the held note, and `_refuse_go_note_close`
|
|
431
|
+
* refuses every close but Accept, so the button would always 409. On a server
|
|
432
|
+
* that records folds the note closes `folded`, not `dismissed` — so anyone
|
|
433
|
+
* checking the old reason against the new status would conclude the guard is
|
|
434
|
+
* obsolete.
|
|
435
|
+
*
|
|
436
|
+
* IT IS NOT. The execution gate counts notes that are OPEN, so EVERY way of
|
|
437
|
+
* closing the go-note releases it and `folded` is simply a new way. Only the
|
|
438
|
+
* user APPLYING it may release that gate, because applying it is what
|
|
439
|
+
* approves the plan. The refusal is about closing, not about which word — and
|
|
440
|
+
* that is why this holds in both flag positions.
|
|
441
|
+
*/
|
|
442
|
+
it.each([false, true])(
|
|
443
|
+
'offers no `Keep both` when the held row is the plan-approval note (records_folds=%s)',
|
|
444
|
+
async (recordsFolds) => {
|
|
445
|
+
server.recordsFolds = recordsFolds
|
|
446
|
+
server.notes.push(
|
|
447
|
+
note({ id: 'n1', by: 'coordinator', bootstrap: true, proposal: BACKEND_TEXT }),
|
|
448
|
+
note({ id: 'n2', by: 'frontend', proposal: FRONTEND_TEXT }),
|
|
449
|
+
)
|
|
450
|
+
render(createElement(PlanEditor, { projectId: PID, density: 'full' }), { wrapper })
|
|
451
|
+
await screen.findByTestId('plan-body')
|
|
452
|
+
await accept('n1')
|
|
453
|
+
await screen.findByTestId('plan-tray')
|
|
454
|
+
await accept('n2')
|
|
455
|
+
|
|
456
|
+
const collide = await screen.findByRole('group', { name: 'Two versions of milestones' })
|
|
457
|
+
expect(within(collide).queryByRole('button', { name: 'Keep both' })).toBeNull()
|
|
458
|
+
expect(within(collide).getByTestId('plan-collide-stack-refused').textContent).toContain(
|
|
459
|
+
'can only be accepted',
|
|
460
|
+
)
|
|
461
|
+
},
|
|
462
|
+
)
|
|
463
|
+
})
|
|
464
|
+
|
|
465
|
+
describe('a proposal written against an older section', () => {
|
|
466
|
+
/**
|
|
467
|
+
* THE SAME FOLD, AGAINST THE DOCUMENT. Here the held side is the section as
|
|
468
|
+
* it stands rather than somebody's proposal, so fitting the change onto it
|
|
469
|
+
* RE-BASES the proposal instead of overwriting whatever moved — and nothing
|
|
470
|
+
* is closed, because the held side is nobody's note.
|
|
471
|
+
*/
|
|
472
|
+
it("fits the proposal onto the current text rather than overwriting it", async () => {
|
|
473
|
+
// The document already carries @backend's tick; @frontend's note was
|
|
474
|
+
// written against the section before it.
|
|
475
|
+
server.body = BODY.replace(MILESTONES, BACKEND_TEXT)
|
|
476
|
+
server.notes.push(
|
|
477
|
+
note({
|
|
478
|
+
id: 'n2',
|
|
479
|
+
by: 'frontend',
|
|
480
|
+
proposal: FRONTEND_TEXT,
|
|
481
|
+
base_section: MILESTONES,
|
|
482
|
+
section_changed: true,
|
|
483
|
+
}),
|
|
484
|
+
)
|
|
485
|
+
render(createElement(PlanEditor, { projectId: PID, density: 'full' }), { wrapper })
|
|
486
|
+
await screen.findByTestId('plan-body')
|
|
487
|
+
await accept('n2')
|
|
488
|
+
|
|
489
|
+
const collide = await screen.findByRole('group', { name: 'Two versions of milestones' })
|
|
490
|
+
fireEvent.click(within(collide).getByRole('button', { name: "Fit @frontend's onto it" }))
|
|
491
|
+
|
|
492
|
+
await waitFor(() => expect(server.draft).toHaveLength(1))
|
|
493
|
+
// Both ticks survive: what the document already said, and what @frontend
|
|
494
|
+
// proposed. Staging their text verbatim would have reverted the first.
|
|
495
|
+
expect(server.draft[0].text).toContain('- [x] **M1** — spec (done)')
|
|
496
|
+
expect(server.draft[0].text).toContain('- [x] **M4** — ship (done)')
|
|
497
|
+
// Nothing was dismissed — there was no second note in the question.
|
|
498
|
+
expect(server.draft.every((r) => r.kind === 'accept')).toBe(true)
|
|
499
|
+
})
|
|
500
|
+
})
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { useId, useState } from 'react'
|
|
2
|
+
import { ChevronRight } from 'lucide-react'
|
|
3
|
+
import { PlanDiff } from './PlanDiff'
|
|
4
|
+
import type { DiffStep } from './planDiffs'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A NOTE'S DIFFS, IN THE ORDER THEY MATTER TO IT.
|
|
8
|
+
*
|
|
9
|
+
* ONE STEP RENDERS BARE, and that is the whole compatibility story. A lone,
|
|
10
|
+
* un-contested, un-moved proposal produces a one-step series and this component
|
|
11
|
+
* emits exactly what `{note.display_diff && <PlanDiff … />}` emitted before it
|
|
12
|
+
* existed: no wrapper, no summary line, no toggle. That is ~95% of notes and
|
|
13
|
+
* nothing about them moves.
|
|
14
|
+
*
|
|
15
|
+
* TWO OR MORE render the first bare and the rest behind ONE disclosure, closed,
|
|
16
|
+
* labelled with what is inside it IN WORDS rather than as a count —
|
|
17
|
+
* "@backend has also proposed a change here", not "2 more". The count is not
|
|
18
|
+
* what a reader needs in order to decide whether to open it; the fact that
|
|
19
|
+
* somebody else wants this same section is.
|
|
20
|
+
*
|
|
21
|
+
* `expanded` is for the collision control, where the comparison IS the question
|
|
22
|
+
* being asked and hiding it behind a click would put the two candidates one
|
|
23
|
+
* interaction further away than the panes it replaced.
|
|
24
|
+
*
|
|
25
|
+
* THE DISCLOSURE IS A `<button>` and not a `<div onClick>`: it is reachable by
|
|
26
|
+
* keyboard, it announces its own state through `aria-expanded`, and it owns the
|
|
27
|
+
* region it opens through `aria-controls`. A surface whose whole job is to stop
|
|
28
|
+
* a decision being made blind cannot be one only a mouse can open.
|
|
29
|
+
*/
|
|
30
|
+
export function PlanDiffSeries({
|
|
31
|
+
steps,
|
|
32
|
+
expanded = false,
|
|
33
|
+
}: {
|
|
34
|
+
steps: DiffStep[]
|
|
35
|
+
expanded?: boolean
|
|
36
|
+
}) {
|
|
37
|
+
const [open, setOpen] = useState(expanded)
|
|
38
|
+
const regionId = useId()
|
|
39
|
+
|
|
40
|
+
if (steps.length === 0) return null
|
|
41
|
+
/* THE DECISION POINT SHOWS EVERYTHING, LABELLED, AND HAS NO HEAD STEP.
|
|
42
|
+
A card has a diff — what this proposal does — and the rest is context. The
|
|
43
|
+
collision control has no such privileged side: `collideSeries` returns the
|
|
44
|
+
two directions of one question, and rendering either of them bare would be
|
|
45
|
+
printing the case for one of two buttons in a larger font. */
|
|
46
|
+
if (expanded) {
|
|
47
|
+
return (
|
|
48
|
+
<div className="plan-diff-series space-y-2 mb-3" data-testid="plan-diff-series">
|
|
49
|
+
{steps.map((step, i) => (
|
|
50
|
+
<Step key={`${step.kind}-${i}`} step={step} labelled />
|
|
51
|
+
))}
|
|
52
|
+
</div>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
if (steps.length === 1) return <PlanDiff text={steps[0].diff} />
|
|
56
|
+
|
|
57
|
+
const [head, ...rest] = steps
|
|
58
|
+
return (
|
|
59
|
+
<div className="plan-diff-series" data-testid="plan-diff-series">
|
|
60
|
+
<Step step={head} />
|
|
61
|
+
<button
|
|
62
|
+
type="button"
|
|
63
|
+
className="mt-1 flex items-center gap-1 text-xs text-amber-800 dark:text-amber-500 hover:underline"
|
|
64
|
+
aria-expanded={open}
|
|
65
|
+
aria-controls={regionId}
|
|
66
|
+
data-testid="plan-diff-series-toggle"
|
|
67
|
+
onClick={() => setOpen((v) => !v)}
|
|
68
|
+
>
|
|
69
|
+
<ChevronRight
|
|
70
|
+
size={13}
|
|
71
|
+
className={`shrink-0 transition-transform ${open ? 'rotate-90' : ''}`}
|
|
72
|
+
/>
|
|
73
|
+
<span>{summary(rest)}</span>
|
|
74
|
+
</button>
|
|
75
|
+
{open && (
|
|
76
|
+
<div id={regionId} className="mt-1 space-y-2">
|
|
77
|
+
{rest.map((step, i) => (
|
|
78
|
+
<Step key={`${step.kind}-${step.noteId}-${i}`} step={step} labelled />
|
|
79
|
+
))}
|
|
80
|
+
</div>
|
|
81
|
+
)}
|
|
82
|
+
</div>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* WHAT IS BEHIND THE DISCLOSURE, SAID RATHER THAN COUNTED.
|
|
88
|
+
*
|
|
89
|
+
* Two facts can be in there and they are not equally surprising, so the rival
|
|
90
|
+
* one is named first when both are: that a second agent wants this same section
|
|
91
|
+
* is news, and it is the fact the old surface withheld until the user had
|
|
92
|
+
* already clicked Accept on one of them.
|
|
93
|
+
*/
|
|
94
|
+
function summary(rest: DiffStep[]): string {
|
|
95
|
+
const rivals = rest.filter((s) => s.kind === 'rival')
|
|
96
|
+
const moved = rest.some((s) => s.kind === 'current')
|
|
97
|
+
if (rivals.length > 0) {
|
|
98
|
+
const names = rivals.map((s) => `@${s.by || 'someone else'}`)
|
|
99
|
+
const who =
|
|
100
|
+
names.length === 1
|
|
101
|
+
? names[0]
|
|
102
|
+
: `${names.slice(0, -1).join(', ')} and ${names[names.length - 1]}`
|
|
103
|
+
const verb = names.length === 1 ? 'has' : 'have'
|
|
104
|
+
return `${who} ${verb} also proposed a change to this section — see what taking theirs would do`
|
|
105
|
+
}
|
|
106
|
+
if (moved) return 'This section has moved — see it against the plan as it stands'
|
|
107
|
+
return 'See the other comparisons'
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** One step: its heading when it needs one, its hint when it has one, and its
|
|
111
|
+
* `PlanDiff`. The head step is never labelled — it is the diff this card has
|
|
112
|
+
* always shown, and a heading over it would be a caption on the status quo. */
|
|
113
|
+
function Step({ step, labelled = false }: { step: DiffStep; labelled?: boolean }) {
|
|
114
|
+
return (
|
|
115
|
+
<div data-step-kind={step.kind}>
|
|
116
|
+
{labelled && (
|
|
117
|
+
<div className="text-xs font-semibold text-channel">{step.label}</div>
|
|
118
|
+
)}
|
|
119
|
+
{labelled && step.hint && (
|
|
120
|
+
<p className="text-xs text-channel mb-1">{step.hint}</p>
|
|
121
|
+
)}
|
|
122
|
+
<PlanDiff text={step.diff} />
|
|
123
|
+
</div>
|
|
124
|
+
)
|
|
125
|
+
}
|