From 5d9c9386c6c50a309808ebf9c71a1a7ce2645ec3 Mon Sep 17 00:00:00 2001 From: 0x-copilot-dev <0x-copilot-dev@users.noreply.github.com> Date: Tue, 11 Aug 2026 21:48:29 +0530 Subject: [PATCH 1/3] refactor!: delete unreachable destinations and the docs that described a dead system Removes 113k lines across two independent classes of dead weight, each verified against the code rather than against what a doc claimed. Dead UI (-51,942): 9 chat-surface destinations (memory, agents, home, inbox, library, routines, team, todos, tools) plus their barrel blocks, and 7 web feature dirs. None is reachable in either host: `memory` is absent from both SOLO_ORDER and TEAM_ORDER and its web URL redirects to Settings, and the rest fall through DestinationOutlet's `default:` to a placeholder. The apparent host references were comment text, not imports -- AgentsRoute.tsx only mentions `` in a header comment. `useStepMachine` moves to connectors/webhooks, its one remaining consumer, rather than to a shared layer: deleting tools/ without that move would have dangled two deep imports that bypass both barrels, reddening the required `host-typecheck` check and breaking the desktop esbuild resolve. Dead docs (-61,354): Six trees whose premises are gone -- docs/roadmap specced ~30 PRs into a `docs/specs/` tree that never existed in git history and was founded on a DEV_AUTH_BYPASS that now only survives as a guard *rejecting* it; docs/new-design built on an Atlas-orange brand decision whose hex is now only Anthropic's provider-mark colour. Also RUN-RESULTS.md, which described a 53-journey layout that commit e8622a1d replaced, and whose durable traps already live in the harness README. Rewrites: JOURNEYS.md now maps G0->AS-1 and G3-G10->IP-2..IP-9 instead of linking 9 deleted scripts; github-actions-strategy.md no longer lists deploy.yml and release-images.yml as "implemented" (neither exists); the ai-backend system map gains the 8 undocumented packages (surfaces_v2, effects, artifacts, harness_quality, control_plane, release, presentation, hyperparameters) and drops the Postgres adapter removed in e03840ed. Verified: tsc clean on chat-surface + frontend + desktop; 3,832 vitest passing; desktop esbuild and vite build both exit 0; the built web bundle boots in a browser with all 25 chunks 200 and renders the sign-in screen. The one failing test (canvasLifecycle.test.ts) is pre-existing on dev -- it imports agent_runtime.presentation.lifecycle, a module that exists on neither dev nor here. Co-Authored-By: Claude Opus 5 --- CLAUDE.md | 2 +- .../src/features/agents/AgentsRoute.test.tsx | 821 ------- .../src/features/agents/AgentsRoute.tsx | 860 ------- .../src/features/inbox/InboxRoute.test.tsx | 548 ----- .../src/features/inbox/InboxRoute.tsx | 408 ---- .../features/library/LibraryRoute.test.tsx | 952 -------- .../src/features/library/LibraryRoute.tsx | 668 ------ .../src/features/memory/MemoryDetailRoute.tsx | 170 -- .../src/features/memory/MemoryGateway.tsx | 90 - .../features/memory/MemoryProposalsRoute.tsx | 219 -- .../src/features/memory/MemoryRoute.tsx | 434 ---- .../memory/__tests__/MemoryGateway.test.tsx | 239 -- apps/frontend/src/features/memory/adapters.ts | 106 - .../features/routines/RoutinesRoute.test.tsx | 562 ----- .../src/features/routines/RoutinesRoute.tsx | 495 ---- .../src/features/todos/TodosRoute.test.tsx | 250 -- .../src/features/todos/TodosRoute.tsx | 256 -- .../src/features/tools/ToolDetailRoute.tsx | 628 ----- .../features/tools/ToolOnboardingRoute.tsx | 106 - .../src/features/tools/ToolsRoute.tsx | 640 ----- apps/frontend/src/features/tools/adapters.ts | 262 --- docs/architecture/desktop-app.md | 4 +- docs/atlas-new-design/PRD.md | 228 -- docs/atlas-new-design/cross-audit.md | 686 ------ .../destinations-master-prd.md | 727 ------ .../destinations/agents-prd.md | 1218 ---------- .../destinations/chats-canvas-prd.md | 623 ----- .../destinations/connectors-prd.md | 485 ---- .../atlas-new-design/destinations/home-prd.md | 1312 ----------- .../destinations/inbox-prd.md | 846 ------- .../destinations/library-prd.md | 1465 ------------ .../destinations/projects-extensions-prd.md | 1043 --------- .../destinations/projects-prd.md | 1316 ----------- .../destinations/routines-prd.md | 988 -------- .../destinations/team-memory-cmdk-prd.md | 494 ---- .../destinations/todos-prd.md | 699 ------ .../destinations/tools-prd.md | 530 ----- docs/atlas-new-design/implementation-plan.md | 459 ---- docs/ci-cd/github-actions-strategy.md | 91 +- docs/decomp/README.md | 57 - docs/decomp/agent-api/_index.md | 49 - .../agent-api/presentation-templates.md | 215 -- docs/decomp/agent-api/presentation.md | 269 --- docs/decomp/agent-api/service.md | 255 -- docs/decomp/capabilities/_index.md | 82 - docs/decomp/capabilities/mcp-cards.md | 156 -- docs/decomp/context-memory/_index.md | 44 - docs/decomp/context-memory/subagent-trace.md | 219 -- docs/decomp/delegation-subagents/_index.md | 45 - docs/decomp/delegation-subagents/contracts.md | 170 -- docs/decomp/execution/_index.md | 48 - docs/decomp/execution/contracts.md | 171 -- docs/decomp/persistence/_index.md | 72 - docs/decomp/runtime-adapters/_index.md | 46 - .../in-memory-runtime-api-store.md | 315 --- .../postgres-runtime-api-store.md | 444 ---- docs/decomp/runtime-worker/_index.md | 82 - docs/decomp/runtime-worker/handlers-run.md | 297 --- docs/decomp/runtime-worker/run-metrics.md | 168 -- docs/decomp/runtime-worker/stream-events.md | 180 -- docs/decomp/runtime-worker/stream-tools.md | 177 -- docs/new-design/0-OVERALL_PLAN.md | 326 --- docs/new-design/01-citations-live-registry.md | 553 ----- docs/new-design/02-citations-followups.md | 232 -- .../new-design/03-citations-model-declared.md | 615 ----- docs/new-design/04-citations-binding-map.md | 697 ------ .../pr-1-2-per-chat-connector-scope.md | 419 ---- ...-2.1-per-chat-connector-scope-followups.md | 293 --- docs/new-design/pr-1.3-draft-artifact.md | 497 ---- docs/new-design/pr-1.3.5-draft-completion.md | 542 ----- docs/new-design/pr-1.4-two-stage-approvals.md | 626 ----- .../pr-1.4.1-approval-forwarding-hardening.md | 877 ------- ...-1.5-subagent-discovery-workspace-feeds.md | 864 ------- ...rkspace-defaults-conversation-lifecycle.md | 701 ------ .../pr-2.1-topbar-chrome-thinking-depth.md | 507 ---- .../pr-2.2-sidebar-user-card-keymap.md | 559 ----- .../pr-2.2.1-background-runs-and-live-pill.md | 460 ---- .../pr-2.3-welcome-state-thread-polish.md | 603 ----- .../pr-3.1-citation-chips-sources-tab.md | 425 ---- .../pr-3.2-workspace-pane-right-rail.md | 525 ----- ...pr-3.2.1-agents-tab-expandable-timeline.md | 599 ----- ...pr-3.2.2-subagent-card-shared-primitive.md | 455 ---- .../pr-3.2.3-subagent-backend-completion.md | 494 ---- .../pr-3.2.4-fleet-nests-compact-rows.md | 638 ----- .../pr-3.2.5-subagent-call-id-propagation.md | 389 --- .../pr-3.2.5-subagent-runtime-correctness.md | 437 ---- ...pr-3.2.6-subagent-paused-resumed-events.md | 382 --- ...paused-fleet-row-and-clickable-timeline.md | 536 ----- .../pr-3.3-mcp-discovery-approval-polish.md | 542 ----- docs/new-design/pr-3.4-connector-popover.md | 520 ---- .../pr-3.4.1-connector-popover-fidelity.md | 709 ------ docs/new-design/pr-3.5-w1-w3-gap-closure.md | 637 ----- ...6-approval-detail-and-subagent-timeline.md | 469 ---- docs/new-design/pr-3.6-thinking-accordion.md | 515 ---- docs/new-design/pr-3.7-sources-orientation.md | 100 - .../pr-3.7.1-sources-live-skeleton.md | 114 - .../pr-3.7.2-source-hover-preview.md | 115 - docs/new-design/pr-3.7.3-sources-scale.md | 117 - .../pr-4.1-gap-fix-you-group-wiring.md | 37 - docs/new-design/pr-4.1-settings-you-group.md | 570 ----- .../pr-4.2-settings-workspace-group.md | 641 ----- .../new-design/pr-4.3-settings-ai-and-data.md | 593 ----- .../pr-4.4-mcp-overlay-test-connection.md | 688 ------ .../pr-4.4.6-mcp-catalog-vs-connected.md | 728 ------ ....4.6.2-approval-card-structured-payload.md | 504 ---- .../pr-4.4.6.3-approval-vendor-recognisers.md | 492 ---- .../pr-4.4.6.4-approval-undo-window.md | 506 ---- .../pr-4.4.7-phase-2-suggested-connectors.md | 337 --- .../pr-4.5-usage-overlay-share-popover.md | 580 ----- .../pr-5.1-login-email-first-idp-discovery.md | 970 -------- .../new-design/pr-6.1-conversation-sharing.md | 869 ------- docs/new-design/pr-6.2-conversation-fork.md | 852 ------- docs/new-design/pr-7.1-audit-log-section.md | 601 ----- .../pr-7.2-per-connector-token-attribution.md | 627 ----- .../pr-8.0-atlas-visual-fidelity.md | 619 ----- ...r-8.0.1-atlas-visual-fidelity-followups.md | 338 --- .../pr-8.0.2-atlas-visible-fidelity-gaps.md | 253 -- .../pr-8.0.3-atlas-completion-plan.md | 160 -- ...0.4-sidebar-header-search-popover-fixes.md | 170 -- .../pr-8.0.5-policy-runtime-integration.md | 446 ---- .../new-design/pr-8.1-settings-ia-overhaul.md | 174 -- docs/new-design/pr-8.2-settings-phase-2.md | 132 -- docs/new-design/pr-8.3-settings-phase-3.md | 181 -- ...pr-9.0-tool-display-metadata-middleware.md | 452 ---- .../pr-w0-dev-identity-framework.md | 752 ------ .../pr-w0-facade-no-content-forwarder.md | 383 --- .../frontend-parity-v3/PRD-A-icon-system.md | 169 -- .../PRD-B-tokens-and-status-tone.md | 179 -- .../plan/frontend-parity-v3/PRD-C-app-rail.md | 150 -- .../PRD-D-command-palette.md | 149 -- .../PRD-E-settings-convergence.md | 162 -- .../frontend-parity-v3/PRD-F-provider-keys.md | 181 -- .../PRD-G-destination-parity.md | 183 -- .../PRD-H-backend-data-plane.md | 191 -- .../PRD-I-writethrough-hardening.md | 137 -- .../PRD-J-main-health-and-verification.md | 97 - docs/plan/frontend-parity-v3/README.md | 117 - docs/plan/frontend-parity-v3/STATUS.md | 50 - .../generative-ui/00-implementation-plan.md | 161 -- .../generative-ui/PRD-01-surface-contract.md | 64 - .../generative-ui/PRD-02-backend-emission.md | 39 - .../PRD-03-archetype-renderers.md | 44 - .../generative-ui/PRD-04-cockpit-wiring.md | 35 - .../generative-ui/PRD-05-web-registration.md | 30 - docs/plan/generative-ui/PRD-06-text-diff.md | 35 - .../generative-ui/PRD-07-spec-generator.md | 44 - .../generative-ui/PRD-08-spec-registry.md | 35 - .../generative-ui/PRD-09-edit-and-commit.md | 45 - .../generative-ui/PRD-10-tier2-completion.md | 30 - .../generative-ui/PRD-11-hardening-evals.md | 34 - ...-12-rowset-review-recovery-architecture.md | 293 --- docs/plan/generative-ui/STATUS.md | 68 - docs/plan/ui-kit-consolidation/DESIGN.md | 60 - docs/roadmap/00-overview.md | 383 --- docs/roadmap/01-c1-deployment-profiles.md | 193 -- docs/roadmap/02-c2-migration-tooling.md | 192 -- docs/roadmap/03-c3-atomicity-fixes.md | 205 -- docs/roadmap/04-c4-pool-tuning.md | 177 -- docs/roadmap/05-a1-user-org-schema.md | 285 --- docs/roadmap/06-a2-sessions.md | 198 -- docs/roadmap/07-a3-oidc-sso.md | 241 -- docs/roadmap/08-a4-local-password.md | 212 -- docs/roadmap/09-a5-saml-sso.md | 186 -- docs/roadmap/10-a7-scim.md | 224 -- docs/roadmap/11-b1-runtime-run-usage.md | 215 -- docs/roadmap/12-b2-per-step-usage.md | 197 -- docs/roadmap/13-b3-pricing-and-cost.md | 200 -- docs/roadmap/14-b4-aggregation-endpoints.md | 211 -- docs/roadmap/15-c5-rls-tenant-isolation.md | 187 -- docs/roadmap/16-a6-mfa.md | 226 -- docs/roadmap/17-a8-lockout.md | 208 -- docs/roadmap/18-a9-frontend-login.md | 170 -- docs/roadmap/19-b5-context-command.md | 186 -- docs/roadmap/20-b6-usage-command.md | 125 - docs/roadmap/21-b7-budgets.md | 223 -- docs/roadmap/22-b8-tool-budget.md | 173 -- docs/roadmap/23-c6-byok-kms.md | 197 -- docs/roadmap/24-c7-field-encryption.md | 199 -- docs/roadmap/25-c8-retention-sweeper.md | 179 -- docs/roadmap/26-c9-siem-export.md | 182 -- docs/roadmap/27-c10-read-replica.md | 139 -- .../roadmap/28-c11-statement-observability.md | 147 -- docs/roadmap/29-a10-rbac-enforcement.md | 211 -- docs/roadmap/30-c12-backup-restore.md | 159 -- docs/roadmap/README.md | 96 - .../ai-backend/01-agent-runtime-execution.md | 51 - .../02-agent-runtime-capabilities.md | 49 - .../03-agent-runtime-context-memory.md | 43 - .../04-agent-runtime-delegation-subagents.md | 38 - .../05-agent-runtime-persistence.md | 44 - .../06-agent-runtime-api-and-services.md | 54 - .../07-agent-runtime-cross-cutting.md | 49 - docs/unused-code/ai-backend/08-runtime-api.md | 54 - .../ai-backend/09-runtime-worker.md | 47 - .../ai-backend/10-runtime-adapters.md | 47 - docs/unused-code/ai-backend/README.md | 98 - .../SUPPLEMENT-deep-scan-vulture50.md | 72 - .../ai-backend/vulture_whitelist.py | 19 - .../01-core-forwarding-and-agent-surface.md | 54 - .../backend-facade/02-auth-and-session.md | 33 - .../03-me-and-workspace-proxies.md | 30 - docs/unused-code/backend-facade/04-scim.md | 27 - .../backend-facade/05-observability.md | 39 - ...06-bootstrap-settings-deployment-health.md | 33 - .../07-vulture-fastapi-inventory.md | 71 - docs/unused-code/backend-facade/README.md | 34 - .../backend-facade/vulture_whitelist.py | 14 - docs/unused-code/backend/README.md | 111 - docs/unused-code/backend/artifacts/README.md | 38 - ...ter-agent-runtime-capabilities-vulture.txt | 130 - ...r-agent-runtime-context-memory-vulture.txt | 42 - ...er-agent-runtime-cross-cutting-vulture.txt | 4 - ...uster-agent-runtime-delegation-vulture.txt | 45 - ...-agent-runtime-domain-services-vulture.txt | 29 - ...luster-agent-runtime-execution-vulture.txt | 55 - ...er-agent-runtime-observability-vulture.txt | 21 - ...er-agent-runtime-ops-economics-vulture.txt | 13 - ...ster-agent-runtime-persistence-vulture.txt | 140 -- .../cluster-runtime-adapters-vulture.txt | 6 - .../artifacts/cluster-runtime-api-vulture.txt | 145 -- .../cluster-runtime-worker-vulture.txt | 9 - .../artifacts/vulture-min60-src-only.txt | 639 ----- .../cluster-agent-runtime-capabilities.md | 48 - .../cluster-agent-runtime-context-memory.md | 45 - .../cluster-agent-runtime-cross-cutting.md | 46 - .../cluster-agent-runtime-delegation.md | 45 - .../cluster-agent-runtime-domain-services.md | 48 - .../cluster-agent-runtime-execution.md | 49 - .../cluster-agent-runtime-observability.md | 44 - .../cluster-agent-runtime-ops-economics.md | 73 - .../cluster-agent-runtime-persistence.md | 47 - .../backend/cluster-runtime-adapters.md | 51 - .../backend/cluster-runtime-api.md | 50 - .../backend/cluster-runtime-worker.md | 49 - .../frontend/01-app-shell-and-utils.md | 27 - docs/unused-code/frontend/02-api-layer.md | 23 - docs/unused-code/frontend/03-auth.md | 28 - docs/unused-code/frontend/04-connectors.md | 29 - .../frontend/05-settings-and-workspace.md | 30 - .../frontend/06-chat-chatmodel-and-events.md | 27 - .../frontend/07-chat-ui-components.md | 40 - .../08-chat-hooks-prompts-utils-markdown.md | 35 - .../frontend/09-share-skills-me.md | 27 - docs/unused-code/frontend/10-observability.md | 29 - .../frontend/11-knip-unused-inventory.md | 119 - docs/unused-code/frontend/README.md | 96 - docs/use-cases/README.md | 78 +- .../destinations/agents/AgentCard.test.tsx | 138 -- .../src/destinations/agents/AgentCard.tsx | 223 -- .../agents/AgentDetailView.test.tsx | 191 -- .../destinations/agents/AgentDetailView.tsx | 481 ---- .../destinations/agents/AgentEditor.test.tsx | 236 -- .../src/destinations/agents/AgentEditor.tsx | 1225 ---------- .../agents/AgentUsageChart.test.tsx | 221 -- .../destinations/agents/AgentUsageChart.tsx | 456 ---- .../agents/AgentsDestination.test.tsx | 164 -- .../destinations/agents/AgentsDestination.tsx | 294 --- .../destinations/agents/AgentsPanel.test.tsx | 88 - .../src/destinations/agents/AgentsPanel.tsx | 311 --- .../destinations/agents/ForkDialog.test.tsx | 98 - .../src/destinations/agents/ForkDialog.tsx | 168 -- .../agents/VersionHistoryTab.test.tsx | 171 -- .../destinations/agents/VersionHistoryTab.tsx | 443 ---- .../destinations/agents/_agents-stub.test.ts | 129 - .../src/destinations/agents/_agents-stub.ts | 202 -- .../src/destinations/agents/index.test.ts | 66 - .../src/destinations/agents/index.ts | 129 - .../webhooks/WebhookCreateWizard.tsx | 6 +- .../webhooks}/useStepMachine.ts | 25 +- .../home/HomeDestination.test.tsx | 393 ---- .../src/destinations/home/HomeDestination.tsx | 197 -- .../src/destinations/home/HomePanel.test.tsx | 121 - .../src/destinations/home/HomePanel.tsx | 151 -- .../src/destinations/home/index.test.ts | 24 - .../src/destinations/home/index.ts | 23 - .../home/sections/HomeGreeting.tsx | 52 - .../home/sections/HomeQuickActionsSection.tsx | 86 - .../home/sections/InFlightStrip.tsx | 148 -- .../home/sections/LiveActivityRail.tsx | 84 - .../home/sections/TodayTimeline.tsx | 223 -- .../home/sections/TriageStrip.tsx | 169 -- .../home/sections/WhatsNewDigest.tsx | 152 -- .../src/destinations/home/sections/index.ts | 18 - .../inbox/InboxDestination.test.tsx | 712 ------ .../destinations/inbox/InboxDestination.tsx | 1105 --------- .../destinations/inbox/InboxDetail.test.tsx | 266 --- .../src/destinations/inbox/InboxDetail.tsx | 566 ----- .../destinations/inbox/InboxPanel.test.tsx | 104 - .../src/destinations/inbox/InboxPanel.tsx | 201 -- .../src/destinations/inbox/_inbox-stub.ts | 168 -- .../destinations/inbox/inbox-reply.test.tsx | 118 - .../src/destinations/inbox/inbox-reply.tsx | 98 - .../src/destinations/inbox/index.test.ts | 24 - .../src/destinations/inbox/index.ts | 94 - .../destinations/inbox/snooze-picker.test.tsx | 119 - .../src/destinations/inbox/snooze-picker.tsx | 276 --- .../src/destinations/inbox/useInboxLayout.tsx | 230 -- .../library/LibraryDestination.test.tsx | 364 --- .../library/LibraryDestination.tsx | 997 -------- .../library/LibraryDetailView.test.tsx | 392 ---- .../library/LibraryDetailView.tsx | 750 ------ .../library/LibraryPanel.test.tsx | 145 -- .../src/destinations/library/LibraryPanel.tsx | 281 --- .../destinations/library/PageEditor.test.tsx | 184 -- .../src/destinations/library/PageEditor.tsx | 430 ---- .../library/SaveToLibraryPopover.test.tsx | 212 -- .../library/SaveToLibraryPopover.tsx | 464 ---- .../src/destinations/library/_library-stub.ts | 195 -- .../src/destinations/library/index.test.ts | 28 - .../src/destinations/library/index.ts | 108 - .../library/preview/DatasetPreview.test.tsx | 101 - .../library/preview/DatasetPreview.tsx | 339 --- .../library/preview/FilePreview.test.tsx | 117 - .../library/preview/FilePreview.tsx | 263 --- .../library/preview/PagePreview.test.tsx | 31 - .../library/preview/PagePreview.tsx | 80 - .../memory/MemoryDestination.test.tsx | 266 --- .../destinations/memory/MemoryDestination.tsx | 638 ----- .../memory/MemoryDetailView.test.tsx | 178 -- .../destinations/memory/MemoryDetailView.tsx | 421 ---- .../destinations/memory/MemoryEditor.test.tsx | 230 -- .../src/destinations/memory/MemoryEditor.tsx | 408 ---- .../destinations/memory/MemoryPanel.test.tsx | 85 - .../src/destinations/memory/MemoryPanel.tsx | 314 --- .../memory/MemoryProposalCard.tsx | 302 --- .../memory/MemoryProposalToast.test.tsx | 232 -- .../memory/MemoryProposalToast.tsx | 306 --- .../src/destinations/memory/index.test.ts | 24 - .../src/destinations/memory/index.ts | 104 - .../routines/RoutineDetail.test.tsx | 638 ----- .../destinations/routines/RoutineDetail.tsx | 1369 ----------- .../routines/RoutineEditor.test.tsx | 714 ------ .../destinations/routines/RoutineEditor.tsx | 2082 ----------------- .../routines/RoutinesDestination.test.tsx | 450 ---- .../routines/RoutinesDestination.tsx | 653 ------ .../routines/RoutinesPanel.test.tsx | 225 -- .../destinations/routines/RoutinesPanel.tsx | 357 --- .../destinations/routines/_routines-stub.ts | 210 -- .../src/destinations/routines/index.test.ts | 24 - .../src/destinations/routines/index.ts | 72 - .../team/OffboardingWizard.test.tsx | 263 --- .../destinations/team/OffboardingWizard.tsx | 904 ------- .../src/destinations/team/PersonCard.test.tsx | 94 - .../src/destinations/team/PersonCard.tsx | 327 --- .../team/PersonDetailView.test.tsx | 200 -- .../destinations/team/PersonDetailView.tsx | 516 ---- .../team/TeamDestination.test.tsx | 214 -- .../src/destinations/team/TeamDestination.tsx | 403 ---- .../team/TeamInviteWizard.test.tsx | 134 -- .../destinations/team/TeamInviteWizard.tsx | 424 ---- .../src/destinations/team/TeamPanel.test.tsx | 64 - .../src/destinations/team/TeamPanel.tsx | 180 -- .../src/destinations/team/index.test.ts | 24 - .../src/destinations/team/index.ts | 78 - .../todos/TodosDestination.test.tsx | 526 ----- .../destinations/todos/TodosDestination.tsx | 1253 ---------- .../destinations/todos/TodosPanel.test.tsx | 146 -- .../src/destinations/todos/TodosPanel.tsx | 341 --- .../src/destinations/todos/_todos-stub.ts | 159 -- .../todos/extraction-banner.test.tsx | 172 -- .../destinations/todos/extraction-banner.tsx | 296 --- .../src/destinations/todos/index.test.ts | 24 - .../src/destinations/todos/index.ts | 64 - .../destinations/todos/inline-add.test.tsx | 191 -- .../src/destinations/todos/inline-add.tsx | 322 --- .../todos/recurrence-editor.test.tsx | 313 --- .../destinations/todos/recurrence-editor.tsx | 593 ----- .../destinations/todos/subtask-tree.test.tsx | 252 -- .../src/destinations/todos/subtask-tree.tsx | 429 ---- .../destinations/tools/OnboardingWizard.tsx | 257 -- .../src/destinations/tools/ToolCard.tsx | 224 -- .../src/destinations/tools/ToolDetailView.tsx | 652 ------ .../src/destinations/tools/ToolEditor.tsx | 878 ------- .../tools/ToolInvocationsTable.tsx | 392 ---- .../src/destinations/tools/ToolUsageChart.tsx | 350 --- .../tools/ToolsDestination.test.tsx | 449 ---- .../destinations/tools/ToolsDestination.tsx | 458 ---- .../src/destinations/tools/ToolsPanel.tsx | 277 --- .../src/destinations/tools/UsedByTab.tsx | 222 -- .../src/destinations/tools/_tools-stub.ts | 303 --- .../src/destinations/tools/index.ts | 52 - .../tools/onboarding/CodeWizard.tsx | 661 ------ .../tools/onboarding/McpWizard.tsx | 519 ---- .../tools/onboarding/OpenApiWizard.tsx | 831 ------- .../tools/onboarding/SkillWizard.tsx | 132 -- .../tools/onboarding/WizardShell.tsx | 278 --- .../destinations/tools/onboarding/index.ts | 39 - packages/chat-surface/src/index.ts | 195 -- services/ai-backend/CLAUDE.md | 7 +- .../docs/architecture/00-system-map.md | 32 +- tools/desktop-journeys/RUN-RESULTS.md | 81 - tools/desktop-journeys/UX-BACKLOG.md | 22 + .../generative-workflows/JOURNEYS.md | 215 +- 393 files changed, 260 insertions(+), 113295 deletions(-) delete mode 100644 apps/frontend/src/features/agents/AgentsRoute.test.tsx delete mode 100644 apps/frontend/src/features/agents/AgentsRoute.tsx delete mode 100644 apps/frontend/src/features/inbox/InboxRoute.test.tsx delete mode 100644 apps/frontend/src/features/inbox/InboxRoute.tsx delete mode 100644 apps/frontend/src/features/library/LibraryRoute.test.tsx delete mode 100644 apps/frontend/src/features/library/LibraryRoute.tsx delete mode 100644 apps/frontend/src/features/memory/MemoryDetailRoute.tsx delete mode 100644 apps/frontend/src/features/memory/MemoryGateway.tsx delete mode 100644 apps/frontend/src/features/memory/MemoryProposalsRoute.tsx delete mode 100644 apps/frontend/src/features/memory/MemoryRoute.tsx delete mode 100644 apps/frontend/src/features/memory/__tests__/MemoryGateway.test.tsx delete mode 100644 apps/frontend/src/features/memory/adapters.ts delete mode 100644 apps/frontend/src/features/routines/RoutinesRoute.test.tsx delete mode 100644 apps/frontend/src/features/routines/RoutinesRoute.tsx delete mode 100644 apps/frontend/src/features/todos/TodosRoute.test.tsx delete mode 100644 apps/frontend/src/features/todos/TodosRoute.tsx delete mode 100644 apps/frontend/src/features/tools/ToolDetailRoute.tsx delete mode 100644 apps/frontend/src/features/tools/ToolOnboardingRoute.tsx delete mode 100644 apps/frontend/src/features/tools/ToolsRoute.tsx delete mode 100644 apps/frontend/src/features/tools/adapters.ts delete mode 100644 docs/atlas-new-design/PRD.md delete mode 100644 docs/atlas-new-design/cross-audit.md delete mode 100644 docs/atlas-new-design/destinations-master-prd.md delete mode 100644 docs/atlas-new-design/destinations/agents-prd.md delete mode 100644 docs/atlas-new-design/destinations/chats-canvas-prd.md delete mode 100644 docs/atlas-new-design/destinations/connectors-prd.md delete mode 100644 docs/atlas-new-design/destinations/home-prd.md delete mode 100644 docs/atlas-new-design/destinations/inbox-prd.md delete mode 100644 docs/atlas-new-design/destinations/library-prd.md delete mode 100644 docs/atlas-new-design/destinations/projects-extensions-prd.md delete mode 100644 docs/atlas-new-design/destinations/projects-prd.md delete mode 100644 docs/atlas-new-design/destinations/routines-prd.md delete mode 100644 docs/atlas-new-design/destinations/team-memory-cmdk-prd.md delete mode 100644 docs/atlas-new-design/destinations/todos-prd.md delete mode 100644 docs/atlas-new-design/destinations/tools-prd.md delete mode 100644 docs/atlas-new-design/implementation-plan.md delete mode 100644 docs/decomp/README.md delete mode 100644 docs/decomp/agent-api/_index.md delete mode 100644 docs/decomp/agent-api/presentation-templates.md delete mode 100644 docs/decomp/agent-api/presentation.md delete mode 100644 docs/decomp/agent-api/service.md delete mode 100644 docs/decomp/capabilities/_index.md delete mode 100644 docs/decomp/capabilities/mcp-cards.md delete mode 100644 docs/decomp/context-memory/_index.md delete mode 100644 docs/decomp/context-memory/subagent-trace.md delete mode 100644 docs/decomp/delegation-subagents/_index.md delete mode 100644 docs/decomp/delegation-subagents/contracts.md delete mode 100644 docs/decomp/execution/_index.md delete mode 100644 docs/decomp/execution/contracts.md delete mode 100644 docs/decomp/persistence/_index.md delete mode 100644 docs/decomp/runtime-adapters/_index.md delete mode 100644 docs/decomp/runtime-adapters/in-memory-runtime-api-store.md delete mode 100644 docs/decomp/runtime-adapters/postgres-runtime-api-store.md delete mode 100644 docs/decomp/runtime-worker/_index.md delete mode 100644 docs/decomp/runtime-worker/handlers-run.md delete mode 100644 docs/decomp/runtime-worker/run-metrics.md delete mode 100644 docs/decomp/runtime-worker/stream-events.md delete mode 100644 docs/decomp/runtime-worker/stream-tools.md delete mode 100644 docs/new-design/0-OVERALL_PLAN.md delete mode 100644 docs/new-design/01-citations-live-registry.md delete mode 100644 docs/new-design/02-citations-followups.md delete mode 100644 docs/new-design/03-citations-model-declared.md delete mode 100644 docs/new-design/04-citations-binding-map.md delete mode 100644 docs/new-design/pr-1-2-per-chat-connector-scope.md delete mode 100644 docs/new-design/pr-1-2.1-per-chat-connector-scope-followups.md delete mode 100644 docs/new-design/pr-1.3-draft-artifact.md delete mode 100644 docs/new-design/pr-1.3.5-draft-completion.md delete mode 100644 docs/new-design/pr-1.4-two-stage-approvals.md delete mode 100644 docs/new-design/pr-1.4.1-approval-forwarding-hardening.md delete mode 100644 docs/new-design/pr-1.5-subagent-discovery-workspace-feeds.md delete mode 100644 docs/new-design/pr-1.6-workspace-defaults-conversation-lifecycle.md delete mode 100644 docs/new-design/pr-2.1-topbar-chrome-thinking-depth.md delete mode 100644 docs/new-design/pr-2.2-sidebar-user-card-keymap.md delete mode 100644 docs/new-design/pr-2.2.1-background-runs-and-live-pill.md delete mode 100644 docs/new-design/pr-2.3-welcome-state-thread-polish.md delete mode 100644 docs/new-design/pr-3.1-citation-chips-sources-tab.md delete mode 100644 docs/new-design/pr-3.2-workspace-pane-right-rail.md delete mode 100644 docs/new-design/pr-3.2.1-agents-tab-expandable-timeline.md delete mode 100644 docs/new-design/pr-3.2.2-subagent-card-shared-primitive.md delete mode 100644 docs/new-design/pr-3.2.3-subagent-backend-completion.md delete mode 100644 docs/new-design/pr-3.2.4-fleet-nests-compact-rows.md delete mode 100644 docs/new-design/pr-3.2.5-subagent-call-id-propagation.md delete mode 100644 docs/new-design/pr-3.2.5-subagent-runtime-correctness.md delete mode 100644 docs/new-design/pr-3.2.6-subagent-paused-resumed-events.md delete mode 100644 docs/new-design/pr-3.2.7-subagent-paused-fleet-row-and-clickable-timeline.md delete mode 100644 docs/new-design/pr-3.3-mcp-discovery-approval-polish.md delete mode 100644 docs/new-design/pr-3.4-connector-popover.md delete mode 100644 docs/new-design/pr-3.4.1-connector-popover-fidelity.md delete mode 100644 docs/new-design/pr-3.5-w1-w3-gap-closure.md delete mode 100644 docs/new-design/pr-3.6-approval-detail-and-subagent-timeline.md delete mode 100644 docs/new-design/pr-3.6-thinking-accordion.md delete mode 100644 docs/new-design/pr-3.7-sources-orientation.md delete mode 100644 docs/new-design/pr-3.7.1-sources-live-skeleton.md delete mode 100644 docs/new-design/pr-3.7.2-source-hover-preview.md delete mode 100644 docs/new-design/pr-3.7.3-sources-scale.md delete mode 100644 docs/new-design/pr-4.1-gap-fix-you-group-wiring.md delete mode 100644 docs/new-design/pr-4.1-settings-you-group.md delete mode 100644 docs/new-design/pr-4.2-settings-workspace-group.md delete mode 100644 docs/new-design/pr-4.3-settings-ai-and-data.md delete mode 100644 docs/new-design/pr-4.4-mcp-overlay-test-connection.md delete mode 100644 docs/new-design/pr-4.4.6-mcp-catalog-vs-connected.md delete mode 100644 docs/new-design/pr-4.4.6.2-approval-card-structured-payload.md delete mode 100644 docs/new-design/pr-4.4.6.3-approval-vendor-recognisers.md delete mode 100644 docs/new-design/pr-4.4.6.4-approval-undo-window.md delete mode 100644 docs/new-design/pr-4.4.7-phase-2-suggested-connectors.md delete mode 100644 docs/new-design/pr-4.5-usage-overlay-share-popover.md delete mode 100644 docs/new-design/pr-5.1-login-email-first-idp-discovery.md delete mode 100644 docs/new-design/pr-6.1-conversation-sharing.md delete mode 100644 docs/new-design/pr-6.2-conversation-fork.md delete mode 100644 docs/new-design/pr-7.1-audit-log-section.md delete mode 100644 docs/new-design/pr-7.2-per-connector-token-attribution.md delete mode 100644 docs/new-design/pr-8.0-atlas-visual-fidelity.md delete mode 100644 docs/new-design/pr-8.0.1-atlas-visual-fidelity-followups.md delete mode 100644 docs/new-design/pr-8.0.2-atlas-visible-fidelity-gaps.md delete mode 100644 docs/new-design/pr-8.0.3-atlas-completion-plan.md delete mode 100644 docs/new-design/pr-8.0.4-sidebar-header-search-popover-fixes.md delete mode 100644 docs/new-design/pr-8.0.5-policy-runtime-integration.md delete mode 100644 docs/new-design/pr-8.1-settings-ia-overhaul.md delete mode 100644 docs/new-design/pr-8.2-settings-phase-2.md delete mode 100644 docs/new-design/pr-8.3-settings-phase-3.md delete mode 100644 docs/new-design/pr-9.0-tool-display-metadata-middleware.md delete mode 100644 docs/new-design/pr-w0-dev-identity-framework.md delete mode 100644 docs/new-design/pr-w0-facade-no-content-forwarder.md delete mode 100644 docs/plan/frontend-parity-v3/PRD-A-icon-system.md delete mode 100644 docs/plan/frontend-parity-v3/PRD-B-tokens-and-status-tone.md delete mode 100644 docs/plan/frontend-parity-v3/PRD-C-app-rail.md delete mode 100644 docs/plan/frontend-parity-v3/PRD-D-command-palette.md delete mode 100644 docs/plan/frontend-parity-v3/PRD-E-settings-convergence.md delete mode 100644 docs/plan/frontend-parity-v3/PRD-F-provider-keys.md delete mode 100644 docs/plan/frontend-parity-v3/PRD-G-destination-parity.md delete mode 100644 docs/plan/frontend-parity-v3/PRD-H-backend-data-plane.md delete mode 100644 docs/plan/frontend-parity-v3/PRD-I-writethrough-hardening.md delete mode 100644 docs/plan/frontend-parity-v3/PRD-J-main-health-and-verification.md delete mode 100644 docs/plan/frontend-parity-v3/README.md delete mode 100644 docs/plan/frontend-parity-v3/STATUS.md delete mode 100644 docs/plan/generative-ui/00-implementation-plan.md delete mode 100644 docs/plan/generative-ui/PRD-01-surface-contract.md delete mode 100644 docs/plan/generative-ui/PRD-02-backend-emission.md delete mode 100644 docs/plan/generative-ui/PRD-03-archetype-renderers.md delete mode 100644 docs/plan/generative-ui/PRD-04-cockpit-wiring.md delete mode 100644 docs/plan/generative-ui/PRD-05-web-registration.md delete mode 100644 docs/plan/generative-ui/PRD-06-text-diff.md delete mode 100644 docs/plan/generative-ui/PRD-07-spec-generator.md delete mode 100644 docs/plan/generative-ui/PRD-08-spec-registry.md delete mode 100644 docs/plan/generative-ui/PRD-09-edit-and-commit.md delete mode 100644 docs/plan/generative-ui/PRD-10-tier2-completion.md delete mode 100644 docs/plan/generative-ui/PRD-11-hardening-evals.md delete mode 100644 docs/plan/generative-ui/PRD-12-rowset-review-recovery-architecture.md delete mode 100644 docs/plan/generative-ui/STATUS.md delete mode 100644 docs/plan/ui-kit-consolidation/DESIGN.md delete mode 100644 docs/roadmap/00-overview.md delete mode 100644 docs/roadmap/01-c1-deployment-profiles.md delete mode 100644 docs/roadmap/02-c2-migration-tooling.md delete mode 100644 docs/roadmap/03-c3-atomicity-fixes.md delete mode 100644 docs/roadmap/04-c4-pool-tuning.md delete mode 100644 docs/roadmap/05-a1-user-org-schema.md delete mode 100644 docs/roadmap/06-a2-sessions.md delete mode 100644 docs/roadmap/07-a3-oidc-sso.md delete mode 100644 docs/roadmap/08-a4-local-password.md delete mode 100644 docs/roadmap/09-a5-saml-sso.md delete mode 100644 docs/roadmap/10-a7-scim.md delete mode 100644 docs/roadmap/11-b1-runtime-run-usage.md delete mode 100644 docs/roadmap/12-b2-per-step-usage.md delete mode 100644 docs/roadmap/13-b3-pricing-and-cost.md delete mode 100644 docs/roadmap/14-b4-aggregation-endpoints.md delete mode 100644 docs/roadmap/15-c5-rls-tenant-isolation.md delete mode 100644 docs/roadmap/16-a6-mfa.md delete mode 100644 docs/roadmap/17-a8-lockout.md delete mode 100644 docs/roadmap/18-a9-frontend-login.md delete mode 100644 docs/roadmap/19-b5-context-command.md delete mode 100644 docs/roadmap/20-b6-usage-command.md delete mode 100644 docs/roadmap/21-b7-budgets.md delete mode 100644 docs/roadmap/22-b8-tool-budget.md delete mode 100644 docs/roadmap/23-c6-byok-kms.md delete mode 100644 docs/roadmap/24-c7-field-encryption.md delete mode 100644 docs/roadmap/25-c8-retention-sweeper.md delete mode 100644 docs/roadmap/26-c9-siem-export.md delete mode 100644 docs/roadmap/27-c10-read-replica.md delete mode 100644 docs/roadmap/28-c11-statement-observability.md delete mode 100644 docs/roadmap/29-a10-rbac-enforcement.md delete mode 100644 docs/roadmap/30-c12-backup-restore.md delete mode 100644 docs/roadmap/README.md delete mode 100644 docs/unused-code/ai-backend/01-agent-runtime-execution.md delete mode 100644 docs/unused-code/ai-backend/02-agent-runtime-capabilities.md delete mode 100644 docs/unused-code/ai-backend/03-agent-runtime-context-memory.md delete mode 100644 docs/unused-code/ai-backend/04-agent-runtime-delegation-subagents.md delete mode 100644 docs/unused-code/ai-backend/05-agent-runtime-persistence.md delete mode 100644 docs/unused-code/ai-backend/06-agent-runtime-api-and-services.md delete mode 100644 docs/unused-code/ai-backend/07-agent-runtime-cross-cutting.md delete mode 100644 docs/unused-code/ai-backend/08-runtime-api.md delete mode 100644 docs/unused-code/ai-backend/09-runtime-worker.md delete mode 100644 docs/unused-code/ai-backend/10-runtime-adapters.md delete mode 100644 docs/unused-code/ai-backend/README.md delete mode 100644 docs/unused-code/ai-backend/SUPPLEMENT-deep-scan-vulture50.md delete mode 100644 docs/unused-code/ai-backend/vulture_whitelist.py delete mode 100644 docs/unused-code/backend-facade/01-core-forwarding-and-agent-surface.md delete mode 100644 docs/unused-code/backend-facade/02-auth-and-session.md delete mode 100644 docs/unused-code/backend-facade/03-me-and-workspace-proxies.md delete mode 100644 docs/unused-code/backend-facade/04-scim.md delete mode 100644 docs/unused-code/backend-facade/05-observability.md delete mode 100644 docs/unused-code/backend-facade/06-bootstrap-settings-deployment-health.md delete mode 100644 docs/unused-code/backend-facade/07-vulture-fastapi-inventory.md delete mode 100644 docs/unused-code/backend-facade/README.md delete mode 100644 docs/unused-code/backend-facade/vulture_whitelist.py delete mode 100644 docs/unused-code/backend/README.md delete mode 100644 docs/unused-code/backend/artifacts/README.md delete mode 100644 docs/unused-code/backend/artifacts/cluster-agent-runtime-capabilities-vulture.txt delete mode 100644 docs/unused-code/backend/artifacts/cluster-agent-runtime-context-memory-vulture.txt delete mode 100644 docs/unused-code/backend/artifacts/cluster-agent-runtime-cross-cutting-vulture.txt delete mode 100644 docs/unused-code/backend/artifacts/cluster-agent-runtime-delegation-vulture.txt delete mode 100644 docs/unused-code/backend/artifacts/cluster-agent-runtime-domain-services-vulture.txt delete mode 100644 docs/unused-code/backend/artifacts/cluster-agent-runtime-execution-vulture.txt delete mode 100644 docs/unused-code/backend/artifacts/cluster-agent-runtime-observability-vulture.txt delete mode 100644 docs/unused-code/backend/artifacts/cluster-agent-runtime-ops-economics-vulture.txt delete mode 100644 docs/unused-code/backend/artifacts/cluster-agent-runtime-persistence-vulture.txt delete mode 100644 docs/unused-code/backend/artifacts/cluster-runtime-adapters-vulture.txt delete mode 100644 docs/unused-code/backend/artifacts/cluster-runtime-api-vulture.txt delete mode 100644 docs/unused-code/backend/artifacts/cluster-runtime-worker-vulture.txt delete mode 100644 docs/unused-code/backend/artifacts/vulture-min60-src-only.txt delete mode 100644 docs/unused-code/backend/cluster-agent-runtime-capabilities.md delete mode 100644 docs/unused-code/backend/cluster-agent-runtime-context-memory.md delete mode 100644 docs/unused-code/backend/cluster-agent-runtime-cross-cutting.md delete mode 100644 docs/unused-code/backend/cluster-agent-runtime-delegation.md delete mode 100644 docs/unused-code/backend/cluster-agent-runtime-domain-services.md delete mode 100644 docs/unused-code/backend/cluster-agent-runtime-execution.md delete mode 100644 docs/unused-code/backend/cluster-agent-runtime-observability.md delete mode 100644 docs/unused-code/backend/cluster-agent-runtime-ops-economics.md delete mode 100644 docs/unused-code/backend/cluster-agent-runtime-persistence.md delete mode 100644 docs/unused-code/backend/cluster-runtime-adapters.md delete mode 100644 docs/unused-code/backend/cluster-runtime-api.md delete mode 100644 docs/unused-code/backend/cluster-runtime-worker.md delete mode 100644 docs/unused-code/frontend/01-app-shell-and-utils.md delete mode 100644 docs/unused-code/frontend/02-api-layer.md delete mode 100644 docs/unused-code/frontend/03-auth.md delete mode 100644 docs/unused-code/frontend/04-connectors.md delete mode 100644 docs/unused-code/frontend/05-settings-and-workspace.md delete mode 100644 docs/unused-code/frontend/06-chat-chatmodel-and-events.md delete mode 100644 docs/unused-code/frontend/07-chat-ui-components.md delete mode 100644 docs/unused-code/frontend/08-chat-hooks-prompts-utils-markdown.md delete mode 100644 docs/unused-code/frontend/09-share-skills-me.md delete mode 100644 docs/unused-code/frontend/10-observability.md delete mode 100644 docs/unused-code/frontend/11-knip-unused-inventory.md delete mode 100644 docs/unused-code/frontend/README.md delete mode 100644 packages/chat-surface/src/destinations/agents/AgentCard.test.tsx delete mode 100644 packages/chat-surface/src/destinations/agents/AgentCard.tsx delete mode 100644 packages/chat-surface/src/destinations/agents/AgentDetailView.test.tsx delete mode 100644 packages/chat-surface/src/destinations/agents/AgentDetailView.tsx delete mode 100644 packages/chat-surface/src/destinations/agents/AgentEditor.test.tsx delete mode 100644 packages/chat-surface/src/destinations/agents/AgentEditor.tsx delete mode 100644 packages/chat-surface/src/destinations/agents/AgentUsageChart.test.tsx delete mode 100644 packages/chat-surface/src/destinations/agents/AgentUsageChart.tsx delete mode 100644 packages/chat-surface/src/destinations/agents/AgentsDestination.test.tsx delete mode 100644 packages/chat-surface/src/destinations/agents/AgentsDestination.tsx delete mode 100644 packages/chat-surface/src/destinations/agents/AgentsPanel.test.tsx delete mode 100644 packages/chat-surface/src/destinations/agents/AgentsPanel.tsx delete mode 100644 packages/chat-surface/src/destinations/agents/ForkDialog.test.tsx delete mode 100644 packages/chat-surface/src/destinations/agents/ForkDialog.tsx delete mode 100644 packages/chat-surface/src/destinations/agents/VersionHistoryTab.test.tsx delete mode 100644 packages/chat-surface/src/destinations/agents/VersionHistoryTab.tsx delete mode 100644 packages/chat-surface/src/destinations/agents/_agents-stub.test.ts delete mode 100644 packages/chat-surface/src/destinations/agents/_agents-stub.ts delete mode 100644 packages/chat-surface/src/destinations/agents/index.test.ts delete mode 100644 packages/chat-surface/src/destinations/agents/index.ts rename packages/chat-surface/src/destinations/{tools/onboarding => connectors/webhooks}/useStepMachine.ts (76%) delete mode 100644 packages/chat-surface/src/destinations/home/HomeDestination.test.tsx delete mode 100644 packages/chat-surface/src/destinations/home/HomeDestination.tsx delete mode 100644 packages/chat-surface/src/destinations/home/HomePanel.test.tsx delete mode 100644 packages/chat-surface/src/destinations/home/HomePanel.tsx delete mode 100644 packages/chat-surface/src/destinations/home/index.test.ts delete mode 100644 packages/chat-surface/src/destinations/home/index.ts delete mode 100644 packages/chat-surface/src/destinations/home/sections/HomeGreeting.tsx delete mode 100644 packages/chat-surface/src/destinations/home/sections/HomeQuickActionsSection.tsx delete mode 100644 packages/chat-surface/src/destinations/home/sections/InFlightStrip.tsx delete mode 100644 packages/chat-surface/src/destinations/home/sections/LiveActivityRail.tsx delete mode 100644 packages/chat-surface/src/destinations/home/sections/TodayTimeline.tsx delete mode 100644 packages/chat-surface/src/destinations/home/sections/TriageStrip.tsx delete mode 100644 packages/chat-surface/src/destinations/home/sections/WhatsNewDigest.tsx delete mode 100644 packages/chat-surface/src/destinations/home/sections/index.ts delete mode 100644 packages/chat-surface/src/destinations/inbox/InboxDestination.test.tsx delete mode 100644 packages/chat-surface/src/destinations/inbox/InboxDestination.tsx delete mode 100644 packages/chat-surface/src/destinations/inbox/InboxDetail.test.tsx delete mode 100644 packages/chat-surface/src/destinations/inbox/InboxDetail.tsx delete mode 100644 packages/chat-surface/src/destinations/inbox/InboxPanel.test.tsx delete mode 100644 packages/chat-surface/src/destinations/inbox/InboxPanel.tsx delete mode 100644 packages/chat-surface/src/destinations/inbox/_inbox-stub.ts delete mode 100644 packages/chat-surface/src/destinations/inbox/inbox-reply.test.tsx delete mode 100644 packages/chat-surface/src/destinations/inbox/inbox-reply.tsx delete mode 100644 packages/chat-surface/src/destinations/inbox/index.test.ts delete mode 100644 packages/chat-surface/src/destinations/inbox/index.ts delete mode 100644 packages/chat-surface/src/destinations/inbox/snooze-picker.test.tsx delete mode 100644 packages/chat-surface/src/destinations/inbox/snooze-picker.tsx delete mode 100644 packages/chat-surface/src/destinations/inbox/useInboxLayout.tsx delete mode 100644 packages/chat-surface/src/destinations/library/LibraryDestination.test.tsx delete mode 100644 packages/chat-surface/src/destinations/library/LibraryDestination.tsx delete mode 100644 packages/chat-surface/src/destinations/library/LibraryDetailView.test.tsx delete mode 100644 packages/chat-surface/src/destinations/library/LibraryDetailView.tsx delete mode 100644 packages/chat-surface/src/destinations/library/LibraryPanel.test.tsx delete mode 100644 packages/chat-surface/src/destinations/library/LibraryPanel.tsx delete mode 100644 packages/chat-surface/src/destinations/library/PageEditor.test.tsx delete mode 100644 packages/chat-surface/src/destinations/library/PageEditor.tsx delete mode 100644 packages/chat-surface/src/destinations/library/SaveToLibraryPopover.test.tsx delete mode 100644 packages/chat-surface/src/destinations/library/SaveToLibraryPopover.tsx delete mode 100644 packages/chat-surface/src/destinations/library/_library-stub.ts delete mode 100644 packages/chat-surface/src/destinations/library/index.test.ts delete mode 100644 packages/chat-surface/src/destinations/library/index.ts delete mode 100644 packages/chat-surface/src/destinations/library/preview/DatasetPreview.test.tsx delete mode 100644 packages/chat-surface/src/destinations/library/preview/DatasetPreview.tsx delete mode 100644 packages/chat-surface/src/destinations/library/preview/FilePreview.test.tsx delete mode 100644 packages/chat-surface/src/destinations/library/preview/FilePreview.tsx delete mode 100644 packages/chat-surface/src/destinations/library/preview/PagePreview.test.tsx delete mode 100644 packages/chat-surface/src/destinations/library/preview/PagePreview.tsx delete mode 100644 packages/chat-surface/src/destinations/memory/MemoryDestination.test.tsx delete mode 100644 packages/chat-surface/src/destinations/memory/MemoryDestination.tsx delete mode 100644 packages/chat-surface/src/destinations/memory/MemoryDetailView.test.tsx delete mode 100644 packages/chat-surface/src/destinations/memory/MemoryDetailView.tsx delete mode 100644 packages/chat-surface/src/destinations/memory/MemoryEditor.test.tsx delete mode 100644 packages/chat-surface/src/destinations/memory/MemoryEditor.tsx delete mode 100644 packages/chat-surface/src/destinations/memory/MemoryPanel.test.tsx delete mode 100644 packages/chat-surface/src/destinations/memory/MemoryPanel.tsx delete mode 100644 packages/chat-surface/src/destinations/memory/MemoryProposalCard.tsx delete mode 100644 packages/chat-surface/src/destinations/memory/MemoryProposalToast.test.tsx delete mode 100644 packages/chat-surface/src/destinations/memory/MemoryProposalToast.tsx delete mode 100644 packages/chat-surface/src/destinations/memory/index.test.ts delete mode 100644 packages/chat-surface/src/destinations/memory/index.ts delete mode 100644 packages/chat-surface/src/destinations/routines/RoutineDetail.test.tsx delete mode 100644 packages/chat-surface/src/destinations/routines/RoutineDetail.tsx delete mode 100644 packages/chat-surface/src/destinations/routines/RoutineEditor.test.tsx delete mode 100644 packages/chat-surface/src/destinations/routines/RoutineEditor.tsx delete mode 100644 packages/chat-surface/src/destinations/routines/RoutinesDestination.test.tsx delete mode 100644 packages/chat-surface/src/destinations/routines/RoutinesDestination.tsx delete mode 100644 packages/chat-surface/src/destinations/routines/RoutinesPanel.test.tsx delete mode 100644 packages/chat-surface/src/destinations/routines/RoutinesPanel.tsx delete mode 100644 packages/chat-surface/src/destinations/routines/_routines-stub.ts delete mode 100644 packages/chat-surface/src/destinations/routines/index.test.ts delete mode 100644 packages/chat-surface/src/destinations/routines/index.ts delete mode 100644 packages/chat-surface/src/destinations/team/OffboardingWizard.test.tsx delete mode 100644 packages/chat-surface/src/destinations/team/OffboardingWizard.tsx delete mode 100644 packages/chat-surface/src/destinations/team/PersonCard.test.tsx delete mode 100644 packages/chat-surface/src/destinations/team/PersonCard.tsx delete mode 100644 packages/chat-surface/src/destinations/team/PersonDetailView.test.tsx delete mode 100644 packages/chat-surface/src/destinations/team/PersonDetailView.tsx delete mode 100644 packages/chat-surface/src/destinations/team/TeamDestination.test.tsx delete mode 100644 packages/chat-surface/src/destinations/team/TeamDestination.tsx delete mode 100644 packages/chat-surface/src/destinations/team/TeamInviteWizard.test.tsx delete mode 100644 packages/chat-surface/src/destinations/team/TeamInviteWizard.tsx delete mode 100644 packages/chat-surface/src/destinations/team/TeamPanel.test.tsx delete mode 100644 packages/chat-surface/src/destinations/team/TeamPanel.tsx delete mode 100644 packages/chat-surface/src/destinations/team/index.test.ts delete mode 100644 packages/chat-surface/src/destinations/team/index.ts delete mode 100644 packages/chat-surface/src/destinations/todos/TodosDestination.test.tsx delete mode 100644 packages/chat-surface/src/destinations/todos/TodosDestination.tsx delete mode 100644 packages/chat-surface/src/destinations/todos/TodosPanel.test.tsx delete mode 100644 packages/chat-surface/src/destinations/todos/TodosPanel.tsx delete mode 100644 packages/chat-surface/src/destinations/todos/_todos-stub.ts delete mode 100644 packages/chat-surface/src/destinations/todos/extraction-banner.test.tsx delete mode 100644 packages/chat-surface/src/destinations/todos/extraction-banner.tsx delete mode 100644 packages/chat-surface/src/destinations/todos/index.test.ts delete mode 100644 packages/chat-surface/src/destinations/todos/index.ts delete mode 100644 packages/chat-surface/src/destinations/todos/inline-add.test.tsx delete mode 100644 packages/chat-surface/src/destinations/todos/inline-add.tsx delete mode 100644 packages/chat-surface/src/destinations/todos/recurrence-editor.test.tsx delete mode 100644 packages/chat-surface/src/destinations/todos/recurrence-editor.tsx delete mode 100644 packages/chat-surface/src/destinations/todos/subtask-tree.test.tsx delete mode 100644 packages/chat-surface/src/destinations/todos/subtask-tree.tsx delete mode 100644 packages/chat-surface/src/destinations/tools/OnboardingWizard.tsx delete mode 100644 packages/chat-surface/src/destinations/tools/ToolCard.tsx delete mode 100644 packages/chat-surface/src/destinations/tools/ToolDetailView.tsx delete mode 100644 packages/chat-surface/src/destinations/tools/ToolEditor.tsx delete mode 100644 packages/chat-surface/src/destinations/tools/ToolInvocationsTable.tsx delete mode 100644 packages/chat-surface/src/destinations/tools/ToolUsageChart.tsx delete mode 100644 packages/chat-surface/src/destinations/tools/ToolsDestination.test.tsx delete mode 100644 packages/chat-surface/src/destinations/tools/ToolsDestination.tsx delete mode 100644 packages/chat-surface/src/destinations/tools/ToolsPanel.tsx delete mode 100644 packages/chat-surface/src/destinations/tools/UsedByTab.tsx delete mode 100644 packages/chat-surface/src/destinations/tools/_tools-stub.ts delete mode 100644 packages/chat-surface/src/destinations/tools/index.ts delete mode 100644 packages/chat-surface/src/destinations/tools/onboarding/CodeWizard.tsx delete mode 100644 packages/chat-surface/src/destinations/tools/onboarding/McpWizard.tsx delete mode 100644 packages/chat-surface/src/destinations/tools/onboarding/OpenApiWizard.tsx delete mode 100644 packages/chat-surface/src/destinations/tools/onboarding/SkillWizard.tsx delete mode 100644 packages/chat-surface/src/destinations/tools/onboarding/WizardShell.tsx delete mode 100644 packages/chat-surface/src/destinations/tools/onboarding/index.ts delete mode 100644 tools/desktop-journeys/RUN-RESULTS.md diff --git a/CLAUDE.md b/CLAUDE.md index b6ee0c80d..4aa90da55 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -121,7 +121,7 @@ curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8200/v1/me/profile **AI backend runtime split:** -- `agent_runtime/` — pure domain. `execution/` (graph, deep agent builder, runtime contracts), `capabilities/` (tools, skills, MCP loaders + middleware + permissions), `context/memory`, `delegation/subagents`, `persistence/` (records, schema, ports), `observability/`, `api/` (presentation/service layer for the runtime API). +- `agent_runtime/` — pure domain, 21 packages. Runtime core: `execution/` (graph, deep agent builder, runtime contracts), `capabilities/` (tools, skills, MCP loaders + middleware + permissions), `context/memory`, `delegation/subagents`, `persistence/` (records + ports), `observability/`, `api/` (presentation/service layer for the runtime API), `prompts/`, `control_plane/`, `hyperparameters/`, `deployment/`. Generative Surfaces: `surfaces_v2/` (the Work Ledger), `effects/` (pure staging domain), `artifacts/`, `presentation/`. Known-misplaced, target home `backend`: `harness_quality/`, `pricing/`, `budgets/`, `release/`, `retention/` — see [BOUNDARY-AUDIT.md](docs/audit/ai-backend-smells/BOUNDARY-AUDIT.md). - `runtime_api/` — FastAPI app exposing conversations, runs, event replay, SSE streaming, cancel, approvals. - `runtime_worker/` — separate process that claims queued runs, drives the LangGraph execution, and emits typed `RuntimeEventEnvelope` records (`model_delta`, `final_response`, `run_completed`, tool/subagent/stream events). The API can also start an in-process worker via `RUNTIME_START_IN_PROCESS_WORKER=true` for local dev. - `runtime_adapters/` — `in_memory` for tests/dev, `file` (JSONL session folders) for the desktop. Selected by `RUNTIME_STORE_BACKEND`, dispatched through `runtime_adapters/registry.py`; adding a backend is a provider module plus one registration, with no edit to any dispatch code. diff --git a/apps/frontend/src/features/agents/AgentsRoute.test.tsx b/apps/frontend/src/features/agents/AgentsRoute.test.tsx deleted file mode 100644 index c9dc93929..000000000 --- a/apps/frontend/src/features/agents/AgentsRoute.test.tsx +++ /dev/null @@ -1,821 +0,0 @@ -import { - act, - fireEvent, - render, - screen, - waitFor, -} from "@testing-library/react"; -import { - afterEach, - beforeEach, - describe, - expect, - it, - vi, - type Mock, -} from "vitest"; - -import type { - Agent, - AgentId, - AgentListResponse, - AgentStreamEnvelope, - AgentUsageResponse, - AgentVersion, - AgentVersionId, - AgentVersionListResponse, - TenantId, - UserId, -} from "../../api/_agents-stub"; - -// Mock the agentsApi module so the tests don't have to drive the real -// fetch / SSE plumbing — that surface is covered in `agentsApi.test.ts`. -const agentsApiMocks = vi.hoisted(() => ({ - fetchAgents: vi.fn(), - fetchAgent: vi.fn(), - fetchAgentVersions: vi.fn(), - fetchAgentUsage: vi.fn(), - installAgent: vi.fn(), - uninstallAgent: vi.fn(), - duplicateAgent: vi.fn(), - patchAgent: vi.fn(), - snapshotAgentVersion: vi.fn(), - streamAgentEvents: vi.fn(), -})); -vi.mock("../../api/agentsApi", async () => { - const actual = await vi.importActual( - "../../api/agentsApi", - ); - return { - ...actual, - fetchAgents: agentsApiMocks.fetchAgents, - fetchAgent: agentsApiMocks.fetchAgent, - fetchAgentVersions: agentsApiMocks.fetchAgentVersions, - fetchAgentUsage: agentsApiMocks.fetchAgentUsage, - installAgent: agentsApiMocks.installAgent, - uninstallAgent: agentsApiMocks.uninstallAgent, - duplicateAgent: agentsApiMocks.duplicateAgent, - patchAgent: agentsApiMocks.patchAgent, - snapshotAgentVersion: agentsApiMocks.snapshotAgentVersion, - streamAgentEvents: agentsApiMocks.streamAgentEvents, - }; -}); - -// Imports below this line resolve through the mocks above. -import { AgentsRoute, applyAgentEnvelope } from "./AgentsRoute"; - -const IDENTITY = { orgId: "org_test", userId: "user_test" }; - -function agentFixture(overrides: Partial = {}): Agent { - return { - id: "agent_1" as AgentId, - tenant_id: "tenant_1" as TenantId, - name: "Inbox Triage", - slug: "inbox-triage", - description: "Triage incoming approvals.", - icon_emoji: "📥", - color_hue: 220, - version: 1, - status: "available", - origin: "system", - owner_user_id: null, - instructions: "You are a triage assistant.", - model_default: { - model_id: "anthropic:claude-sonnet-4-7-1m", - reasoning_depth: "balanced", - }, - connectors_default: [], - skills: [], - permissions: { - autonomy: "manual_approval", - max_tool_calls_per_run: 10, - max_output_tokens: 4000, - read_only: false, - }, - memory_ref: null, - created_at: "2026-05-01T00:00:00Z", - updated_at: "2026-05-18T09:00:00Z", - viewer_install_status: "available", - viewer_usage_7d: null, - ...overrides, - }; -} - -function versionFixture(overrides: Partial = {}): AgentVersion { - return { - id: "agentver_1" as AgentVersionId, - agent_id: "agent_1" as AgentId, - version: 1, - instructions_snapshot: "You are a triage assistant.", - model_default_snapshot: { - model_id: "anthropic:claude-sonnet-4-7-1m", - reasoning_depth: "balanced", - }, - skills_snapshot: [], - connectors_default_snapshot: [], - permissions_snapshot: { - autonomy: "manual_approval", - max_tool_calls_per_run: 10, - max_output_tokens: 4000, - read_only: false, - }, - created_at: "2026-05-18T09:00:00Z", - created_by: "user_test" as UserId, - label: null, - ...overrides, - }; -} - -function listResponse(items: ReadonlyArray): AgentListResponse { - return { items, next_cursor: null }; -} - -function versionListResponse( - items: ReadonlyArray, -): AgentVersionListResponse { - return { items, next_cursor: null }; -} - -function usageResponse(): AgentUsageResponse { - return { - agent_id: "agent_1" as AgentId, - period: "week", - rollups: [], - totals: { - agent_id: "agent_1" as AgentId, - period: "week", - run_count: 5, - token_in: 120, - token_out: 240, - cost_usd_micro: 1234, - }, - }; -} - -function envelope( - type: AgentStreamEnvelope["event_type"], - payload: AgentStreamEnvelope["payload"], - agentId: AgentId, - sequenceNo = 1, -): AgentStreamEnvelope { - return { - sequence_no: sequenceNo, - event_type: type, - agent_id: agentId, - payload, - emitted_at: "2026-05-18T09:00:00Z", - }; -} - -function captureStreamCallbacks(closeMock = vi.fn()): { - readonly close: Mock; - readonly lastCall: () => { - onEvent: (e: AgentStreamEnvelope) => void; - onError: (e: Event) => void; - onOpen?: () => void; - }; -} { - let lastCallbacks: { - onEvent: (e: AgentStreamEnvelope) => void; - onError: (e: Event) => void; - onOpen?: () => void; - } = { onEvent: () => undefined, onError: () => undefined }; - agentsApiMocks.streamAgentEvents.mockImplementation( - ({ - onEvent, - onError, - onOpen, - }: { - onEvent: (e: AgentStreamEnvelope) => void; - onError: (e: Event) => void; - onOpen?: () => void; - }) => { - lastCallbacks = { onEvent, onError, onOpen }; - return { close: closeMock }; - }, - ); - return { - close: closeMock, - lastCall: () => lastCallbacks, - }; -} - -// Default the version-history + usage fetches to resolved-empty so they -// don't reject and surface errors in render tests that don't care about -// the detail pane's data path. -function defaultDetailFetches(): void { - agentsApiMocks.fetchAgentVersions.mockResolvedValue(versionListResponse([])); - agentsApiMocks.fetchAgentUsage.mockResolvedValue(usageResponse()); -} - -// =========================================================================== -// PURE REDUCER — applyAgentEnvelope -// =========================================================================== - -describe("applyAgentEnvelope", () => { - it("flips status in place on agent_status_changed", () => { - const a = agentFixture({ id: "a" as AgentId, status: "available" }); - const next = applyAgentEnvelope( - [a], - envelope( - "agent_status_changed", - { - agent_id: "a" as AgentId, - status: "disabled", - prior_status: "available", - }, - "a" as AgentId, - ), - ); - expect(next[0].status).toBe("disabled"); - }); - - it("is a no-op for agent_installed / agent_uninstalled / agent_updated at the list layer", () => { - const a = agentFixture({ id: "a" as AgentId }); - const before = [a]; - - const installed = applyAgentEnvelope( - before, - envelope( - "agent_installed", - { agent_id: "a" as AgentId, user_id: "user_test" as UserId }, - "a" as AgentId, - ), - ); - expect(installed).toBe(before); - - const uninstalled = applyAgentEnvelope( - before, - envelope( - "agent_uninstalled", - { agent_id: "a" as AgentId, user_id: "user_test" as UserId }, - "a" as AgentId, - ), - ); - expect(uninstalled).toBe(before); - - const updated = applyAgentEnvelope( - before, - envelope( - "agent_updated", - { agent_id: "a" as AgentId, version: 2 }, - "a" as AgentId, - ), - ); - expect(updated).toBe(before); - }); - - it("returns the same array on agent_status_changed for an unknown id", () => { - const a = agentFixture({ id: "a" as AgentId, status: "available" }); - const before = [a]; - const after = applyAgentEnvelope( - before, - envelope( - "agent_status_changed", - { - agent_id: "b" as AgentId, - status: "disabled", - prior_status: "available", - }, - "b" as AgentId, - ), - ); - expect(after).toBe(before); - }); -}); - -// =========================================================================== -// RENDER — happy + error paths -// =========================================================================== - -describe("AgentsRoute render", () => { - beforeEach(() => { - agentsApiMocks.fetchAgents.mockReset(); - agentsApiMocks.fetchAgent.mockReset(); - agentsApiMocks.fetchAgentVersions.mockReset(); - agentsApiMocks.fetchAgentUsage.mockReset(); - agentsApiMocks.installAgent.mockReset(); - agentsApiMocks.uninstallAgent.mockReset(); - agentsApiMocks.duplicateAgent.mockReset(); - agentsApiMocks.patchAgent.mockReset(); - agentsApiMocks.snapshotAgentVersion.mockReset(); - agentsApiMocks.streamAgentEvents.mockReset(); - agentsApiMocks.streamAgentEvents.mockReturnValue({ close: vi.fn() }); - defaultDetailFetches(); - }); - afterEach(() => { - vi.clearAllMocks(); - }); - - it("renders the loading state, then the ready list", async () => { - agentsApiMocks.fetchAgents.mockResolvedValueOnce( - listResponse([agentFixture({ name: "Inbox Triage" })]), - ); - - render(); - - expect(screen.getByTestId("agents-route")).toHaveAttribute( - "data-state", - "loading", - ); - - await waitFor(() => { - expect(screen.getByTestId("agents-route")).toHaveAttribute( - "data-state", - "ready", - ); - }); - expect(screen.getByText("Inbox Triage")).toBeInTheDocument(); - expect(screen.getByTestId("agents-route")).toHaveAttribute( - "data-item-count", - "1", - ); - }); - - it("renders the empty state when the server returns no items", async () => { - agentsApiMocks.fetchAgents.mockResolvedValueOnce(listResponse([])); - render(); - await waitFor(() => { - expect(screen.getByTestId("agents-route-empty")).toBeInTheDocument(); - }); - }); - - it("renders the error state on fetch failure and retries on click", async () => { - agentsApiMocks.fetchAgents.mockRejectedValueOnce(new Error("boom")); - agentsApiMocks.fetchAgents.mockResolvedValueOnce( - listResponse([agentFixture()]), - ); - - render(); - - await waitFor(() => { - expect(screen.getByTestId("agents-route-error")).toBeInTheDocument(); - }); - expect( - screen.getByTestId("agents-route-error-message").textContent, - ).toContain("boom"); - - fireEvent.click(screen.getByTestId("agents-route-retry")); - - await waitFor(() => { - expect(screen.getByTestId("agents-route")).toHaveAttribute( - "data-state", - "ready", - ); - }); - expect(agentsApiMocks.fetchAgents).toHaveBeenCalledTimes(2); - }); -}); - -// =========================================================================== -// SSE — deltas merge + refetch for install/uninstall/update events -// =========================================================================== - -describe("AgentsRoute SSE", () => { - beforeEach(() => { - agentsApiMocks.fetchAgents.mockReset(); - agentsApiMocks.fetchAgent.mockReset(); - agentsApiMocks.streamAgentEvents.mockReset(); - defaultDetailFetches(); - }); - afterEach(() => { - vi.clearAllMocks(); - }); - - it("subscribes after the initial load and flips status on agent_status_changed deltas", async () => { - agentsApiMocks.fetchAgents.mockResolvedValueOnce( - listResponse([agentFixture({ id: "a" as AgentId, status: "available" })]), - ); - const sse = captureStreamCallbacks(); - - render(); - - await waitFor(() => { - expect(agentsApiMocks.streamAgentEvents).toHaveBeenCalledTimes(1); - }); - - act(() => { - sse.lastCall().onEvent( - envelope( - "agent_status_changed", - { - agent_id: "a" as AgentId, - status: "disabled", - prior_status: "available", - }, - "a" as AgentId, - 1, - ), - ); - }); - - await waitFor(() => { - expect(screen.getByTestId("agents-route-row")).toHaveAttribute( - "data-agent-status", - "disabled", - ); - }); - }); - - it("refetches the affected row on agent_installed (merged-overrides view, sub-PRD §3.3)", async () => { - agentsApiMocks.fetchAgents.mockResolvedValueOnce( - listResponse([ - agentFixture({ - id: "a" as AgentId, - viewer_install_status: "available", - }), - ]), - ); - agentsApiMocks.fetchAgent.mockResolvedValueOnce( - agentFixture({ - id: "a" as AgentId, - viewer_install_status: "installed", - }), - ); - const sse = captureStreamCallbacks(); - - render(); - - await waitFor(() => { - expect(agentsApiMocks.streamAgentEvents).toHaveBeenCalledTimes(1); - }); - - act(() => { - sse.lastCall().onEvent( - envelope( - "agent_installed", - { - agent_id: "a" as AgentId, - user_id: "user_test" as UserId, - scope: "user", - }, - "a" as AgentId, - 5, - ), - ); - }); - - await waitFor(() => { - expect(agentsApiMocks.fetchAgent).toHaveBeenCalledWith(IDENTITY, "a"); - }); - }); - - it("closes the active stream when the stream errors out (reconnect is then scheduled)", async () => { - agentsApiMocks.fetchAgents.mockResolvedValueOnce( - listResponse([agentFixture()]), - ); - const sse = captureStreamCallbacks(); - - render(); - - await waitFor(() => { - expect(agentsApiMocks.streamAgentEvents).toHaveBeenCalledTimes(1); - }); - - // Trigger an error → component closes the active handle and queues - // an exponential-backoff reconnect via setTimeout. Same pattern as - // ProjectsRoute / RoutinesRoute — we assert on the observable close - // side-effect; the reconnect timing is covered structurally by the - // RECONNECT_BACKOFF_* constants. - act(() => { - sse.lastCall().onError(new Event("error")); - }); - expect(sse.close).toHaveBeenCalled(); - }); -}); - -// =========================================================================== -// MUTATIONS — install / uninstall / duplicate -// =========================================================================== - -describe("AgentsRoute mutations", () => { - beforeEach(() => { - agentsApiMocks.fetchAgents.mockReset(); - agentsApiMocks.fetchAgent.mockReset(); - agentsApiMocks.installAgent.mockReset(); - agentsApiMocks.uninstallAgent.mockReset(); - agentsApiMocks.duplicateAgent.mockReset(); - agentsApiMocks.streamAgentEvents.mockReset(); - agentsApiMocks.streamAgentEvents.mockReturnValue({ close: vi.fn() }); - defaultDetailFetches(); - }); - afterEach(() => { - vi.clearAllMocks(); - }); - - it("calls installAgent and merges the updated row", async () => { - const a = agentFixture({ - id: "a" as AgentId, - viewer_install_status: "available", - }); - agentsApiMocks.fetchAgents.mockResolvedValueOnce(listResponse([a])); - agentsApiMocks.installAgent.mockResolvedValueOnce( - agentFixture({ - id: "a" as AgentId, - viewer_install_status: "installed", - status: "installed", - }), - ); - - render(); - - await waitFor(() => { - expect(screen.getByTestId("agents-route-install")).toBeInTheDocument(); - }); - - fireEvent.click(screen.getByTestId("agents-route-install")); - - await waitFor(() => { - expect(agentsApiMocks.installAgent).toHaveBeenCalledWith(IDENTITY, "a"); - }); - await waitFor(() => { - expect(screen.getByTestId("agents-route-uninstall")).toBeInTheDocument(); - }); - }); - - it("calls uninstallAgent and merges the updated row", async () => { - const a = agentFixture({ - id: "a" as AgentId, - viewer_install_status: "installed", - status: "installed", - }); - agentsApiMocks.fetchAgents.mockResolvedValueOnce(listResponse([a])); - agentsApiMocks.uninstallAgent.mockResolvedValueOnce( - agentFixture({ - id: "a" as AgentId, - viewer_install_status: "available", - status: "available", - }), - ); - - render(); - - await waitFor(() => { - expect(screen.getByTestId("agents-route-uninstall")).toBeInTheDocument(); - }); - fireEvent.click(screen.getByTestId("agents-route-uninstall")); - - await waitFor(() => { - expect(agentsApiMocks.uninstallAgent).toHaveBeenCalledWith(IDENTITY, "a"); - }); - await waitFor(() => { - expect(screen.getByTestId("agents-route-install")).toBeInTheDocument(); - }); - }); - - it("calls duplicateAgent and prepends the forked row", async () => { - const a = agentFixture({ id: "a" as AgentId, origin: "system" }); - agentsApiMocks.fetchAgents.mockResolvedValueOnce(listResponse([a])); - agentsApiMocks.duplicateAgent.mockResolvedValueOnce( - agentFixture({ - id: "a_custom" as AgentId, - origin: "custom", - owner_user_id: "user_test" as UserId, - name: "Inbox Triage (custom)", - viewer_install_status: "draft", - status: "draft", - }), - ); - - render(); - - await waitFor(() => { - expect(screen.getByTestId("agents-route-duplicate")).toBeInTheDocument(); - }); - fireEvent.click(screen.getByTestId("agents-route-duplicate")); - - await waitFor(() => { - expect(agentsApiMocks.duplicateAgent).toHaveBeenCalledWith(IDENTITY, "a"); - }); - await waitFor(() => { - expect(screen.getByText("Inbox Triage (custom)")).toBeInTheDocument(); - }); - }); - - it("surfaces a pending-error banner when install fails and keeps rendering the list", async () => { - const a = agentFixture({ - id: "a" as AgentId, - viewer_install_status: "available", - }); - agentsApiMocks.fetchAgents.mockResolvedValueOnce(listResponse([a])); - agentsApiMocks.installAgent.mockRejectedValueOnce( - new Error("install_forbidden"), - ); - - render(); - - await waitFor(() => { - expect(screen.getByTestId("agents-route-install")).toBeInTheDocument(); - }); - fireEvent.click(screen.getByTestId("agents-route-install")); - - await waitFor(() => { - expect( - screen.getByTestId("agents-route-pending-error"), - ).toBeInTheDocument(); - }); - expect( - screen.getByTestId("agents-route-pending-error").textContent, - ).toContain("install_forbidden"); - // The list itself is still rendered — the user can retry. - expect(screen.getByTestId("agents-route-row")).toBeInTheDocument(); - }); -}); - -// =========================================================================== -// DETAIL PANEL — editor + version history + usage -// =========================================================================== - -describe("AgentsRoute detail panel", () => { - beforeEach(() => { - agentsApiMocks.fetchAgents.mockReset(); - agentsApiMocks.fetchAgent.mockReset(); - agentsApiMocks.fetchAgentVersions.mockReset(); - agentsApiMocks.fetchAgentUsage.mockReset(); - agentsApiMocks.patchAgent.mockReset(); - agentsApiMocks.snapshotAgentVersion.mockReset(); - agentsApiMocks.streamAgentEvents.mockReset(); - agentsApiMocks.streamAgentEvents.mockReturnValue({ close: vi.fn() }); - }); - afterEach(() => { - vi.clearAllMocks(); - }); - - it("opens the detail panel on row select and surfaces version history + usage", async () => { - const a = agentFixture({ id: "a" as AgentId }); - agentsApiMocks.fetchAgents.mockResolvedValueOnce(listResponse([a])); - agentsApiMocks.fetchAgentVersions.mockResolvedValueOnce( - versionListResponse([versionFixture({ version: 1, label: "Initial" })]), - ); - agentsApiMocks.fetchAgentUsage.mockResolvedValueOnce(usageResponse()); - - render(); - - await waitFor(() => { - expect(screen.getByTestId("agents-route-select")).toBeInTheDocument(); - }); - fireEvent.click(screen.getByTestId("agents-route-select")); - - await waitFor(() => { - expect(screen.getByTestId("agents-route-detail")).toBeInTheDocument(); - }); - - // Version history block fetches against the selected agent id. - await waitFor(() => { - expect(agentsApiMocks.fetchAgentVersions).toHaveBeenCalledWith( - IDENTITY, - "a", - { limit: 20 }, - ); - }); - await waitFor(() => { - expect(screen.getByTestId("agents-route-version-row")).toHaveAttribute( - "data-version", - "1", - ); - }); - - // Usage block fetches and renders the totals. - await waitFor(() => { - expect(agentsApiMocks.fetchAgentUsage).toHaveBeenCalledWith( - IDENTITY, - "a", - { period: "week" }, - ); - }); - await waitFor(() => { - expect(screen.getByTestId("agents-route-usage-totals")).toHaveAttribute( - "data-run-count", - "5", - ); - }); - }); - - it("saves the edited instructions through patchAgent and merges the updated row", async () => { - const a = agentFixture({ - id: "a" as AgentId, - instructions: "old", - origin: "custom", - owner_user_id: "user_test" as UserId, - }); - agentsApiMocks.fetchAgents.mockResolvedValueOnce(listResponse([a])); - agentsApiMocks.fetchAgentVersions.mockResolvedValueOnce( - versionListResponse([]), - ); - agentsApiMocks.fetchAgentUsage.mockResolvedValueOnce(usageResponse()); - agentsApiMocks.patchAgent.mockResolvedValueOnce( - agentFixture({ - id: "a" as AgentId, - instructions: "new", - origin: "custom", - owner_user_id: "user_test" as UserId, - }), - ); - - render(); - - await waitFor(() => { - expect(screen.getByTestId("agents-route-select")).toBeInTheDocument(); - }); - fireEvent.click(screen.getByTestId("agents-route-select")); - - await waitFor(() => { - expect( - screen.getByTestId("agents-route-instructions"), - ).toBeInTheDocument(); - }); - const ta = screen.getByTestId("agents-route-instructions"); - fireEvent.change(ta, { target: { value: "new" } }); - fireEvent.click(screen.getByTestId("agents-route-save")); - - await waitFor(() => { - expect(agentsApiMocks.patchAgent).toHaveBeenCalledWith(IDENTITY, "a", { - instructions: "new", - }); - }); - }); - - it("surfaces a 409 agent_origin_immutable error when patching a system/community agent", async () => { - const a = agentFixture({ id: "a" as AgentId, origin: "system" }); - agentsApiMocks.fetchAgents.mockResolvedValueOnce(listResponse([a])); - agentsApiMocks.fetchAgentVersions.mockResolvedValueOnce( - versionListResponse([]), - ); - agentsApiMocks.fetchAgentUsage.mockResolvedValueOnce(usageResponse()); - agentsApiMocks.patchAgent.mockRejectedValueOnce( - new Error("agent_origin_immutable"), - ); - - render(); - - await waitFor(() => { - expect(screen.getByTestId("agents-route-select")).toBeInTheDocument(); - }); - fireEvent.click(screen.getByTestId("agents-route-select")); - - await waitFor(() => { - expect(screen.getByTestId("agents-route-save")).toBeInTheDocument(); - }); - fireEvent.click(screen.getByTestId("agents-route-save")); - - await waitFor(() => { - expect( - screen.getByTestId("agents-route-pending-error"), - ).toBeInTheDocument(); - }); - expect( - screen.getByTestId("agents-route-pending-error").textContent, - ).toContain("agent_origin_immutable"); - }); - - it("snapshots a new version via snapshotAgentVersion + refetches the agent", async () => { - const a = agentFixture({ - id: "a" as AgentId, - version: 2, - origin: "custom", - owner_user_id: "user_test" as UserId, - }); - agentsApiMocks.fetchAgents.mockResolvedValueOnce(listResponse([a])); - agentsApiMocks.fetchAgentVersions.mockResolvedValueOnce( - versionListResponse([]), - ); - agentsApiMocks.fetchAgentUsage.mockResolvedValueOnce(usageResponse()); - agentsApiMocks.snapshotAgentVersion.mockResolvedValueOnce( - versionFixture({ version: 3, label: "v3-label" }), - ); - agentsApiMocks.fetchAgent.mockResolvedValueOnce( - agentFixture({ - id: "a" as AgentId, - version: 3, - origin: "custom", - owner_user_id: "user_test" as UserId, - }), - ); - - render(); - - await waitFor(() => { - expect(screen.getByTestId("agents-route-select")).toBeInTheDocument(); - }); - fireEvent.click(screen.getByTestId("agents-route-select")); - - await waitFor(() => { - expect(screen.getByTestId("agents-route-snapshot")).toBeInTheDocument(); - }); - fireEvent.change(screen.getByTestId("agents-route-version-label"), { - target: { value: "v3-label" }, - }); - fireEvent.click(screen.getByTestId("agents-route-snapshot")); - - await waitFor(() => { - expect(agentsApiMocks.snapshotAgentVersion).toHaveBeenCalledWith( - IDENTITY, - "a", - { label: "v3-label" }, - ); - }); - await waitFor(() => { - expect(agentsApiMocks.fetchAgent).toHaveBeenCalledWith(IDENTITY, "a"); - }); - }); -}); diff --git a/apps/frontend/src/features/agents/AgentsRoute.tsx b/apps/frontend/src/features/agents/AgentsRoute.tsx deleted file mode 100644 index a2818a77e..000000000 --- a/apps/frontend/src/features/agents/AgentsRoute.tsx +++ /dev/null @@ -1,860 +0,0 @@ -// AgentsRoute — data binder for the Phase 8 Agents destination -// (the 14th destination per -// `docs/atlas-new-design/destinations/agents-prd.md`). -// -// Mirrors the P6-C ProjectsRoute / P5-C RoutinesRoute pattern: -// 1. Fetches `GET /v1/agents` via `agentsApi` and owns -// loading / error / ready states (sub-PRD §4.1 list view). -// 2. Opens the `/v1/agents/stream` SSE channel (sub-PRD §4.12) -// with exponential-backoff reconnect, tracking the highest -// `sequence_no` for `?after_sequence=N` resume (cross-audit §5.2). -// 3. Merges `agent_installed` / `agent_uninstalled` / -// `agent_updated` / `agent_status_changed` envelopes into the -// local list — installs and status flips refetch the affected -// row so the merged-overrides view stays correct (sub-PRD §3.3). -// 4. Proxies install / uninstall mutations back to the backend, -// optimistically driving the SSE-merged local list while the -// server confirms. -// 5. Renders a host-side scaffolding today with a detail panel -// that surfaces the editor + version history + per-agent usage. -// The package-shipped `` exists as a Wave-0 -// placeholder; this route is the feature-binder that adds the -// real fetch / mutate / SSE behaviour the destination -// component does not own. -// -// Why a feature-level wrapper, not props on `` -// today: the package component is intentionally a dignified -// placeholder (cross-audit + impl-plan §1.6). Owning the data flow -// + state mutation + SSE here lets the destination component reshape -// without forcing an App.tsx-level rewrite — same compromise the -// InboxRoute / TodosRoute / RoutinesRoute / ProjectsRoute waves made. - -import { - useCallback, - useEffect, - useRef, - useState, - type ReactElement, -} from "react"; - -import type { RequestIdentity } from "../../api/config"; -import { - duplicateAgent, - fetchAgent, - fetchAgents, - fetchAgentUsage, - fetchAgentVersions, - installAgent, - patchAgent, - snapshotAgentVersion, - streamAgentEvents, - uninstallAgent, -} from "../../api/agentsApi"; -import type { - Agent, - AgentId, - AgentListResponse, - AgentStreamEnvelope, - AgentUsageResponse, - AgentVersion, - AgentVersionListResponse, -} from "../../api/_agents-stub"; -import { errorMessage } from "../../utils/errors"; - -/** Reconnect backoff bounds (mirrors ProjectsRoute / RoutinesRoute). */ -const RECONNECT_BACKOFF_MIN_MS = 1_000; -const RECONNECT_BACKOFF_MAX_MS = 30_000; - -interface AgentsRouteProps { - readonly identity: RequestIdentity; -} - -type ViewState = - | { readonly kind: "loading" } - | { readonly kind: "error"; readonly message: string } - | { - readonly kind: "ready"; - readonly items: ReadonlyArray; - readonly highestSequenceNo: number; - }; - -/** - * Apply one durable SSE envelope to the local agents list. Pure - * function so a test can drive it without a mounted component. - * - * Semantics (sub-PRD §4.12 event types): - * - `agent_installed` → no-op at list layer; caller refetches the affected row. - * - `agent_uninstalled` → no-op at list layer; caller refetches the affected row. - * - `agent_updated` → no-op at list layer; caller refetches the affected row. - * - `agent_version_snapshot` → no-op (version row, not agent row). - * - `agent_status_changed` → in-place status flip when row is present. - * - * For every event type we leave list mutation that affects the - * merged-overrides view to a refetch effect in the component — the - * status flip is the only one that can be reflected purely from the - * envelope payload itself. - */ -export function applyAgentEnvelope( - items: ReadonlyArray, - envelope: AgentStreamEnvelope, -): ReadonlyArray { - if (envelope.event_type !== "agent_status_changed") { - return items; - } - const idx = items.findIndex((a) => a.id === envelope.agent_id); - if (idx === -1) { - return items; - } - const payload = envelope.payload as { - readonly status?: Agent["status"]; - }; - if (payload.status === undefined) { - return items; - } - const next = items.slice(); - next[idx] = { ...next[idx], status: payload.status }; - return next; -} - -export function AgentsRoute({ identity }: AgentsRouteProps): ReactElement { - const [state, setState] = useState({ kind: "loading" }); - const [reloadToken, setReloadToken] = useState(0); - const [pendingError, setPendingError] = useState(null); - const [selectedId, setSelectedId] = useState(null); - - // ---- Initial fetch ------------------------------------------------ - useEffect(() => { - let cancelled = false; - setState({ kind: "loading" }); - - fetchAgents(identity, { limit: 50 }) - .then((list: AgentListResponse) => { - if (cancelled) return; - setState({ - kind: "ready", - items: list.items, - highestSequenceNo: 0, - }); - }) - .catch((error: unknown) => { - if (cancelled) return; - setState({ - kind: "error", - message: errorMessage(error, "Could not load agents."), - }); - }); - - return () => { - cancelled = true; - }; - }, [identity, reloadToken]); - - // ---- SSE subscription with exponential-backoff reconnect --------- - const backoffRef = useRef(RECONNECT_BACKOFF_MIN_MS); - useEffect(() => { - if (state.kind !== "ready") { - return; - } - let cancelled = false; - let activeHandle: { close(): void } | null = null; - let reconnectTimer: ReturnType | null = null; - backoffRef.current = RECONNECT_BACKOFF_MIN_MS; - - function open(): void { - if (cancelled) return; - let afterSequence = 0; - setState((prev) => { - if (prev.kind === "ready") afterSequence = prev.highestSequenceNo; - return prev; - }); - - activeHandle = streamAgentEvents({ - identity, - afterSequence: afterSequence > 0 ? afterSequence : undefined, - onOpen: () => { - backoffRef.current = RECONNECT_BACKOFF_MIN_MS; - }, - onEvent: (envelope) => { - if (cancelled) return; - setState((prev) => { - if (prev.kind !== "ready") return prev; - const items = applyAgentEnvelope(prev.items, envelope); - const highestSequenceNo = Math.max( - prev.highestSequenceNo, - envelope.sequence_no, - ); - return { kind: "ready", items, highestSequenceNo }; - }); - - // Refetch-driven merge for events that touch the merged- - // overrides view (sub-PRD §3.3). The reducer can't synthesize - // these because the install state + 7d usage projection are - // server-computed. - if ( - envelope.event_type === "agent_installed" || - envelope.event_type === "agent_uninstalled" || - envelope.event_type === "agent_updated" - ) { - void fetchAgent(identity, envelope.agent_id) - .then((agent) => { - if (cancelled) return; - setState((prev) => { - if (prev.kind !== "ready") return prev; - const idx = prev.items.findIndex((a) => a.id === agent.id); - if (idx === -1) { - return { ...prev, items: [agent, ...prev.items] }; - } - const next = prev.items.slice(); - next[idx] = agent; - return { ...prev, items: next }; - }); - }) - .catch(() => undefined); - } - }, - onError: () => { - if (cancelled) return; - activeHandle?.close(); - activeHandle = null; - const delay = backoffRef.current; - backoffRef.current = Math.min( - backoffRef.current * 2, - RECONNECT_BACKOFF_MAX_MS, - ); - reconnectTimer = setTimeout(open, delay); - }, - }); - } - - open(); - - return () => { - cancelled = true; - if (reconnectTimer !== null) { - clearTimeout(reconnectTimer); - } - activeHandle?.close(); - }; - }, [identity, state.kind]); - - // ---- Mutation helpers (install / uninstall / duplicate / patch) -- - - const mergeUpdated = useCallback((updated: Agent): void => { - setState((prev) => { - if (prev.kind !== "ready") return prev; - const idx = prev.items.findIndex((a) => a.id === updated.id); - if (idx === -1) { - return { ...prev, items: [updated, ...prev.items] }; - } - const next = prev.items.slice(); - next[idx] = updated; - return { ...prev, items: next }; - }); - }, []); - - const handleInstall = useCallback( - async (id: AgentId): Promise => { - setPendingError(null); - try { - const updated = await installAgent(identity, id); - mergeUpdated(updated); - } catch (error: unknown) { - setPendingError(errorMessage(error, "Could not install agent.")); - } - }, - [identity, mergeUpdated], - ); - - const handleUninstall = useCallback( - async (id: AgentId): Promise => { - setPendingError(null); - try { - const updated = await uninstallAgent(identity, id); - mergeUpdated(updated); - } catch (error: unknown) { - setPendingError(errorMessage(error, "Could not uninstall agent.")); - } - }, - [identity, mergeUpdated], - ); - - const handleDuplicate = useCallback( - async (id: AgentId): Promise => { - setPendingError(null); - try { - const forked = await duplicateAgent(identity, id); - mergeUpdated(forked); - } catch (error: unknown) { - setPendingError(errorMessage(error, "Could not duplicate agent.")); - } - }, - [identity, mergeUpdated], - ); - - // ---- Render ------------------------------------------------------- - if (state.kind === "error") { - return ( -
-
-
- Could not load agents -
-
- {state.message} -
- -
-
- ); - } - - const items = state.kind === "ready" ? state.items : []; - const selected = - selectedId !== null - ? (items.find((a) => a.id === selectedId) ?? null) - : null; - - return ( -
- {/* List pane */} -
- {pendingError !== null && ( -
- {pendingError} -
- )} - {state.kind === "loading" ? ( -
- Loading agents… -
- ) : items.length === 0 ? ( -
- No agents yet. -
- ) : ( -
    - {items.map((agent) => ( -
  • - - {agent.viewer_install_status === "installed" ? ( - - ) : ( - - )} - -
  • - ))} -
- )} -
- - {/* Detail pane (editor + version history + usage) */} - {selected !== null && ( - setSelectedId(null)} - onSaved={mergeUpdated} - onError={(msg) => setPendingError(msg)} - /> - )} -
- ); -} - -// =========================================================================== -// Detail panel — editor + version history + per-agent usage -// =========================================================================== - -interface AgentDetailPanelProps { - readonly identity: RequestIdentity; - readonly agent: Agent; - readonly onClose: () => void; - readonly onSaved: (agent: Agent) => void; - readonly onError: (message: string) => void; -} - -function AgentDetailPanel({ - identity, - agent, - onClose, - onSaved, - onError, -}: AgentDetailPanelProps): ReactElement { - // Editor — keyed by agent id so switching the selection resets the form. - const [draftInstructions, setDraftInstructions] = useState( - agent.instructions, - ); - const [versionLabel, setVersionLabel] = useState(""); - const editorKey = agent.id; - // Sync the draft instructions when the upstream agent record changes - // (e.g. an SSE-driven refetch lands while the detail pane is open). - useEffect(() => { - setDraftInstructions(agent.instructions); - }, [editorKey, agent.instructions]); - - const handleSave = useCallback(async (): Promise => { - try { - const updated = await patchAgent(identity, agent.id, { - instructions: draftInstructions, - }); - onSaved(updated); - } catch (error: unknown) { - onError(errorMessage(error, "Could not save agent.")); - } - }, [identity, agent.id, draftInstructions, onSaved, onError]); - - const handleSnapshot = useCallback(async (): Promise => { - try { - await snapshotAgentVersion(identity, agent.id, { - label: versionLabel.length > 0 ? versionLabel : undefined, - }); - setVersionLabel(""); - // Refresh the agent record so the bumped version reflects in the - // header — the explicit fetch sidesteps waiting for the SSE delta. - const refreshed = await fetchAgent(identity, agent.id); - onSaved(refreshed); - } catch (error: unknown) { - onError(errorMessage(error, "Could not snapshot agent version.")); - } - }, [identity, agent.id, versionLabel, onSaved, onError]); - - return ( -
-
-
-
- - {agent.name} -
-
- {agent.origin} · v{agent.version} · {agent.status} -
-
- -
- - {/* Editor */} -
- -