From a40f9917db0110313e4f93fe15202bc69c2fecc6 Mon Sep 17 00:00:00 2001 From: Jason Hedman <40368124+jasonhedman@users.noreply.github.com> Date: Fri, 4 Sep 2026 11:38:29 -0400 Subject: [PATCH 1/2] refactor: establish explicit source ownership --- .oxlintrc.jsonc | 14 +- AGENTS.md | 12 +- agent/agent.ts | 8 +- agent/channels/eve.ts | 13 +- agent/channels/linq.ts | 16 +- agent/channels/scheduled-run.ts | 4 +- agent/hooks/scheduled-run-completion.ts | 6 +- agent/hooks/session-owner.ts | 8 +- agent/instructions/10-execution-safety.ts | 2 +- agent/instructions/20-role.ts | 2 +- agent/instructions/25-worker-coordination.ts | 2 +- agent/instructions/30-message-style.ts | 2 +- agent/lib/google-workspace/client.ts | 4 +- ...google-workspace-generated-clients.test.ts | 8 +- .../tests/google-workspace.test.ts | 12 +- .../lib/linq-image-artifact/delivery.test.ts | 4 +- agent/lib/linq-image-artifact/delivery.ts | 10 +- agent/lib/linq-image-artifact/markdown.ts | 2 +- agent/lib/principal-scope.ts | 5 +- agent/lib/profile-memory.ts | 4 +- agent/lib/schedules/report-lifecycle.ts | 4 +- agent/lib/schedules/report.ts | 2 +- agent/lib/schedules/request.ts | 4 +- agent/lib/schedules/tools.ts | 4 +- agent/lib/tests/principal-scope.test.ts | 4 +- agent/lib/tests/profile-memory.test.ts | 6 +- agent/memory/personal_info.ts | 8 +- agent/memory/profile.ts | 2 +- agent/schedules/dynamic.ts | 8 +- agent/subagents/browser-agent/agent.ts | 4 +- .../browser-agent/hooks/session-owner.ts | 6 +- .../browser-agent/hooks/trace-telemetry.ts | 14 +- agent/subagents/browser-agent/lib/access.ts | 4 +- .../browser-agent/lib/autofill/native.ts | 2 +- .../browser-agent/lib/autofill/provider.ts | 4 +- .../browser-agent/lib/autofill/service.ts | 2 +- .../lib/autofill/tests/vault-autofill.test.ts | 14 +- .../subagents/browser-agent/lib/completion.ts | 2 +- .../subagents/browser-agent}/lib/kernel.ts | 2 +- .../browser-agent/lib/owned-browser.ts | 4 +- .../browser-agent/lib/semantic-loop.ts | 2 +- .../lib/tests/vault-screenshot-mask.test.ts | 2 +- .../lib/tests/worker-access.test.ts | 6 +- .../browser-agent/lib/trace/domains.ts | 6 +- .../lib/vault-screenshot-mask.ts | 2 +- .../tools/capture_browser_image.ts | 14 +- .../browser-agent/tools/computer_action.ts | 8 +- .../browser-agent/tools/fill_from_vault.ts | 8 +- .../browser-agent/tools/list_vault.ts | 4 +- .../browser-agent/tools/manage_browsers.ts | 12 +- .../browser-agent/tools/semantic_browser.ts | 4 +- agent/tools/calendar.ts | 4 +- agent/tools/contacts.ts | 4 +- agent/tools/gmail.ts | 4 +- agent/tools/messaging.ts | 4 +- agent/tools/schedules.ts | 12 +- agent/tools/vault.ts | 9 +- .../_components/google-workspace-action.tsx | 6 +- .../_components/model-selector.tsx | 8 +- .../(workspace)/_tests/workspace-linq.test.ts | 2 +- .../(authenticated)/(workspace)/page.tsx | 14 +- .../_components/account-control.tsx | 4 +- .../_components/authenticated-navigation.tsx | 2 +- .../chat/(new)/_components/new-chat.test.tsx | 6 +- .../chat/(new)/_components/new-chat.tsx | 4 +- .../(authenticated)/chat/(new)/page.tsx | 0 .../[sessionId]/_components/activity/card.tsx | 14 +- .../_components/activity/index.tsx | 10 +- .../_components/activity/presentation.tsx | 4 +- .../_components/activity/preview.tsx | 4 +- .../_components/activity/trace.tsx | 10 +- .../_components/activity/use-chat-usage.ts | 4 +- .../activity/use-session-history.ts | 0 .../[sessionId]/_components/chat-agent.ts | 0 .../_components/chat-session.test.tsx | 0 .../[sessionId]/_components/chat-session.tsx | 2 +- .../_components/conversation/index.test.tsx | 0 .../_components/conversation/index.tsx | 10 +- .../conversation/message/attachment.tsx | 4 +- .../conversation/message/authorization.tsx | 6 +- .../conversation/message/index.test.tsx | 0 .../conversation/message/index.tsx | 4 +- .../conversation/message/input-request.tsx | 6 +- .../conversation/message/parts.tsx | 6 +- .../_components/conversation/message/types.ts | 0 .../[sessionId]/_components/input/index.tsx | 4 +- .../_components/use-session-agent.ts | 0 .../[sessionId]/_lib/message-events.test.ts | 0 .../chat/[sessionId]/_lib/message-events.ts | 4 +- .../[sessionId]/_lib/session-history.test.ts | 0 .../chat/[sessionId]/_lib/session-history.ts | 0 .../chat/[sessionId]/_lib/trace-view.test.ts | 0 .../chat/[sessionId]/_lib/trace-view.ts | 0 .../[sessionId]/_lib/turn-failure.test.ts | 0 .../chat/[sessionId]/_lib/turn-failure.ts | 0 .../(authenticated)/chat/[sessionId]/page.tsx | 4 +- .../chat/_lib/chat-usage.test.ts | 0 .../(authenticated)/chat/_lib/chat-usage.ts | 2 +- .../chat/_lib/message-input.test.ts | 0 .../chat/_lib/message-input.ts | 2 +- .../(authenticated)/chat/history/page.tsx | 12 +- {src/app => app}/(authenticated)/error.tsx | 2 +- {src/app => app}/(authenticated)/layout.tsx | 8 +- {src/app => app}/(authenticated)/loading.tsx | 2 +- .../_components/personal-info-form.tsx | 15 +- .../(authenticated)/personal-info/page.tsx | 4 +- .../(overview)/_components/trace-history.tsx | 12 +- .../(authenticated)/tasks/(overview)/page.tsx | 6 +- .../_components/refresh-button.tsx | 2 +- .../tasks/[sessionId]/page.tsx | 14 +- .../vault/_components/addresses/form.tsx | 10 +- .../vault/_components/addresses/index.tsx | 6 +- .../vault/_components/cards/form.tsx | 14 +- .../vault/_components/cards/index.tsx | 6 +- .../vault/_components/contacts/form.tsx | 10 +- .../vault/_components/contacts/index.tsx | 6 +- .../vault/_components/field.tsx | 4 +- .../vault/_components/logins/form.tsx | 12 +- .../vault/_components/logins/import.tsx | 14 +- .../vault/_components/logins/index.tsx | 6 +- .../vault/_components/other.tsx | 2 +- .../vault/_components/section.tsx | 16 +- .../vault/_components/setup.ts | 2 +- .../vault/opengraph-image.alt.txt | 0 .../(authenticated)/vault/opengraph-image.png | Bin .../(authenticated)/vault/page.tsx | 4 +- {src/app => app}/_components/og-mark.tsx | 0 .../_lib/subagent-sessions.test.ts | 0 {src/app => app}/_lib/subagent-sessions.ts | 0 .../app => app}/_providers/query-provider.tsx | 0 .../auth/[...all]/_tests/auth-route.test.ts | 4 +- {src/app => app}/api/auth/[...all]/route.ts | 2 +- {src/app => app}/api/trpc/[trpc]/route.ts | 4 +- .../_tests/browser-image-route.test.ts | 8 +- .../artifacts/[artifactId]/route.ts | 8 +- {src/app => app}/globals.css | 2 +- {src/app => app}/icon.tsx | 0 {src/app => app}/layout.tsx | 10 +- .../sign-in/_components/local-form.tsx | 8 +- .../sign-in/_components/otp-form.tsx | 14 +- .../sign-in/_components/phone-field.tsx | 4 +- {src/app => app}/sign-in/_lib/phone-auth.ts | 2 +- .../sign-in/_tests/phone-auth-form.test.ts | 4 +- {src/app => app}/sign-in/page.tsx | 10 +- {src/app => app}/styles/brand/foundation.css | 0 {src/app => app}/styles/brand/motion.css | 0 {src/app => app}/styles/brand/shadcn.css | 0 {src/app => app}/styles/brand/typography.css | 0 components.json | 12 +- db/README.md | 2 +- db/env/migration.ts | 2 +- db/index.ts | 2 +- db/schema/browser.ts | 2 +- db/schema/vault.ts | 2 +- {src => db/services}/auth/index.ts | 10 +- {src => db/services}/auth/linq.ts | 2 +- {src => db/services}/auth/session.ts | 2 +- .../services/auth/tests/linq-delivery.test.ts | 2 +- {src => db/services}/auth/tests/linq.test.ts | 2 +- .../services/auth/tests/session.test.ts | 6 +- db/services/browser-images.ts | 6 +- db/services/browser-traces.ts | 4 +- db/services/browsers.ts | 4 +- db/services/chats.ts | 10 +- .../services}/installation-secrets.ts | 6 +- db/services/scheduled-agent-jobs.ts | 8 +- db/services/scheduled-agent-run-leases.ts | 2 +- db/services/scope.ts | 4 +- db/services/secrets.ts | 4 +- db/services/sessions.ts | 4 +- db/services/settings.ts | 4 +- db/services/user-profile.ts | 6 +- db/services/vault.ts | 12 +- db/tests/database-schema.test.ts | 2 +- .../tests/installation-secrets.test.ts | 4 +- db/tests/scheduled-agent-jobs.test.ts | 8 +- db/tests/services.test.ts | 22 +-- evals/agent/browser-agent.eval.ts | 2 +- evals/agent/conversation.eval.ts | 4 +- evals/agent/memory.eval.ts | 2 +- evals/agent/personal-info.eval.ts | 6 +- evals/agent/routing.eval.ts | 2 +- evals/agent/safety.eval.ts | 4 +- evals/agent/scheduled-lifecycle.eval.ts | 8 +- evals/agent/schedules.eval.ts | 2 +- evals/agent/shared.ts | 2 +- evals/browser/benchmark-activity.ts | 2 +- evals/browser/benchmark-reporter.ts | 15 +- evals/browser/browser.eval.ts | 8 +- .../browser/dashboard/app/(overview)/page.tsx | 2 +- evals/browser/dashboard/app/layout.tsx | 2 +- .../runs/[runId]/traces/[sessionId]/page.tsx | 4 +- .../dashboard/components/run-detail.tsx | 4 +- evals/browser/live-status-schema.ts | 2 +- .../tests/browser-benchmark-tasks.test.ts | 2 +- .../browser/tests/worker-events.test.ts | 5 +- {src/lib => evals/browser}/worker-events.ts | 2 +- knip.config.ts | 4 +- oxfmt.config.ts | 2 +- package.json | 3 +- src/proxy.ts => proxy.ts | 2 +- scripts/seed-browser-benchmark-vault.ts | 4 +- .../browser/artifact.ts | 0 .../chat/message-delivery.ts | 0 .../chat/reaction.ts | 0 src/lib/chat.ts => shared/chat/schema.ts | 0 .../environment/database-url.ts | 0 {src => shared/environment}/env.ts | 4 +- .../environment/environment.test.ts | 32 ++-- .../environment/origin.test.ts | 6 +- .../environment/origin.ts | 2 +- .../google-workspace/connection.ts | 0 {src/lib => shared/identity}/access-scope.ts | 0 .../identity/phone-number.test.ts | 4 +- {src/auth => shared/identity}/phone-number.ts | 0 {agent/lib => shared}/schedules/outcome.ts | 0 .../agent => shared}/schedules/timing.test.ts | 2 +- {agent/lib => shared}/schedules/timing.ts | 0 .../user-profile/schema.test.ts | 2 +- .../user-profile/schema.ts | 0 .../vault/payload.test.ts | 2 +- .../vault}/payment-card.test.ts | 2 +- src/lib/vault.ts => shared/vault/schema.ts | 0 .../vault/setup.test.ts | 2 +- tests/agent-tool-boundaries.test.ts | 8 +- tests/agent/agent.test.ts | 10 +- tests/agent/capabilities.test.ts | 16 +- tests/agent/channels/eve-channel-auth.test.ts | 8 +- .../channels/eve-message-delivery.test.ts | 6 +- .../agent/channels/linq-inbound-auth.test.ts | 8 +- .../channels/linq-message-delivery.test.ts | 16 +- .../agent/channels/scheduled-run-auth.test.ts | 2 +- tests/agent/hooks/evlog.test.ts | 2 +- .../hooks/scheduled-run-completion.test.ts | 6 +- tests/agent/hooks/session-owner.test.ts | 14 +- tests/agent/instructions.test.ts | 8 +- tests/agent/schedules/dynamic.test.ts | 14 +- tests/agent/schedules/request.test.ts | 6 +- .../hooks/browser-trace-telemetry.test.ts | 18 +-- .../tools/kernel-browser-contract.test.ts | 28 ++-- .../tools/worker-browser-images.test.ts | 14 +- .../tools/worker-browser-tools.test.ts | 10 +- tests/agent/tools/google-workspace.test.ts | 8 +- tests/agent/tools/schedules.test.ts | 8 +- .../browser-artifacts.test.ts | 6 +- tests/source-layout.test.ts | 84 ++++------ tools/oxlint/README.md | 5 + tools/oxlint/architecture/index.ts | 14 ++ .../rules/no-forbidden-layer-imports.ts | 149 ++++++++++++++++++ .../tests/oxlint-architecture-plugin.test.ts | 102 ++++++++++++ tools/oxlint/next/helpers/next-app-router.ts | 7 +- .../next/tests/oxlint-next-plugin.test.ts | 12 +- tsconfig.json | 11 +- vitest.config.ts | 20 ++- .../_lib/auth-client.ts => web/auth/client.ts | 0 {src/lib => web/auth}/request-scope.ts | 7 +- {src => web}/auth/tests/proxy.test.ts | 6 +- .../browser/activity.ts | 0 .../components/ai-elements/conversation.tsx | 4 +- .../components/ai-elements/message.tsx | 10 +- .../components/ai-elements/model-selector.tsx | 6 +- .../components/ai-elements/prompt-input.tsx | 16 +- .../components/ai-elements/question.tsx | 6 +- .../components/ai-elements/reasoning.tsx | 4 +- .../components/ai-elements/shimmer.tsx | 2 +- .../tests/message-response.test.tsx | 2 +- .../ai-elements/tests/prompt-input.test.tsx | 2 +- {src => web}/components/ai-elements/tool.tsx | 4 +- .../browser/activity-duration-breakdown.tsx | 2 +- .../utils.ts => web/components/class-names.ts | 0 {src => web}/components/ui/alert.tsx | 2 +- {src => web}/components/ui/badge.tsx | 2 +- {src => web}/components/ui/button-group.tsx | 4 +- {src => web}/components/ui/button.tsx | 2 +- {src => web}/components/ui/card.tsx | 2 +- {src => web}/components/ui/collapsible.tsx | 0 {src => web}/components/ui/command.tsx | 6 +- {src => web}/components/ui/dialog.tsx | 4 +- {src => web}/components/ui/dropdown-menu.tsx | 2 +- {src => web}/components/ui/field.tsx | 6 +- {src => web}/components/ui/hover-card.tsx | 2 +- {src => web}/components/ui/input-group.tsx | 8 +- {src => web}/components/ui/input.tsx | 2 +- {src => web}/components/ui/label.tsx | 2 +- {src => web}/components/ui/logo.tsx | 0 {src => web}/components/ui/select.tsx | 2 +- {src => web}/components/ui/separator.tsx | 2 +- {src => web}/components/ui/sheet.tsx | 4 +- {src => web}/components/ui/sidebar.tsx | 16 +- {src => web}/components/ui/skeleton.tsx | 2 +- {src => web}/components/ui/spinner.tsx | 2 +- {src => web}/components/ui/switch.tsx | 2 +- {src => web}/components/ui/table.tsx | 2 +- {src => web}/components/ui/textarea.tsx | 2 +- {src => web}/components/ui/tooltip.tsx | 2 +- {src => web}/hooks/use-mobile.ts | 0 {src => web}/trpc/client.tsx | 0 {src => web}/trpc/context.ts | 2 +- {src => web}/trpc/http-context.test.ts | 2 +- {src => web}/trpc/http-context.ts | 7 +- {src => web}/trpc/init.ts | 0 {src => web}/trpc/router.test.ts | 6 +- {src => web}/trpc/router.ts | 25 +-- {src/lib => web/trpc}/same-origin.ts | 0 {src => web}/trpc/types.ts | 0 305 files changed, 1100 insertions(+), 780 deletions(-) rename src/lib/worker-completion.ts => agent/subagents/browser-agent/lib/completion.ts (91%) rename {src => agent/subagents/browser-agent}/lib/kernel.ts (70%) rename {src/app => app}/(authenticated)/(workspace)/_components/google-workspace-action.tsx (86%) rename {src/app => app}/(authenticated)/(workspace)/_components/model-selector.tsx (95%) rename {src/app => app}/(authenticated)/(workspace)/_tests/workspace-linq.test.ts (95%) rename {src/app => app}/(authenticated)/(workspace)/page.tsx (94%) rename {src/app => app}/(authenticated)/_components/account-control.tsx (91%) rename {src/app => app}/(authenticated)/_components/authenticated-navigation.tsx (98%) rename {src/app => app}/(authenticated)/chat/(new)/_components/new-chat.test.tsx (94%) rename {src/app => app}/(authenticated)/chat/(new)/_components/new-chat.tsx (95%) rename {src/app => app}/(authenticated)/chat/(new)/page.tsx (100%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/activity/card.tsx (91%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/activity/index.tsx (96%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/activity/presentation.tsx (80%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/activity/preview.tsx (95%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/activity/trace.tsx (92%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/activity/use-chat-usage.ts (94%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/activity/use-session-history.ts (100%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/chat-agent.ts (100%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/chat-session.test.tsx (100%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/chat-session.tsx (96%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/conversation/index.test.tsx (100%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/conversation/index.tsx (95%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/conversation/message/attachment.tsx (95%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/conversation/message/authorization.tsx (94%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/conversation/message/index.test.tsx (100%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/conversation/message/index.tsx (95%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/conversation/message/input-request.tsx (95%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/conversation/message/parts.tsx (94%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/conversation/message/types.ts (100%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/input/index.tsx (97%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_components/use-session-agent.ts (100%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_lib/message-events.test.ts (100%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_lib/message-events.ts (97%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_lib/session-history.test.ts (100%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_lib/session-history.ts (100%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_lib/trace-view.test.ts (100%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_lib/trace-view.ts (100%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_lib/turn-failure.test.ts (100%) rename {src/app => app}/(authenticated)/chat/[sessionId]/_lib/turn-failure.ts (100%) rename {src/app => app}/(authenticated)/chat/[sessionId]/page.tsx (78%) rename {src/app => app}/(authenticated)/chat/_lib/chat-usage.test.ts (100%) rename {src/app => app}/(authenticated)/chat/_lib/chat-usage.ts (97%) rename {src/app => app}/(authenticated)/chat/_lib/message-input.test.ts (100%) rename {src/app => app}/(authenticated)/chat/_lib/message-input.ts (88%) rename {src/app => app}/(authenticated)/chat/history/page.tsx (89%) rename {src/app => app}/(authenticated)/error.tsx (91%) rename {src/app => app}/(authenticated)/layout.tsx (87%) rename {src/app => app}/(authenticated)/loading.tsx (85%) rename {src/app => app}/(authenticated)/personal-info/_components/personal-info-form.tsx (94%) rename {src/app => app}/(authenticated)/personal-info/page.tsx (65%) rename {src/app => app}/(authenticated)/tasks/(overview)/_components/trace-history.tsx (95%) rename {src/app => app}/(authenticated)/tasks/(overview)/page.tsx (88%) rename {src/app => app}/(authenticated)/tasks/[sessionId]/_components/refresh-button.tsx (91%) rename {src/app => app}/(authenticated)/tasks/[sessionId]/page.tsx (91%) rename {src/app => app}/(authenticated)/vault/_components/addresses/form.tsx (94%) rename {src/app => app}/(authenticated)/vault/_components/addresses/index.tsx (94%) rename {src/app => app}/(authenticated)/vault/_components/cards/form.tsx (96%) rename {src/app => app}/(authenticated)/vault/_components/cards/index.tsx (94%) rename {src/app => app}/(authenticated)/vault/_components/contacts/form.tsx (92%) rename {src/app => app}/(authenticated)/vault/_components/contacts/index.tsx (94%) rename {src/app => app}/(authenticated)/vault/_components/field.tsx (90%) rename {src/app => app}/(authenticated)/vault/_components/logins/form.tsx (96%) rename {src/app => app}/(authenticated)/vault/_components/logins/import.tsx (96%) rename {src/app => app}/(authenticated)/vault/_components/logins/index.tsx (96%) rename {src/app => app}/(authenticated)/vault/_components/other.tsx (90%) rename {src/app => app}/(authenticated)/vault/_components/section.tsx (95%) rename {src/app => app}/(authenticated)/vault/_components/setup.ts (82%) rename {src/app => app}/(authenticated)/vault/opengraph-image.alt.txt (100%) rename {src/app => app}/(authenticated)/vault/opengraph-image.png (100%) rename {src/app => app}/(authenticated)/vault/page.tsx (90%) rename {src/app => app}/_components/og-mark.tsx (100%) rename {src/app => app}/_lib/subagent-sessions.test.ts (100%) rename {src/app => app}/_lib/subagent-sessions.ts (100%) rename {src/app => app}/_providers/query-provider.tsx (100%) rename {src/app => app}/api/auth/[...all]/_tests/auth-route.test.ts (90%) rename {src/app => app}/api/auth/[...all]/route.ts (93%) rename {src/app => app}/api/trpc/[trpc]/route.ts (74%) rename {src/app => app}/artifacts/[artifactId]/_tests/browser-image-route.test.ts (94%) rename {src/app => app}/artifacts/[artifactId]/route.ts (91%) rename {src/app => app}/globals.css (90%) rename {src/app => app}/icon.tsx (100%) rename {src/app => app}/layout.tsx (71%) rename {src/app => app}/sign-in/_components/local-form.tsx (83%) rename {src/app => app}/sign-in/_components/otp-form.tsx (92%) rename {src/app => app}/sign-in/_components/phone-field.tsx (75%) rename {src/app => app}/sign-in/_lib/phone-auth.ts (92%) rename {src/app => app}/sign-in/_tests/phone-auth-form.test.ts (95%) rename {src/app => app}/sign-in/page.tsx (83%) rename {src/app => app}/styles/brand/foundation.css (100%) rename {src/app => app}/styles/brand/motion.css (100%) rename {src/app => app}/styles/brand/shadcn.css (100%) rename {src/app => app}/styles/brand/typography.css (100%) rename {src => db/services}/auth/index.ts (90%) rename {src => db/services}/auth/linq.ts (98%) rename {src => db/services}/auth/session.ts (92%) rename src/auth/tests/auth-linq.test.ts => db/services/auth/tests/linq-delivery.test.ts (96%) rename {src => db/services}/auth/tests/linq.test.ts (99%) rename src/auth/tests/auth-session.test.ts => db/services/auth/tests/session.test.ts (88%) rename {src/lib => db/services}/installation-secrets.ts (97%) rename {src/lib => db}/tests/installation-secrets.test.ts (97%) rename src/lib/tests/browser-benchmark.test.ts => evals/browser/tests/worker-events.test.ts (98%) rename {src/lib => evals/browser}/worker-events.ts (98%) rename src/proxy.ts => proxy.ts (93%) rename src/lib/browser-artifact.ts => shared/browser/artifact.ts (100%) rename agent/lib/send-message.ts => shared/chat/message-delivery.ts (100%) rename agent/lib/react-to-message.ts => shared/chat/reaction.ts (100%) rename src/lib/chat.ts => shared/chat/schema.ts (100%) rename db/env/utils.ts => shared/environment/database-url.ts (100%) rename {src => shared/environment}/env.ts (96%) rename src/lib/tests/env.test.ts => shared/environment/environment.test.ts (85%) rename src/lib/tests/application-origin.test.ts => shared/environment/origin.test.ts (91%) rename src/lib/application-origin.ts => shared/environment/origin.ts (95%) rename src/lib/google-workspace.ts => shared/google-workspace/connection.ts (100%) rename {src/lib => shared/identity}/access-scope.ts (100%) rename src/auth/tests/session-auth.test.ts => shared/identity/phone-number.test.ts (85%) rename {src/auth => shared/identity}/phone-number.ts (100%) rename {agent/lib => shared}/schedules/outcome.ts (100%) rename {tests/agent => shared}/schedules/timing.test.ts (97%) rename {agent/lib => shared}/schedules/timing.ts (100%) rename src/lib/tests/user-profile.test.ts => shared/user-profile/schema.test.ts (97%) rename src/lib/user-profile.ts => shared/user-profile/schema.ts (100%) rename src/lib/tests/vault-payload.test.ts => shared/vault/payload.test.ts (99%) rename {src/lib/tests => shared/vault}/payment-card.test.ts (98%) rename src/lib/vault.ts => shared/vault/schema.ts (100%) rename src/lib/tests/vault-setup.test.ts => shared/vault/setup.test.ts (98%) rename src/lib/tests/browser-images.test.ts => tests/browser-artifacts.test.ts (95%) create mode 100644 tools/oxlint/architecture/index.ts create mode 100644 tools/oxlint/architecture/rules/no-forbidden-layer-imports.ts create mode 100644 tools/oxlint/architecture/tests/oxlint-architecture-plugin.test.ts rename src/app/_lib/auth-client.ts => web/auth/client.ts (100%) rename {src/lib => web/auth}/request-scope.ts (75%) rename {src => web}/auth/tests/proxy.test.ts (90%) rename src/lib/browser-activity.ts => web/browser/activity.ts (100%) rename {src => web}/components/ai-elements/conversation.tsx (98%) rename {src => web}/components/ai-elements/message.tsx (97%) rename {src => web}/components/ai-elements/model-selector.tsx (95%) rename {src => web}/components/ai-elements/prompt-input.tsx (99%) rename {src => web}/components/ai-elements/question.tsx (97%) rename {src => web}/components/ai-elements/reasoning.tsx (98%) rename {src => web}/components/ai-elements/shimmer.tsx (97%) rename {src => web}/components/ai-elements/tests/message-response.test.tsx (97%) rename {src => web}/components/ai-elements/tests/prompt-input.test.tsx (98%) rename {src => web}/components/ai-elements/tool.tsx (98%) rename {src => web}/components/browser/activity-duration-breakdown.tsx (98%) rename src/lib/utils.ts => web/components/class-names.ts (100%) rename {src => web}/components/ui/alert.tsx (98%) rename {src => web}/components/ui/badge.tsx (97%) rename {src => web}/components/ui/button-group.tsx (95%) rename {src => web}/components/ui/button.tsx (98%) rename {src => web}/components/ui/card.tsx (98%) rename {src => web}/components/ui/collapsible.tsx (100%) rename {src => web}/components/ui/command.tsx (96%) rename {src => web}/components/ui/dialog.tsx (98%) rename {src => web}/components/ui/dropdown-menu.tsx (99%) rename {src => web}/components/ui/field.tsx (97%) rename {src => web}/components/ui/hover-card.tsx (97%) rename {src => web}/components/ui/input-group.tsx (96%) rename {src => web}/components/ui/input.tsx (97%) rename {src => web}/components/ui/label.tsx (96%) rename {src => web}/components/ui/logo.tsx (100%) rename {src => web}/components/ui/select.tsx (99%) rename {src => web}/components/ui/separator.tsx (95%) rename {src => web}/components/ui/sheet.tsx (97%) rename {src => web}/components/ui/sidebar.tsx (98%) rename {src => web}/components/ui/skeleton.tsx (84%) rename {src => web}/components/ui/spinner.tsx (85%) rename {src => web}/components/ui/switch.tsx (97%) rename {src => web}/components/ui/table.tsx (98%) rename {src => web}/components/ui/textarea.tsx (96%) rename {src => web}/components/ui/tooltip.tsx (98%) rename {src => web}/hooks/use-mobile.ts (100%) rename {src => web}/trpc/client.tsx (100%) rename {src => web}/trpc/context.ts (58%) rename {src => web}/trpc/http-context.test.ts (95%) rename {src => web}/trpc/http-context.ts (77%) rename {src => web}/trpc/init.ts (100%) rename {src => web}/trpc/router.test.ts (86%) rename {src => web}/trpc/router.ts (85%) rename {src/lib => web/trpc}/same-origin.ts (100%) rename {src => web}/trpc/types.ts (100%) diff --git a/.oxlintrc.jsonc b/.oxlintrc.jsonc index 903401f6..83a1c1ea 100644 --- a/.oxlintrc.jsonc +++ b/.oxlintrc.jsonc @@ -24,6 +24,7 @@ }, "ignorePatterns": ["tools/oxlint/anti-slop/**"], "jsPlugins": [ + "./tools/oxlint/architecture/index.ts", "./tools/oxlint/anti-slop/index.ts", "./tools/oxlint/next/index.ts", "eslint-plugin-turbo", @@ -35,10 +36,11 @@ ], "settings": { "tailwindcss": { - "entryPoint": "src/app/globals.css" + "entryPoint": "app/globals.css" } }, "rules": { + "local-architecture/no-forbidden-layer-imports": "error", "anti-slop/no-chained-type-assertions": "error", "anti-slop/no-conditional-empty-object-spread": "error", "anti-slop/no-known-value-widening": "error", @@ -273,7 +275,7 @@ "tailwindcss/no-deprecated-classes": "warn", "tailwindcss/no-duplicate-classes": "error", // The semantic typography utilities are hand-authored `@layer utilities` - // classes in src/app/styles/brand/typography.css. + // classes in app/styles/brand/typography.css. "tailwindcss/no-unknown-classes": [ "warn", { @@ -407,7 +409,7 @@ { // shadcn registry source uses behavior utilities that the Tailwind // linter cannot resolve through package stylesheet imports. - "files": ["src/components/ui/**/*.tsx"], + "files": ["web/components/ui/**/*.tsx"], "rules": { "tailwindcss/no-unknown-classes": "off" } @@ -417,9 +419,9 @@ // package styles that the Tailwind linter cannot resolve from the app // entrypoint. Keep this exception limited to the affected components. "files": [ - "src/components/ai-elements/message.tsx", - "src/components/ai-elements/reasoning.tsx", - "src/components/ai-elements/tool.tsx" + "web/components/ai-elements/message.tsx", + "web/components/ai-elements/reasoning.tsx", + "web/components/ai-elements/tool.tsx" ], "rules": { "tailwindcss/no-unknown-classes": "off" diff --git a/AGENTS.md b/AGENTS.md index 76a9faac..da21c8ce 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -58,15 +58,15 @@ Run the validation the task requests. When it does not establish the behavior yo - The repository root owns the single Next.js application, Eve agent, and shared UI contract. - The workspace manager lives on `/` and the agent chat on `/chat`; browser execution belongs only to the declared browser-agent subagent's flat tool surface under `agent/subagents/browser-agent/tools`. -- Keep each worker browser tool's schema and implementation together. Share the Kernel SDK client through `src/lib/kernel.ts`; do not add a Kernel extension or root browser connection. +- Keep each worker browser tool's schema and implementation together. Share the Kernel SDK client through `agent/subagents/browser-agent/lib/kernel.ts`; do not add a Kernel extension or root browser connection. - `agent/subagents/browser-agent/lib` is for code genuinely shared by worker tools. Group a shared worker domain in a lower-case folder, such as `trace/domains.ts` or `autofill/provider.ts`; do not use it as a holding area for a tool's one-off logic. -- Validate runtime environment variables through `src/env.ts`. `KERNEL_API_KEY` is required by the worker browser tools. +- Validate runtime environment variables through `shared/environment/env.ts`. `KERNEL_API_KEY` is required by the worker browser tools. - Run `pnpm check` and `pnpm build` before handing off changes. ## Code organization -- Treat `src/lib` as a small shared infrastructure and contract boundary, not a default destination for application code. A file belongs there only when it has real cross-feature ownership; put database access in `db/services`, agent behavior under `agent`, and route or section behavior with its route. -- Do not add a generic `src/modules` layer. Give code a concrete owner and colocate it there. A route section owns its section components, forms, and local parsing; split it only when the files have distinct responsibilities. +- Treat `shared` as a narrow contract boundary, not a default destination for application code. A file belongs there only when at least two of `agent`, `app`, `web`, and `db` consume it; put database access in `db/services`, agent behavior under `agent`, and route or section behavior with its route. +- Do not add a generic `modules` layer. Give code a concrete owner and colocate it there. A route section owns its section components, forms, and local parsing; split it only when the files have distinct responsibilities. - Prefer one cohesive call-site file for code used once. Do not add production factories, dependency containers, server wrappers, or files solely to make a unit test easier to mock. - Mock imported modules at their owning or external boundary in tests. Do not export mutable dependency bags, dependency setters, reset hooks, or other test-only seams from production modules; keep production exports limited to application behavior and real domain contracts. - Use lower-case file and folder names. When several files share a domain prefix, make that prefix a folder and name files for their role, such as `trace/domains.ts` rather than `trace-domains.ts`. Do not introduce camel-case filenames. @@ -76,8 +76,8 @@ Run the validation the task requests. When it does not establish the behavior yo Before planning or changing product UI: -- Build from the primitives in `src/components/ui` and the semantic `type-*` - typography utilities defined in `src/app/styles/brand/typography.css`. +- Build from the primitives in `web/components/ui` and the semantic `type-*` + typography utilities defined in `app/styles/brand/typography.css`. - Preserve the current `components.json` primitive base and local extensions; add new primitives with the official shadcn CLI. diff --git a/agent/agent.ts b/agent/agent.ts index 829e34b2..c0f8fb1c 100644 --- a/agent/agent.ts +++ b/agent/agent.ts @@ -1,8 +1,8 @@ import { defineAgent, defineDynamic } from "eve"; -import { scheduledRunIdentity } from "@/agent/lib/schedules/identity"; -import { isScheduledAgentRunLeaseActive } from "@/db/services/scheduled-agent-run-leases"; -import { getGatewayModel } from "@/db/services/settings"; -import { scopeFromPrincipal } from "@/agent/lib/principal-scope"; +import { scheduledRunIdentity } from "@agent/lib/schedules/identity"; +import { isScheduledAgentRunLeaseActive } from "@db/services/scheduled-agent-run-leases"; +import { getGatewayModel } from "@db/services/settings"; +import { scopeFromPrincipal } from "@agent/lib/principal-scope"; export default defineAgent({ experimental: { diff --git a/agent/channels/eve.ts b/agent/channels/eve.ts index 98dc67ed..ab613f8c 100644 --- a/agent/channels/eve.ts +++ b/agent/channels/eve.ts @@ -5,15 +5,18 @@ import { UnauthenticatedError, } from "eve/channels/auth"; import { z } from "zod"; -import { isSessionOwned } from "@/db/services/sessions"; -import { accessScopeForUser, type AccessScope } from "@/lib/access-scope"; -import { getAuthSession } from "@/auth/session"; -import { sendMessageToolResultSchema } from "@/agent/lib/send-message"; +import { isSessionOwned } from "@db/services/sessions"; +import { + accessScopeForUser, + type AccessScope, +} from "@shared/identity/access-scope"; +import { getAuthSession } from "@db/services/auth/session"; +import { sendMessageToolResultSchema } from "@shared/chat/message-delivery"; import { finalizeScheduledReportDelivery, releaseScheduledReportDelivery, scheduledReportFromSession, -} from "@/agent/lib/schedules/report-lifecycle"; +} from "@agent/lib/schedules/report-lifecycle"; const authenticateLocalDev = localDev(); diff --git a/agent/channels/linq.ts b/agent/channels/linq.ts index c3b82720..ee4d0acb 100644 --- a/agent/channels/linq.ts +++ b/agent/channels/linq.ts @@ -8,23 +8,23 @@ import { } from "eve/channels/linq"; import { vercelOidc } from "eve/channels/auth"; import { z } from "zod"; -import { getAuth } from "@/auth"; -import { reactToMessageToolResultSchema } from "@/agent/lib/react-to-message"; -import { sendMessageToolResultSchema } from "@/agent/lib/send-message"; -import { normalizeAuthPhoneNumber } from "@/auth/phone-number"; -import { scopeFromPrincipal } from "@/agent/lib/principal-scope"; -import { accessScopeForUser } from "@/lib/access-scope"; +import { getAuth } from "@db/services/auth"; +import { reactToMessageToolResultSchema } from "@shared/chat/reaction"; +import { sendMessageToolResultSchema } from "@shared/chat/message-delivery"; +import { normalizeAuthPhoneNumber } from "@shared/identity/phone-number"; +import { scopeFromPrincipal } from "@agent/lib/principal-scope"; +import { accessScopeForUser } from "@shared/identity/access-scope"; import { prepareLinqImageArtifactDelivery } from "../lib/linq-image-artifact/delivery"; import { extractImageArtifactMarkdownReferences, stripImageArtifactMarkdownReferences, } from "../lib/linq-image-artifact/markdown"; -import { env } from "@/env"; +import { env } from "@shared/environment"; import { finalizeScheduledReportDelivery, releaseScheduledReportDelivery, scheduledReportFromSession, -} from "@/agent/lib/schedules/report-lifecycle"; +} from "@agent/lib/schedules/report-lifecycle"; const verifiedPhoneUserSchema = z.object({ id: z.string().min(1), diff --git a/agent/channels/scheduled-run.ts b/agent/channels/scheduled-run.ts index 9e7a7f48..aa1b39e3 100644 --- a/agent/channels/scheduled-run.ts +++ b/agent/channels/scheduled-run.ts @@ -2,12 +2,12 @@ import { defineChannel, POST } from "eve/channels"; import { localDev, routeAuth, vercelOidc } from "eve/channels/auth"; import { parseInputResponses, resolveTextToResponses } from "eve/client"; import { z } from "zod"; -import { dispatchScheduledReport } from "@/agent/lib/schedules/report"; +import { dispatchScheduledReport } from "@agent/lib/schedules/report"; import { claimScheduledAgentRunInput, finishScheduledAgentRunInput, restoreScheduledAgentRunInput, -} from "@/db/services/scheduled-agent-jobs"; +} from "@db/services/scheduled-agent-jobs"; const scheduledRunTargetSchema = z.strictObject({ restart: z.boolean().optional(), diff --git a/agent/hooks/scheduled-run-completion.ts b/agent/hooks/scheduled-run-completion.ts index a3280e1a..26c11ba5 100644 --- a/agent/hooks/scheduled-run-completion.ts +++ b/agent/hooks/scheduled-run-completion.ts @@ -1,13 +1,13 @@ import { defineHook } from "eve/hooks"; -import { scheduledRunIdentity } from "@/agent/lib/schedules/identity"; -import { scheduledRunOutcomeSchema } from "@/agent/lib/schedules/outcome"; +import { scheduledRunIdentity } from "@agent/lib/schedules/identity"; +import { scheduledRunOutcomeSchema } from "@shared/schedules/outcome"; import { completeScheduledAgentRun, deferScheduledAgentRunCompletion, markScheduledAgentRunStarted, releaseScheduledAgentRun, waitForScheduledAgentRunInput, -} from "@/db/services/scheduled-agent-jobs"; +} from "@db/services/scheduled-agent-jobs"; const workerRuntimeLimitMs = 6 * 60 * 60_000; diff --git a/agent/hooks/session-owner.ts b/agent/hooks/session-owner.ts index 770b584c..83795f70 100644 --- a/agent/hooks/session-owner.ts +++ b/agent/hooks/session-owner.ts @@ -1,8 +1,8 @@ import { defineHook, type HookContext } from "eve/hooks"; -import { saveChat } from "@/db/services/chats"; -import { ensureScope } from "@/db/services/scope"; -import { claimSession } from "@/db/services/sessions"; -import { scopeFromPrincipal } from "@/agent/lib/principal-scope"; +import { saveChat } from "@db/services/chats"; +import { ensureScope } from "@db/services/scope"; +import { claimSession } from "@db/services/sessions"; +import { scopeFromPrincipal } from "@agent/lib/principal-scope"; export default defineHook({ events: { diff --git a/agent/instructions/10-execution-safety.ts b/agent/instructions/10-execution-safety.ts index 21be2cc5..0aa8a6d4 100644 --- a/agent/instructions/10-execution-safety.ts +++ b/agent/instructions/10-execution-safety.ts @@ -1,5 +1,5 @@ import { defineDynamic } from "eve/instructions"; -import { resolveModeInstructions } from "@/agent/lib/mode"; +import { resolveModeInstructions } from "@agent/lib/mode"; import executionSafety from "./content/execution-safety.md?raw"; export default defineDynamic({ diff --git a/agent/instructions/20-role.ts b/agent/instructions/20-role.ts index 06a76b4a..4646520e 100644 --- a/agent/instructions/20-role.ts +++ b/agent/instructions/20-role.ts @@ -1,5 +1,5 @@ import { defineDynamic } from "eve/instructions"; -import { resolveModeInstructions } from "@/agent/lib/mode"; +import { resolveModeInstructions } from "@agent/lib/mode"; import interactiveInstructions from "./content/role/interactive.md?raw"; import scheduledReportInstructions from "./content/role/scheduled-report.md?raw"; import scheduledWorkerInstructions from "./content/role/scheduled-worker.md?raw"; diff --git a/agent/instructions/25-worker-coordination.ts b/agent/instructions/25-worker-coordination.ts index 32785070..72f16466 100644 --- a/agent/instructions/25-worker-coordination.ts +++ b/agent/instructions/25-worker-coordination.ts @@ -1,5 +1,5 @@ import { defineDynamic } from "eve/instructions"; -import { resolveModeInstructions } from "@/agent/lib/mode"; +import { resolveModeInstructions } from "@agent/lib/mode"; import workerCoordination from "./content/worker-coordination.md?raw"; export default defineDynamic({ diff --git a/agent/instructions/30-message-style.ts b/agent/instructions/30-message-style.ts index 1ada6b67..157dc904 100644 --- a/agent/instructions/30-message-style.ts +++ b/agent/instructions/30-message-style.ts @@ -1,5 +1,5 @@ import { defineDynamic } from "eve/instructions"; -import { resolveModeInstructions } from "@/agent/lib/mode"; +import { resolveModeInstructions } from "@agent/lib/mode"; import messageStyle from "./content/message-style.md?raw"; export default defineDynamic({ diff --git a/agent/lib/google-workspace/client.ts b/agent/lib/google-workspace/client.ts index 08e09366..ed386343 100644 --- a/agent/lib/google-workspace/client.ts +++ b/agent/lib/google-workspace/client.ts @@ -2,11 +2,11 @@ import { auth } from "@googleapis/gmail"; import { connect, type EveAuthorizationOptions } from "@vercel/connect/eve"; import type { ToolContext } from "eve/tools"; import { z } from "zod"; -import { env } from "@/env"; +import { env } from "@shared/environment"; import { googleWorkspaceSubject, googleWorkspaceScopes, -} from "@/lib/google-workspace"; +} from "@shared/google-workspace/connection"; export const googleWorkspaceAuthOptions = { connector: env.GOOGLE_CONNECTOR_UID, diff --git a/agent/lib/google-workspace/tests/google-workspace-generated-clients.test.ts b/agent/lib/google-workspace/tests/google-workspace-generated-clients.test.ts index 0aa8c397..43899812 100644 --- a/agent/lib/google-workspace/tests/google-workspace-generated-clients.test.ts +++ b/agent/lib/google-workspace/tests/google-workspace-generated-clients.test.ts @@ -4,10 +4,10 @@ import * as GmailApi from "@googleapis/gmail"; import * as PeopleApi from "@googleapis/people"; import type { ToolContext } from "eve/tools"; import { afterEach, describe, expect, it, vi } from "vitest"; -import { createCalendarEvent } from "@/agent/lib/google-workspace/calendar"; -import { withGoogleAuth } from "@/agent/lib/google-workspace/client"; -import { searchGoogleContacts } from "@/agent/lib/google-workspace/contacts"; -import { sendGmail } from "@/agent/lib/google-workspace/gmail"; +import { createCalendarEvent } from "@agent/lib/google-workspace/calendar"; +import { withGoogleAuth } from "@agent/lib/google-workspace/client"; +import { searchGoogleContacts } from "@agent/lib/google-workspace/contacts"; +import { sendGmail } from "@agent/lib/google-workspace/gmail"; interface RequestOptions { signal: AbortSignal; diff --git a/agent/lib/google-workspace/tests/google-workspace.test.ts b/agent/lib/google-workspace/tests/google-workspace.test.ts index 9b870ed8..bf217132 100644 --- a/agent/lib/google-workspace/tests/google-workspace.test.ts +++ b/agent/lib/google-workspace/tests/google-workspace.test.ts @@ -1,14 +1,14 @@ import { describe, expect, it } from "vitest"; -import { parseCalendarAvailability } from "@/agent/lib/google-workspace/calendar"; -import { googleWorkspaceAuthOptions } from "@/agent/lib/google-workspace/client"; -import { gmailUpdateLabels } from "@/agent/lib/google-workspace/gmail"; -import { calendarCreateEvent } from "@/agent/tools/calendar"; -import { gmailSend, gmailUpdate } from "@/agent/tools/gmail"; +import { parseCalendarAvailability } from "@agent/lib/google-workspace/calendar"; +import { googleWorkspaceAuthOptions } from "@agent/lib/google-workspace/client"; +import { gmailUpdateLabels } from "@agent/lib/google-workspace/gmail"; +import { calendarCreateEvent } from "@agent/tools/calendar"; +import { gmailSend, gmailUpdate } from "@agent/tools/gmail"; import { googleWorkspaceScopes, googleWorkspaceSubject, googleWorkspaceTokenParams, -} from "@/lib/google-workspace"; +} from "@shared/google-workspace/connection"; const userId = "better-auth:user-123"; diff --git a/agent/lib/linq-image-artifact/delivery.test.ts b/agent/lib/linq-image-artifact/delivery.test.ts index 0d57b95c..9519be12 100644 --- a/agent/lib/linq-image-artifact/delivery.test.ts +++ b/agent/lib/linq-image-artifact/delivery.test.ts @@ -1,12 +1,12 @@ /* oxlint-disable vitest/require-mock-type-parameters -- The Blob mock implements only the read operation exercised here. */ import { beforeEach, describe, expect, it, vi } from "vitest"; -import type { AccessScope } from "@/lib/access-scope"; +import type { AccessScope } from "@shared/identity/access-scope"; const firstId = "0d01e667-d128-4bb7-a248-1ae21db72f4f"; const secondId = "206c3a7e-c0b8-4317-9e34-552cff646673"; const mocks = vi.hoisted(() => ({ getBlob: vi.fn(), readArtifact: vi.fn() })); -vi.mock("@/db/services/browser-images", () => ({ +vi.mock("@db/services/browser-images", () => ({ readReadyBrowserImageArtifact: mocks.readArtifact, })); vi.mock("@vercel/blob", () => ({ diff --git a/agent/lib/linq-image-artifact/delivery.ts b/agent/lib/linq-image-artifact/delivery.ts index 421bdc92..e1a3e870 100644 --- a/agent/lib/linq-image-artifact/delivery.ts +++ b/agent/lib/linq-image-artifact/delivery.ts @@ -1,10 +1,10 @@ import { createHash } from "node:crypto"; import { get } from "@vercel/blob"; -import type { AccessScope } from "@/lib/access-scope"; -import { readReadyBrowserImageArtifact } from "@/db/services/browser-images"; -import { maximumBrowserImageBytes } from "@/lib/browser-artifact"; -import { env } from "@/env"; -import { maximumWorkerCompletionImages } from "@/lib/worker-completion"; +import type { AccessScope } from "@shared/identity/access-scope"; +import { readReadyBrowserImageArtifact } from "@db/services/browser-images"; +import { maximumBrowserImageBytes } from "@shared/browser/artifact"; +import { env } from "@shared/environment"; +import { maximumWorkerCompletionImages } from "@agent/subagents/browser-agent/lib/completion"; import { extractImageArtifactMarkdownReferences, stripImageArtifactMarkdownReferences, diff --git a/agent/lib/linq-image-artifact/markdown.ts b/agent/lib/linq-image-artifact/markdown.ts index 01ee54ef..905a1734 100644 --- a/agent/lib/linq-image-artifact/markdown.ts +++ b/agent/lib/linq-image-artifact/markdown.ts @@ -1,4 +1,4 @@ -import { isBrowserImageArtifactUrl } from "@/lib/browser-artifact"; +import { isBrowserImageArtifactUrl } from "@shared/browser/artifact"; const imageArtifactMarkdownPattern = /!\[((?:\\.|[^\]])*)\]\((\/artifacts\/([^\s)]+))\)/giu; diff --git a/agent/lib/principal-scope.ts b/agent/lib/principal-scope.ts index 83e25f0b..792d3289 100644 --- a/agent/lib/principal-scope.ts +++ b/agent/lib/principal-scope.ts @@ -1,7 +1,10 @@ import type { ConnectionPrincipal } from "eve/connections"; import type { SessionAuthContext } from "eve/context"; import { z } from "zod"; -import { accessScopeForUser, type AccessScope } from "@/lib/access-scope"; +import { + accessScopeForUser, + type AccessScope, +} from "@shared/identity/access-scope"; const principalScopeSchema = z.object({ attributes: z.object({ diff --git a/agent/lib/profile-memory.ts b/agent/lib/profile-memory.ts index 8b2b8596..b97405c1 100644 --- a/agent/lib/profile-memory.ts +++ b/agent/lib/profile-memory.ts @@ -6,8 +6,8 @@ import { type MemoryScopeContext, } from "eve/memory"; import { z } from "zod"; -import type { env } from "@/env"; -import { resolveModeValue } from "@/agent/lib/mode"; +import type { env } from "@shared/environment"; +import { resolveModeValue } from "@agent/lib/mode"; export function resolveProfileMemoryBackend( environment: Pick< diff --git a/agent/lib/schedules/report-lifecycle.ts b/agent/lib/schedules/report-lifecycle.ts index b1bacab1..60c9c52c 100644 --- a/agent/lib/schedules/report-lifecycle.ts +++ b/agent/lib/schedules/report-lifecycle.ts @@ -2,8 +2,8 @@ import type { SessionContext } from "eve/context"; import { finalizeScheduledReport, releaseScheduledReport, -} from "@/db/services/scheduled-agent-jobs"; -import { scheduledReportIdentity } from "@/agent/lib/schedules/identity"; +} from "@db/services/scheduled-agent-jobs"; +import { scheduledReportIdentity } from "@agent/lib/schedules/identity"; export function scheduledReportFromSession(session: SessionContext) { return scheduledReportIdentity(session.session.auth); diff --git a/agent/lib/schedules/report.ts b/agent/lib/schedules/report.ts index b82a144a..837c4615 100644 --- a/agent/lib/schedules/report.ts +++ b/agent/lib/schedules/report.ts @@ -4,7 +4,7 @@ import { claimScheduledReport, finalizeScheduledReport, releaseScheduledReport, -} from "@/db/services/scheduled-agent-jobs"; +} from "@db/services/scheduled-agent-jobs"; import linq from "../../channels/linq"; export async function dispatchScheduledReport( diff --git a/agent/lib/schedules/request.ts b/agent/lib/schedules/request.ts index 304dcd82..30ade446 100644 --- a/agent/lib/schedules/request.ts +++ b/agent/lib/schedules/request.ts @@ -1,8 +1,8 @@ import { readFile } from "node:fs/promises"; import { getVercelOidcToken } from "@vercel/oidc"; import { z } from "zod"; -import { env } from "@/env"; -import { applicationOrigin } from "@/lib/application-origin"; +import { env } from "@shared/environment"; +import { applicationOrigin } from "@shared/environment/origin"; const eveDevServerSchema = z.object({ appRoot: z.string(), diff --git a/agent/lib/schedules/tools.ts b/agent/lib/schedules/tools.ts index 45dc19a9..50701d96 100644 --- a/agent/lib/schedules/tools.ts +++ b/agent/lib/schedules/tools.ts @@ -3,8 +3,8 @@ import { z } from "zod"; import type { createScheduledAgentJob, listScheduledAgentJobs, -} from "@/db/services/scheduled-agent-jobs"; -import { scopeFromPrincipal } from "@/agent/lib/principal-scope"; +} from "@db/services/scheduled-agent-jobs"; +import { scopeFromPrincipal } from "@agent/lib/principal-scope"; export function scheduleOwner(context: ToolContext) { const auth = context.session.auth.current; diff --git a/agent/lib/tests/principal-scope.test.ts b/agent/lib/tests/principal-scope.test.ts index 0e82ee3a..c15c8f3e 100644 --- a/agent/lib/tests/principal-scope.test.ts +++ b/agent/lib/tests/principal-scope.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import { scopeFromPrincipal } from "@/agent/lib/principal-scope"; -import { accessScopeForUser } from "@/lib/access-scope"; +import { scopeFromPrincipal } from "@agent/lib/principal-scope"; +import { accessScopeForUser } from "@shared/identity/access-scope"; describe("principal scope", () => { it("accepts the workspace derived from the authenticated user", () => { diff --git a/agent/lib/tests/profile-memory.test.ts b/agent/lib/tests/profile-memory.test.ts index 34895410..64fea9fc 100644 --- a/agent/lib/tests/profile-memory.test.ts +++ b/agent/lib/tests/profile-memory.test.ts @@ -5,13 +5,13 @@ import { type MemoryToolsContext, } from "eve/memory"; import { describe, expect, it } from "vitest"; -import personalInfoMemory from "@/agent/memory/personal_info"; +import personalInfoMemory from "@agent/memory/personal_info"; import { preserveProfileMemoryCancellation, resolveProfileMemoryBackend, resolveProfileMemoryScope, -} from "@/agent/lib/profile-memory"; -import { accessScopeForUser } from "@/lib/access-scope"; +} from "@agent/lib/profile-memory"; +import { accessScopeForUser } from "@shared/identity/access-scope"; const derivedWorkspaceId = accessScopeForUser("better-auth:user").workspaceId; diff --git a/agent/memory/personal_info.ts b/agent/memory/personal_info.ts index d8259840..195a5e5b 100644 --- a/agent/memory/personal_info.ts +++ b/agent/memory/personal_info.ts @@ -7,14 +7,14 @@ import { } from "eve/memory"; import { defineTool } from "eve/tools"; import { z } from "zod"; -import { scopeFromPrincipal } from "@/agent/lib/principal-scope"; -import { readUserProfile, patchUserProfile } from "@/db/services/user-profile"; -import type { AccessScope } from "@/lib/access-scope"; +import { scopeFromPrincipal } from "@agent/lib/principal-scope"; +import { readUserProfile, patchUserProfile } from "@db/services/user-profile"; +import type { AccessScope } from "@shared/identity/access-scope"; import { hasUserProfileValues, userProfilePatchSchema, userProfileSchema, -} from "@/lib/user-profile"; +} from "@shared/user-profile/schema"; import { resolveModeValue } from "../lib/mode"; function resolvePersonalInfoAccessScope( diff --git a/agent/memory/profile.ts b/agent/memory/profile.ts index 7febb89f..178161ff 100644 --- a/agent/memory/profile.ts +++ b/agent/memory/profile.ts @@ -6,7 +6,7 @@ import { resolveProfileMemoryBackend, resolveProfileMemoryScope, } from "../lib/profile-memory"; -import { env } from "@/env"; +import { env } from "@shared/environment"; const backend = resolveProfileMemoryBackend(env); const provider = preserveProfileMemoryCancellation( diff --git a/agent/schedules/dynamic.ts b/agent/schedules/dynamic.ts index a0c35995..6cee4d1b 100644 --- a/agent/schedules/dynamic.ts +++ b/agent/schedules/dynamic.ts @@ -1,14 +1,14 @@ import { defineSchedule, type ScheduleToFn } from "eve/schedules"; -import scheduledRunChannel from "@/agent/channels/scheduled-run"; -import { dispatchScheduledReport } from "@/agent/lib/schedules/report"; -import { postScheduledReport } from "@/agent/lib/schedules/request"; +import scheduledRunChannel from "@agent/channels/scheduled-run"; +import { dispatchScheduledReport } from "@agent/lib/schedules/report"; +import { postScheduledReport } from "@agent/lib/schedules/request"; import { claimReadyScheduledAgentRuns, listRecoverableScheduledReports, materializeDueScheduledAgentRuns, releaseScheduledAgentRun, setScheduledRunSession, -} from "@/db/services/scheduled-agent-jobs"; +} from "@db/services/scheduled-agent-jobs"; const workerStartupLimitMs = 5 * 60_000; diff --git a/agent/subagents/browser-agent/agent.ts b/agent/subagents/browser-agent/agent.ts index 23cb7dda..0cbd52af 100644 --- a/agent/subagents/browser-agent/agent.ts +++ b/agent/subagents/browser-agent/agent.ts @@ -1,6 +1,6 @@ import { defineAgent, defineDynamic } from "eve"; -import { resolveModeValue } from "@/agent/lib/mode"; -import { taskCompletionSchema } from "@/lib/worker-completion"; +import { resolveModeValue } from "@agent/lib/mode"; +import { taskCompletionSchema } from "@agent/subagents/browser-agent/lib/completion"; export default defineDynamic({ build: { diff --git a/agent/subagents/browser-agent/hooks/session-owner.ts b/agent/subagents/browser-agent/hooks/session-owner.ts index e35dc91f..ccee8af8 100644 --- a/agent/subagents/browser-agent/hooks/session-owner.ts +++ b/agent/subagents/browser-agent/hooks/session-owner.ts @@ -1,7 +1,7 @@ import { defineHook } from "eve/hooks"; -import { ensureScope } from "@/db/services/scope"; -import { claimSession } from "@/db/services/sessions"; -import { scopeFromPrincipal } from "@/agent/lib/principal-scope"; +import { ensureScope } from "@db/services/scope"; +import { claimSession } from "@db/services/sessions"; +import { scopeFromPrincipal } from "@agent/lib/principal-scope"; export default defineHook({ events: { diff --git a/agent/subagents/browser-agent/hooks/trace-telemetry.ts b/agent/subagents/browser-agent/hooks/trace-telemetry.ts index 4d2b7a28..65667e22 100644 --- a/agent/subagents/browser-agent/hooks/trace-telemetry.ts +++ b/agent/subagents/browser-agent/hooks/trace-telemetry.ts @@ -4,13 +4,13 @@ import { beginBrowserTrace, completeBrowserTrace, recordBrowserTraceEvents, -} from "@/db/services/browser-traces"; -import { traceTimelineRows } from "@/agent/subagents/browser-agent/lib/trace/timeline"; -import { listWorkerBrowserSessions } from "@/db/services/browsers"; -import type { AccessScope } from "@/lib/access-scope"; -import { scopeFromPrincipal } from "@/agent/lib/principal-scope"; -import { taskCompletionOutputSchema } from "@/lib/worker-completion"; -import { harvestBrowserTraceDomains } from "@/agent/subagents/browser-agent/lib/trace/domains"; +} from "@db/services/browser-traces"; +import { traceTimelineRows } from "@agent/subagents/browser-agent/lib/trace/timeline"; +import { listWorkerBrowserSessions } from "@db/services/browsers"; +import type { AccessScope } from "@shared/identity/access-scope"; +import { scopeFromPrincipal } from "@agent/lib/principal-scope"; +import { taskCompletionOutputSchema } from "@agent/subagents/browser-agent/lib/completion"; +import { harvestBrowserTraceDomains } from "@agent/subagents/browser-agent/lib/trace/domains"; function traceScope(ctx: HookContext) { const initiator = ctx.session.auth.initiator; diff --git a/agent/subagents/browser-agent/lib/access.ts b/agent/subagents/browser-agent/lib/access.ts index 89a4aaf9..03dfc428 100644 --- a/agent/subagents/browser-agent/lib/access.ts +++ b/agent/subagents/browser-agent/lib/access.ts @@ -1,6 +1,6 @@ import type { SessionContext } from "eve/context"; -import { isSessionOwned } from "@/db/services/sessions"; -import { scopeFromPrincipal } from "@/agent/lib/principal-scope"; +import { isSessionOwned } from "@db/services/sessions"; +import { scopeFromPrincipal } from "@agent/lib/principal-scope"; export async function requireWorkerScope( context: Pick diff --git a/agent/subagents/browser-agent/lib/autofill/native.ts b/agent/subagents/browser-agent/lib/autofill/native.ts index 7b6bc21d..2eeab78c 100644 --- a/agent/subagents/browser-agent/lib/autofill/native.ts +++ b/agent/subagents/browser-agent/lib/autofill/native.ts @@ -1,6 +1,6 @@ import Kernel from "@onkernel/sdk"; import { z } from "zod"; -import { env } from "@/env"; +import { env } from "@shared/environment"; import type { AutofillClaim } from "./protocol"; import { classifyNativeLoginControl, diff --git a/agent/subagents/browser-agent/lib/autofill/provider.ts b/agent/subagents/browser-agent/lib/autofill/provider.ts index 4d69b8cb..8c2aa5e9 100644 --- a/agent/subagents/browser-agent/lib/autofill/provider.ts +++ b/agent/subagents/browser-agent/lib/autofill/provider.ts @@ -3,14 +3,14 @@ import { listVaultItems, readVaultItem, readVaultSecret, -} from "@/db/services/vault"; +} from "@db/services/vault"; import { parseAddressVaultPayload, parseContactVaultPayload, parseLoginVaultPayload, parsePaymentCardSecret, type VaultItemKind, -} from "@/lib/vault"; +} from "@shared/vault/schema"; import type { DetectedAutofillSurface } from "./protocol"; import type { AutofillVaultAdapter } from "./service"; diff --git a/agent/subagents/browser-agent/lib/autofill/service.ts b/agent/subagents/browser-agent/lib/autofill/service.ts index 8a4b6509..6e07c73d 100644 --- a/agent/subagents/browser-agent/lib/autofill/service.ts +++ b/agent/subagents/browser-agent/lib/autofill/service.ts @@ -1,4 +1,4 @@ -import type { AccessScope } from "@/lib/access-scope"; +import type { AccessScope } from "@shared/identity/access-scope"; import type { AutofillClaim, AutofillSuggestion, diff --git a/agent/subagents/browser-agent/lib/autofill/tests/vault-autofill.test.ts b/agent/subagents/browser-agent/lib/autofill/tests/vault-autofill.test.ts index 669b5eed..74b3e349 100644 --- a/agent/subagents/browser-agent/lib/autofill/tests/vault-autofill.test.ts +++ b/agent/subagents/browser-agent/lib/autofill/tests/vault-autofill.test.ts @@ -1,32 +1,32 @@ import { runInNewContext } from "node:vm"; import { describe, expect, it, vi } from "vitest"; import { z } from "zod"; -import type { AccessScope } from "@/lib/access-scope"; +import type { AccessScope } from "@shared/identity/access-scope"; import { serializeAddressVaultPayload, serializeContactVaultPayload, serializeLoginVaultPayload, serializePaymentCard, type VaultItemKind, -} from "@/lib/vault"; +} from "@shared/vault/schema"; import { classifyNativeLoginControl, frameOriginExpression, nativeLoginFillFunctionDeclaration, selectNativeLoginFills, type NativeLoginControlDescriptor, -} from "@/agent/subagents/browser-agent/lib/autofill/login"; +} from "@agent/subagents/browser-agent/lib/autofill/login"; import { buildNativeAutofillPayload, nativeAutofillSecretMarkingExpression, nativeAutofillTokens, -} from "@/agent/subagents/browser-agent/lib/autofill/native"; +} from "@agent/subagents/browser-agent/lib/autofill/native"; import { listAutofillSuggestions, materializeAutofillClaims, type AutofillVaultAdapter, -} from "@/agent/subagents/browser-agent/lib/autofill/service"; -import { vaultAutofillProvider } from "@/agent/subagents/browser-agent/lib/autofill/provider"; +} from "@agent/subagents/browser-agent/lib/autofill/service"; +import { vaultAutofillProvider } from "@agent/subagents/browser-agent/lib/autofill/provider"; interface VaultStore { items: { id: string }[]; @@ -42,7 +42,7 @@ function createVaultStore(): VaultStore { const vaultStore = vi.hoisted(createVaultStore); -vi.mock("@/db/services/vault", () => ({ +vi.mock("@db/services/vault", () => ({ hasVaultSecret: async () => true, listVaultItems: async () => vaultStore.items, readVaultItem: async (_scope: AccessScope, id: string) => diff --git a/src/lib/worker-completion.ts b/agent/subagents/browser-agent/lib/completion.ts similarity index 91% rename from src/lib/worker-completion.ts rename to agent/subagents/browser-agent/lib/completion.ts index 157e257a..9f953c20 100644 --- a/src/lib/worker-completion.ts +++ b/agent/subagents/browser-agent/lib/completion.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import { browserImageArtifactReferenceSchema } from "@/lib/browser-artifact"; +import { browserImageArtifactReferenceSchema } from "@shared/browser/artifact"; export const maximumWorkerCompletionImages = 4; diff --git a/src/lib/kernel.ts b/agent/subagents/browser-agent/lib/kernel.ts similarity index 70% rename from src/lib/kernel.ts rename to agent/subagents/browser-agent/lib/kernel.ts index d0c8be1d..0d683b3a 100644 --- a/src/lib/kernel.ts +++ b/agent/subagents/browser-agent/lib/kernel.ts @@ -1,4 +1,4 @@ import Kernel from "@onkernel/sdk"; -import { env } from "@/env"; +import { env } from "@shared/environment"; export const kernel = new Kernel({ apiKey: env.KERNEL_API_KEY }); diff --git a/agent/subagents/browser-agent/lib/owned-browser.ts b/agent/subagents/browser-agent/lib/owned-browser.ts index d2e590f1..07d7593d 100644 --- a/agent/subagents/browser-agent/lib/owned-browser.ts +++ b/agent/subagents/browser-agent/lib/owned-browser.ts @@ -1,5 +1,5 @@ -import { readBrowserSession } from "@/db/services/browsers"; -import type { AccessScope } from "@/lib/access-scope"; +import { readBrowserSession } from "@db/services/browsers"; +import type { AccessScope } from "@shared/identity/access-scope"; export async function requireOwnedBrowserSession( scope: AccessScope, diff --git a/agent/subagents/browser-agent/lib/semantic-loop.ts b/agent/subagents/browser-agent/lib/semantic-loop.ts index 33602269..d71b6e62 100644 --- a/agent/subagents/browser-agent/lib/semantic-loop.ts +++ b/agent/subagents/browser-agent/lib/semantic-loop.ts @@ -5,7 +5,7 @@ import { type LoopToolSpec, } from "@onkernel/browser-loop"; import { defineState } from "eve/context"; -import { kernel } from "@/lib/kernel"; +import { kernel } from "@agent/subagents/browser-agent/lib/kernel"; /* oxlint-disable anti-slop/no-unsafe-dictionary-type -- Browser Loop's materialized vendor tool accepts arbitrary JSON input by contract. */ diff --git a/agent/subagents/browser-agent/lib/tests/vault-screenshot-mask.test.ts b/agent/subagents/browser-agent/lib/tests/vault-screenshot-mask.test.ts index ed7966f0..1d8ec247 100644 --- a/agent/subagents/browser-agent/lib/tests/vault-screenshot-mask.test.ts +++ b/agent/subagents/browser-agent/lib/tests/vault-screenshot-mask.test.ts @@ -12,7 +12,7 @@ const mocks = vi.hoisted(() => ({ >(), })); -vi.mock("@/lib/kernel", () => ({ +vi.mock("@agent/subagents/browser-agent/lib/kernel", () => ({ kernel: { browsers: { playwright: { execute: mocks.execute } } }, })); diff --git a/agent/subagents/browser-agent/lib/tests/worker-access.test.ts b/agent/subagents/browser-agent/lib/tests/worker-access.test.ts index 3be286d2..763d640a 100644 --- a/agent/subagents/browser-agent/lib/tests/worker-access.test.ts +++ b/agent/subagents/browser-agent/lib/tests/worker-access.test.ts @@ -1,7 +1,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -import * as SessionService from "@/db/services/sessions"; -import { accessScopeForUser } from "@/lib/access-scope"; -import { requireWorkerScope } from "@/agent/subagents/browser-agent/lib/access"; +import * as SessionService from "@db/services/sessions"; +import { accessScopeForUser } from "@shared/identity/access-scope"; +import { requireWorkerScope } from "@agent/subagents/browser-agent/lib/access"; const isSessionOwnedMock = vi.spyOn(SessionService, "isSessionOwned"); diff --git a/agent/subagents/browser-agent/lib/trace/domains.ts b/agent/subagents/browser-agent/lib/trace/domains.ts index 33b9c622..170d0a5c 100644 --- a/agent/subagents/browser-agent/lib/trace/domains.ts +++ b/agent/subagents/browser-agent/lib/trace/domains.ts @@ -1,6 +1,6 @@ -import { recordBrowserTraceDomains } from "@/db/services/browser-traces"; -import type { AccessScope } from "@/lib/access-scope"; -import { kernel } from "@/lib/kernel"; +import { recordBrowserTraceDomains } from "@db/services/browser-traces"; +import type { AccessScope } from "@shared/identity/access-scope"; +import { kernel } from "@agent/subagents/browser-agent/lib/kernel"; const maximumTelemetryEvents = 5000; diff --git a/agent/subagents/browser-agent/lib/vault-screenshot-mask.ts b/agent/subagents/browser-agent/lib/vault-screenshot-mask.ts index 675ed42f..61102c85 100644 --- a/agent/subagents/browser-agent/lib/vault-screenshot-mask.ts +++ b/agent/subagents/browser-agent/lib/vault-screenshot-mask.ts @@ -1,4 +1,4 @@ -import { kernel } from "@/lib/kernel"; +import { kernel } from "@agent/subagents/browser-agent/lib/kernel"; export async function withVaultScreenshotMask( sessionId: string, diff --git a/agent/subagents/browser-agent/tools/capture_browser_image.ts b/agent/subagents/browser-agent/tools/capture_browser_image.ts index 36c2f418..345451d6 100644 --- a/agent/subagents/browser-agent/tools/capture_browser_image.ts +++ b/agent/subagents/browser-agent/tools/capture_browser_image.ts @@ -2,21 +2,21 @@ import { createHash, randomUUID } from "node:crypto"; import { del, put } from "@vercel/blob"; import { defineTool, toolOutput } from "eve/tools"; import { z } from "zod"; -import { requireWorkerScope } from "@/agent/subagents/browser-agent/lib/access"; -import { requireOwnedBrowserSession } from "@/agent/subagents/browser-agent/lib/owned-browser"; -import { withVaultScreenshotMask } from "@/agent/subagents/browser-agent/lib/vault-screenshot-mask"; +import { requireWorkerScope } from "@agent/subagents/browser-agent/lib/access"; +import { requireOwnedBrowserSession } from "@agent/subagents/browser-agent/lib/owned-browser"; +import { withVaultScreenshotMask } from "@agent/subagents/browser-agent/lib/vault-screenshot-mask"; import { finalizeBrowserImageArtifact, reserveBrowserImageArtifact, type BrowserImageArtifactReservation, -} from "@/db/services/browser-images"; +} from "@db/services/browser-images"; import { browserImageArtifactReferenceSchema, maximumBrowserImageBytes, sniffBrowserImageMediaType, -} from "@/lib/browser-artifact"; -import { env } from "@/env"; -import { kernel } from "@/lib/kernel"; +} from "@shared/browser/artifact"; +import { env } from "@shared/environment"; +import { kernel } from "@agent/subagents/browser-agent/lib/kernel"; const regionSchema = z.object({ height: z.number().int().positive(), diff --git a/agent/subagents/browser-agent/tools/computer_action.ts b/agent/subagents/browser-agent/tools/computer_action.ts index 2f8b341d..429fc7ec 100644 --- a/agent/subagents/browser-agent/tools/computer_action.ts +++ b/agent/subagents/browser-agent/tools/computer_action.ts @@ -1,10 +1,10 @@ import { defineTool, toolOutput, toolOutputPart } from "eve/tools"; import type { ComputerBatchParams } from "@onkernel/sdk/resources/browsers/computer"; import { z } from "zod"; -import { kernel } from "@/lib/kernel"; -import { requireWorkerScope } from "@/agent/subagents/browser-agent/lib/access"; -import { requireOwnedBrowserSession } from "@/agent/subagents/browser-agent/lib/owned-browser"; -import { withVaultScreenshotMask } from "@/agent/subagents/browser-agent/lib/vault-screenshot-mask"; +import { kernel } from "@agent/subagents/browser-agent/lib/kernel"; +import { requireWorkerScope } from "@agent/subagents/browser-agent/lib/access"; +import { requireOwnedBrowserSession } from "@agent/subagents/browser-agent/lib/owned-browser"; +import { withVaultScreenshotMask } from "@agent/subagents/browser-agent/lib/vault-screenshot-mask"; const actionSchema = z.object({ type: z.enum([ diff --git a/agent/subagents/browser-agent/tools/fill_from_vault.ts b/agent/subagents/browser-agent/tools/fill_from_vault.ts index 754a3d87..5e783ce8 100644 --- a/agent/subagents/browser-agent/tools/fill_from_vault.ts +++ b/agent/subagents/browser-agent/tools/fill_from_vault.ts @@ -1,9 +1,9 @@ import { defineTool } from "eve/tools"; import { z } from "zod"; -import { requireOwnedBrowserSession } from "@/agent/subagents/browser-agent/lib/owned-browser"; -import { requireWorkerScope } from "@/agent/subagents/browser-agent/lib/access"; -import { readVaultItem } from "@/db/services/vault"; -import { kernel } from "@/lib/kernel"; +import { requireOwnedBrowserSession } from "@agent/subagents/browser-agent/lib/owned-browser"; +import { requireWorkerScope } from "@agent/subagents/browser-agent/lib/access"; +import { readVaultItem } from "@db/services/vault"; +import { kernel } from "@agent/subagents/browser-agent/lib/kernel"; import { currentKernelPageOrigin, fillWithKernelNativeAutofill, diff --git a/agent/subagents/browser-agent/tools/list_vault.ts b/agent/subagents/browser-agent/tools/list_vault.ts index 82d1a4e5..3bcf6eda 100644 --- a/agent/subagents/browser-agent/tools/list_vault.ts +++ b/agent/subagents/browser-agent/tools/list_vault.ts @@ -1,7 +1,7 @@ import { defineTool } from "eve/tools"; import { z } from "zod"; -import { requireWorkerScope } from "@/agent/subagents/browser-agent/lib/access"; -import { readVaultItems } from "@/db/services/vault"; +import { requireWorkerScope } from "@agent/subagents/browser-agent/lib/access"; +import { readVaultItems } from "@db/services/vault"; export default defineTool({ description: diff --git a/agent/subagents/browser-agent/tools/manage_browsers.ts b/agent/subagents/browser-agent/tools/manage_browsers.ts index e2840ec7..64b6cbd1 100644 --- a/agent/subagents/browser-agent/tools/manage_browsers.ts +++ b/agent/subagents/browser-agent/tools/manage_browsers.ts @@ -12,16 +12,16 @@ import { deleteBrowserSession, listBrowserSessions, withBrowserProfileWriteLock, -} from "@/db/services/browsers"; -import { recordBrowserTraceDomains } from "@/db/services/browser-traces"; -import { kernel } from "@/lib/kernel"; -import { requireWorkerScope } from "@/agent/subagents/browser-agent/lib/access"; +} from "@db/services/browsers"; +import { recordBrowserTraceDomains } from "@db/services/browser-traces"; +import { kernel } from "@agent/subagents/browser-agent/lib/kernel"; +import { requireWorkerScope } from "@agent/subagents/browser-agent/lib/access"; import { disposeBrowserLoopSession } from "../lib/semantic-loop"; -import { requireOwnedBrowserSession } from "@/agent/subagents/browser-agent/lib/owned-browser"; +import { requireOwnedBrowserSession } from "@agent/subagents/browser-agent/lib/owned-browser"; import { domainFromUrl, harvestBrowserTraceDomains, -} from "@/agent/subagents/browser-agent/lib/trace/domains"; +} from "@agent/subagents/browser-agent/lib/trace/domains"; const browserTimeoutFloorSeconds = 15 * 60; diff --git a/agent/subagents/browser-agent/tools/semantic_browser.ts b/agent/subagents/browser-agent/tools/semantic_browser.ts index 1d2f85bd..2c773a50 100644 --- a/agent/subagents/browser-agent/tools/semantic_browser.ts +++ b/agent/subagents/browser-agent/tools/semantic_browser.ts @@ -10,8 +10,8 @@ import { toolOutput, toolOutputPart, } from "eve/tools"; -import { requireWorkerScope } from "@/agent/subagents/browser-agent/lib/access"; -import { requireOwnedBrowserSession } from "@/agent/subagents/browser-agent/lib/owned-browser"; +import { requireWorkerScope } from "@agent/subagents/browser-agent/lib/access"; +import { requireOwnedBrowserSession } from "@agent/subagents/browser-agent/lib/owned-browser"; import { executeBrowserLoopTool, modelText } from "../lib/semantic-loop"; /* oxlint-disable anti-slop/no-known-value-widening, anti-slop/no-runtime-typeof, anti-slop/no-unknown-parameters, anti-slop/no-unsafe-dictionary-type -- Browser Loop supplies runtime-selected JSON Schemas and JSON inputs, so this adapter must preserve its dynamic vendor boundary. */ diff --git a/agent/tools/calendar.ts b/agent/tools/calendar.ts index a3b62332..0cd90bff 100644 --- a/agent/tools/calendar.ts +++ b/agent/tools/calendar.ts @@ -6,8 +6,8 @@ import { checkCalendarAvailability, createCalendarEvent, listCalendarEvents, -} from "@/agent/lib/google-workspace/calendar"; -import { resolveModeValue } from "@/agent/lib/mode"; +} from "@agent/lib/google-workspace/calendar"; +import { resolveModeValue } from "@agent/lib/mode"; export const calendarListEvents = defineTool({ description: diff --git a/agent/tools/contacts.ts b/agent/tools/contacts.ts index 7675551c..dfb5a1d6 100644 --- a/agent/tools/contacts.ts +++ b/agent/tools/contacts.ts @@ -1,7 +1,7 @@ import { defineDynamic, defineTool } from "eve/tools"; import { z } from "zod"; -import { searchGoogleContacts } from "@/agent/lib/google-workspace/contacts"; -import { resolveModeValue } from "@/agent/lib/mode"; +import { searchGoogleContacts } from "@agent/lib/google-workspace/contacts"; +import { resolveModeValue } from "@agent/lib/mode"; export const contactsSearch = defineTool({ description: diff --git a/agent/tools/gmail.ts b/agent/tools/gmail.ts index 6a404bae..274f8c29 100644 --- a/agent/tools/gmail.ts +++ b/agent/tools/gmail.ts @@ -8,8 +8,8 @@ import { searchGmail, sendGmail, updateGmail, -} from "@/agent/lib/google-workspace/gmail"; -import { resolveModeValue } from "@/agent/lib/mode"; +} from "@agent/lib/google-workspace/gmail"; +import { resolveModeValue } from "@agent/lib/mode"; export const gmailSearch = defineTool({ description: diff --git a/agent/tools/messaging.ts b/agent/tools/messaging.ts index ec60090c..917d48d0 100644 --- a/agent/tools/messaging.ts +++ b/agent/tools/messaging.ts @@ -3,8 +3,8 @@ import { resolveModeValue } from "../lib/mode"; import { addReactionToMessageOutputSchema, reactToMessageOutputSchema, -} from "../lib/react-to-message"; -import { sendMessageOutputSchema } from "../lib/send-message"; +} from "@shared/chat/reaction"; +import { sendMessageOutputSchema } from "@shared/chat/message-delivery"; export default defineDynamic({ events: { diff --git a/agent/tools/schedules.ts b/agent/tools/schedules.ts index e1ffd657..72da780c 100644 --- a/agent/tools/schedules.ts +++ b/agent/tools/schedules.ts @@ -1,21 +1,21 @@ import { defineDynamic, defineTool, type ToolContext } from "eve/tools"; import { z } from "zod"; -import { resolveModeValue } from "@/agent/lib/mode"; -import { scheduledReportIdentity } from "@/agent/lib/schedules/identity"; -import { postScheduledRunRoute } from "@/agent/lib/schedules/request"; +import { resolveModeValue } from "@agent/lib/mode"; +import { scheduledReportIdentity } from "@agent/lib/schedules/identity"; +import { postScheduledRunRoute } from "@agent/lib/schedules/request"; import { scheduleListSummary, scheduleOwner, scheduleSummary, -} from "@/agent/lib/schedules/tools"; -import { scheduleTimingSchema } from "@/agent/lib/schedules/timing"; +} from "@agent/lib/schedules/tools"; +import { scheduleTimingSchema } from "@shared/schedules/timing"; import { createScheduledAgentJob, getScheduledAgentRunInput, getScheduledAgentRunInputForReport, listScheduledAgentJobs, updateScheduledAgentJob, -} from "@/db/services/scheduled-agent-jobs"; +} from "@db/services/scheduled-agent-jobs"; export const createSchedule = defineTool({ description: diff --git a/agent/tools/vault.ts b/agent/tools/vault.ts index 816b554e..440fb369 100644 --- a/agent/tools/vault.ts +++ b/agent/tools/vault.ts @@ -1,8 +1,11 @@ import { defineDynamic, defineTool } from "eve/tools"; import { z } from "zod"; -import { resolveModeValue } from "@/agent/lib/mode"; -import { applicationOrigin } from "@/lib/application-origin"; -import { createVaultSetupUrl, vaultSetupRequestSchema } from "@/lib/vault"; +import { resolveModeValue } from "@agent/lib/mode"; +import { applicationOrigin } from "@shared/environment/origin"; +import { + createVaultSetupUrl, + vaultSetupRequestSchema, +} from "@shared/vault/schema"; export const requestVaultImport = defineTool({ description: diff --git a/src/app/(authenticated)/(workspace)/_components/google-workspace-action.tsx b/app/(authenticated)/(workspace)/_components/google-workspace-action.tsx similarity index 86% rename from src/app/(authenticated)/(workspace)/_components/google-workspace-action.tsx rename to app/(authenticated)/(workspace)/_components/google-workspace-action.tsx index 3dc55769..00c1ac93 100644 --- a/src/app/(authenticated)/(workspace)/_components/google-workspace-action.tsx +++ b/app/(authenticated)/(workspace)/_components/google-workspace-action.tsx @@ -1,8 +1,8 @@ "use client"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { api } from "@/trpc/client"; +import { Badge } from "@web/components/ui/badge"; +import { Button } from "@web/components/ui/button"; +import { api } from "@web/trpc/client"; export function GoogleWorkspaceAction({ state, diff --git a/src/app/(authenticated)/(workspace)/_components/model-selector.tsx b/app/(authenticated)/(workspace)/_components/model-selector.tsx similarity index 95% rename from src/app/(authenticated)/(workspace)/_components/model-selector.tsx rename to app/(authenticated)/(workspace)/_components/model-selector.tsx index 8b4795bb..c683e0c7 100644 --- a/src/app/(authenticated)/(workspace)/_components/model-selector.tsx +++ b/app/(authenticated)/(workspace)/_components/model-selector.tsx @@ -14,10 +14,10 @@ import { ModelSelectorLogo, ModelSelectorShortcut, ModelSelectorTrigger, -} from "@/components/ai-elements/model-selector"; -import { Button } from "@/components/ui/button"; -import { api } from "@/trpc/client"; -import type { RouterOutputs } from "@/trpc/types"; +} from "@web/components/ai-elements/model-selector"; +import { Button } from "@web/components/ui/button"; +import { api } from "@web/trpc/client"; +import type { RouterOutputs } from "@web/trpc/types"; type ModelCatalogItem = RouterOutputs["models"]["list"][number]; diff --git a/src/app/(authenticated)/(workspace)/_tests/workspace-linq.test.ts b/app/(authenticated)/(workspace)/_tests/workspace-linq.test.ts similarity index 95% rename from src/app/(authenticated)/(workspace)/_tests/workspace-linq.test.ts rename to app/(authenticated)/(workspace)/_tests/workspace-linq.test.ts index 00f55948..a51df987 100644 --- a/src/app/(authenticated)/(workspace)/_tests/workspace-linq.test.ts +++ b/app/(authenticated)/(workspace)/_tests/workspace-linq.test.ts @@ -1,7 +1,7 @@ import { createElement } from "react"; import { renderToStaticMarkup } from "react-dom/server"; import { describe, expect, it } from "vitest"; -import { ChannelsSection } from "@/app/(authenticated)/(workspace)/page"; +import { ChannelsSection } from "@app/(authenticated)/(workspace)/page"; describe("workspace Linq channel", () => { it("disables iMessage without advertising another deployment's number", () => { diff --git a/src/app/(authenticated)/(workspace)/page.tsx b/app/(authenticated)/(workspace)/page.tsx similarity index 94% rename from src/app/(authenticated)/(workspace)/page.tsx rename to app/(authenticated)/(workspace)/page.tsx index 9c632728..f48e7412 100644 --- a/src/app/(authenticated)/(workspace)/page.tsx +++ b/app/(authenticated)/(workspace)/page.tsx @@ -13,13 +13,13 @@ import { UserAuthorizationRequiredError, } from "@vercel/connect"; import { z } from "zod"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { getGatewayModel } from "@/db/services/settings"; -import { env } from "@/env"; -import { googleWorkspaceTokenParams } from "@/lib/google-workspace"; -import { requireRequestScope } from "@/lib/request-scope"; +import { Alert, AlertDescription, AlertTitle } from "@web/components/ui/alert"; +import { Badge } from "@web/components/ui/badge"; +import { Button } from "@web/components/ui/button"; +import { getGatewayModel } from "@db/services/settings"; +import { env } from "@shared/environment"; +import { googleWorkspaceTokenParams } from "@shared/google-workspace/connection"; +import { requireRequestScope } from "@web/auth/request-scope"; import { GoogleWorkspaceAction } from "./_components/google-workspace-action"; import { ModelSelector } from "./_components/model-selector"; diff --git a/src/app/(authenticated)/_components/account-control.tsx b/app/(authenticated)/_components/account-control.tsx similarity index 91% rename from src/app/(authenticated)/_components/account-control.tsx rename to app/(authenticated)/_components/account-control.tsx index f2351b7e..0992143f 100644 --- a/src/app/(authenticated)/_components/account-control.tsx +++ b/app/(authenticated)/_components/account-control.tsx @@ -1,13 +1,13 @@ "use client"; import { LogOutIcon, UserIcon } from "lucide-react"; -import { authClient } from "@/app/_lib/auth-client"; +import { authClient } from "@web/auth/client"; import { SidebarMenu, SidebarMenuAction, SidebarMenuButton, SidebarMenuItem, -} from "@/components/ui/sidebar"; +} from "@web/components/ui/sidebar"; export function AuthenticatedAccountControl() { const { data: session } = authClient.useSession(); diff --git a/src/app/(authenticated)/_components/authenticated-navigation.tsx b/app/(authenticated)/_components/authenticated-navigation.tsx similarity index 98% rename from src/app/(authenticated)/_components/authenticated-navigation.tsx rename to app/(authenticated)/_components/authenticated-navigation.tsx index d3c82503..8db5877e 100644 --- a/src/app/(authenticated)/_components/authenticated-navigation.tsx +++ b/app/(authenticated)/_components/authenticated-navigation.tsx @@ -17,7 +17,7 @@ import { SidebarMenuButton, SidebarMenuItem, SidebarTrigger, -} from "@/components/ui/sidebar"; +} from "@web/components/ui/sidebar"; const navigation = [ { href: "/", icon: PanelsTopLeftIcon, id: "workspace", label: "Workspace" }, diff --git a/src/app/(authenticated)/chat/(new)/_components/new-chat.test.tsx b/app/(authenticated)/chat/(new)/_components/new-chat.test.tsx similarity index 94% rename from src/app/(authenticated)/chat/(new)/_components/new-chat.test.tsx rename to app/(authenticated)/chat/(new)/_components/new-chat.test.tsx index 309117f1..aa21774a 100644 --- a/src/app/(authenticated)/chat/(new)/_components/new-chat.test.tsx +++ b/app/(authenticated)/chat/(new)/_components/new-chat.test.tsx @@ -2,7 +2,7 @@ import type { useEveAgent } from "eve/react"; import type { ReactNode } from "react"; import { renderToStaticMarkup } from "react-dom/server"; import { beforeEach, describe, expect, it, type Mock, vi } from "vitest"; -import type { PromptInputMessage } from "@/components/ai-elements/prompt-input"; +import type { PromptInputMessage } from "@web/components/ai-elements/prompt-input"; type AgentOptions = Parameters[0]; @@ -46,13 +46,13 @@ vi.mock("eve/react", () => ({ }, })); -vi.mock("@/trpc/client", () => ({ +vi.mock("@web/trpc/client", () => ({ api: { chats: { save: { useMutation: () => ({ mutateAsync: mocks.saveChat }) } }, }, })); -vi.mock("@/components/ai-elements/prompt-input", () => ({ +vi.mock("@web/components/ai-elements/prompt-input", () => ({ PromptInput: ({ children, onSubmit, diff --git a/src/app/(authenticated)/chat/(new)/_components/new-chat.tsx b/app/(authenticated)/chat/(new)/_components/new-chat.tsx similarity index 95% rename from src/app/(authenticated)/chat/(new)/_components/new-chat.tsx rename to app/(authenticated)/chat/(new)/_components/new-chat.tsx index ff43314f..a4556fd4 100644 --- a/src/app/(authenticated)/chat/(new)/_components/new-chat.tsx +++ b/app/(authenticated)/chat/(new)/_components/new-chat.tsx @@ -11,9 +11,9 @@ import { PromptInputSubmit, PromptInputTextarea, PromptInputTools, -} from "@/components/ai-elements/prompt-input"; +} from "@web/components/ai-elements/prompt-input"; import { chatTitle, messageContent } from "../../_lib/message-input"; -import { api } from "@/trpc/client"; +import { api } from "@web/trpc/client"; export function NewChat() { const router = useRouter(); diff --git a/src/app/(authenticated)/chat/(new)/page.tsx b/app/(authenticated)/chat/(new)/page.tsx similarity index 100% rename from src/app/(authenticated)/chat/(new)/page.tsx rename to app/(authenticated)/chat/(new)/page.tsx diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/activity/card.tsx b/app/(authenticated)/chat/[sessionId]/_components/activity/card.tsx similarity index 91% rename from src/app/(authenticated)/chat/[sessionId]/_components/activity/card.tsx rename to app/(authenticated)/chat/[sessionId]/_components/activity/card.tsx index 4e8dec61..d971e7eb 100644 --- a/src/app/(authenticated)/chat/[sessionId]/_components/activity/card.tsx +++ b/app/(authenticated)/chat/[sessionId]/_components/activity/card.tsx @@ -4,13 +4,13 @@ import { getSubagentTask, type SubagentSession, type SubagentStatus, -} from "@/app/_lib/subagent-sessions"; -import { formatChatUsage } from "@/app/(authenticated)/chat/_lib/chat-usage"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent } from "@/components/ui/card"; -import { Field } from "@/components/ui/field"; -import { Switch } from "@/components/ui/switch"; -import type { ChatUsage } from "@/lib/chat"; +} from "@app/_lib/subagent-sessions"; +import { formatChatUsage } from "@app/(authenticated)/chat/_lib/chat-usage"; +import { Button } from "@web/components/ui/button"; +import { Card, CardContent } from "@web/components/ui/card"; +import { Field } from "@web/components/ui/field"; +import { Switch } from "@web/components/ui/switch"; +import type { ChatUsage } from "@shared/chat/schema"; import type { TraceView } from "../../_lib/trace-view"; import { agentLabel, StatusIndicator } from "./presentation"; diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/activity/index.tsx b/app/(authenticated)/chat/[sessionId]/_components/activity/index.tsx similarity index 96% rename from src/app/(authenticated)/chat/[sessionId]/_components/activity/index.tsx rename to app/(authenticated)/chat/[sessionId]/_components/activity/index.tsx index 4b0a8754..aafdc966 100644 --- a/src/app/(authenticated)/chat/[sessionId]/_components/activity/index.tsx +++ b/app/(authenticated)/chat/[sessionId]/_components/activity/index.tsx @@ -3,20 +3,20 @@ import type { MessageStreamEvent } from "eve/client"; import { ListTreeIcon } from "lucide-react"; import { useEffect, useMemo, useRef, useState } from "react"; -import { Button } from "@/components/ui/button"; +import { Button } from "@web/components/ui/button"; import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, -} from "@/components/ui/sheet"; +} from "@web/components/ui/sheet"; import { collectSubagentSessions, getSubagentStatus, -} from "@/app/_lib/subagent-sessions"; -import type { ChatUsage } from "@/lib/chat"; -import { cn } from "@/lib/utils"; +} from "@app/_lib/subagent-sessions"; +import type { ChatUsage } from "@shared/chat/schema"; +import { cn } from "@web/components/class-names"; import type { TraceView } from "../../_lib/trace-view"; import { ActivityCard } from "./card"; import { TracePreview } from "./preview"; diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/activity/presentation.tsx b/app/(authenticated)/chat/[sessionId]/_components/activity/presentation.tsx similarity index 80% rename from src/app/(authenticated)/chat/[sessionId]/_components/activity/presentation.tsx rename to app/(authenticated)/chat/[sessionId]/_components/activity/presentation.tsx index dfd9349c..6024402a 100644 --- a/src/app/(authenticated)/chat/[sessionId]/_components/activity/presentation.tsx +++ b/app/(authenticated)/chat/[sessionId]/_components/activity/presentation.tsx @@ -1,5 +1,5 @@ -import type { SubagentStatus } from "@/app/_lib/subagent-sessions"; -import { Badge } from "@/components/ui/badge"; +import type { SubagentStatus } from "@app/_lib/subagent-sessions"; +import { Badge } from "@web/components/ui/badge"; export function agentLabel(name: string) { return `${name.charAt(0).toUpperCase()}${name.slice(1)}`; diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/activity/preview.tsx b/app/(authenticated)/chat/[sessionId]/_components/activity/preview.tsx similarity index 95% rename from src/app/(authenticated)/chat/[sessionId]/_components/activity/preview.tsx rename to app/(authenticated)/chat/[sessionId]/_components/activity/preview.tsx index 3a021906..fc94d6c4 100644 --- a/src/app/(authenticated)/chat/[sessionId]/_components/activity/preview.tsx +++ b/app/(authenticated)/chat/[sessionId]/_components/activity/preview.tsx @@ -3,8 +3,8 @@ import type { RefObject } from "react"; import { getSubagentStatus, type SubagentSession, -} from "@/app/_lib/subagent-sessions"; -import { Button } from "@/components/ui/button"; +} from "@app/_lib/subagent-sessions"; +import { Button } from "@web/components/ui/button"; import { agentLabel } from "./presentation"; import { SubagentTrace } from "./trace"; import { useSessionHistory } from "./use-session-history"; diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/activity/trace.tsx b/app/(authenticated)/chat/[sessionId]/_components/activity/trace.tsx similarity index 92% rename from src/app/(authenticated)/chat/[sessionId]/_components/activity/trace.tsx rename to app/(authenticated)/chat/[sessionId]/_components/activity/trace.tsx index fa54177c..e4ddccbd 100644 --- a/src/app/(authenticated)/chat/[sessionId]/_components/activity/trace.tsx +++ b/app/(authenticated)/chat/[sessionId]/_components/activity/trace.tsx @@ -7,18 +7,18 @@ import { } from "eve/client"; import { BotIcon, LoaderCircleIcon } from "lucide-react"; import { useMemo } from "react"; -import { Shimmer } from "@/components/ai-elements/shimmer"; +import { Shimmer } from "@web/components/ai-elements/shimmer"; import { Alert, AlertAction, AlertDescription, AlertTitle, -} from "@/components/ui/alert"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; +} from "@web/components/ui/alert"; +import { Badge } from "@web/components/ui/badge"; +import { Button } from "@web/components/ui/button"; import { getLatestTurnFailure } from "../../_lib/turn-failure"; import { messageTimestamps } from "../../_lib/message-events"; -import type { SubagentStatus } from "@/app/_lib/subagent-sessions"; +import type { SubagentStatus } from "@app/_lib/subagent-sessions"; import { AgentMessage } from "../conversation/message"; const messageReducer = defaultMessageReducer(); diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/activity/use-chat-usage.ts b/app/(authenticated)/chat/[sessionId]/_components/activity/use-chat-usage.ts similarity index 94% rename from src/app/(authenticated)/chat/[sessionId]/_components/activity/use-chat-usage.ts rename to app/(authenticated)/chat/[sessionId]/_components/activity/use-chat-usage.ts index b1b30cd5..54358fb3 100644 --- a/src/app/(authenticated)/chat/[sessionId]/_components/activity/use-chat-usage.ts +++ b/app/(authenticated)/chat/[sessionId]/_components/activity/use-chat-usage.ts @@ -1,8 +1,8 @@ import type { MessageStreamEvent } from "eve/client"; import { useEffect, useMemo, useRef } from "react"; import { summarizeChatUsage } from "../../../_lib/chat-usage"; -import type { ChatUsage } from "@/lib/chat"; -import { api } from "@/trpc/client"; +import type { ChatUsage } from "@shared/chat/schema"; +import { api } from "@web/trpc/client"; export function useChatUsage({ events, diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/activity/use-session-history.ts b/app/(authenticated)/chat/[sessionId]/_components/activity/use-session-history.ts similarity index 100% rename from src/app/(authenticated)/chat/[sessionId]/_components/activity/use-session-history.ts rename to app/(authenticated)/chat/[sessionId]/_components/activity/use-session-history.ts diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/chat-agent.ts b/app/(authenticated)/chat/[sessionId]/_components/chat-agent.ts similarity index 100% rename from src/app/(authenticated)/chat/[sessionId]/_components/chat-agent.ts rename to app/(authenticated)/chat/[sessionId]/_components/chat-agent.ts diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/chat-session.test.tsx b/app/(authenticated)/chat/[sessionId]/_components/chat-session.test.tsx similarity index 100% rename from src/app/(authenticated)/chat/[sessionId]/_components/chat-session.test.tsx rename to app/(authenticated)/chat/[sessionId]/_components/chat-session.test.tsx diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/chat-session.tsx b/app/(authenticated)/chat/[sessionId]/_components/chat-session.tsx similarity index 96% rename from src/app/(authenticated)/chat/[sessionId]/_components/chat-session.tsx rename to app/(authenticated)/chat/[sessionId]/_components/chat-session.tsx index eeda4fed..8fcf1633 100644 --- a/src/app/(authenticated)/chat/[sessionId]/_components/chat-session.tsx +++ b/app/(authenticated)/chat/[sessionId]/_components/chat-session.tsx @@ -1,7 +1,7 @@ "use client"; import { useState } from "react"; -import type { ChatUsage } from "@/lib/chat"; +import type { ChatUsage } from "@shared/chat/schema"; import type { TraceView } from "../_lib/trace-view"; import { SubagentPanel } from "./activity"; import { ChatConversation } from "./conversation"; diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/conversation/index.test.tsx b/app/(authenticated)/chat/[sessionId]/_components/conversation/index.test.tsx similarity index 100% rename from src/app/(authenticated)/chat/[sessionId]/_components/conversation/index.test.tsx rename to app/(authenticated)/chat/[sessionId]/_components/conversation/index.test.tsx diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/conversation/index.tsx b/app/(authenticated)/chat/[sessionId]/_components/conversation/index.tsx similarity index 95% rename from src/app/(authenticated)/chat/[sessionId]/_components/conversation/index.tsx rename to app/(authenticated)/chat/[sessionId]/_components/conversation/index.tsx index eb9fb9c1..0e95fc79 100644 --- a/src/app/(authenticated)/chat/[sessionId]/_components/conversation/index.tsx +++ b/app/(authenticated)/chat/[sessionId]/_components/conversation/index.tsx @@ -11,11 +11,11 @@ import { Conversation, ConversationContent, ConversationScrollButton, -} from "@/components/ai-elements/conversation"; -import { Message, MessageContent } from "@/components/ai-elements/message"; -import { Shimmer } from "@/components/ai-elements/shimmer"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; -import { Button } from "@/components/ui/button"; +} from "@web/components/ai-elements/conversation"; +import { Message, MessageContent } from "@web/components/ai-elements/message"; +import { Shimmer } from "@web/components/ai-elements/shimmer"; +import { Alert, AlertDescription, AlertTitle } from "@web/components/ui/alert"; +import { Button } from "@web/components/ui/button"; import { AgentMessage } from "./message"; import type { ChatAgent } from "../chat-agent"; diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/attachment.tsx b/app/(authenticated)/chat/[sessionId]/_components/conversation/message/attachment.tsx similarity index 95% rename from src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/attachment.tsx rename to app/(authenticated)/chat/[sessionId]/_components/conversation/message/attachment.tsx index 0e6822b8..7adf0190 100644 --- a/src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/attachment.tsx +++ b/app/(authenticated)/chat/[sessionId]/_components/conversation/message/attachment.tsx @@ -1,7 +1,7 @@ import type { EveMessagePart } from "eve/react"; import { ExternalLinkIcon, FileIcon, ImageIcon } from "lucide-react"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent } from "@/components/ui/card"; +import { Button } from "@web/components/ui/button"; +import { Card, CardContent } from "@web/components/ui/card"; type EveFilePart = Extract; diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/authorization.tsx b/app/(authenticated)/chat/[sessionId]/_components/conversation/message/authorization.tsx similarity index 94% rename from src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/authorization.tsx rename to app/(authenticated)/chat/[sessionId]/_components/conversation/message/authorization.tsx index 5e53548d..fc338cf0 100644 --- a/src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/authorization.tsx +++ b/app/(authenticated)/chat/[sessionId]/_components/conversation/message/authorization.tsx @@ -5,9 +5,9 @@ import { KeyRoundIcon, XCircleIcon, } from "lucide-react"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; +import { Alert, AlertDescription, AlertTitle } from "@web/components/ui/alert"; +import { Badge } from "@web/components/ui/badge"; +import { Button } from "@web/components/ui/button"; export function AuthorizationPrompt({ part, diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/index.test.tsx b/app/(authenticated)/chat/[sessionId]/_components/conversation/message/index.test.tsx similarity index 100% rename from src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/index.test.tsx rename to app/(authenticated)/chat/[sessionId]/_components/conversation/message/index.test.tsx diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/index.tsx b/app/(authenticated)/chat/[sessionId]/_components/conversation/message/index.tsx similarity index 95% rename from src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/index.tsx rename to app/(authenticated)/chat/[sessionId]/_components/conversation/message/index.tsx index 301ecfdb..325dd9ea 100644 --- a/src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/index.tsx +++ b/app/(authenticated)/chat/[sessionId]/_components/conversation/message/index.tsx @@ -2,8 +2,8 @@ import type { EveMessage } from "eve/react"; import { useState } from "react"; -import { Message, MessageContent } from "@/components/ai-elements/message"; -import { cn } from "@/lib/utils"; +import { Message, MessageContent } from "@web/components/ai-elements/message"; +import { cn } from "@web/components/class-names"; import { AgentMessagePart, partKey } from "./parts"; import type { RespondToAgentInput } from "./types"; diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/input-request.tsx b/app/(authenticated)/chat/[sessionId]/_components/conversation/message/input-request.tsx similarity index 95% rename from src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/input-request.tsx rename to app/(authenticated)/chat/[sessionId]/_components/conversation/message/input-request.tsx index 0fe95225..dc7ae058 100644 --- a/src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/input-request.tsx +++ b/app/(authenticated)/chat/[sessionId]/_components/conversation/message/input-request.tsx @@ -9,9 +9,9 @@ import { QuestionPrompt, type QuestionResponse, QuestionSubmit, -} from "@/components/ai-elements/question"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; -import { Button } from "@/components/ui/button"; +} from "@web/components/ai-elements/question"; +import { Alert, AlertDescription, AlertTitle } from "@web/components/ui/alert"; +import { Button } from "@web/components/ui/button"; import type { InputResponse } from "eve/client"; import type { RespondToAgentInput } from "./types"; diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/parts.tsx b/app/(authenticated)/chat/[sessionId]/_components/conversation/message/parts.tsx similarity index 94% rename from src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/parts.tsx rename to app/(authenticated)/chat/[sessionId]/_components/conversation/message/parts.tsx index 3b495bd2..5fdd3d60 100644 --- a/src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/parts.tsx +++ b/app/(authenticated)/chat/[sessionId]/_components/conversation/message/parts.tsx @@ -1,17 +1,17 @@ import type { EveMessagePart } from "eve/react"; -import { MessageResponse } from "@/components/ai-elements/message"; +import { MessageResponse } from "@web/components/ai-elements/message"; import { Reasoning, ReasoningContent, ReasoningTrigger, -} from "@/components/ai-elements/reasoning"; +} from "@web/components/ai-elements/reasoning"; import { Tool, ToolContent, ToolHeader, ToolInput, ToolOutput, -} from "@/components/ai-elements/tool"; +} from "@web/components/ai-elements/tool"; import { AttachmentPart } from "./attachment"; import { AuthorizationPrompt } from "./authorization"; import { InputRequestActions, QuestionRequest } from "./input-request"; diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/types.ts b/app/(authenticated)/chat/[sessionId]/_components/conversation/message/types.ts similarity index 100% rename from src/app/(authenticated)/chat/[sessionId]/_components/conversation/message/types.ts rename to app/(authenticated)/chat/[sessionId]/_components/conversation/message/types.ts diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/input/index.tsx b/app/(authenticated)/chat/[sessionId]/_components/input/index.tsx similarity index 97% rename from src/app/(authenticated)/chat/[sessionId]/_components/input/index.tsx rename to app/(authenticated)/chat/[sessionId]/_components/input/index.tsx index 9b0475c9..e0fa0cd9 100644 --- a/src/app/(authenticated)/chat/[sessionId]/_components/input/index.tsx +++ b/app/(authenticated)/chat/[sessionId]/_components/input/index.tsx @@ -7,10 +7,10 @@ import { PromptInputSubmit, PromptInputTextarea, PromptInputTools, -} from "@/components/ai-elements/prompt-input"; +} from "@web/components/ai-elements/prompt-input"; import { messageContent } from "../../../_lib/message-input"; import { hasPendingBackgroundWorker } from "../../_lib/trace-view"; -import { api } from "@/trpc/client"; +import { api } from "@web/trpc/client"; import type { ChatAgent } from "../chat-agent"; export function ChatInput({ diff --git a/src/app/(authenticated)/chat/[sessionId]/_components/use-session-agent.ts b/app/(authenticated)/chat/[sessionId]/_components/use-session-agent.ts similarity index 100% rename from src/app/(authenticated)/chat/[sessionId]/_components/use-session-agent.ts rename to app/(authenticated)/chat/[sessionId]/_components/use-session-agent.ts diff --git a/src/app/(authenticated)/chat/[sessionId]/_lib/message-events.test.ts b/app/(authenticated)/chat/[sessionId]/_lib/message-events.test.ts similarity index 100% rename from src/app/(authenticated)/chat/[sessionId]/_lib/message-events.test.ts rename to app/(authenticated)/chat/[sessionId]/_lib/message-events.test.ts diff --git a/src/app/(authenticated)/chat/[sessionId]/_lib/message-events.ts b/app/(authenticated)/chat/[sessionId]/_lib/message-events.ts similarity index 97% rename from src/app/(authenticated)/chat/[sessionId]/_lib/message-events.ts rename to app/(authenticated)/chat/[sessionId]/_lib/message-events.ts index bb9b4d60..7497e8ea 100644 --- a/src/app/(authenticated)/chat/[sessionId]/_lib/message-events.ts +++ b/app/(authenticated)/chat/[sessionId]/_lib/message-events.ts @@ -3,8 +3,8 @@ import type { EveMessagePart } from "eve/react"; import { reactionTextFor, reactToMessageToolResultSchema, -} from "@/agent/lib/react-to-message"; -import { sendMessageToolResultSchema } from "@/agent/lib/send-message"; +} from "@shared/chat/reaction"; +import { sendMessageToolResultSchema } from "@shared/chat/message-delivery"; export function messageTimestamps(events: readonly MessageStreamEvent[]) { const timestamps = new Map(); diff --git a/src/app/(authenticated)/chat/[sessionId]/_lib/session-history.test.ts b/app/(authenticated)/chat/[sessionId]/_lib/session-history.test.ts similarity index 100% rename from src/app/(authenticated)/chat/[sessionId]/_lib/session-history.test.ts rename to app/(authenticated)/chat/[sessionId]/_lib/session-history.test.ts diff --git a/src/app/(authenticated)/chat/[sessionId]/_lib/session-history.ts b/app/(authenticated)/chat/[sessionId]/_lib/session-history.ts similarity index 100% rename from src/app/(authenticated)/chat/[sessionId]/_lib/session-history.ts rename to app/(authenticated)/chat/[sessionId]/_lib/session-history.ts diff --git a/src/app/(authenticated)/chat/[sessionId]/_lib/trace-view.test.ts b/app/(authenticated)/chat/[sessionId]/_lib/trace-view.test.ts similarity index 100% rename from src/app/(authenticated)/chat/[sessionId]/_lib/trace-view.test.ts rename to app/(authenticated)/chat/[sessionId]/_lib/trace-view.test.ts diff --git a/src/app/(authenticated)/chat/[sessionId]/_lib/trace-view.ts b/app/(authenticated)/chat/[sessionId]/_lib/trace-view.ts similarity index 100% rename from src/app/(authenticated)/chat/[sessionId]/_lib/trace-view.ts rename to app/(authenticated)/chat/[sessionId]/_lib/trace-view.ts diff --git a/src/app/(authenticated)/chat/[sessionId]/_lib/turn-failure.test.ts b/app/(authenticated)/chat/[sessionId]/_lib/turn-failure.test.ts similarity index 100% rename from src/app/(authenticated)/chat/[sessionId]/_lib/turn-failure.test.ts rename to app/(authenticated)/chat/[sessionId]/_lib/turn-failure.test.ts diff --git a/src/app/(authenticated)/chat/[sessionId]/_lib/turn-failure.ts b/app/(authenticated)/chat/[sessionId]/_lib/turn-failure.ts similarity index 100% rename from src/app/(authenticated)/chat/[sessionId]/_lib/turn-failure.ts rename to app/(authenticated)/chat/[sessionId]/_lib/turn-failure.ts diff --git a/src/app/(authenticated)/chat/[sessionId]/page.tsx b/app/(authenticated)/chat/[sessionId]/page.tsx similarity index 78% rename from src/app/(authenticated)/chat/[sessionId]/page.tsx rename to app/(authenticated)/chat/[sessionId]/page.tsx index caeeb42d..3d56ad07 100644 --- a/src/app/(authenticated)/chat/[sessionId]/page.tsx +++ b/app/(authenticated)/chat/[sessionId]/page.tsx @@ -1,6 +1,6 @@ import { ChatSession } from "./_components/chat-session"; -import { readChat } from "@/db/services/chats"; -import { requireRequestScope } from "@/lib/request-scope"; +import { readChat } from "@db/services/chats"; +import { requireRequestScope } from "@web/auth/request-scope"; export default async function ChatSessionPage({ params, diff --git a/src/app/(authenticated)/chat/_lib/chat-usage.test.ts b/app/(authenticated)/chat/_lib/chat-usage.test.ts similarity index 100% rename from src/app/(authenticated)/chat/_lib/chat-usage.test.ts rename to app/(authenticated)/chat/_lib/chat-usage.test.ts diff --git a/src/app/(authenticated)/chat/_lib/chat-usage.ts b/app/(authenticated)/chat/_lib/chat-usage.ts similarity index 97% rename from src/app/(authenticated)/chat/_lib/chat-usage.ts rename to app/(authenticated)/chat/_lib/chat-usage.ts index 86a3cd39..d551b8d1 100644 --- a/src/app/(authenticated)/chat/_lib/chat-usage.ts +++ b/app/(authenticated)/chat/_lib/chat-usage.ts @@ -1,5 +1,5 @@ import type { MessageStreamEvent } from "eve/client"; -import type { ChatUsage } from "@/lib/chat"; +import type { ChatUsage } from "@shared/chat/schema"; export function summarizeChatUsage( events: readonly MessageStreamEvent[] diff --git a/src/app/(authenticated)/chat/_lib/message-input.test.ts b/app/(authenticated)/chat/_lib/message-input.test.ts similarity index 100% rename from src/app/(authenticated)/chat/_lib/message-input.test.ts rename to app/(authenticated)/chat/_lib/message-input.test.ts diff --git a/src/app/(authenticated)/chat/_lib/message-input.ts b/app/(authenticated)/chat/_lib/message-input.ts similarity index 88% rename from src/app/(authenticated)/chat/_lib/message-input.ts rename to app/(authenticated)/chat/_lib/message-input.ts index 77b6da97..4e1f6a65 100644 --- a/src/app/(authenticated)/chat/_lib/message-input.ts +++ b/app/(authenticated)/chat/_lib/message-input.ts @@ -1,5 +1,5 @@ import type { UserContent } from "ai"; -import type { PromptInputMessage } from "@/components/ai-elements/prompt-input"; +import type { PromptInputMessage } from "@web/components/ai-elements/prompt-input"; export function messageContent(message: PromptInputMessage) { const text = message.text.trim(); diff --git a/src/app/(authenticated)/chat/history/page.tsx b/app/(authenticated)/chat/history/page.tsx similarity index 89% rename from src/app/(authenticated)/chat/history/page.tsx rename to app/(authenticated)/chat/history/page.tsx index 52eba07b..662cc2aa 100644 --- a/src/app/(authenticated)/chat/history/page.tsx +++ b/app/(authenticated)/chat/history/page.tsx @@ -3,12 +3,12 @@ import Link from "next/link"; import { combineChatUsage, formatChatUsage, -} from "@/app/(authenticated)/chat/_lib/chat-usage"; -import { Alert, AlertDescription } from "@/components/ui/alert"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { listChats } from "@/db/services/chats"; -import { requireRequestScope } from "@/lib/request-scope"; +} from "@app/(authenticated)/chat/_lib/chat-usage"; +import { Alert, AlertDescription } from "@web/components/ui/alert"; +import { Badge } from "@web/components/ui/badge"; +import { Button } from "@web/components/ui/button"; +import { listChats } from "@db/services/chats"; +import { requireRequestScope } from "@web/auth/request-scope"; export const dynamic = "force-dynamic"; diff --git a/src/app/(authenticated)/error.tsx b/app/(authenticated)/error.tsx similarity index 91% rename from src/app/(authenticated)/error.tsx rename to app/(authenticated)/error.tsx index b5909385..54a3e9b2 100644 --- a/src/app/(authenticated)/error.tsx +++ b/app/(authenticated)/error.tsx @@ -1,6 +1,6 @@ "use client"; -import { Button } from "@/components/ui/button"; +import { Button } from "@web/components/ui/button"; export default function AuthenticatedError({ reset, diff --git a/src/app/(authenticated)/layout.tsx b/app/(authenticated)/layout.tsx similarity index 87% rename from src/app/(authenticated)/layout.tsx rename to app/(authenticated)/layout.tsx index b3c51f89..87946a54 100644 --- a/src/app/(authenticated)/layout.tsx +++ b/app/(authenticated)/layout.tsx @@ -1,5 +1,5 @@ import Link from "next/link"; -import { Logo } from "@/components/ui/logo"; +import { Logo } from "@web/components/ui/logo"; import { Sidebar, SidebarContent, @@ -10,9 +10,9 @@ import { SidebarMenuButton, SidebarMenuItem, SidebarProvider, -} from "@/components/ui/sidebar"; -import { requireRequestScope } from "@/lib/request-scope"; -import { TRPCProvider } from "@/trpc/client"; +} from "@web/components/ui/sidebar"; +import { requireRequestScope } from "@web/auth/request-scope"; +import { TRPCProvider } from "@web/trpc/client"; import { AuthenticatedAccountControl } from "./_components/account-control"; import { AuthenticatedMobileHeader, diff --git a/src/app/(authenticated)/loading.tsx b/app/(authenticated)/loading.tsx similarity index 85% rename from src/app/(authenticated)/loading.tsx rename to app/(authenticated)/loading.tsx index b22a9c2a..2eb91a6b 100644 --- a/src/app/(authenticated)/loading.tsx +++ b/app/(authenticated)/loading.tsx @@ -1,4 +1,4 @@ -import { Skeleton } from "@/components/ui/skeleton"; +import { Skeleton } from "@web/components/ui/skeleton"; export default function Loading() { return ( diff --git a/src/app/(authenticated)/personal-info/_components/personal-info-form.tsx b/app/(authenticated)/personal-info/_components/personal-info-form.tsx similarity index 94% rename from src/app/(authenticated)/personal-info/_components/personal-info-form.tsx rename to app/(authenticated)/personal-info/_components/personal-info-form.tsx index c3cd3d9a..432cec15 100644 --- a/src/app/(authenticated)/personal-info/_components/personal-info-form.tsx +++ b/app/(authenticated)/personal-info/_components/personal-info-form.tsx @@ -2,12 +2,15 @@ import { type SubmitEvent, useState } from "react"; import { z } from "zod"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { userProfileSchema, type UserProfile } from "@/lib/user-profile"; -import { api } from "@/trpc/client"; +import { Alert, AlertDescription, AlertTitle } from "@web/components/ui/alert"; +import { Button } from "@web/components/ui/button"; +import { Input } from "@web/components/ui/input"; +import { Label } from "@web/components/ui/label"; +import { + userProfileSchema, + type UserProfile, +} from "@shared/user-profile/schema"; +import { api } from "@web/trpc/client"; export function PersonalInfoForm({ initialProfile, diff --git a/src/app/(authenticated)/personal-info/page.tsx b/app/(authenticated)/personal-info/page.tsx similarity index 65% rename from src/app/(authenticated)/personal-info/page.tsx rename to app/(authenticated)/personal-info/page.tsx index 8c65713a..689f11a0 100644 --- a/src/app/(authenticated)/personal-info/page.tsx +++ b/app/(authenticated)/personal-info/page.tsx @@ -1,6 +1,6 @@ import { PersonalInfoForm } from "./_components/personal-info-form"; -import { readUserProfile } from "@/db/services/user-profile"; -import { requireRequestScope } from "@/lib/request-scope"; +import { readUserProfile } from "@db/services/user-profile"; +import { requireRequestScope } from "@web/auth/request-scope"; export default async function Page() { const scope = await requireRequestScope(); diff --git a/src/app/(authenticated)/tasks/(overview)/_components/trace-history.tsx b/app/(authenticated)/tasks/(overview)/_components/trace-history.tsx similarity index 95% rename from src/app/(authenticated)/tasks/(overview)/_components/trace-history.tsx rename to app/(authenticated)/tasks/(overview)/_components/trace-history.tsx index 45ef209b..f6850721 100644 --- a/src/app/(authenticated)/tasks/(overview)/_components/trace-history.tsx +++ b/app/(authenticated)/tasks/(overview)/_components/trace-history.tsx @@ -4,9 +4,9 @@ import { RefreshCwIcon } from "lucide-react"; import Link from "next/link"; import { useMemo } from "react"; import { z } from "zod"; -import { Alert, AlertDescription } from "@/components/ui/alert"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; +import { Alert, AlertDescription } from "@web/components/ui/alert"; +import { Badge } from "@web/components/ui/badge"; +import { Button } from "@web/components/ui/button"; import { Table, TableBody, @@ -14,9 +14,9 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; -import type { BrowserTracePage } from "@/db/services/browser-traces"; -import { api } from "@/trpc/client"; +} from "@web/components/ui/table"; +import type { BrowserTracePage } from "@db/services/browser-traces"; +import { api } from "@web/trpc/client"; const statusLabels = { cancelled: { label: "Cancelled", variant: "secondary" }, diff --git a/src/app/(authenticated)/tasks/(overview)/page.tsx b/app/(authenticated)/tasks/(overview)/page.tsx similarity index 88% rename from src/app/(authenticated)/tasks/(overview)/page.tsx rename to app/(authenticated)/tasks/(overview)/page.tsx index 0af26616..1078cee4 100644 --- a/src/app/(authenticated)/tasks/(overview)/page.tsx +++ b/app/(authenticated)/tasks/(overview)/page.tsx @@ -1,8 +1,8 @@ import { MessageSquareIcon } from "lucide-react"; import Link from "next/link"; -import { Button } from "@/components/ui/button"; -import { listBrowserTraces } from "@/db/services/browser-traces"; -import { requireRequestScope } from "@/lib/request-scope"; +import { Button } from "@web/components/ui/button"; +import { listBrowserTraces } from "@db/services/browser-traces"; +import { requireRequestScope } from "@web/auth/request-scope"; import { TraceHistory } from "./_components/trace-history"; export default async function TasksPage() { diff --git a/src/app/(authenticated)/tasks/[sessionId]/_components/refresh-button.tsx b/app/(authenticated)/tasks/[sessionId]/_components/refresh-button.tsx similarity index 91% rename from src/app/(authenticated)/tasks/[sessionId]/_components/refresh-button.tsx rename to app/(authenticated)/tasks/[sessionId]/_components/refresh-button.tsx index e319911f..7dd6895a 100644 --- a/src/app/(authenticated)/tasks/[sessionId]/_components/refresh-button.tsx +++ b/app/(authenticated)/tasks/[sessionId]/_components/refresh-button.tsx @@ -3,7 +3,7 @@ import { RefreshCwIcon } from "lucide-react"; import { useRouter } from "next/navigation"; import { useTransition } from "react"; -import { Button } from "@/components/ui/button"; +import { Button } from "@web/components/ui/button"; export function RefreshButton() { const router = useRouter(); diff --git a/src/app/(authenticated)/tasks/[sessionId]/page.tsx b/app/(authenticated)/tasks/[sessionId]/page.tsx similarity index 91% rename from src/app/(authenticated)/tasks/[sessionId]/page.tsx rename to app/(authenticated)/tasks/[sessionId]/page.tsx index 4e3649ea..2907a1cc 100644 --- a/src/app/(authenticated)/tasks/[sessionId]/page.tsx +++ b/app/(authenticated)/tasks/[sessionId]/page.tsx @@ -1,9 +1,9 @@ import { ArrowLeftIcon } from "lucide-react"; import Link from "next/link"; import { notFound } from "next/navigation"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { ActivityDurationBreakdown } from "@/components/browser/activity-duration-breakdown"; +import { Badge } from "@web/components/ui/badge"; +import { Button } from "@web/components/ui/button"; +import { ActivityDurationBreakdown } from "@web/components/browser/activity-duration-breakdown"; import { Table, TableBody, @@ -11,13 +11,13 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; +} from "@web/components/ui/table"; import { listBrowserTraceEvents, readBrowserTrace, -} from "@/db/services/browser-traces"; -import { requireRequestScope } from "@/lib/request-scope"; -import { browserTraceActivityDurations } from "@/lib/browser-activity"; +} from "@db/services/browser-traces"; +import { requireRequestScope } from "@web/auth/request-scope"; +import { browserTraceActivityDurations } from "@web/browser/activity"; import { RefreshButton } from "./_components/refresh-button"; import { z } from "zod"; diff --git a/src/app/(authenticated)/vault/_components/addresses/form.tsx b/app/(authenticated)/vault/_components/addresses/form.tsx similarity index 94% rename from src/app/(authenticated)/vault/_components/addresses/form.tsx rename to app/(authenticated)/vault/_components/addresses/form.tsx index b94a9078..a0fdd079 100644 --- a/src/app/(authenticated)/vault/_components/addresses/form.tsx +++ b/app/(authenticated)/vault/_components/addresses/form.tsx @@ -3,11 +3,11 @@ import { type SubmitEvent, useState } from "react"; import { useRouter } from "next/navigation"; import { z } from "zod"; -import { Button } from "@/components/ui/button"; -import { DialogFooter } from "@/components/ui/dialog"; -import { FieldGroup } from "@/components/ui/field"; -import { serializeAddressVaultPayload } from "@/lib/vault"; -import { api } from "@/trpc/client"; +import { Button } from "@web/components/ui/button"; +import { DialogFooter } from "@web/components/ui/dialog"; +import { FieldGroup } from "@web/components/ui/field"; +import { serializeAddressVaultPayload } from "@shared/vault/schema"; +import { api } from "@web/trpc/client"; import { FormField } from "../field"; const addressFormSchema = z.object({ diff --git a/src/app/(authenticated)/vault/_components/addresses/index.tsx b/app/(authenticated)/vault/_components/addresses/index.tsx similarity index 94% rename from src/app/(authenticated)/vault/_components/addresses/index.tsx rename to app/(authenticated)/vault/_components/addresses/index.tsx index 451d9f1b..7777bfd4 100644 --- a/src/app/(authenticated)/vault/_components/addresses/index.tsx +++ b/app/(authenticated)/vault/_components/addresses/index.tsx @@ -1,13 +1,13 @@ "use client"; import { PlusIcon } from "lucide-react"; -import type { VaultItem } from "@/lib/vault"; -import { Button } from "@/components/ui/button"; +import type { VaultItem } from "@shared/vault/schema"; +import { Button } from "@web/components/ui/button"; import { DialogDescription, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; +} from "@web/components/ui/dialog"; import { AddressForm } from "./form"; import { useVaultSection, diff --git a/src/app/(authenticated)/vault/_components/cards/form.tsx b/app/(authenticated)/vault/_components/cards/form.tsx similarity index 96% rename from src/app/(authenticated)/vault/_components/cards/form.tsx rename to app/(authenticated)/vault/_components/cards/form.tsx index 9fc0d61a..904585be 100644 --- a/src/app/(authenticated)/vault/_components/cards/form.tsx +++ b/app/(authenticated)/vault/_components/cards/form.tsx @@ -3,22 +3,22 @@ import { type SubmitEvent, useState } from "react"; import { useRouter } from "next/navigation"; import { z } from "zod"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { DialogFooter } from "@/components/ui/dialog"; +import { Badge } from "@web/components/ui/badge"; +import { Button } from "@web/components/ui/button"; +import { DialogFooter } from "@web/components/ui/dialog"; import { Field, FieldError, FieldGroup, FieldLabel, -} from "@/components/ui/field"; -import { Input } from "@/components/ui/input"; +} from "@web/components/ui/field"; +import { Input } from "@web/components/ui/input"; import { paymentCardBrand, paymentCardType, serializePaymentCard, -} from "@/lib/vault"; -import { api } from "@/trpc/client"; +} from "@shared/vault/schema"; +import { api } from "@web/trpc/client"; const paymentCardFormSchema = z.object({ billingPostalCode: z.string().trim().min(1, "Enter the billing postal code."), diff --git a/src/app/(authenticated)/vault/_components/cards/index.tsx b/app/(authenticated)/vault/_components/cards/index.tsx similarity index 94% rename from src/app/(authenticated)/vault/_components/cards/index.tsx rename to app/(authenticated)/vault/_components/cards/index.tsx index 629e7650..d2c32f63 100644 --- a/src/app/(authenticated)/vault/_components/cards/index.tsx +++ b/app/(authenticated)/vault/_components/cards/index.tsx @@ -1,13 +1,13 @@ "use client"; import { PlusIcon } from "lucide-react"; -import type { VaultItem } from "@/lib/vault"; -import { Button } from "@/components/ui/button"; +import type { VaultItem } from "@shared/vault/schema"; +import { Button } from "@web/components/ui/button"; import { DialogDescription, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; +} from "@web/components/ui/dialog"; import { CardForm } from "./form"; import { useVaultSection, diff --git a/src/app/(authenticated)/vault/_components/contacts/form.tsx b/app/(authenticated)/vault/_components/contacts/form.tsx similarity index 92% rename from src/app/(authenticated)/vault/_components/contacts/form.tsx rename to app/(authenticated)/vault/_components/contacts/form.tsx index 550aad7d..41c437a2 100644 --- a/src/app/(authenticated)/vault/_components/contacts/form.tsx +++ b/app/(authenticated)/vault/_components/contacts/form.tsx @@ -3,11 +3,11 @@ import { type SubmitEvent, useState } from "react"; import { useRouter } from "next/navigation"; import { z } from "zod"; -import { Button } from "@/components/ui/button"; -import { DialogFooter } from "@/components/ui/dialog"; -import { FieldGroup } from "@/components/ui/field"; -import { serializeContactVaultPayload } from "@/lib/vault"; -import { api } from "@/trpc/client"; +import { Button } from "@web/components/ui/button"; +import { DialogFooter } from "@web/components/ui/dialog"; +import { FieldGroup } from "@web/components/ui/field"; +import { serializeContactVaultPayload } from "@shared/vault/schema"; +import { api } from "@web/trpc/client"; import { FormField } from "../field"; const contactFormSchema = z diff --git a/src/app/(authenticated)/vault/_components/contacts/index.tsx b/app/(authenticated)/vault/_components/contacts/index.tsx similarity index 94% rename from src/app/(authenticated)/vault/_components/contacts/index.tsx rename to app/(authenticated)/vault/_components/contacts/index.tsx index 8328494f..20a22cae 100644 --- a/src/app/(authenticated)/vault/_components/contacts/index.tsx +++ b/app/(authenticated)/vault/_components/contacts/index.tsx @@ -1,13 +1,13 @@ "use client"; import { PlusIcon } from "lucide-react"; -import type { VaultItem } from "@/lib/vault"; -import { Button } from "@/components/ui/button"; +import type { VaultItem } from "@shared/vault/schema"; +import { Button } from "@web/components/ui/button"; import { DialogDescription, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; +} from "@web/components/ui/dialog"; import { ContactForm } from "./form"; import { useVaultSection, diff --git a/src/app/(authenticated)/vault/_components/field.tsx b/app/(authenticated)/vault/_components/field.tsx similarity index 90% rename from src/app/(authenticated)/vault/_components/field.tsx rename to app/(authenticated)/vault/_components/field.tsx index 4744f1ce..afdca458 100644 --- a/src/app/(authenticated)/vault/_components/field.tsx +++ b/app/(authenticated)/vault/_components/field.tsx @@ -5,8 +5,8 @@ import { FieldDescription, FieldError, FieldLabel, -} from "@/components/ui/field"; -import { Input } from "@/components/ui/input"; +} from "@web/components/ui/field"; +import { Input } from "@web/components/ui/input"; export function FormField({ error, diff --git a/src/app/(authenticated)/vault/_components/logins/form.tsx b/app/(authenticated)/vault/_components/logins/form.tsx similarity index 96% rename from src/app/(authenticated)/vault/_components/logins/form.tsx rename to app/(authenticated)/vault/_components/logins/form.tsx index a237bd6b..1691ff07 100644 --- a/src/app/(authenticated)/vault/_components/logins/form.tsx +++ b/app/(authenticated)/vault/_components/logins/form.tsx @@ -3,23 +3,23 @@ import { type SubmitEvent, useState } from "react"; import { useRouter } from "next/navigation"; import { z } from "zod"; -import { Button } from "@/components/ui/button"; -import { Field, FieldGroup, FieldLabel } from "@/components/ui/field"; -import { DialogFooter } from "@/components/ui/dialog"; +import { Button } from "@web/components/ui/button"; +import { Field, FieldGroup, FieldLabel } from "@web/components/ui/field"; +import { DialogFooter } from "@web/components/ui/dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; +} from "@web/components/ui/select"; import { loginIdentifierSchema, loginIdentifierTypeSchema, loginOriginSchema, serializeLoginVaultPayload, -} from "@/lib/vault"; -import { api } from "@/trpc/client"; +} from "@shared/vault/schema"; +import { api } from "@web/trpc/client"; import { FormField } from "../field"; const loginFormSchema = z diff --git a/src/app/(authenticated)/vault/_components/logins/import.tsx b/app/(authenticated)/vault/_components/logins/import.tsx similarity index 96% rename from src/app/(authenticated)/vault/_components/logins/import.tsx rename to app/(authenticated)/vault/_components/logins/import.tsx index a6390ec6..d26ddda3 100644 --- a/src/app/(authenticated)/vault/_components/logins/import.tsx +++ b/app/(authenticated)/vault/_components/logins/import.tsx @@ -8,22 +8,22 @@ import { } from "lucide-react"; import { useState } from "react"; import { useRouter } from "next/navigation"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; -import { Button } from "@/components/ui/button"; +import { Alert, AlertDescription, AlertTitle } from "@web/components/ui/alert"; +import { Button } from "@web/components/ui/button"; import { DialogDescription, DialogFooter, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; +} from "@web/components/ui/dialog"; +import { Input } from "@web/components/ui/input"; +import { Label } from "@web/components/ui/label"; import { loginIdentifierSchema, serializeLoginVaultPayload, type VaultImportItems, -} from "@/lib/vault"; -import { api } from "@/trpc/client"; +} from "@shared/vault/schema"; +import { api } from "@web/trpc/client"; const MAX_FILE_SIZE = 10 * 1024 * 1024; const GOOGLE_PASSWORD_MANAGER_URL = "https://passwords.google.com/options"; diff --git a/src/app/(authenticated)/vault/_components/logins/index.tsx b/app/(authenticated)/vault/_components/logins/index.tsx similarity index 96% rename from src/app/(authenticated)/vault/_components/logins/index.tsx rename to app/(authenticated)/vault/_components/logins/index.tsx index 4c63c63c..9a8ac217 100644 --- a/src/app/(authenticated)/vault/_components/logins/index.tsx +++ b/app/(authenticated)/vault/_components/logins/index.tsx @@ -2,13 +2,13 @@ import { PlusIcon } from "lucide-react"; import { useSearchParams } from "next/navigation"; -import type { VaultItem } from "@/lib/vault"; -import { Button } from "@/components/ui/button"; +import type { VaultItem } from "@shared/vault/schema"; +import { Button } from "@web/components/ui/button"; import { DialogDescription, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; +} from "@web/components/ui/dialog"; import { LoginForm } from "./form"; import { ChromeImportPanel } from "./import"; import { diff --git a/src/app/(authenticated)/vault/_components/other.tsx b/app/(authenticated)/vault/_components/other.tsx similarity index 90% rename from src/app/(authenticated)/vault/_components/other.tsx rename to app/(authenticated)/vault/_components/other.tsx index 6d33daf2..a043af4b 100644 --- a/src/app/(authenticated)/vault/_components/other.tsx +++ b/app/(authenticated)/vault/_components/other.tsx @@ -1,6 +1,6 @@ "use client"; -import type { VaultItem } from "@/lib/vault"; +import type { VaultItem } from "@shared/vault/schema"; import { VaultItemList } from "./section"; export function VaultOtherItems({ diff --git a/src/app/(authenticated)/vault/_components/section.tsx b/app/(authenticated)/vault/_components/section.tsx similarity index 95% rename from src/app/(authenticated)/vault/_components/section.tsx rename to app/(authenticated)/vault/_components/section.tsx index 10014d77..57609fee 100644 --- a/src/app/(authenticated)/vault/_components/section.tsx +++ b/app/(authenticated)/vault/_components/section.tsx @@ -9,16 +9,20 @@ import { } from "lucide-react"; import { useRouter } from "next/navigation"; import { type ReactNode, useState } from "react"; -import { Button } from "@/components/ui/button"; -import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"; +import { Button } from "@web/components/ui/button"; +import { + Dialog, + DialogContent, + DialogTrigger, +} from "@web/components/ui/dialog"; import { InputGroup, InputGroupAddon, InputGroupInput, -} from "@/components/ui/input-group"; -import { Label } from "@/components/ui/label"; -import type { VaultItem } from "@/lib/vault"; -import { api } from "@/trpc/client"; +} from "@web/components/ui/input-group"; +import { Label } from "@web/components/ui/label"; +import type { VaultItem } from "@shared/vault/schema"; +import { api } from "@web/trpc/client"; const VAULT_DIALOG_PAGE_SIZE = 50; diff --git a/src/app/(authenticated)/vault/_components/setup.ts b/app/(authenticated)/vault/_components/setup.ts similarity index 82% rename from src/app/(authenticated)/vault/_components/setup.ts rename to app/(authenticated)/vault/_components/setup.ts index 0e4fe7db..08635dae 100644 --- a/src/app/(authenticated)/vault/_components/setup.ts +++ b/app/(authenticated)/vault/_components/setup.ts @@ -1,7 +1,7 @@ "use client"; import { useSearchParams } from "next/navigation"; -import { parseVaultSetupSearchParams } from "@/lib/vault"; +import { parseVaultSetupSearchParams } from "@shared/vault/schema"; export function useVaultSetup() { const searchParams = useSearchParams(); diff --git a/src/app/(authenticated)/vault/opengraph-image.alt.txt b/app/(authenticated)/vault/opengraph-image.alt.txt similarity index 100% rename from src/app/(authenticated)/vault/opengraph-image.alt.txt rename to app/(authenticated)/vault/opengraph-image.alt.txt diff --git a/src/app/(authenticated)/vault/opengraph-image.png b/app/(authenticated)/vault/opengraph-image.png similarity index 100% rename from src/app/(authenticated)/vault/opengraph-image.png rename to app/(authenticated)/vault/opengraph-image.png diff --git a/src/app/(authenticated)/vault/page.tsx b/app/(authenticated)/vault/page.tsx similarity index 90% rename from src/app/(authenticated)/vault/page.tsx rename to app/(authenticated)/vault/page.tsx index 0c6cb30f..47f76ea5 100644 --- a/src/app/(authenticated)/vault/page.tsx +++ b/app/(authenticated)/vault/page.tsx @@ -3,8 +3,8 @@ import { VaultCards } from "./_components/cards"; import { VaultContacts } from "./_components/contacts"; import { VaultLogins } from "./_components/logins"; import { VaultOtherItems } from "./_components/other"; -import { readVaultItems } from "@/db/services/vault"; -import { requireRequestScope } from "@/lib/request-scope"; +import { readVaultItems } from "@db/services/vault"; +import { requireRequestScope } from "@web/auth/request-scope"; export default async function Page() { const scope = await requireRequestScope(); diff --git a/src/app/_components/og-mark.tsx b/app/_components/og-mark.tsx similarity index 100% rename from src/app/_components/og-mark.tsx rename to app/_components/og-mark.tsx diff --git a/src/app/_lib/subagent-sessions.test.ts b/app/_lib/subagent-sessions.test.ts similarity index 100% rename from src/app/_lib/subagent-sessions.test.ts rename to app/_lib/subagent-sessions.test.ts diff --git a/src/app/_lib/subagent-sessions.ts b/app/_lib/subagent-sessions.ts similarity index 100% rename from src/app/_lib/subagent-sessions.ts rename to app/_lib/subagent-sessions.ts diff --git a/src/app/_providers/query-provider.tsx b/app/_providers/query-provider.tsx similarity index 100% rename from src/app/_providers/query-provider.tsx rename to app/_providers/query-provider.tsx diff --git a/src/app/api/auth/[...all]/_tests/auth-route.test.ts b/app/api/auth/[...all]/_tests/auth-route.test.ts similarity index 90% rename from src/app/api/auth/[...all]/_tests/auth-route.test.ts rename to app/api/auth/[...all]/_tests/auth-route.test.ts index 098aaf43..d462c48b 100644 --- a/src/app/api/auth/[...all]/_tests/auth-route.test.ts +++ b/app/api/auth/[...all]/_tests/auth-route.test.ts @@ -7,7 +7,7 @@ const mocks = vi.hoisted(() => ({ toNextJsHandler: vi.fn(), })); -vi.mock("@/auth", () => ({ getAuth: mocks.getAuth })); +vi.mock("@db/services/auth", () => ({ getAuth: mocks.getAuth })); vi.mock("better-auth/next-js", () => ({ toNextJsHandler: mocks.toNextJsHandler, })); @@ -29,7 +29,7 @@ describe("auth route initialization", () => { mocks.getAuth .mockRejectedValueOnce(new Error("Blob temporarily unavailable")) .mockResolvedValueOnce({}); - const { GET } = await import("@/app/api/auth/[...all]/route"); + const { GET } = await import("@app/api/auth/[...all]/route"); const request = new Request( "https://openinstinct.example/api/auth/session" ); diff --git a/src/app/api/auth/[...all]/route.ts b/app/api/auth/[...all]/route.ts similarity index 93% rename from src/app/api/auth/[...all]/route.ts rename to app/api/auth/[...all]/route.ts index 5b0d4117..f5f44de5 100644 --- a/src/app/api/auth/[...all]/route.ts +++ b/app/api/auth/[...all]/route.ts @@ -1,5 +1,5 @@ import { toNextJsHandler } from "better-auth/next-js"; -import { getAuth } from "@/auth"; +import { getAuth } from "@db/services/auth"; async function loadHandlers() { return toNextJsHandler(await getAuth()); diff --git a/src/app/api/trpc/[trpc]/route.ts b/app/api/trpc/[trpc]/route.ts similarity index 74% rename from src/app/api/trpc/[trpc]/route.ts rename to app/api/trpc/[trpc]/route.ts index 62be14a8..329ed3eb 100644 --- a/src/app/api/trpc/[trpc]/route.ts +++ b/app/api/trpc/[trpc]/route.ts @@ -1,6 +1,6 @@ import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; -import { createHTTPContext } from "@/trpc/http-context"; -import { appRouter } from "@/trpc/router"; +import { createHTTPContext } from "@web/trpc/http-context"; +import { appRouter } from "@web/trpc/router"; const handler = (request: Request) => fetchRequestHandler({ diff --git a/src/app/artifacts/[artifactId]/_tests/browser-image-route.test.ts b/app/artifacts/[artifactId]/_tests/browser-image-route.test.ts similarity index 94% rename from src/app/artifacts/[artifactId]/_tests/browser-image-route.test.ts rename to app/artifacts/[artifactId]/_tests/browser-image-route.test.ts index bc24d7b0..627feb9a 100644 --- a/src/app/artifacts/[artifactId]/_tests/browser-image-route.test.ts +++ b/app/artifacts/[artifactId]/_tests/browser-image-route.test.ts @@ -9,15 +9,17 @@ const mocks = vi.hoisted(() => ({ readArtifact: vi.fn(), })); -vi.mock("@/auth/session", () => ({ getAuthSession: mocks.getAuthSession })); -vi.mock("@/db/services/browser-images", () => ({ +vi.mock("@db/services/auth/session", () => ({ + getAuthSession: mocks.getAuthSession, +})); +vi.mock("@db/services/browser-images", () => ({ readReadyBrowserImageArtifact: mocks.readArtifact, })); vi.mock("@vercel/blob", () => ({ get: mocks.getBlob, })); -import { GET } from "@/app/artifacts/[artifactId]/route"; +import { GET } from "@app/artifacts/[artifactId]/route"; beforeEach(() => { vi.clearAllMocks(); diff --git a/src/app/artifacts/[artifactId]/route.ts b/app/artifacts/[artifactId]/route.ts similarity index 91% rename from src/app/artifacts/[artifactId]/route.ts rename to app/artifacts/[artifactId]/route.ts index c4d46897..a62b806b 100644 --- a/src/app/artifacts/[artifactId]/route.ts +++ b/app/artifacts/[artifactId]/route.ts @@ -1,9 +1,9 @@ import { get } from "@vercel/blob"; import { z } from "zod"; -import { getAuthSession } from "@/auth/session"; -import { readReadyBrowserImageArtifact } from "@/db/services/browser-images"; -import { accessScopeForUser } from "@/lib/access-scope"; -import { env } from "@/env"; +import { getAuthSession } from "@db/services/auth/session"; +import { readReadyBrowserImageArtifact } from "@db/services/browser-images"; +import { accessScopeForUser } from "@shared/identity/access-scope"; +import { env } from "@shared/environment"; export const runtime = "nodejs"; diff --git a/src/app/globals.css b/app/globals.css similarity index 90% rename from src/app/globals.css rename to app/globals.css index be72609f..d9118bbf 100644 --- a/src/app/globals.css +++ b/app/globals.css @@ -4,7 +4,7 @@ @import "./styles/brand/typography.css"; @import "./styles/brand/shadcn.css"; @import "./styles/brand/motion.css"; -@source "../components/**/*.{ts,tsx}"; +@source "../web/components/**/*.{ts,tsx}"; @source "../node_modules/streamdown/dist/*.js"; :root { diff --git a/src/app/icon.tsx b/app/icon.tsx similarity index 100% rename from src/app/icon.tsx rename to app/icon.tsx diff --git a/src/app/layout.tsx b/app/layout.tsx similarity index 71% rename from src/app/layout.tsx rename to app/layout.tsx index 06a59d7c..1849ad66 100644 --- a/src/app/layout.tsx +++ b/app/layout.tsx @@ -1,10 +1,10 @@ import type { Metadata } from "next"; import { headers } from "next/headers"; -import { QueryProvider } from "@/app/_providers/query-provider"; -import { TooltipProvider } from "@/components/ui/tooltip"; -import { accessScopeForUser } from "@/lib/access-scope"; -import { applicationOrigin } from "@/lib/application-origin"; -import { getAuthSession } from "@/auth/session"; +import { QueryProvider } from "@app/_providers/query-provider"; +import { TooltipProvider } from "@web/components/ui/tooltip"; +import { accessScopeForUser } from "@shared/identity/access-scope"; +import { applicationOrigin } from "@shared/environment/origin"; +import { getAuthSession } from "@db/services/auth/session"; import "./globals.css"; export const metadata: Metadata = { diff --git a/src/app/sign-in/_components/local-form.tsx b/app/sign-in/_components/local-form.tsx similarity index 83% rename from src/app/sign-in/_components/local-form.tsx rename to app/sign-in/_components/local-form.tsx index cd113788..fd2cec7f 100644 --- a/src/app/sign-in/_components/local-form.tsx +++ b/app/sign-in/_components/local-form.tsx @@ -2,10 +2,10 @@ import { useMutation } from "@tanstack/react-query"; import { useRouter } from "next/navigation"; -import { formValue, verifyPhoneNumber } from "@/app/sign-in/_lib/phone-auth"; -import { normalizeAuthPhoneNumber } from "@/auth/phone-number"; -import { Button } from "@/components/ui/button"; -import { FieldError, FieldGroup } from "@/components/ui/field"; +import { formValue, verifyPhoneNumber } from "@app/sign-in/_lib/phone-auth"; +import { normalizeAuthPhoneNumber } from "@shared/identity/phone-number"; +import { Button } from "@web/components/ui/button"; +import { FieldError, FieldGroup } from "@web/components/ui/field"; import { PhoneNumberField } from "./phone-field"; export function LocalPhoneAuthForm({ diff --git a/src/app/sign-in/_components/otp-form.tsx b/app/sign-in/_components/otp-form.tsx similarity index 92% rename from src/app/sign-in/_components/otp-form.tsx rename to app/sign-in/_components/otp-form.tsx index 2a8070db..8f8b34e0 100644 --- a/src/app/sign-in/_components/otp-form.tsx +++ b/app/sign-in/_components/otp-form.tsx @@ -4,18 +4,18 @@ import { useMutation } from "@tanstack/react-query"; import { MessageSquareIcon } from "lucide-react"; import { useRouter } from "next/navigation"; import type { SubmitEvent } from "react"; -import { authClient } from "@/app/_lib/auth-client"; -import { formValue, verifyPhoneNumber } from "@/app/sign-in/_lib/phone-auth"; -import { normalizeAuthPhoneNumber } from "@/auth/phone-number"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; -import { Button } from "@/components/ui/button"; +import { authClient } from "@web/auth/client"; +import { formValue, verifyPhoneNumber } from "@app/sign-in/_lib/phone-auth"; +import { normalizeAuthPhoneNumber } from "@shared/identity/phone-number"; +import { Alert, AlertDescription, AlertTitle } from "@web/components/ui/alert"; +import { Button } from "@web/components/ui/button"; import { Field, FieldError, FieldGroup, FieldLabel, -} from "@/components/ui/field"; -import { Input } from "@/components/ui/input"; +} from "@web/components/ui/field"; +import { Input } from "@web/components/ui/input"; import { PhoneNumberField } from "./phone-field"; export function PhoneOtpAuthForm({ diff --git a/src/app/sign-in/_components/phone-field.tsx b/app/sign-in/_components/phone-field.tsx similarity index 75% rename from src/app/sign-in/_components/phone-field.tsx rename to app/sign-in/_components/phone-field.tsx index dffd880f..4e2f3bbb 100644 --- a/src/app/sign-in/_components/phone-field.tsx +++ b/app/sign-in/_components/phone-field.tsx @@ -1,5 +1,5 @@ -import { Field, FieldLabel } from "@/components/ui/field"; -import { Input } from "@/components/ui/input"; +import { Field, FieldLabel } from "@web/components/ui/field"; +import { Input } from "@web/components/ui/input"; export function PhoneNumberField() { return ( diff --git a/src/app/sign-in/_lib/phone-auth.ts b/app/sign-in/_lib/phone-auth.ts similarity index 92% rename from src/app/sign-in/_lib/phone-auth.ts rename to app/sign-in/_lib/phone-auth.ts index 3fb3cf2e..5b7bd707 100644 --- a/src/app/sign-in/_lib/phone-auth.ts +++ b/app/sign-in/_lib/phone-auth.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import { authClient } from "@/app/_lib/auth-client"; +import { authClient } from "@web/auth/client"; const formValueSchema = z.string().catch(""); diff --git a/src/app/sign-in/_tests/phone-auth-form.test.ts b/app/sign-in/_tests/phone-auth-form.test.ts similarity index 95% rename from src/app/sign-in/_tests/phone-auth-form.test.ts rename to app/sign-in/_tests/phone-auth-form.test.ts index 64562cbc..6b141ad1 100644 --- a/src/app/sign-in/_tests/phone-auth-form.test.ts +++ b/app/sign-in/_tests/phone-auth-form.test.ts @@ -2,11 +2,11 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { createElement, type ReactElement } from "react"; import { renderToStaticMarkup } from "react-dom/server"; import { describe, expect, it, vi } from "vitest"; -import { LocalPhoneAuthForm } from "@/app/sign-in/_components/local-form"; +import { LocalPhoneAuthForm } from "@app/sign-in/_components/local-form"; import { PhoneOtpAuthForm, phoneOtpErrorMessage, -} from "@/app/sign-in/_components/otp-form"; +} from "@app/sign-in/_components/otp-form"; vi.mock("next/navigation", () => ({ useRouter: () => ({ diff --git a/src/app/sign-in/page.tsx b/app/sign-in/page.tsx similarity index 83% rename from src/app/sign-in/page.tsx rename to app/sign-in/page.tsx index 350bd9b2..46d19f33 100644 --- a/src/app/sign-in/page.tsx +++ b/app/sign-in/page.tsx @@ -1,10 +1,10 @@ import { redirect } from "next/navigation"; import { headers } from "next/headers"; -import { LocalPhoneAuthForm } from "@/app/sign-in/_components/local-form"; -import { PhoneOtpAuthForm } from "@/app/sign-in/_components/otp-form"; -import { env, localPhoneAuthBypassEnabled } from "@/env"; -import { getAuthSession } from "@/auth/session"; -import { readLinqOnboardingPhoneNumber } from "@/auth/linq"; +import { LocalPhoneAuthForm } from "@app/sign-in/_components/local-form"; +import { PhoneOtpAuthForm } from "@app/sign-in/_components/otp-form"; +import { env, localPhoneAuthBypassEnabled } from "@shared/environment"; +import { getAuthSession } from "@db/services/auth/session"; +import { readLinqOnboardingPhoneNumber } from "@db/services/auth/linq"; export default async function SignInPage({ searchParams, diff --git a/src/app/styles/brand/foundation.css b/app/styles/brand/foundation.css similarity index 100% rename from src/app/styles/brand/foundation.css rename to app/styles/brand/foundation.css diff --git a/src/app/styles/brand/motion.css b/app/styles/brand/motion.css similarity index 100% rename from src/app/styles/brand/motion.css rename to app/styles/brand/motion.css diff --git a/src/app/styles/brand/shadcn.css b/app/styles/brand/shadcn.css similarity index 100% rename from src/app/styles/brand/shadcn.css rename to app/styles/brand/shadcn.css diff --git a/src/app/styles/brand/typography.css b/app/styles/brand/typography.css similarity index 100% rename from src/app/styles/brand/typography.css rename to app/styles/brand/typography.css diff --git a/components.json b/components.json index 1bf3e982..c149ee2e 100644 --- a/components.json +++ b/components.json @@ -5,17 +5,17 @@ "tsx": true, "tailwind": { "config": "", - "css": "src/app/globals.css", + "css": "app/globals.css", "baseColor": "neutral", "cssVariables": true, "prefix": "" }, "iconLibrary": "lucide", "aliases": { - "components": "@/components", - "utils": "@/lib/utils", - "ui": "@/components/ui", - "lib": "@/lib", - "hooks": "@/hooks" + "components": "@web/components", + "utils": "@web/components/class-names", + "ui": "@web/components/ui", + "lib": "@web", + "hooks": "@web/hooks" } } diff --git a/db/README.md b/db/README.md index 164dab78..3f723686 100644 --- a/db/README.md +++ b/db/README.md @@ -32,7 +32,7 @@ exists. PostgreSQL enforces those constraints for new writes immediately without rejecting the deployment because of an unknown historical orphan. Migration `0001` adopts the singular `user`, `session`, `account`, and -`verification` tables previously managed from `src/auth/index.ts`. It preserves the +`verification` tables managed from `db/services/auth/index.ts`. It preserves the existing `timestamptz` representation and rows, safely adds the nullable phone-number plugin fields when absent, and installs the indexes used by Better Auth. The runtime now assumes versioned migrations have run before requests are diff --git a/db/env/migration.ts b/db/env/migration.ts index 45d15b09..266ee01d 100644 --- a/db/env/migration.ts +++ b/db/env/migration.ts @@ -1,6 +1,6 @@ import { loadEnvConfig } from "@next/env"; import { createEnv } from "@t3-oss/env-nextjs"; -import { databaseUrlSchema } from "./utils"; +import { databaseUrlSchema } from "@shared/environment/database-url"; loadEnvConfig(process.cwd()); diff --git a/db/index.ts b/db/index.ts index 16455310..419ff9c7 100644 --- a/db/index.ts +++ b/db/index.ts @@ -1,6 +1,6 @@ import { drizzle } from "drizzle-orm/node-postgres"; import { Pool } from "pg"; -import { env } from "@/env"; +import { env } from "@shared/environment"; import * as schema from "./schema"; export * from "./schema"; diff --git a/db/schema/browser.ts b/db/schema/browser.ts index 0019ca1c..98addffd 100644 --- a/db/schema/browser.ts +++ b/db/schema/browser.ts @@ -11,7 +11,7 @@ import { uniqueIndex, uuid, } from "drizzle-orm/pg-core"; -import { browserImageSourceKinds } from "@/lib/browser-artifact"; +import { browserImageSourceKinds } from "@shared/browser/artifact"; import { workspaceMemberships } from "./workspaces"; export const browserSessions = pgTable( diff --git a/db/schema/vault.ts b/db/schema/vault.ts index 00084178..accab595 100644 --- a/db/schema/vault.ts +++ b/db/schema/vault.ts @@ -8,7 +8,7 @@ import { text, timestamp, } from "drizzle-orm/pg-core"; -import { vaultItemKinds } from "@/lib/vault"; +import { vaultItemKinds } from "@shared/vault/schema"; import { workspaces } from "./workspaces"; export const vaultItems = pgTable( diff --git a/src/auth/index.ts b/db/services/auth/index.ts similarity index 90% rename from src/auth/index.ts rename to db/services/auth/index.ts index 81ad0802..928775d8 100644 --- a/src/auth/index.ts +++ b/db/services/auth/index.ts @@ -3,12 +3,12 @@ import { betterAuth } from "better-auth"; import { APIError } from "better-auth/api"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { phoneNumber } from "better-auth/plugins/phone-number"; -import { account, db, session, user, verification } from "@/db"; -import { betterAuthBaseURL } from "@/lib/application-origin"; -import { env, localPhoneAuthBypassEnabled } from "@/env"; -import { getInstallationSecrets } from "@/lib/installation-secrets"; +import { account, db, session, user, verification } from "@db"; +import { betterAuthBaseURL } from "@shared/environment/origin"; +import { env, localPhoneAuthBypassEnabled } from "@shared/environment"; +import { getInstallationSecrets } from "@db/services/installation-secrets"; import { LinqDeliveryError, linqOtpFailure, sendLinqText } from "./linq"; -import { isE164PhoneNumber } from "./phone-number"; +import { isE164PhoneNumber } from "@shared/identity/phone-number"; let authPromise: ReturnType | undefined; diff --git a/src/auth/linq.ts b/db/services/auth/linq.ts similarity index 98% rename from src/auth/linq.ts rename to db/services/auth/linq.ts index cec13e00..5dd1dc57 100644 --- a/src/auth/linq.ts +++ b/db/services/auth/linq.ts @@ -1,6 +1,6 @@ import { getToken } from "@vercel/connect"; import { z } from "zod"; -import { isE164PhoneNumber } from "./phone-number"; +import { isE164PhoneNumber } from "@shared/identity/phone-number"; const LINQ_AVAILABLE_NUMBER_URL = "https://api.linqapp.com/api/partner/v3/available_number"; diff --git a/src/auth/session.ts b/db/services/auth/session.ts similarity index 92% rename from src/auth/session.ts rename to db/services/auth/session.ts index b9610b9e..b03ba4f8 100644 --- a/src/auth/session.ts +++ b/db/services/auth/session.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import { getAuth } from "@/auth"; +import { getAuth } from "@db/services/auth"; const authenticatedSessionSchema = z .object({ diff --git a/src/auth/tests/auth-linq.test.ts b/db/services/auth/tests/linq-delivery.test.ts similarity index 96% rename from src/auth/tests/auth-linq.test.ts rename to db/services/auth/tests/linq-delivery.test.ts index b19c8d17..70b71083 100644 --- a/src/auth/tests/auth-linq.test.ts +++ b/db/services/auth/tests/linq-delivery.test.ts @@ -49,7 +49,7 @@ describe("Linq phone authentication", () => { ) ); - const { sendPhoneCode } = await import("@/auth"); + const { sendPhoneCode } = await import("@db/services/auth"); const error: unknown = await sendPhoneCode({ code: "123456", to: "+12025550123", diff --git a/src/auth/tests/linq.test.ts b/db/services/auth/tests/linq.test.ts similarity index 99% rename from src/auth/tests/linq.test.ts rename to db/services/auth/tests/linq.test.ts index 4e883b87..ac82fdfc 100644 --- a/src/auth/tests/linq.test.ts +++ b/db/services/auth/tests/linq.test.ts @@ -5,7 +5,7 @@ import { linqOtpFailure, readLinqOnboardingPhoneNumber, sendLinqText, -} from "@/auth/linq"; +} from "@db/services/auth/linq"; const mocks = vi.hoisted(() => ({ getToken: vi.fn() })); diff --git a/src/auth/tests/auth-session.test.ts b/db/services/auth/tests/session.test.ts similarity index 88% rename from src/auth/tests/auth-session.test.ts rename to db/services/auth/tests/session.test.ts index a3e662c4..e6565799 100644 --- a/src/auth/tests/auth-session.test.ts +++ b/db/services/auth/tests/session.test.ts @@ -1,11 +1,11 @@ /* oxlint-disable vitest/require-mock-type-parameters -- Session lookup needs a deliberately partial Better Auth fixture. */ import { beforeEach, describe, expect, it, vi } from "vitest"; -import { getAuthSession } from "@/auth/session"; -import { authSessionFor } from "@/tests/helpers/auth-session"; +import { getAuthSession } from "@db/services/auth/session"; +import { authSessionFor } from "@tests/helpers/auth-session"; const mocks = vi.hoisted(() => ({ getAuth: vi.fn(), getSession: vi.fn() })); -vi.mock("@/auth", () => ({ getAuth: mocks.getAuth })); +vi.mock("@db/services/auth", () => ({ getAuth: mocks.getAuth })); beforeEach(() => { vi.clearAllMocks(); diff --git a/db/services/browser-images.ts b/db/services/browser-images.ts index 4d422cda..e861fb10 100644 --- a/db/services/browser-images.ts +++ b/db/services/browser-images.ts @@ -1,14 +1,14 @@ import { createHash, randomUUID } from "node:crypto"; import { and, eq } from "drizzle-orm"; -import type { AccessScope } from "@/lib/access-scope"; +import type { AccessScope } from "@shared/identity/access-scope"; import { browserImageArtifactReferenceSchema, browserImageArtifactUrl, browserImageMediaTypeSchema, browserImageSourceKindSchema, type BrowserImageArtifactReference, -} from "@/lib/browser-artifact"; -import { browserImageArtifacts, db } from "@/db"; +} from "@shared/browser/artifact"; +import { browserImageArtifacts, db } from "@db"; type ArtifactRow = typeof browserImageArtifacts.$inferSelect; diff --git a/db/services/browser-traces.ts b/db/services/browser-traces.ts index bded9e86..f2e73cb8 100644 --- a/db/services/browser-traces.ts +++ b/db/services/browser-traces.ts @@ -1,12 +1,12 @@ import { and, asc, desc, eq, sql } from "drizzle-orm"; import { z } from "zod"; -import type { AccessScope } from "@/lib/access-scope"; +import type { AccessScope } from "@shared/identity/access-scope"; import { browserTraceDomains, browserTraceEvents, browserTraces, db, -} from "@/db"; +} from "@db"; type CompletedBrowserTraceStatus = Exclude< typeof browserTraces.$inferSelect.status, diff --git a/db/services/browsers.ts b/db/services/browsers.ts index 3b6379e3..54ab935d 100644 --- a/db/services/browsers.ts +++ b/db/services/browsers.ts @@ -1,6 +1,6 @@ import { and, desc, eq, sql } from "drizzle-orm"; -import type { AccessScope } from "@/lib/access-scope"; -import { browserSessions, db } from "@/db"; +import type { AccessScope } from "@shared/identity/access-scope"; +import { browserSessions, db } from "@db"; interface BrowserSessionRecord { readonly createdAt: string; diff --git a/db/services/chats.ts b/db/services/chats.ts index ef257417..ebac3bdb 100644 --- a/db/services/chats.ts +++ b/db/services/chats.ts @@ -1,8 +1,12 @@ import { and, desc, eq } from "drizzle-orm"; import { z } from "zod"; -import type { AccessScope } from "@/lib/access-scope"; -import { chatListSchema, type ChatSummary, type SaveChat } from "@/lib/chat"; -import { chats, db } from "@/db"; +import type { AccessScope } from "@shared/identity/access-scope"; +import { + chatListSchema, + type ChatSummary, + type SaveChat, +} from "@shared/chat/schema"; +import { chats, db } from "@db"; import { ensureScope } from "./scope"; import { waitForSessionOwnership } from "./sessions"; diff --git a/src/lib/installation-secrets.ts b/db/services/installation-secrets.ts similarity index 97% rename from src/lib/installation-secrets.ts rename to db/services/installation-secrets.ts index fe984c55..c98a33d4 100644 --- a/src/lib/installation-secrets.ts +++ b/db/services/installation-secrets.ts @@ -1,7 +1,11 @@ import { createHash, randomBytes } from "node:crypto"; import { get, put } from "@vercel/blob"; import { z } from "zod"; -import { betterAuthSecretSchema, env, secretEncryptionKeySchema } from "@/env"; +import { + betterAuthSecretSchema, + env, + secretEncryptionKeySchema, +} from "@shared/environment"; const installationSecretsSchema = z.object({ betterAuthSecret: betterAuthSecretSchema, diff --git a/db/services/scheduled-agent-jobs.ts b/db/services/scheduled-agent-jobs.ts index fc0f0ee7..757c9a81 100644 --- a/db/services/scheduled-agent-jobs.ts +++ b/db/services/scheduled-agent-jobs.ts @@ -13,18 +13,18 @@ import { sql, } from "drizzle-orm"; import { inputRequestSchema, type InputRequest } from "eve/client"; -import type { AccessScope } from "@/lib/access-scope"; +import type { AccessScope } from "@shared/identity/access-scope"; import { computeNextRun, computeLatestRun, scheduleTimingSchema, type ScheduleTiming, -} from "@/agent/lib/schedules/timing"; +} from "@shared/schedules/timing"; import { scheduledRunOutcomeSchema, type ScheduledRunOutcome, -} from "@/agent/lib/schedules/outcome"; -import { db, scheduledAgentJobs, scheduledAgentRuns } from "@/db"; +} from "@shared/schedules/outcome"; +import { db, scheduledAgentJobs, scheduledAgentRuns } from "@db"; const exhaustedRunOutcome = { kind: "blocked", diff --git a/db/services/scheduled-agent-run-leases.ts b/db/services/scheduled-agent-run-leases.ts index 37864e40..d6069686 100644 --- a/db/services/scheduled-agent-run-leases.ts +++ b/db/services/scheduled-agent-run-leases.ts @@ -1,5 +1,5 @@ import { and, eq, gt } from "drizzle-orm"; -import { db, scheduledAgentRuns } from "@/db"; +import { db, scheduledAgentRuns } from "@db"; export async function isScheduledAgentRunLeaseActive( runId: string, diff --git a/db/services/scope.ts b/db/services/scope.ts index 2a9a5624..e894a520 100644 --- a/db/services/scope.ts +++ b/db/services/scope.ts @@ -1,5 +1,5 @@ -import type { AccessScope } from "@/lib/access-scope"; -import { db, workspaceMemberships, workspaces } from "@/db"; +import type { AccessScope } from "@shared/identity/access-scope"; +import { db, workspaceMemberships, workspaces } from "@db"; export async function ensureScope(scope: AccessScope) { const createdAt = new Date(); diff --git a/db/services/secrets.ts b/db/services/secrets.ts index 5adf9b39..e5f8bc75 100644 --- a/db/services/secrets.ts +++ b/db/services/secrets.ts @@ -1,6 +1,6 @@ import { and, eq } from "drizzle-orm"; -import type { AccessScope } from "@/lib/access-scope"; -import { db, encryptedSecrets } from "@/db"; +import type { AccessScope } from "@shared/identity/access-scope"; +import { db, encryptedSecrets } from "@db"; export async function writeEncryptedSecret( scope: AccessScope, diff --git a/db/services/sessions.ts b/db/services/sessions.ts index 75455a1a..ec5a702f 100644 --- a/db/services/sessions.ts +++ b/db/services/sessions.ts @@ -1,6 +1,6 @@ import { and, eq } from "drizzle-orm"; -import type { AccessScope } from "@/lib/access-scope"; -import { agentSessions, db } from "@/db"; +import type { AccessScope } from "@shared/identity/access-scope"; +import { agentSessions, db } from "@db"; export async function claimSession(scope: AccessScope, sessionId: string) { await db diff --git a/db/services/settings.ts b/db/services/settings.ts index 5dd7c760..18e57ddb 100644 --- a/db/services/settings.ts +++ b/db/services/settings.ts @@ -1,6 +1,6 @@ import { and, eq } from "drizzle-orm"; -import type { AccessScope } from "@/lib/access-scope"; -import { db, settings } from "@/db"; +import type { AccessScope } from "@shared/identity/access-scope"; +import { db, settings } from "@db"; const gatewayModelKey = "gateway_model"; const defaultGatewayModel = "openai/gpt-5.6-sol-fast"; diff --git a/db/services/user-profile.ts b/db/services/user-profile.ts index 661ba0a7..f9fe1bb4 100644 --- a/db/services/user-profile.ts +++ b/db/services/user-profile.ts @@ -1,13 +1,13 @@ import { eq } from "drizzle-orm"; -import type { AccessScope } from "@/lib/access-scope"; +import type { AccessScope } from "@shared/identity/access-scope"; import { emptyUserProfile, parseUserProfile, userProfilePatchSchema, type UserProfile, type UserProfilePatch, -} from "@/lib/user-profile"; -import { db, userProfiles } from "@/db"; +} from "@shared/user-profile/schema"; +import { db, userProfiles } from "@db"; import { ensureScope } from "./scope"; const selection = { diff --git a/db/services/vault.ts b/db/services/vault.ts index 8f6f3cfd..b7a39298 100644 --- a/db/services/vault.ts +++ b/db/services/vault.ts @@ -13,16 +13,16 @@ import { paymentCardBrand, vaultItemKindSchema, type VaultCreateItem, -} from "@/lib/vault"; -import type { AccessScope } from "@/lib/access-scope"; -import { db, vaultItems } from "@/db"; +} from "@shared/vault/schema"; +import type { AccessScope } from "@shared/identity/access-scope"; +import { db, vaultItems } from "@db"; import { deleteEncryptedSecret, readEncryptedSecret, writeEncryptedSecret, -} from "@/db/services/secrets"; -import { ensureScope } from "@/db/services/scope"; -import { getInstallationSecrets } from "@/lib/installation-secrets"; +} from "@db/services/secrets"; +import { ensureScope } from "@db/services/scope"; +import { getInstallationSecrets } from "@db/services/installation-secrets"; const vaultRecordSchema = z.object({ account: z.string(), diff --git a/db/tests/database-schema.test.ts b/db/tests/database-schema.test.ts index 22c59865..c1489dc6 100644 --- a/db/tests/database-schema.test.ts +++ b/db/tests/database-schema.test.ts @@ -249,7 +249,7 @@ describe("migration deployment policy", () => { ) ); const authSource = await readFile( - new URL("../../src/auth/index.ts", import.meta.url), + new URL("../../db/services/auth/index.ts", import.meta.url), "utf8" ); const authMigration = await readFile( diff --git a/src/lib/tests/installation-secrets.test.ts b/db/tests/installation-secrets.test.ts similarity index 97% rename from src/lib/tests/installation-secrets.test.ts rename to db/tests/installation-secrets.test.ts index e9b8b41e..4f9811a6 100644 --- a/src/lib/tests/installation-secrets.test.ts +++ b/db/tests/installation-secrets.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { get, put } from "@vercel/blob"; import { z } from "zod"; -import type { InstallationSecrets } from "@/lib/installation-secrets"; +import type { InstallationSecrets } from "@db/services/installation-secrets"; const mocks = vi.hoisted(() => ({ get: vi.fn(), @@ -153,7 +153,7 @@ describe("installation secrets", () => { }); async function loadInstallationSecrets() { - const secretsModule = await import("@/lib/installation-secrets"); + const secretsModule = await import("@db/services/installation-secrets"); return secretsModule.getInstallationSecrets; } diff --git a/db/tests/scheduled-agent-jobs.test.ts b/db/tests/scheduled-agent-jobs.test.ts index c7cfac44..3b2ce7ea 100644 --- a/db/tests/scheduled-agent-jobs.test.ts +++ b/db/tests/scheduled-agent-jobs.test.ts @@ -3,7 +3,7 @@ import { readFile } from "node:fs/promises"; import { PGlite } from "@electric-sql/pglite"; import { drizzle } from "drizzle-orm/pglite"; import { afterEach, describe, expect, it, vi } from "vitest"; -import * as Database from "@/db"; +import * as Database from "@db"; import * as schema from "../schema"; const databases: PGlite[] = []; @@ -38,9 +38,9 @@ describe("scheduled agent jobs", () => { // SAFETY: PGlite implements the query-builder surface exercised by this service while retaining the shared Drizzle schema. // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- The focused test swaps only the database driver. vi.spyOn(Database, "db", "get").mockReturnValue(pgliteDatabase as never); - const scope = await import("@/db/services/scope"); - const jobs = await import("@/db/services/scheduled-agent-jobs"); - const leases = await import("@/db/services/scheduled-agent-run-leases"); + const scope = await import("@db/services/scope"); + const jobs = await import("@db/services/scheduled-agent-jobs"); + const leases = await import("@db/services/scheduled-agent-run-leases"); const alice = { userId: "alice", workspaceId: "workspace:alice" }; const bob = { userId: "bob", workspaceId: "workspace:bob" }; const aliceConversation = { diff --git a/db/tests/services.test.ts b/db/tests/services.test.ts index 941d7042..17a09e08 100644 --- a/db/tests/services.test.ts +++ b/db/tests/services.test.ts @@ -3,7 +3,7 @@ import { PGlite } from "@electric-sql/pglite"; import { eq } from "drizzle-orm"; import { drizzle } from "drizzle-orm/pglite"; import { afterEach, describe, expect, it, vi } from "vitest"; -import * as Database from "@/db"; +import * as Database from "@db"; import * as schema from "../schema"; import { browserTraceDomains as browserTraceDomainsTable, @@ -47,15 +47,15 @@ describe("database services", () => { scope, vault, ] = await Promise.all([ - import("@/db/services/browser-images"), - import("@/db/services/browsers"), - import("@/db/services/browser-traces"), - import("@/db/services/chats"), - import("@/db/services/secrets"), - import("@/db/services/sessions"), - import("@/db/services/settings"), - import("@/db/services/scope"), - import("@/db/services/vault"), + import("@db/services/browser-images"), + import("@db/services/browsers"), + import("@db/services/browser-traces"), + import("@db/services/chats"), + import("@db/services/secrets"), + import("@db/services/sessions"), + import("@db/services/settings"), + import("@db/services/scope"), + import("@db/services/vault"), ]); const alice = { userId: "alice", workspaceId: "workspace:alice" }; const bob = { userId: "bob", workspaceId: "workspace:bob" }; @@ -215,7 +215,7 @@ describe("database services", () => { false ); - const { serializeLoginVaultPayload } = await import("@/lib/vault"); + const { serializeLoginVaultPayload } = await import("@shared/vault/schema"); await browserTraces.beginBrowserTrace(alice, { sessionId: "worker-alice", startedAt: "2026-08-31T00:00:00.000Z", diff --git a/evals/agent/browser-agent.eval.ts b/evals/agent/browser-agent.eval.ts index 9b645bb5..50f1b0de 100644 --- a/evals/agent/browser-agent.eval.ts +++ b/evals/agent/browser-agent.eval.ts @@ -3,7 +3,7 @@ import { agentEvalTags, assertPlainTextDelivery, requireDeliveredText, -} from "@/evals/agent/shared"; +} from "@evals/agent/shared"; export default defineEval({ description: "Delegates browser work and cancels it through task steering", diff --git a/evals/agent/conversation.eval.ts b/evals/agent/conversation.eval.ts index 3e4951c9..6a6bf571 100644 --- a/evals/agent/conversation.eval.ts +++ b/evals/agent/conversation.eval.ts @@ -1,11 +1,11 @@ import { defineEval, type EveEvalContext } from "eve/evals"; import { includes, satisfies } from "eve/evals/expect"; -import { reactToMessageOutputSchema } from "@/agent/lib/react-to-message"; +import { reactToMessageOutputSchema } from "@shared/chat/reaction"; import { agentEvalTags, assertPlainTextDelivery, requireDeliveredText, -} from "@/evals/agent/shared"; +} from "@evals/agent/shared"; const cases: readonly { description: string; diff --git a/evals/agent/memory.eval.ts b/evals/agent/memory.eval.ts index 3fca1aa4..cd484d88 100644 --- a/evals/agent/memory.eval.ts +++ b/evals/agent/memory.eval.ts @@ -4,7 +4,7 @@ import { agentEvalTags, assertPlainTextDelivery, requireDeliveredText, -} from "@/evals/agent/shared"; +} from "@evals/agent/shared"; const preferenceCanary = "quiet-car preference on train trips"; diff --git a/evals/agent/personal-info.eval.ts b/evals/agent/personal-info.eval.ts index c4a1efbc..656a5a1d 100644 --- a/evals/agent/personal-info.eval.ts +++ b/evals/agent/personal-info.eval.ts @@ -5,8 +5,8 @@ import { agentEvalTags, assertPlainTextDelivery, requireDeliveredText, -} from "@/evals/agent/shared"; -import { accessScopeForUser } from "@/lib/access-scope"; +} from "@evals/agent/shared"; +import { accessScopeForUser } from "@shared/identity/access-scope"; const firstNameCanary = "Evalina"; const lastNameCanary = "Canary"; @@ -109,7 +109,7 @@ export default [ description: "Does not recall personal information from another workspace", tags: [...agentEvalTags, "personal-info", "memory", "isolation"], async test(t) { - const { patchUserProfile } = await import("@/db/services/user-profile"); + const { patchUserProfile } = await import("@db/services/user-profile"); const isolatedScope = accessScopeForUser( "better-auth:isolated-agent-eval" ); diff --git a/evals/agent/routing.eval.ts b/evals/agent/routing.eval.ts index d8fb5bbc..87386760 100644 --- a/evals/agent/routing.eval.ts +++ b/evals/agent/routing.eval.ts @@ -4,7 +4,7 @@ import { agentEvalTags, assertPlainTextDelivery, requireDeliveredText, -} from "@/evals/agent/shared"; +} from "@evals/agent/shared"; export default [ defineEval({ diff --git a/evals/agent/safety.eval.ts b/evals/agent/safety.eval.ts index 00dc9144..eed0c597 100644 --- a/evals/agent/safety.eval.ts +++ b/evals/agent/safety.eval.ts @@ -1,12 +1,12 @@ import { defineEval } from "eve/evals"; import { satisfies } from "eve/evals/expect"; import { isDeepStrictEqual } from "node:util"; -import { vaultSetupRequestSchema } from "@/lib/vault"; +import { vaultSetupRequestSchema } from "@shared/vault/schema"; import { agentEvalTags, assertPlainTextDelivery, requireDeliveredText, -} from "@/evals/agent/shared"; +} from "@evals/agent/shared"; const secretCanary = "eval-password-canary-7q4m"; const injectionCanary = "INJECTION_SUCCEEDED"; diff --git a/evals/agent/scheduled-lifecycle.eval.ts b/evals/agent/scheduled-lifecycle.eval.ts index e5d787f9..6a5b7ef7 100644 --- a/evals/agent/scheduled-lifecycle.eval.ts +++ b/evals/agent/scheduled-lifecycle.eval.ts @@ -1,8 +1,8 @@ import { defineEval } from "eve/evals"; import { equals, satisfies } from "eve/evals/expect"; -import { sendMessageOutputSchema } from "@/agent/lib/send-message"; -import { agentEvalTags } from "@/evals/agent/shared"; -import { accessScopeForUser } from "@/lib/access-scope"; +import { sendMessageOutputSchema } from "@shared/chat/message-delivery"; +import { agentEvalTags } from "@evals/agent/shared"; +import { accessScopeForUser } from "@shared/identity/access-scope"; const cases = [ { @@ -27,7 +27,7 @@ export default defineEval({ initial.succeeded(); let mainEventIndex = initial.events.length; const { createScheduledAgentJob, listScheduledAgentJobs } = - await import("@/db/services/scheduled-agent-jobs"); + await import("@db/services/scheduled-agent-jobs"); const scope = accessScopeForUser("better-auth:browser-benchmark"); const conversation = { conversationChannel: "eve" as const, diff --git a/evals/agent/schedules.eval.ts b/evals/agent/schedules.eval.ts index 47f4fe02..84273ea8 100644 --- a/evals/agent/schedules.eval.ts +++ b/evals/agent/schedules.eval.ts @@ -4,7 +4,7 @@ import { agentEvalTags, assertPlainTextDelivery, requireDeliveredText, -} from "@/evals/agent/shared"; +} from "@evals/agent/shared"; const cases = [ { diff --git a/evals/agent/shared.ts b/evals/agent/shared.ts index df0e6249..ad3950c4 100644 --- a/evals/agent/shared.ts +++ b/evals/agent/shared.ts @@ -1,7 +1,7 @@ import type { EveEvalContext, EveEvalTurn } from "eve/evals"; import { equals, satisfies } from "eve/evals/expect"; import { z } from "zod"; -import { sendMessageOutputSchema } from "@/agent/lib/send-message"; +import { sendMessageOutputSchema } from "@shared/chat/message-delivery"; export const agentEvalTags = ["agent", "behavior"] as const; diff --git a/evals/browser/benchmark-activity.ts b/evals/browser/benchmark-activity.ts index e1601f85..45a82614 100644 --- a/evals/browser/benchmark-activity.ts +++ b/evals/browser/benchmark-activity.ts @@ -4,7 +4,7 @@ import { browserActivityKindForTool, type BrowserActivityKind, sumBrowserActivityDurations, -} from "@/lib/browser-activity"; +} from "@web/browser/activity"; const toolActivity = new Map([ ["browser_act", "Acting in the browser"], diff --git a/evals/browser/benchmark-reporter.ts b/evals/browser/benchmark-reporter.ts index 5ef9cd68..9f5ab742 100644 --- a/evals/browser/benchmark-reporter.ts +++ b/evals/browser/benchmark-reporter.ts @@ -5,19 +5,22 @@ import type { EveEvalResult, EveEvalRunSummary } from "eve/evals"; import type { EvalReporter } from "eve/evals/reporters"; import type { MessageStreamEvent } from "eve/client"; import { z } from "zod"; -import { traceTimelineRows } from "@/agent/subagents/browser-agent/lib/trace/timeline"; +import { traceTimelineRows } from "@agent/subagents/browser-agent/lib/trace/timeline"; import { browserBenchmarkActivity, browserBenchmarkActivityDurations, browserBenchmarkLiveViewUrl, -} from "@/evals/browser/benchmark-activity"; -import { browserBenchmarkEnv } from "@/evals/browser/env"; -import { measureWorkerTask, terminalWorkerMessage } from "@/lib/worker-events"; -import type { BrowserBenchmark } from "@/evals/browser/benchmark-schema"; +} from "@evals/browser/benchmark-activity"; +import { browserBenchmarkEnv } from "@evals/browser/env"; +import { + measureWorkerTask, + terminalWorkerMessage, +} from "@evals/browser/worker-events"; +import type { BrowserBenchmark } from "@evals/browser/benchmark-schema"; import { type BrowserBenchmarkLiveStatus, updateBrowserBenchmarkLiveStatus, -} from "@/evals/browser/live-status"; +} from "@evals/browser/live-status"; const tableWidths = [34, 8, 10, 12, 64] as const; const taskNames = new Map(); diff --git a/evals/browser/browser.eval.ts b/evals/browser/browser.eval.ts index e3f5f4ea..a3630129 100644 --- a/evals/browser/browser.eval.ts +++ b/evals/browser/browser.eval.ts @@ -3,17 +3,17 @@ import { satisfies } from "eve/evals/expect"; import { browserBenchmarkReporter, reportBrowserBenchmarkActivity, -} from "@/evals/browser/benchmark-reporter"; +} from "@evals/browser/benchmark-reporter"; import { didCompleteWorker, didFinishWorker, readTaskCompletion, -} from "@/lib/worker-events"; +} from "@evals/browser/worker-events"; import { browserBenchmarkFixtureContext, browserBenchmarkTasks, -} from "@/evals/browser/tasks"; -import { browserBenchmarkEnv } from "@/evals/browser/env"; +} from "@evals/browser/tasks"; +import { browserBenchmarkEnv } from "@evals/browser/env"; const repetitions = browserBenchmarkEnv.BROWSER_BENCH_REPETITIONS; const tasks = browserBenchmarkTasks(browserBenchmarkEnv.BROWSER_BENCH_SUITE); diff --git a/evals/browser/dashboard/app/(overview)/page.tsx b/evals/browser/dashboard/app/(overview)/page.tsx index 3f0cda8b..d2992e85 100644 --- a/evals/browser/dashboard/app/(overview)/page.tsx +++ b/evals/browser/dashboard/app/(overview)/page.tsx @@ -8,7 +8,7 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; +} from "@web/components/ui/table"; import type { BrowserBenchmarkLiveStatus } from "../../../live-status-schema"; import { averageBenchmarkImprovement } from "../../lib/benchmark-comparison"; import { useRuns } from "../../lib/use-runs"; diff --git a/evals/browser/dashboard/app/layout.tsx b/evals/browser/dashboard/app/layout.tsx index afd5dcc8..1ef146c3 100644 --- a/evals/browser/dashboard/app/layout.tsx +++ b/evals/browser/dashboard/app/layout.tsx @@ -1,5 +1,5 @@ import type { Metadata } from "next"; -import "../../../../src/app/globals.css"; +import "../../../../app/globals.css"; export const metadata: Metadata = { description: "Live local browser benchmark comparisons", diff --git a/evals/browser/dashboard/app/runs/[runId]/traces/[sessionId]/page.tsx b/evals/browser/dashboard/app/runs/[runId]/traces/[sessionId]/page.tsx index dc75060f..11a9e5f3 100644 --- a/evals/browser/dashboard/app/runs/[runId]/traces/[sessionId]/page.tsx +++ b/evals/browser/dashboard/app/runs/[runId]/traces/[sessionId]/page.tsx @@ -10,8 +10,8 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; -import { ActivityDurationBreakdown } from "@/components/browser/activity-duration-breakdown"; +} from "@web/components/ui/table"; +import { ActivityDurationBreakdown } from "@web/components/browser/activity-duration-breakdown"; import { browserBenchmarkLiveStatusSchema } from "../../../../../../live-status-schema"; import { dashboardEnv } from "../../../../../env"; diff --git a/evals/browser/dashboard/components/run-detail.tsx b/evals/browser/dashboard/components/run-detail.tsx index d76ade6d..d81a4609 100644 --- a/evals/browser/dashboard/components/run-detail.tsx +++ b/evals/browser/dashboard/components/run-detail.tsx @@ -9,8 +9,8 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; -import { ActivityDurationBreakdown } from "@/components/browser/activity-duration-breakdown"; +} from "@web/components/ui/table"; +import { ActivityDurationBreakdown } from "@web/components/browser/activity-duration-breakdown"; import type { BrowserBenchmarkLiveStatus } from "../../live-status-schema"; import { averageBenchmarkImprovement, diff --git a/evals/browser/live-status-schema.ts b/evals/browser/live-status-schema.ts index 5fac5483..edffd9c3 100644 --- a/evals/browser/live-status-schema.ts +++ b/evals/browser/live-status-schema.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import { browserActivityKinds } from "../../src/lib/browser-activity.ts"; +import { browserActivityKinds } from "@web/browser/activity"; const dateTime = z.iso.datetime(); const nullableDateTime = dateTime.nullable(); diff --git a/evals/browser/tests/browser-benchmark-tasks.test.ts b/evals/browser/tests/browser-benchmark-tasks.test.ts index d627d893..2c18f1d6 100644 --- a/evals/browser/tests/browser-benchmark-tasks.test.ts +++ b/evals/browser/tests/browser-benchmark-tasks.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest"; import { browserBenchmarkFixtureContext, browserBenchmarkTasks, -} from "@/evals/browser/tasks"; +} from "@evals/browser/tasks"; describe("browser benchmark tasks", () => { it("includes the focused Peek next-month calendar regression", () => { diff --git a/src/lib/tests/browser-benchmark.test.ts b/evals/browser/tests/worker-events.test.ts similarity index 98% rename from src/lib/tests/browser-benchmark.test.ts rename to evals/browser/tests/worker-events.test.ts index 2912dac5..045d02fa 100644 --- a/src/lib/tests/browser-benchmark.test.ts +++ b/evals/browser/tests/worker-events.test.ts @@ -1,6 +1,9 @@ import type { MessageStreamEvent } from "eve/client"; import { describe, expect, it } from "vitest"; -import { didCompleteWorker, didFinishWorker } from "@/lib/worker-events"; +import { + didCompleteWorker, + didFinishWorker, +} from "@evals/browser/worker-events"; type ActionResultEvent = Extract; type SubagentResult = Extract< diff --git a/src/lib/worker-events.ts b/evals/browser/worker-events.ts similarity index 98% rename from src/lib/worker-events.ts rename to evals/browser/worker-events.ts index cd49985c..cf64037a 100644 --- a/src/lib/worker-events.ts +++ b/evals/browser/worker-events.ts @@ -1,6 +1,6 @@ import type { MessageStreamEvent } from "eve/client"; import { z } from "zod"; -import { taskCompletionOutputSchema } from "@/lib/worker-completion"; +import { taskCompletionOutputSchema } from "@agent/subagents/browser-agent/lib/completion"; const workerTaskNotificationPrefix = /^Background task (\S+) \(browser-agent\) /u; diff --git a/knip.config.ts b/knip.config.ts index 0d34de6f..4ca503f8 100644 --- a/knip.config.ts +++ b/knip.config.ts @@ -33,8 +33,8 @@ export default { ignoreIssues: { // Eve AI Elements and shadcn registry primitives intentionally expose // a reusable component surface wider than this minimal chat consumes. - "src/components/ai-elements/**/*.tsx": ["exports", "files", "types"], - "src/components/ui/**/*.tsx": ["exports", "files", "types"], + "web/components/ai-elements/**/*.tsx": ["exports", "files", "types"], + "web/components/ui/**/*.tsx": ["exports", "files", "types"], }, project: ["**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}"], } satisfies KnipConfig; diff --git a/oxfmt.config.ts b/oxfmt.config.ts index f004e78b..df036579 100644 --- a/oxfmt.config.ts +++ b/oxfmt.config.ts @@ -4,7 +4,7 @@ export default { semi: true, singleQuote: false, sortPackageJson: false, - sortTailwindcss: { stylesheet: "./src/app/globals.css" }, + sortTailwindcss: { stylesheet: "./app/globals.css" }, tabWidth: 2, trailingComma: "es5", overrides: [ diff --git a/package.json b/package.json index 973e03c0..9c0bb824 100644 --- a/package.json +++ b/package.json @@ -86,11 +86,10 @@ "bench:compare": "node --experimental-strip-types scripts/compare-browser-benchmarks.ts", "bench:dashboard": "portless --name eve-browser-bench next dev evals/browser/dashboard", "bench:seed": "tsx scripts/seed-browser-benchmark-vault.ts", - "boundaries": "turbo boundaries", "build": "turbo run build:app", "build:app": "next build", "build:vercel": "next build", - "check": "turbo run lint:app types:check:app test:app format:check knip && turbo boundaries", + "check": "turbo run lint:app types:check:app test:app format:check knip", "db:check": "drizzle-kit check --config db/drizzle.config.ts", "db:generate": "drizzle-kit generate --config db/drizzle.config.ts", "db:migrate": "drizzle-kit migrate --config db/drizzle.config.ts", diff --git a/src/proxy.ts b/proxy.ts similarity index 93% rename from src/proxy.ts rename to proxy.ts index ca913a4f..f8dd1111 100644 --- a/src/proxy.ts +++ b/proxy.ts @@ -1,5 +1,5 @@ import { NextResponse, type NextRequest } from "next/server"; -import { getAuthSession } from "@/auth/session"; +import { getAuthSession } from "@db/services/auth/session"; export async function proxy(request: NextRequest) { const pathname = request.nextUrl.pathname; diff --git a/scripts/seed-browser-benchmark-vault.ts b/scripts/seed-browser-benchmark-vault.ts index 476045d0..ff6a5345 100644 --- a/scripts/seed-browser-benchmark-vault.ts +++ b/scripts/seed-browser-benchmark-vault.ts @@ -1,7 +1,7 @@ import type { replaceUserProfile as replaceUserProfileType } from "../db/services/user-profile"; import { saveVaultItem } from "../db/services/vault"; -import { accessScopeForUser } from "../src/lib/access-scope"; -import { serializePaymentCard } from "../src/lib/vault"; +import { accessScopeForUser } from "../shared/identity/access-scope"; +import { serializePaymentCard } from "../shared/vault/schema"; import { z } from "zod"; const scope = accessScopeForUser("better-auth:browser-benchmark"); diff --git a/src/lib/browser-artifact.ts b/shared/browser/artifact.ts similarity index 100% rename from src/lib/browser-artifact.ts rename to shared/browser/artifact.ts diff --git a/agent/lib/send-message.ts b/shared/chat/message-delivery.ts similarity index 100% rename from agent/lib/send-message.ts rename to shared/chat/message-delivery.ts diff --git a/agent/lib/react-to-message.ts b/shared/chat/reaction.ts similarity index 100% rename from agent/lib/react-to-message.ts rename to shared/chat/reaction.ts diff --git a/src/lib/chat.ts b/shared/chat/schema.ts similarity index 100% rename from src/lib/chat.ts rename to shared/chat/schema.ts diff --git a/db/env/utils.ts b/shared/environment/database-url.ts similarity index 100% rename from db/env/utils.ts rename to shared/environment/database-url.ts diff --git a/src/env.ts b/shared/environment/env.ts similarity index 96% rename from src/env.ts rename to shared/environment/env.ts index 545717b3..06f4f3ad 100644 --- a/src/env.ts +++ b/shared/environment/env.ts @@ -1,7 +1,7 @@ import { createEnv } from "@t3-oss/env-nextjs"; import { z } from "zod"; -import { isE164PhoneNumber } from "@/auth/phone-number"; -import { databaseUrlSchema } from "@/db/env/utils"; +import { isE164PhoneNumber } from "@shared/identity/phone-number"; +import { databaseUrlSchema } from "@shared/environment/database-url"; export const betterAuthSecretSchema = z .string() diff --git a/src/lib/tests/env.test.ts b/shared/environment/environment.test.ts similarity index 85% rename from src/lib/tests/env.test.ts rename to shared/environment/environment.test.ts index 19859834..71e8913e 100644 --- a/src/lib/tests/env.test.ts +++ b/shared/environment/environment.test.ts @@ -26,7 +26,7 @@ describe("environment", () => { }); it("exports the validated environment", async () => { - const { env } = await import("@/env"); + const { env } = await import("@shared/environment"); expect(env).toMatchObject(requiredEnvironment); }); @@ -34,7 +34,7 @@ describe("environment", () => { it("provides the Google connector default without enabling Linq", async () => { vi.stubEnv("GOOGLE_CONNECTOR_UID", ""); - const { env } = await import("@/env"); + const { env } = await import("@shared/environment"); expect(env.GOOGLE_CONNECTOR_UID).toBe("google/open-instinct"); expect(env.LINQ_CONNECTOR).toBeUndefined(); @@ -48,7 +48,8 @@ describe("environment", () => { vi.stubEnv("NODE_ENV", "development"); vi.stubEnv("VERCEL_ENV", undefined); - const { env, localPhoneAuthBypassEnabled } = await import("@/env"); + const { env, localPhoneAuthBypassEnabled } = + await import("@shared/environment"); expect(env).toMatchObject({ BETTER_AUTH_SECRET: "openinstinct-local-auth-development-secret", @@ -69,7 +70,7 @@ describe("environment", () => { vi.stubEnv("NODE_ENV", "development"); vi.stubEnv("VERCEL_ENV", undefined); - await expect(import("@/env")).rejects.toThrow( + await expect(import("@shared/environment")).rejects.toThrow( "Set both BETTER_AUTH_SECRET and SECRET_ENCRYPTION_KEY" ); } @@ -80,7 +81,7 @@ describe("environment", () => { vi.stubEnv("LINQ_CONNECTOR", "linq/custom"); vi.stubEnv("LINQ_PHONE_NUMBER", "+12025550123"); - const { env } = await import("@/env"); + const { env } = await import("@shared/environment"); expect(env.GOOGLE_CONNECTOR_UID).toBe("google/custom"); expect(env.LINQ_CONNECTOR).toBe("linq/custom"); @@ -95,7 +96,7 @@ describe("environment", () => { vi.stubEnv("VERCEL_ENV", "development"); vi.stubEnv("VERCEL_URL", "open-instinct-preview.vercel.app"); - const { env } = await import("@/env"); + const { env } = await import("@shared/environment"); expect(env.BETTER_AUTH_SECRET).toBeUndefined(); expect(env.BETTER_AUTH_URL).toBeUndefined(); @@ -109,7 +110,7 @@ describe("environment", () => { vi.stubEnv("NODE_ENV", "development"); vi.stubEnv("VERCEL_ENV", undefined); - await expect(import("@/env")).rejects.toThrow( + await expect(import("@shared/environment")).rejects.toThrow( "Invalid environment variables" ); } @@ -121,7 +122,7 @@ describe("environment", () => { ])("accepts a Node-compatible 32-byte encryption key", async (key) => { vi.stubEnv("SECRET_ENCRYPTION_KEY", key); - const { env } = await import("@/env"); + const { env } = await import("@shared/environment"); expect(env.SECRET_ENCRYPTION_KEY).toBe(key); }); @@ -133,14 +134,14 @@ describe("environment", () => { async (name, errorMessage) => { vi.stubEnv(name, ""); - await expect(import("@/env")).rejects.toThrow(errorMessage); + await expect(import("@shared/environment")).rejects.toThrow(errorMessage); } ); it("rejects an encryption key that does not decode to 32 bytes", async () => { vi.stubEnv("SECRET_ENCRYPTION_KEY", Buffer.alloc(31, 1).toString("base64")); - await expect(import("@/env")).rejects.toThrow( + await expect(import("@shared/environment")).rejects.toThrow( "Invalid environment variables" ); }); @@ -148,7 +149,7 @@ describe("environment", () => { it("rejects a non-Postgres database URL", async () => { vi.stubEnv("DATABASE_URL", "https://example.com/database"); - await expect(import("@/env")).rejects.toThrow( + await expect(import("@shared/environment")).rejects.toThrow( "Invalid environment variables" ); }); @@ -157,7 +158,7 @@ describe("environment", () => { vi.stubEnv("LINQ_CONNECTOR", "linq/open-instinct"); vi.stubEnv("LINQ_PHONE_NUMBER", ""); - const { env } = await import("@/env"); + const { env } = await import("@shared/environment"); expect(env.LINQ_CONNECTOR).toBe("linq/open-instinct"); expect(env.LINQ_PHONE_NUMBER).toBeUndefined(); @@ -167,7 +168,7 @@ describe("environment", () => { vi.stubEnv("BLOB_READ_WRITE_TOKEN", ""); vi.stubEnv("BLOB_STORE_ID", "store_openinstinct"); - const { env } = await import("@/env"); + const { env } = await import("@shared/environment"); expect(env.BLOB_READ_WRITE_TOKEN).toBeUndefined(); expect(env.BLOB_STORE_ID).toBe("store_openinstinct"); @@ -177,7 +178,7 @@ describe("environment", () => { vi.stubEnv("LINQ_CONNECTOR", "linq/open-instinct"); vi.stubEnv("LINQ_PHONE_NUMBER", "(202) 555-0123"); - await expect(import("@/env")).rejects.toThrow( + await expect(import("@shared/environment")).rejects.toThrow( "Invalid environment variables" ); }); @@ -195,7 +196,8 @@ describe("environment", () => { vi.stubEnv("NODE_ENV", nodeEnv); vi.stubEnv("VERCEL_ENV", vercelEnv); - const { localPhoneAuthBypassEnabled } = await import("@/env"); + const { localPhoneAuthBypassEnabled } = + await import("@shared/environment"); expect(localPhoneAuthBypassEnabled).toBe(expected); } diff --git a/src/lib/tests/application-origin.test.ts b/shared/environment/origin.test.ts similarity index 91% rename from src/lib/tests/application-origin.test.ts rename to shared/environment/origin.test.ts index 42151aa5..15b69a3e 100644 --- a/src/lib/tests/application-origin.test.ts +++ b/shared/environment/origin.test.ts @@ -20,7 +20,7 @@ describe("application origin", () => { vi.stubEnv("BETTER_AUTH_URL", "https://assistant.example/path"); const { applicationOrigin, betterAuthBaseURL } = - await import("@/lib/application-origin"); + await import("@shared/environment/origin"); expect(applicationOrigin()).toBe("https://assistant.example"); expect(betterAuthBaseURL()).toBe("https://assistant.example"); @@ -33,7 +33,7 @@ describe("application origin", () => { vi.stubEnv("VERCEL_URL", "openinstinct-preview-123.vercel.app"); const { applicationOrigin, betterAuthBaseURL } = - await import("@/lib/application-origin"); + await import("@shared/environment/origin"); expect(applicationOrigin()).toBe("https://openinstinct.example.com"); expect(betterAuthBaseURL()).toEqual({ @@ -51,7 +51,7 @@ describe("application origin", () => { it("fails clearly when a non-Vercel production host has no URL", async () => { vi.stubEnv("VERCEL_URL", "stale-preview.vercel.app"); - const { applicationOrigin } = await import("@/lib/application-origin"); + const { applicationOrigin } = await import("@shared/environment/origin"); expect(() => applicationOrigin()).toThrow("Set BETTER_AUTH_URL"); }); diff --git a/src/lib/application-origin.ts b/shared/environment/origin.ts similarity index 95% rename from src/lib/application-origin.ts rename to shared/environment/origin.ts index 52adda80..8eb8784f 100644 --- a/src/lib/application-origin.ts +++ b/shared/environment/origin.ts @@ -1,4 +1,4 @@ -import { env } from "@/env"; +import { env } from "@shared/environment"; export function applicationOrigin() { if (env.BETTER_AUTH_URL) return new URL(env.BETTER_AUTH_URL).origin; diff --git a/src/lib/google-workspace.ts b/shared/google-workspace/connection.ts similarity index 100% rename from src/lib/google-workspace.ts rename to shared/google-workspace/connection.ts diff --git a/src/lib/access-scope.ts b/shared/identity/access-scope.ts similarity index 100% rename from src/lib/access-scope.ts rename to shared/identity/access-scope.ts diff --git a/src/auth/tests/session-auth.test.ts b/shared/identity/phone-number.test.ts similarity index 85% rename from src/auth/tests/session-auth.test.ts rename to shared/identity/phone-number.test.ts index 72585540..682b58d0 100644 --- a/src/auth/tests/session-auth.test.ts +++ b/shared/identity/phone-number.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import { accessScopeForUser } from "@/lib/access-scope"; -import { normalizeAuthPhoneNumber } from "@/auth/phone-number"; +import { accessScopeForUser } from "@shared/identity/access-scope"; +import { normalizeAuthPhoneNumber } from "@shared/identity/phone-number"; describe("multi-user request identity", () => { it("derives stable personal workspaces without exposing provider ids", () => { diff --git a/src/auth/phone-number.ts b/shared/identity/phone-number.ts similarity index 100% rename from src/auth/phone-number.ts rename to shared/identity/phone-number.ts diff --git a/agent/lib/schedules/outcome.ts b/shared/schedules/outcome.ts similarity index 100% rename from agent/lib/schedules/outcome.ts rename to shared/schedules/outcome.ts diff --git a/tests/agent/schedules/timing.test.ts b/shared/schedules/timing.test.ts similarity index 97% rename from tests/agent/schedules/timing.test.ts rename to shared/schedules/timing.test.ts index 9709aeb0..2c59354f 100644 --- a/tests/agent/schedules/timing.test.ts +++ b/shared/schedules/timing.test.ts @@ -3,7 +3,7 @@ import { computeLatestRun, computeNextRun, scheduleTimingSchema, -} from "@/agent/lib/schedules/timing"; +} from "@shared/schedules/timing"; describe("schedule timing", () => { it("finds the latest elapsed interval without walking every occurrence", () => { diff --git a/agent/lib/schedules/timing.ts b/shared/schedules/timing.ts similarity index 100% rename from agent/lib/schedules/timing.ts rename to shared/schedules/timing.ts diff --git a/src/lib/tests/user-profile.test.ts b/shared/user-profile/schema.test.ts similarity index 97% rename from src/lib/tests/user-profile.test.ts rename to shared/user-profile/schema.test.ts index 30bfb6cb..bb9636c7 100644 --- a/src/lib/tests/user-profile.test.ts +++ b/shared/user-profile/schema.test.ts @@ -5,7 +5,7 @@ import { hasUserProfileValues, parseUserProfile, userProfilePatchSchema, -} from "@/lib/user-profile"; +} from "@shared/user-profile/schema"; describe("user profile", () => { it("validates and normalizes form-ready personal information", () => { diff --git a/src/lib/user-profile.ts b/shared/user-profile/schema.ts similarity index 100% rename from src/lib/user-profile.ts rename to shared/user-profile/schema.ts diff --git a/src/lib/tests/vault-payload.test.ts b/shared/vault/payload.test.ts similarity index 99% rename from src/lib/tests/vault-payload.test.ts rename to shared/vault/payload.test.ts index a9d97df8..e8e5c17a 100644 --- a/src/lib/tests/vault-payload.test.ts +++ b/shared/vault/payload.test.ts @@ -12,7 +12,7 @@ import { serializeAddressVaultPayload, serializeContactVaultPayload, serializeLoginVaultPayload, -} from "@/lib/vault"; +} from "@shared/vault/schema"; describe("versioned vault payloads", () => { it("stores password and passwordless login methods", () => { diff --git a/src/lib/tests/payment-card.test.ts b/shared/vault/payment-card.test.ts similarity index 98% rename from src/lib/tests/payment-card.test.ts rename to shared/vault/payment-card.test.ts index b0cf26c3..aa5f6a05 100644 --- a/src/lib/tests/payment-card.test.ts +++ b/shared/vault/payment-card.test.ts @@ -4,7 +4,7 @@ import { paymentCardSecretStringSchema, paymentCardType, serializePaymentCard, -} from "@/lib/vault"; +} from "@shared/vault/schema"; describe("payment card vault values", () => { it("serializes a complete structured card secret", () => { diff --git a/src/lib/vault.ts b/shared/vault/schema.ts similarity index 100% rename from src/lib/vault.ts rename to shared/vault/schema.ts diff --git a/src/lib/tests/vault-setup.test.ts b/shared/vault/setup.test.ts similarity index 98% rename from src/lib/tests/vault-setup.test.ts rename to shared/vault/setup.test.ts index 9972c6fb..770b1dc4 100644 --- a/src/lib/tests/vault-setup.test.ts +++ b/shared/vault/setup.test.ts @@ -6,7 +6,7 @@ import { vaultCreateItemSchema, vaultImportItemsSchema, vaultSetupRequestSchema, -} from "@/lib/vault"; +} from "@shared/vault/schema"; describe("vault setup", () => { it("creates and validates a secret-free setup link", () => { diff --git a/tests/agent-tool-boundaries.test.ts b/tests/agent-tool-boundaries.test.ts index b4a355b9..cc0da449 100644 --- a/tests/agent-tool-boundaries.test.ts +++ b/tests/agent-tool-boundaries.test.ts @@ -165,14 +165,18 @@ describe("root and worker capability boundaries", () => { expect(existsSync(`${workerRoot}/lib/browser-runtime.ts`)).toBe(false); expect(existsSync(`${workerRoot}/lib/owned-browser.ts`)).toBe(true); - expect(readFileSync("src/lib/kernel.ts", "utf8")).toContain("new Kernel("); + expect(readFileSync(`${workerRoot}/lib/kernel.ts`, "utf8")).toContain( + "new Kernel(" + ); for (const tool of [ "capture_browser_image", "computer_action", "manage_browsers", ]) { const source = readFileSync(`${workerTools}/${tool}.ts`, "utf8"); - expect(source).toContain('from "@/lib/kernel"'); + expect(source).toContain( + 'from "@agent/subagents/browser-agent/lib/kernel"' + ); expect(source).not.toContain("new Kernel("); } expect(readFileSync(`${workerTools}/fill_from_vault.ts`, "utf8")).toContain( diff --git a/tests/agent/agent.test.ts b/tests/agent/agent.test.ts index 860dc465..67e99d3e 100644 --- a/tests/agent/agent.test.ts +++ b/tests/agent/agent.test.ts @@ -1,21 +1,21 @@ import type { DynamicResolveContext } from "eve"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import type { isScheduledAgentRunLeaseActive } from "@/db/services/scheduled-agent-run-leases"; -import type { getGatewayModel } from "@/db/services/settings"; +import type { isScheduledAgentRunLeaseActive } from "@db/services/scheduled-agent-run-leases"; +import type { getGatewayModel } from "@db/services/settings"; const services = vi.hoisted(() => ({ getModel: vi.fn(), isActive: vi.fn(), })); -vi.mock("@/db/services/scheduled-agent-run-leases", () => ({ +vi.mock("@db/services/scheduled-agent-run-leases", () => ({ isScheduledAgentRunLeaseActive: services.isActive, })); -vi.mock("@/db/services/settings", () => ({ +vi.mock("@db/services/settings", () => ({ getGatewayModel: services.getModel, })); -import agent from "@/agent/agent"; +import agent from "@agent/agent"; const runId = "00000000-0000-4000-8000-000000000001"; const oldLeaseToken = "00000000-0000-4000-8000-000000000002"; diff --git a/tests/agent/capabilities.test.ts b/tests/agent/capabilities.test.ts index 16102da3..f86b2639 100644 --- a/tests/agent/capabilities.test.ts +++ b/tests/agent/capabilities.test.ts @@ -1,13 +1,13 @@ import type { DynamicResolveContext } from "eve/tools"; import { describe, expect, it } from "vitest"; -import personalInfoMemory from "@/agent/memory/personal_info"; -import browserAgent from "@/agent/subagents/browser-agent/agent"; -import calendar from "@/agent/tools/calendar"; -import contacts from "@/agent/tools/contacts"; -import gmail from "@/agent/tools/gmail"; -import messaging from "@/agent/tools/messaging"; -import schedules from "@/agent/tools/schedules"; -import vault from "@/agent/tools/vault"; +import personalInfoMemory from "@agent/memory/personal_info"; +import browserAgent from "@agent/subagents/browser-agent/agent"; +import calendar from "@agent/tools/calendar"; +import contacts from "@agent/tools/contacts"; +import gmail from "@agent/tools/gmail"; +import messaging from "@agent/tools/messaging"; +import schedules from "@agent/tools/schedules"; +import vault from "@agent/tools/vault"; const groupedTools = [calendar, contacts, gmail, messaging, schedules, vault]; diff --git a/tests/agent/channels/eve-channel-auth.test.ts b/tests/agent/channels/eve-channel-auth.test.ts index cfdb505b..5f0cda25 100644 --- a/tests/agent/channels/eve-channel-auth.test.ts +++ b/tests/agent/channels/eve-channel-auth.test.ts @@ -1,9 +1,9 @@ import type { RouteHandlerArgs } from "eve/channels"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import * as AuthSession from "@/auth/session"; -import * as SessionService from "@/db/services/sessions"; -import { authSessionFor } from "@/tests/helpers/auth-session"; -import eveChannel, { sessionIdFromPath } from "@/agent/channels/eve"; +import * as AuthSession from "@db/services/auth/session"; +import * as SessionService from "@db/services/sessions"; +import { authSessionFor } from "@tests/helpers/auth-session"; +import eveChannel, { sessionIdFromPath } from "@agent/channels/eve"; const getAuthSessionMock = vi.spyOn(AuthSession, "getAuthSession"); const isSessionOwnedMock = vi.spyOn(SessionService, "isSessionOwned"); diff --git a/tests/agent/channels/eve-message-delivery.test.ts b/tests/agent/channels/eve-message-delivery.test.ts index 3b5c0d37..be3bc6d9 100644 --- a/tests/agent/channels/eve-message-delivery.test.ts +++ b/tests/agent/channels/eve-message-delivery.test.ts @@ -3,7 +3,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import type { finalizeScheduledReport, releaseScheduledReport, -} from "@/db/services/scheduled-agent-jobs"; +} from "@db/services/scheduled-agent-jobs"; const channelCapture = vi.hoisted(() => { const configs: EveChannelInput[] = []; @@ -24,13 +24,13 @@ vi.mock(import("eve/channels/eve"), async (importOriginal) => { }, }; }); -vi.mock("@/db/services/scheduled-agent-jobs", () => ({ +vi.mock("@db/services/scheduled-agent-jobs", () => ({ finalizeScheduledReport: delivery.finalize, releaseScheduledReport: delivery.release, })); // Loads the production channel so the mocked factory captures its event configuration. -await import("@/agent/channels/eve"); +await import("@agent/channels/eve"); const events = channelCapture.configs[0]?.events; const handleActionResult = events?.["action.result"]; diff --git a/tests/agent/channels/linq-inbound-auth.test.ts b/tests/agent/channels/linq-inbound-auth.test.ts index 43adf8d2..456c7757 100644 --- a/tests/agent/channels/linq-inbound-auth.test.ts +++ b/tests/agent/channels/linq-inbound-auth.test.ts @@ -1,9 +1,9 @@ import type { LinqChannelConfig } from "eve/channels/linq"; import { Message } from "chat"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import type * as EnvModule from "@/env"; +import type * as EnvModule from "@shared/environment"; // oxlint-disable-next-line import/no-unassigned-import -- Loads the production module so the mocked channel factory can capture its configuration. -import "@/agent/channels/linq"; +import "@agent/channels/linq"; interface AuthUserRow { readonly id: string; @@ -16,7 +16,7 @@ const capture = vi.hoisted(() => ({ findOne: vi.fn<() => Promise>(), })); -vi.mock("@/env", async (importOriginal) => { +vi.mock("@shared/environment", async (importOriginal) => { const original = await importOriginal(); return { ...original, @@ -36,7 +36,7 @@ vi.mock(import("eve/channels/linq"), async (importOriginal) => { }, }; }); -vi.mock("@/auth", () => ({ +vi.mock("@db/services/auth", () => ({ getAuth: async () => ({ $context: Promise.resolve({ adapter: { findOne: capture.findOne } }), }), diff --git a/tests/agent/channels/linq-message-delivery.test.ts b/tests/agent/channels/linq-message-delivery.test.ts index e7571d47..09bf4efc 100644 --- a/tests/agent/channels/linq-message-delivery.test.ts +++ b/tests/agent/channels/linq-message-delivery.test.ts @@ -4,15 +4,15 @@ import type { LinqAPIV3 } from "@linqapp/sdk"; import type { AdapterPostableMessage } from "chat"; import { beforeEach, describe, expect, it, vi } from "vitest"; import type * as Blob from "@vercel/blob"; -import type * as EnvModule from "@/env"; -import { sendMessageOutputSchema } from "@/agent/lib/send-message"; -import type { AccessScope } from "@/lib/access-scope"; +import type * as EnvModule from "@shared/environment"; +import { sendMessageOutputSchema } from "@shared/chat/message-delivery"; +import type { AccessScope } from "@shared/identity/access-scope"; import type { finalizeScheduledReport, releaseScheduledReport, -} from "@/db/services/scheduled-agent-jobs"; +} from "@db/services/scheduled-agent-jobs"; // oxlint-disable-next-line import/no-unassigned-import -- Loads the production module so the mocked channel factory can capture its configuration. -import "@/agent/channels/linq"; +import "@agent/channels/linq"; interface BrowserImage { bytes: Uint8Array; @@ -68,11 +68,11 @@ const scheduleDeliveryCapture = vi.hoisted(() => ({ finalize: vi.fn(), release: vi.fn(), })); -vi.mock("@/db/services/scheduled-agent-jobs", () => ({ +vi.mock("@db/services/scheduled-agent-jobs", () => ({ finalizeScheduledReport: scheduleDeliveryCapture.finalize, releaseScheduledReport: scheduleDeliveryCapture.release, })); -vi.mock("@/env", async (importOriginal) => { +vi.mock("@shared/environment", async (importOriginal) => { const original = await importOriginal(); return { ...original, @@ -105,7 +105,7 @@ vi.mock(import("eve/channels/linq"), async (importOriginal) => { }, }; }); -vi.mock("@/db/services/browser-images", () => ({ +vi.mock("@db/services/browser-images", () => ({ async readReadyBrowserImageArtifact( scope: AccessScope, id: string, diff --git a/tests/agent/channels/scheduled-run-auth.test.ts b/tests/agent/channels/scheduled-run-auth.test.ts index 27025174..03cd2502 100644 --- a/tests/agent/channels/scheduled-run-auth.test.ts +++ b/tests/agent/channels/scheduled-run-auth.test.ts @@ -5,7 +5,7 @@ import type { Session, } from "eve/channels"; import { describe, expect, it, vi } from "vitest"; -import scheduledRunChannel from "@/agent/channels/scheduled-run"; +import scheduledRunChannel from "@agent/channels/scheduled-run"; const scheduledRunPaths = [ "/internal/scheduled-run/report", diff --git a/tests/agent/hooks/evlog.test.ts b/tests/agent/hooks/evlog.test.ts index 6c60bf1c..86d9b4a6 100644 --- a/tests/agent/hooks/evlog.test.ts +++ b/tests/agent/hooks/evlog.test.ts @@ -3,7 +3,7 @@ import type { DrainContext, WideEvent } from "evlog"; import { initLogger } from "evlog"; import { resetEvlogEveForTests, useLogger } from "evlog/eve"; import { beforeAll, describe, expect, it } from "vitest"; -import evlogHook from "@/agent/hooks/evlog"; +import evlogHook from "@agent/hooks/evlog"; const capturedEvents: WideEvent[] = []; diff --git a/tests/agent/hooks/scheduled-run-completion.test.ts b/tests/agent/hooks/scheduled-run-completion.test.ts index 7b635f4d..4b593c51 100644 --- a/tests/agent/hooks/scheduled-run-completion.test.ts +++ b/tests/agent/hooks/scheduled-run-completion.test.ts @@ -6,7 +6,7 @@ import type { markScheduledAgentRunStarted, releaseScheduledAgentRun, waitForScheduledAgentRunInput, -} from "@/db/services/scheduled-agent-jobs"; +} from "@db/services/scheduled-agent-jobs"; const services = vi.hoisted(() => ({ complete: vi.fn(), @@ -16,7 +16,7 @@ const services = vi.hoisted(() => ({ waitForInput: vi.fn(), })); -vi.mock("@/db/services/scheduled-agent-jobs", () => ({ +vi.mock("@db/services/scheduled-agent-jobs", () => ({ completeScheduledAgentRun: services.complete, deferScheduledAgentRunCompletion: services.deferCompletion, markScheduledAgentRunStarted: services.markStarted, @@ -24,7 +24,7 @@ vi.mock("@/db/services/scheduled-agent-jobs", () => ({ waitForScheduledAgentRunInput: services.waitForInput, })); -import completionHook from "@/agent/hooks/scheduled-run-completion"; +import completionHook from "@agent/hooks/scheduled-run-completion"; const runId = "00000000-0000-4000-8000-000000000001"; const leaseToken = "00000000-0000-4000-8000-000000000002"; diff --git a/tests/agent/hooks/session-owner.test.ts b/tests/agent/hooks/session-owner.test.ts index b6593e0f..4a4ecbc0 100644 --- a/tests/agent/hooks/session-owner.test.ts +++ b/tests/agent/hooks/session-owner.test.ts @@ -1,9 +1,9 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import type { HookContext } from "eve/hooks"; -import type { saveChat } from "@/db/services/chats"; -import type { ensureScope } from "@/db/services/scope"; -import type { claimSession } from "@/db/services/sessions"; -import sessionOwner from "@/agent/hooks/session-owner"; +import type { saveChat } from "@db/services/chats"; +import type { ensureScope } from "@db/services/scope"; +import type { claimSession } from "@db/services/sessions"; +import sessionOwner from "@agent/hooks/session-owner"; const mocks = vi.hoisted(() => ({ claimSession: vi.fn(), @@ -11,9 +11,9 @@ const mocks = vi.hoisted(() => ({ saveChat: vi.fn(), })); -vi.mock("@/db/services/chats", () => ({ saveChat: mocks.saveChat })); -vi.mock("@/db/services/scope", () => ({ ensureScope: mocks.ensureScope })); -vi.mock("@/db/services/sessions", () => ({ +vi.mock("@db/services/chats", () => ({ saveChat: mocks.saveChat })); +vi.mock("@db/services/scope", () => ({ ensureScope: mocks.ensureScope })); +vi.mock("@db/services/sessions", () => ({ claimSession: mocks.claimSession, })); diff --git a/tests/agent/instructions.test.ts b/tests/agent/instructions.test.ts index b7ca2270..8fa44aad 100644 --- a/tests/agent/instructions.test.ts +++ b/tests/agent/instructions.test.ts @@ -1,9 +1,9 @@ import type { DynamicResolveContext } from "eve/instructions"; import { describe, expect, it } from "vitest"; -import executionSafety from "@/agent/instructions/10-execution-safety"; -import roleInstructions from "@/agent/instructions/20-role"; -import workerCoordination from "@/agent/instructions/25-worker-coordination"; -import messageStyle from "@/agent/instructions/30-message-style"; +import executionSafety from "@agent/instructions/10-execution-safety"; +import roleInstructions from "@agent/instructions/20-role"; +import workerCoordination from "@agent/instructions/25-worker-coordination"; +import messageStyle from "@agent/instructions/30-message-style"; describe("agent instructions", () => { it.each([ diff --git a/tests/agent/schedules/dynamic.test.ts b/tests/agent/schedules/dynamic.test.ts index e80ca458..e45cd082 100644 --- a/tests/agent/schedules/dynamic.test.ts +++ b/tests/agent/schedules/dynamic.test.ts @@ -10,7 +10,7 @@ import type { releaseScheduledAgentRun, releaseScheduledReport, setScheduledRunSession, -} from "@/db/services/scheduled-agent-jobs"; +} from "@db/services/scheduled-agent-jobs"; const services = vi.hoisted(() => ({ claimReports: vi.fn(), @@ -26,7 +26,7 @@ const requests = vi.hoisted(() => ({ report: vi.fn<(runId: string) => Promise>(), })); -vi.mock("@/db/services/scheduled-agent-jobs", () => ({ +vi.mock("@db/services/scheduled-agent-jobs", () => ({ claimReadyScheduledAgentRuns: services.claimRuns, claimScheduledReport: services.claimReports, finalizeScheduledReport: services.finalizeReport, @@ -36,16 +36,16 @@ vi.mock("@/db/services/scheduled-agent-jobs", () => ({ releaseScheduledReport: services.releaseReport, setScheduledRunSession: services.setSession, })); -vi.mock("@/agent/channels/linq", () => ({ default: { channel: "linq" } })); -vi.mock("@/agent/lib/schedules/request", () => ({ +vi.mock("@agent/channels/linq", () => ({ default: { channel: "linq" } })); +vi.mock("@agent/lib/schedules/request", () => ({ postScheduledReport: requests.report, })); -vi.mock("@/agent/channels/scheduled-run", () => ({ +vi.mock("@agent/channels/scheduled-run", () => ({ default: { channel: "scheduled-run" }, })); -import dynamicSchedule from "@/agent/schedules/dynamic"; -import { dispatchScheduledReport } from "@/agent/lib/schedules/report"; +import dynamicSchedule from "@agent/schedules/dynamic"; +import { dispatchScheduledReport } from "@agent/lib/schedules/report"; describe("dynamic schedule dispatch", () => { beforeEach(() => { diff --git a/tests/agent/schedules/request.test.ts b/tests/agent/schedules/request.test.ts index a27a4560..bdbe7c2b 100644 --- a/tests/agent/schedules/request.test.ts +++ b/tests/agent/schedules/request.test.ts @@ -23,12 +23,12 @@ const mocks = vi.hoisted(() => { vi.mock("node:fs/promises", () => ({ readFile: mocks.readFile })); vi.mock("@vercel/oidc", () => ({ getVercelOidcToken: mocks.getToken })); -vi.mock("@/env", () => ({ env: mocks.env })); -vi.mock("@/lib/application-origin", () => ({ +vi.mock("@shared/environment", () => ({ env: mocks.env })); +vi.mock("@shared/environment/origin", () => ({ applicationOrigin: () => "https://example.com", })); -import { postScheduledRunRoute } from "@/agent/lib/schedules/request"; +import { postScheduledRunRoute } from "@agent/lib/schedules/request"; describe("scheduled run requests", () => { beforeEach(() => { diff --git a/tests/agent/subagents/browser-agent/hooks/browser-trace-telemetry.test.ts b/tests/agent/subagents/browser-agent/hooks/browser-trace-telemetry.test.ts index a14634c9..c45341d1 100644 --- a/tests/agent/subagents/browser-agent/hooks/browser-trace-telemetry.test.ts +++ b/tests/agent/subagents/browser-agent/hooks/browser-trace-telemetry.test.ts @@ -5,12 +5,12 @@ import type { beginBrowserTrace, completeBrowserTrace, recordBrowserTraceEvents, -} from "@/db/services/browser-traces"; -import type { listWorkerBrowserSessions } from "@/db/services/browsers"; -import type * as TraceDomainsModule from "@/agent/subagents/browser-agent/lib/trace/domains"; -import type { harvestBrowserTraceDomains } from "@/agent/subagents/browser-agent/lib/trace/domains"; -import { domainFromUrl } from "@/agent/subagents/browser-agent/lib/trace/domains"; -import traceTelemetry from "@/agent/subagents/browser-agent/hooks/trace-telemetry"; +} from "@db/services/browser-traces"; +import type { listWorkerBrowserSessions } from "@db/services/browsers"; +import type * as TraceDomainsModule from "@agent/subagents/browser-agent/lib/trace/domains"; +import type { harvestBrowserTraceDomains } from "@agent/subagents/browser-agent/lib/trace/domains"; +import { domainFromUrl } from "@agent/subagents/browser-agent/lib/trace/domains"; +import traceTelemetry from "@agent/subagents/browser-agent/hooks/trace-telemetry"; const mocks = vi.hoisted(() => ({ beginBrowserTrace: vi.fn(), @@ -20,16 +20,16 @@ const mocks = vi.hoisted(() => ({ recordBrowserTraceEvents: vi.fn(), })); -vi.mock("@/db/services/browser-traces", () => ({ +vi.mock("@db/services/browser-traces", () => ({ beginBrowserTrace: mocks.beginBrowserTrace, completeBrowserTrace: mocks.completeBrowserTrace, recordBrowserTraceEvents: mocks.recordBrowserTraceEvents, })); -vi.mock("@/db/services/browsers", () => ({ +vi.mock("@db/services/browsers", () => ({ listWorkerBrowserSessions: mocks.listWorkerBrowserSessions, })); vi.mock( - "@/agent/subagents/browser-agent/lib/trace/domains", + "@agent/subagents/browser-agent/lib/trace/domains", async (importOriginal) => ({ ...(await importOriginal()), harvestBrowserTraceDomains: mocks.harvestBrowserTraceDomains, diff --git a/tests/agent/subagents/browser-agent/tools/kernel-browser-contract.test.ts b/tests/agent/subagents/browser-agent/tools/kernel-browser-contract.test.ts index 8f0d6a9a..d716e84a 100644 --- a/tests/agent/subagents/browser-agent/tools/kernel-browser-contract.test.ts +++ b/tests/agent/subagents/browser-agent/tools/kernel-browser-contract.test.ts @@ -6,17 +6,17 @@ import type { deleteBrowserSession, listBrowserSessions, withBrowserProfileWriteLock, -} from "@/db/services/browsers"; -import type { recordBrowserTraceDomains } from "@/db/services/browser-traces"; -import type { requireWorkerScope } from "@/agent/subagents/browser-agent/lib/access"; -import type { requireOwnedBrowserSession } from "@/agent/subagents/browser-agent/lib/owned-browser"; -import type * as TraceDomainsModule from "@/agent/subagents/browser-agent/lib/trace/domains"; -import type { harvestBrowserTraceDomains } from "@/agent/subagents/browser-agent/lib/trace/domains"; -import { kernel } from "@/lib/kernel"; -import { toolContextFor } from "@/tests/helpers/tool-context"; +} from "@db/services/browsers"; +import type { recordBrowserTraceDomains } from "@db/services/browser-traces"; +import type { requireWorkerScope } from "@agent/subagents/browser-agent/lib/access"; +import type { requireOwnedBrowserSession } from "@agent/subagents/browser-agent/lib/owned-browser"; +import type * as TraceDomainsModule from "@agent/subagents/browser-agent/lib/trace/domains"; +import type { harvestBrowserTraceDomains } from "@agent/subagents/browser-agent/lib/trace/domains"; +import { kernel } from "@agent/subagents/browser-agent/lib/kernel"; +import { toolContextFor } from "@tests/helpers/tool-context"; import manageBrowsers, { kernelProfileNameForWorkspace, -} from "@/agent/subagents/browser-agent/tools/manage_browsers"; +} from "@agent/subagents/browser-agent/tools/manage_browsers"; const serviceMocks = vi.hoisted(() => ({ createBrowserSession: vi.fn(), @@ -29,23 +29,23 @@ const serviceMocks = vi.hoisted(() => ({ withBrowserProfileWriteLock: vi.fn(), })); -vi.mock("@/db/services/browsers", () => ({ +vi.mock("@db/services/browsers", () => ({ createBrowserSession: serviceMocks.createBrowserSession, deleteBrowserSession: serviceMocks.deleteBrowserSession, listBrowserSessions: serviceMocks.listBrowserSessions, withBrowserProfileWriteLock: serviceMocks.withBrowserProfileWriteLock, })); -vi.mock("@/db/services/browser-traces", () => ({ +vi.mock("@db/services/browser-traces", () => ({ recordBrowserTraceDomains: serviceMocks.recordBrowserTraceDomains, })); -vi.mock("@/agent/subagents/browser-agent/lib/access", () => ({ +vi.mock("@agent/subagents/browser-agent/lib/access", () => ({ requireWorkerScope: serviceMocks.requireWorkerScope, })); -vi.mock("@/agent/subagents/browser-agent/lib/owned-browser", () => ({ +vi.mock("@agent/subagents/browser-agent/lib/owned-browser", () => ({ requireOwnedBrowserSession: serviceMocks.requireOwnedBrowserSession, })); vi.mock( - "@/agent/subagents/browser-agent/lib/trace/domains", + "@agent/subagents/browser-agent/lib/trace/domains", async (importOriginal) => ({ ...(await importOriginal()), harvestBrowserTraceDomains: serviceMocks.harvestBrowserTraceDomains, diff --git a/tests/agent/subagents/browser-agent/tools/worker-browser-images.test.ts b/tests/agent/subagents/browser-agent/tools/worker-browser-images.test.ts index ed8738fa..6229f4ea 100644 --- a/tests/agent/subagents/browser-agent/tools/worker-browser-images.test.ts +++ b/tests/agent/subagents/browser-agent/tools/worker-browser-images.test.ts @@ -1,6 +1,6 @@ /* oxlint-disable vitest/require-mock-type-parameters -- The test fixtures implement only the external API surface exercised by the tool. */ import { beforeEach, describe, expect, it, vi } from "vitest"; -import { toolContextFor } from "@/tests/helpers/tool-context"; +import { toolContextFor } from "@tests/helpers/tool-context"; const artifactId = "0d01e667-d128-4bb7-a248-1ae21db72f4f"; const png = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]); @@ -29,16 +29,16 @@ const mocks = vi.hoisted(() => ({ requireWorkerScope: vi.fn(), })); -vi.mock("@/agent/subagents/browser-agent/lib/access", () => ({ +vi.mock("@agent/subagents/browser-agent/lib/access", () => ({ requireWorkerScope: mocks.requireWorkerScope, })); -vi.mock("@/agent/subagents/browser-agent/lib/owned-browser", () => ({ +vi.mock("@agent/subagents/browser-agent/lib/owned-browser", () => ({ requireOwnedBrowserSession: mocks.requireOwnedBrowserSession, })); -vi.mock("@/agent/subagents/browser-agent/lib/vault-screenshot-mask", () => ({ +vi.mock("@agent/subagents/browser-agent/lib/vault-screenshot-mask", () => ({ withVaultScreenshotMask: mocks.mask, })); -vi.mock("@/db/services/browser-images", () => ({ +vi.mock("@db/services/browser-images", () => ({ finalizeBrowserImageArtifact: mocks.persist, reserveBrowserImageArtifact: mocks.reserve, })); @@ -46,7 +46,7 @@ vi.mock("@vercel/blob", () => ({ del: mocks.del, put: mocks.put, })); -vi.mock("@/lib/kernel", () => ({ +vi.mock("@agent/subagents/browser-agent/lib/kernel", () => ({ kernel: { browsers: { computer: { captureScreenshot: mocks.captureScreenshot }, @@ -58,7 +58,7 @@ vi.mock("@/lib/kernel", () => ({ }, })); -import captureBrowserImage from "@/agent/subagents/browser-agent/tools/capture_browser_image"; +import captureBrowserImage from "@agent/subagents/browser-agent/tools/capture_browser_image"; const scope = { userId: "user-1", workspaceId: "workspace-1" }; const reservation = { diff --git a/tests/agent/subagents/browser-agent/tools/worker-browser-tools.test.ts b/tests/agent/subagents/browser-agent/tools/worker-browser-tools.test.ts index a2516fae..174d99f0 100644 --- a/tests/agent/subagents/browser-agent/tools/worker-browser-tools.test.ts +++ b/tests/agent/subagents/browser-agent/tools/worker-browser-tools.test.ts @@ -1,9 +1,9 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -import * as WorkerAccess from "@/agent/subagents/browser-agent/lib/access"; -import * as OwnedBrowser from "@/agent/subagents/browser-agent/lib/owned-browser"; -import { kernel } from "@/lib/kernel"; -import { toolContextFor } from "@/tests/helpers/tool-context"; -import computerAction from "@/agent/subagents/browser-agent/tools/computer_action"; +import * as WorkerAccess from "@agent/subagents/browser-agent/lib/access"; +import * as OwnedBrowser from "@agent/subagents/browser-agent/lib/owned-browser"; +import { kernel } from "@agent/subagents/browser-agent/lib/kernel"; +import { toolContextFor } from "@tests/helpers/tool-context"; +import computerAction from "@agent/subagents/browser-agent/tools/computer_action"; const mocks = { batch: vi.spyOn(kernel.browsers.computer, "batch"), diff --git a/tests/agent/tools/google-workspace.test.ts b/tests/agent/tools/google-workspace.test.ts index c5674a48..013426e5 100644 --- a/tests/agent/tools/google-workspace.test.ts +++ b/tests/agent/tools/google-workspace.test.ts @@ -1,7 +1,7 @@ import type { ToolContext } from "eve/tools"; import { describe, expect, it, vi } from "vitest"; -import type * as GmailModule from "@/agent/lib/google-workspace/gmail"; -import type { updateGmail } from "@/agent/lib/google-workspace/gmail"; +import type * as GmailModule from "@agent/lib/google-workspace/gmail"; +import type { updateGmail } from "@agent/lib/google-workspace/gmail"; const gmail = vi.hoisted(() => ({ update: vi @@ -9,12 +9,12 @@ const gmail = vi.hoisted(() => ({ .mockResolvedValue({ action: "archive", updatedCount: 2 }), })); -vi.mock("@/agent/lib/google-workspace/gmail", async (importOriginal) => ({ +vi.mock("@agent/lib/google-workspace/gmail", async (importOriginal) => ({ ...(await importOriginal()), updateGmail: gmail.update, })); -import { gmailUpdate } from "@/agent/tools/gmail"; +import { gmailUpdate } from "@agent/tools/gmail"; describe("Google Workspace tools", () => { it("reports the selected Gmail update without an action discriminator", async () => { diff --git a/tests/agent/tools/schedules.test.ts b/tests/agent/tools/schedules.test.ts index 70a49f85..1959ab09 100644 --- a/tests/agent/tools/schedules.test.ts +++ b/tests/agent/tools/schedules.test.ts @@ -11,7 +11,7 @@ import type { getScheduledAgentRunInputForReport, listScheduledAgentJobs, updateScheduledAgentJob, -} from "@/db/services/scheduled-agent-jobs"; +} from "@db/services/scheduled-agent-jobs"; const services = vi.hoisted(() => ({ create: vi.fn(), @@ -21,7 +21,7 @@ const services = vi.hoisted(() => ({ update: vi.fn(), })); -vi.mock("@/db/services/scheduled-agent-jobs", () => ({ +vi.mock("@db/services/scheduled-agent-jobs", () => ({ createScheduledAgentJob: services.create, getScheduledAgentRunInput: services.getInput, getScheduledAgentRunInputForReport: services.getInputForReport, @@ -29,12 +29,12 @@ vi.mock("@/db/services/scheduled-agent-jobs", () => ({ updateScheduledAgentJob: services.update, })); -import messaging from "@/agent/tools/messaging"; +import messaging from "@agent/tools/messaging"; import schedules, { createSchedule, listSchedules, updateSchedule, -} from "@/agent/tools/schedules"; +} from "@agent/tools/schedules"; describe("schedule tools", () => { beforeEach(() => { diff --git a/src/lib/tests/browser-images.test.ts b/tests/browser-artifacts.test.ts similarity index 95% rename from src/lib/tests/browser-images.test.ts rename to tests/browser-artifacts.test.ts index 03cc816d..e93ccdac 100644 --- a/src/lib/tests/browser-images.test.ts +++ b/tests/browser-artifacts.test.ts @@ -4,15 +4,15 @@ import { browserImageArtifactUrl, isBrowserImageArtifactUrl, sniffBrowserImageMediaType, -} from "@/lib/browser-artifact"; +} from "@shared/browser/artifact"; import { taskCompletionOutputSchema, taskCompletionSchema, -} from "@/lib/worker-completion"; +} from "@agent/subagents/browser-agent/lib/completion"; import { extractImageArtifactMarkdownReferences, stripImageArtifactMarkdownReferences, -} from "@/agent/lib/linq-image-artifact/markdown"; +} from "@agent/lib/linq-image-artifact/markdown"; const artifactId = "0d01e667-d128-4bb7-a248-1ae21db72f4f"; diff --git a/tests/source-layout.test.ts b/tests/source-layout.test.ts index 3bd4f810..12e7d94a 100644 --- a/tests/source-layout.test.ts +++ b/tests/source-layout.test.ts @@ -1,45 +1,7 @@ -import { readdirSync, statSync } from "node:fs"; +import { existsSync, readdirSync, statSync } from "node:fs"; import { join } from "node:path"; import { describe, expect, it } from "vitest"; -const allowedSrcDirectories = [ - "app", - "auth", - "components", - "hooks", - "lib", - "trpc", -]; - -const expectedSrcFiles = ["env.ts", "proxy.ts"]; - -const disallowedLibDirectories = [ - "browser", - "browser-images", - "google-workspace", - "manager", - "model-catalog", - "task-history", -]; - -const expectedLibFiles = [ - "access-scope.ts", - "application-origin.ts", - "browser-activity.ts", - "browser-artifact.ts", - "chat.ts", - "google-workspace.ts", - "installation-secrets.ts", - "kernel.ts", - "request-scope.ts", - "same-origin.ts", - "user-profile.ts", - "utils.ts", - "vault.ts", - "worker-completion.ts", - "worker-events.ts", -]; - function directories(directory: string) { return readdirSync(directory) .filter((entry) => statSync(join(directory, entry)).isDirectory()) @@ -53,17 +15,41 @@ function files(directory: string) { } describe("source layout", () => { - it("keeps src limited to application layers", () => { - expect(directories("src")).toEqual(allowedSrcDirectories); - expect(files("src")).toEqual(expectedSrcFiles); + it("keeps the Eve agent and Next route tree at the repository root", () => { + expect(existsSync("agent/agent.ts")).toBe(true); + expect(existsSync("agent/instructions.md")).toBe(true); + expect(existsSync("app/layout.tsx")).toBe(true); + expect(existsSync("app/(authenticated)/(workspace)/page.tsx")).toBe(true); + expect(existsSync("app/(authenticated)/chat/(new)/page.tsx")).toBe(true); + expect(existsSync("proxy.ts")).toBe(true); + expect(existsSync("src")).toBe(false); }); - it("keeps lib limited to shared infrastructure and contracts", () => { - const libDirectories = directories("src/lib"); - - for (const directory of disallowedLibDirectories) { - expect(libDirectories).not.toContain(directory); - } - expect(files("src/lib")).toEqual(expectedLibFiles); + it("keeps browser support and cross-boundary contracts explicitly owned", () => { + expect(directories("web")).toEqual([ + "auth", + "browser", + "components", + "hooks", + "trpc", + ]); + expect(files("web")).toEqual([]); + expect(directories("shared")).toEqual([ + "browser", + "chat", + "environment", + "google-workspace", + "identity", + "schedules", + "user-profile", + "vault", + ]); + expect(files("shared")).toEqual([]); + expect(existsSync("shared/environment/env.ts")).toBe(true); + expect(existsSync("agent/subagents/browser-agent/lib/kernel.ts")).toBe( + true + ); + expect(existsSync("db/services/installation-secrets.ts")).toBe(true); + expect(existsSync("evals/browser/worker-events.ts")).toBe(true); }); }); diff --git a/tools/oxlint/README.md b/tools/oxlint/README.md index bcbb2870..4e5a118f 100644 --- a/tools/oxlint/README.md +++ b/tools/oxlint/README.md @@ -9,6 +9,11 @@ internal packages. The adaptation supports both root-level `app/` and `src/app/` Next.js projects. Rule activation belongs in the root `.oxlintrc.jsonc`. +The `architecture` plugin enforces the repository's production dependency +direction across `agent`, `app`, `db`, `shared`, and `web`. Root `proxy.ts` is +treated as web-owned. Violations are reported on static imports and exports, +dynamic imports, and Vitest or Jest module mocks. + The `anti-slop` plugin vendors the generic rules and shared helpers from [`dmmulroy/anti-slop`](https://github.com/dmmulroy/anti-slop) at commit `0b863049ca2173b74ae6ebf1f8d0f6f911f9a220`. The upstream Effect integration diff --git a/tools/oxlint/architecture/index.ts b/tools/oxlint/architecture/index.ts new file mode 100644 index 00000000..8b9ba6f1 --- /dev/null +++ b/tools/oxlint/architecture/index.ts @@ -0,0 +1,14 @@ +import { definePlugin } from "@oxlint/plugins"; + +import { noForbiddenLayerImportsRule } from "./rules/no-forbidden-layer-imports.ts"; + +const plugin = definePlugin({ + meta: { + name: "local-architecture", + }, + rules: { + "no-forbidden-layer-imports": noForbiddenLayerImportsRule, + }, +}); + +export default plugin; diff --git a/tools/oxlint/architecture/rules/no-forbidden-layer-imports.ts b/tools/oxlint/architecture/rules/no-forbidden-layer-imports.ts new file mode 100644 index 00000000..5f4bfa19 --- /dev/null +++ b/tools/oxlint/architecture/rules/no-forbidden-layer-imports.ts @@ -0,0 +1,149 @@ +import path from "node:path"; + +import { defineRule } from "@oxlint/plugins"; + +import type { ESTree } from "@oxlint/plugins"; + +import { isStringLiteral } from "../../shared/literals.ts"; + +const productionLayers = ["agent", "app", "db", "shared", "web"] as const; +type ProductionLayer = (typeof productionLayers)[number]; + +const moduleMockMethods = new Set(["doMock", "mock", "unstable_mockModule"]); + +const forbiddenDependencies = { + agent: new Set(["app", "web"]), + app: new Set(["agent"]), + db: new Set(["agent", "app", "web"]), + shared: new Set(["agent", "app", "db", "web"]), + web: new Set(["agent", "app"]), +} satisfies Record>; + +function productionLayerForPath( + filePath: string, + repositoryRoot: string +): ProductionLayer | undefined { + const normalizedPath = path.resolve(filePath); + if (normalizedPath === path.join(repositoryRoot, "proxy.ts")) return "web"; + + const relativePath = path.relative(repositoryRoot, normalizedPath); + if (relativePath.startsWith("..") || path.isAbsolute(relativePath)) { + return undefined; + } + + const [root] = relativePath.split(path.sep); + return productionLayers.find((candidate) => candidate === root); +} + +function importedProductionLayer( + importer: string, + source: string, + repositoryRoot: string +): ProductionLayer | undefined { + if (source.startsWith(".")) { + return productionLayerForPath( + path.resolve(path.dirname(importer), source), + repositoryRoot + ); + } + + const match = /^@(agent|app|db|shared|web)(?:\/(.*))?$/u.exec(source); + const aliasRoot = match?.[1]; + if (!aliasRoot) return undefined; + + return productionLayerForPath( + path.resolve(repositoryRoot, `${aliasRoot}/${match[2] ?? ""}`), + repositoryRoot + ); +} + +function moduleMockSource( + node: ESTree.CallExpression +): ESTree.Node | undefined { + const callee = node.callee; + if ( + !("object" in callee) || + !("property" in callee) || + !("computed" in callee) || + callee.object.type !== "Identifier" || + (callee.object.name !== "vi" && callee.object.name !== "jest") + ) { + return undefined; + } + + const method = callee.computed + ? isStringLiteral(callee.property) + ? callee.property.value + : undefined + : callee.property.type === "Identifier" + ? callee.property.name + : undefined; + if (!method || !moduleMockMethods.has(method)) return undefined; + + const [source] = node.arguments; + return source && isStringLiteral(source) ? source : undefined; +} + +export const noForbiddenLayerImportsRule = defineRule({ + meta: { + type: "problem", + docs: { + description: + "Keep production dependencies directed away from agent and web ownership toward shared contracts and persistence.", + }, + messages: { + forbiddenImport: + "{{owner}} cannot import {{dependency}} under the repository dependency direction.", + }, + schema: [], + }, + createOnce(context) { + let repositoryRoot = ""; + let importer = ""; + let owner: ProductionLayer | undefined; + + const checkImport = (node: ESTree.Node, source: string) => { + if (!owner) return; + const dependency = importedProductionLayer( + importer, + source, + repositoryRoot + ); + if (!dependency || !forbiddenDependencies[owner].has(dependency)) return; + + context.report({ + node, + messageId: "forbiddenImport", + data: { owner, dependency }, + }); + }; + + return { + before() { + repositoryRoot = path.resolve(context.cwd); + importer = path.resolve(context.filename); + owner = productionLayerForPath(importer, repositoryRoot); + }, + ExportAllDeclaration(node) { + checkImport(node.source, node.source.value); + }, + ExportNamedDeclaration(node) { + if (node.source) checkImport(node.source, node.source.value); + }, + ImportDeclaration(node) { + checkImport(node.source, node.source.value); + }, + ImportExpression(node) { + if (isStringLiteral(node.source)) { + checkImport(node.source, node.source.value); + } + }, + CallExpression(node) { + const source = moduleMockSource(node); + if (source && isStringLiteral(source)) { + checkImport(source, source.value); + } + }, + }; + }, +}); diff --git a/tools/oxlint/architecture/tests/oxlint-architecture-plugin.test.ts b/tools/oxlint/architecture/tests/oxlint-architecture-plugin.test.ts new file mode 100644 index 00000000..0d0f3cb0 --- /dev/null +++ b/tools/oxlint/architecture/tests/oxlint-architecture-plugin.test.ts @@ -0,0 +1,102 @@ +import assert from "node:assert/strict"; +import { RuleTester } from "oxlint/plugins-dev"; +import { test } from "vitest"; +import plugin from "@tools/oxlint/architecture/index.ts"; +import { noForbiddenLayerImportsRule } from "@tools/oxlint/architecture/rules/no-forbidden-layer-imports.ts"; + +const tester = new RuleTester(); +const repositoryRoot = "/repo"; + +test("exports the repository architecture rules", () => { + assert.deepEqual(Object.keys(plugin.rules), ["no-forbidden-layer-imports"]); +}); + +tester.run( + "local-architecture/no-forbidden-layer-imports", + noForbiddenLayerImportsRule, + { + valid: [ + { + code: 'import "@db/services/chats"; import "@shared/chat/schema";', + cwd: repositoryRoot, + filename: "/repo/agent/tool.ts", + }, + { + code: 'import "@web/components/ui/button"; import "@db";', + cwd: repositoryRoot, + filename: "/repo/app/page.tsx", + }, + { + code: 'import "@db/services/chats"; import "@shared/chat/schema";', + cwd: repositoryRoot, + filename: "/repo/web/trpc.ts", + }, + { + code: 'import "@db/services/chats";', + cwd: repositoryRoot, + filename: "/repo/proxy.ts", + }, + { + code: 'import "@agent/agent";', + cwd: repositoryRoot, + filename: "/repo/evals/agent/agent.eval.ts", + }, + ], + invalid: [ + { + code: 'import "@web/browser/activity";', + cwd: repositoryRoot, + filename: "/repo/agent/tool.ts", + errors: [{ messageId: "forbiddenImport" }], + }, + { + code: 'import value from "../agent/value"; void value;', + cwd: repositoryRoot, + filename: "/repo/db/service.ts", + errors: [{ messageId: "forbiddenImport" }], + }, + { + code: 'export { tool } from "@agent/tool";', + cwd: repositoryRoot, + filename: "/repo/app/page.tsx", + errors: [{ messageId: "forbiddenImport" }], + }, + { + code: 'void import("@db/services/chats");', + cwd: repositoryRoot, + filename: "/repo/shared/chat/schema.ts", + errors: [{ messageId: "forbiddenImport" }], + }, + { + code: 'vi.mock("@agent/agent");', + cwd: repositoryRoot, + filename: "/repo/web/auth/auth.test.ts", + errors: [{ messageId: "forbiddenImport" }], + }, + { + code: 'vi.doMock("@shared/../agent/agent");', + cwd: repositoryRoot, + filename: "/repo/app/page.test.ts", + errors: [{ messageId: "forbiddenImport" }], + }, + { + code: 'import "@shared//../agent/agent";', + cwd: repositoryRoot, + filename: "/repo/app/page.ts", + errors: [{ messageId: "forbiddenImport" }], + }, + { + code: 'jest.unstable_mockModule("@web/../agent/agent", () => ({}));', + cwd: repositoryRoot, + filename: "/repo/db/service.test.ts", + errors: [{ messageId: "forbiddenImport" }], + }, + { + code: 'import "@agent/agent";', + cwd: repositoryRoot, + filename: "/repo/proxy.ts", + errors: [{ messageId: "forbiddenImport" }], + }, + ], + } +); diff --git a/tools/oxlint/next/helpers/next-app-router.ts b/tools/oxlint/next/helpers/next-app-router.ts index 0eb9bd7a..60571e4b 100644 --- a/tools/oxlint/next/helpers/next-app-router.ts +++ b/tools/oxlint/next/helpers/next-app-router.ts @@ -126,8 +126,11 @@ export const resolveLocalImport = ( source: string, sourceDirectory: string ): string | undefined => { - if (source.startsWith("@/")) { - return normalizePath(path.join(sourceDirectory, source.slice(2))); + const alias = /^@(agent|app|db|evals|shared|tests|tools|web)\/(.+)$/u.exec( + source + ); + if (alias?.[1] && alias[2]) { + return normalizePath(path.join(sourceDirectory, alias[1], alias[2])); } if (source.startsWith(".")) { diff --git a/tools/oxlint/next/tests/oxlint-next-plugin.test.ts b/tools/oxlint/next/tests/oxlint-next-plugin.test.ts index 2d27db08..b6dac3d6 100644 --- a/tools/oxlint/next/tests/oxlint-next-plugin.test.ts +++ b/tools/oxlint/next/tests/oxlint-next-plugin.test.ts @@ -4,11 +4,11 @@ import os from "node:os"; import path from "node:path"; import { RuleTester } from "oxlint/plugins-dev"; import { test } from "vitest"; -import plugin from "@/tools/oxlint/next/index.ts"; -import { noRoutePrivateImportsRule } from "@/tools/oxlint/next/rules/no-route-private-imports.ts"; -import { preferNearestRoutePrivateOwnerRule } from "@/tools/oxlint/next/rules/prefer-nearest-route-private-owner.ts"; -import { requireGeneratedRoutePropsRule } from "@/tools/oxlint/next/rules/require-generated-route-props.ts"; -import { requirePageRouteGroupRule } from "@/tools/oxlint/next/rules/require-page-route-group.ts"; +import plugin from "@tools/oxlint/next/index.ts"; +import { noRoutePrivateImportsRule } from "@tools/oxlint/next/rules/no-route-private-imports.ts"; +import { preferNearestRoutePrivateOwnerRule } from "@tools/oxlint/next/rules/prefer-nearest-route-private-owner.ts"; +import { requireGeneratedRoutePropsRule } from "@tools/oxlint/next/rules/require-generated-route-props.ts"; +import { requirePageRouteGroupRule } from "@tools/oxlint/next/rules/require-page-route-group.ts"; const tester = new RuleTester(); @@ -39,7 +39,7 @@ tester.run("local-next/no-route-private-imports", noRoutePrivateImportsRule, { ], invalid: [ { - code: 'import "../account/_components/card";', + code: 'import "@app/account/_components/card";', cwd: privateImportRoot, filename: path.join(privateImportRoot, "app/admin/page.tsx"), before() { diff --git a/tsconfig.json b/tsconfig.json index 38f79421..ef5f820f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,7 +23,16 @@ } ], "paths": { - "@/*": ["./src/*", "./*"] + "@agent/*": ["./agent/*"], + "@app/*": ["./app/*"], + "@db": ["./db/index.ts"], + "@db/*": ["./db/*"], + "@evals/*": ["./evals/*"], + "@shared/environment": ["./shared/environment/env.ts"], + "@shared/*": ["./shared/*"], + "@tests/*": ["./tests/*"], + "@tools/*": ["./tools/*"], + "@web/*": ["./web/*"] } }, "include": [ diff --git a/vitest.config.ts b/vitest.config.ts index 85f9c682..ebb1a930 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -11,17 +11,21 @@ export default defineConfig({ ), }, { - find: "@/env", - replacement: fileURLToPath(new URL("src/env.ts", import.meta.url)), + find: /^@db$/u, + replacement: fileURLToPath(new URL("db/index.ts", import.meta.url)), }, { - find: /^@\/(app|auth|components|hooks|lib|trpc)(\/.*)?$/, - replacement: fileURLToPath(new URL("src/$1$2", import.meta.url)), - }, - { - find: "@", - replacement: fileURLToPath(new URL(".", import.meta.url)), + find: /^@shared\/environment$/u, + replacement: fileURLToPath( + new URL("shared/environment/env.ts", import.meta.url) + ), }, + ...["agent", "app", "db", "evals", "shared", "tests", "tools", "web"].map( + (owner) => ({ + find: new RegExp(`^@${owner}/(.*)$`, "u"), + replacement: fileURLToPath(new URL(`${owner}/$1`, import.meta.url)), + }) + ), ], }, test: { diff --git a/src/app/_lib/auth-client.ts b/web/auth/client.ts similarity index 100% rename from src/app/_lib/auth-client.ts rename to web/auth/client.ts diff --git a/src/lib/request-scope.ts b/web/auth/request-scope.ts similarity index 75% rename from src/lib/request-scope.ts rename to web/auth/request-scope.ts index 51aba12c..5a21b7a7 100644 --- a/src/lib/request-scope.ts +++ b/web/auth/request-scope.ts @@ -1,7 +1,10 @@ import { headers } from "next/headers"; import { cache } from "react"; -import { getAuthSession } from "@/auth/session"; -import { accessScopeForUser, type AccessScope } from "@/lib/access-scope"; +import { getAuthSession } from "@db/services/auth/session"; +import { + accessScopeForUser, + type AccessScope, +} from "@shared/identity/access-scope"; export const requireRequestScope = cache(async (): Promise => { const session = await getAuthSession(await headers()); diff --git a/src/auth/tests/proxy.test.ts b/web/auth/tests/proxy.test.ts similarity index 90% rename from src/auth/tests/proxy.test.ts rename to web/auth/tests/proxy.test.ts index c2514699..58f6520d 100644 --- a/src/auth/tests/proxy.test.ts +++ b/web/auth/tests/proxy.test.ts @@ -1,14 +1,14 @@ import { unstable_doesMiddlewareMatch } from "next/experimental/testing/server"; import { NextRequest } from "next/server"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import { getAuthSession } from "@/auth/session"; -import { config, proxy } from "../../proxy"; +import { getAuthSession } from "@db/services/auth/session"; +import { config, proxy } from "../../../proxy"; const mocks = vi.hoisted(() => ({ getAuthSession: vi.fn(), })); -vi.mock("@/auth/session", () => ({ +vi.mock("@db/services/auth/session", () => ({ getAuthSession: mocks.getAuthSession, })); diff --git a/src/lib/browser-activity.ts b/web/browser/activity.ts similarity index 100% rename from src/lib/browser-activity.ts rename to web/browser/activity.ts diff --git a/src/components/ai-elements/conversation.tsx b/web/components/ai-elements/conversation.tsx similarity index 98% rename from src/components/ai-elements/conversation.tsx rename to web/components/ai-elements/conversation.tsx index 8279b7e2..d53d8563 100644 --- a/src/components/ai-elements/conversation.tsx +++ b/web/components/ai-elements/conversation.tsx @@ -1,7 +1,7 @@ "use client"; -import { Button } from "@/components/ui/button"; -import { cn } from "@/lib/utils"; +import { Button } from "@web/components/ui/button"; +import { cn } from "@web/components/class-names"; import type { UIMessage } from "ai"; import { ArrowDownIcon, DownloadIcon } from "lucide-react"; import type { ComponentProps } from "react"; diff --git a/src/components/ai-elements/message.tsx b/web/components/ai-elements/message.tsx similarity index 97% rename from src/components/ai-elements/message.tsx rename to web/components/ai-elements/message.tsx index 170d9ef8..5bf2ab7c 100644 --- a/src/components/ai-elements/message.tsx +++ b/web/components/ai-elements/message.tsx @@ -1,14 +1,14 @@ "use client"; -import { Button } from "@/components/ui/button"; -import { ButtonGroup, ButtonGroupText } from "@/components/ui/button-group"; +import { Button } from "@web/components/ui/button"; +import { ButtonGroup, ButtonGroupText } from "@web/components/ui/button-group"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, -} from "@/components/ui/tooltip"; -import { cn } from "@/lib/utils"; +} from "@web/components/ui/tooltip"; +import { cn } from "@web/components/class-names"; import { cjk } from "@streamdown/cjk"; import { code } from "@streamdown/code"; import { math } from "@streamdown/math"; @@ -28,7 +28,7 @@ import { } from "react"; import { Streamdown, type Components } from "streamdown"; import { z } from "zod"; -import { isBrowserImageArtifactUrl } from "@/lib/browser-artifact"; +import { isBrowserImageArtifactUrl } from "@shared/browser/artifact"; export type MessageProps = HTMLAttributes & { from: UIMessage["role"]; diff --git a/src/components/ai-elements/model-selector.tsx b/web/components/ai-elements/model-selector.tsx similarity index 95% rename from src/components/ai-elements/model-selector.tsx rename to web/components/ai-elements/model-selector.tsx index 0adc13b5..83ec1136 100644 --- a/src/components/ai-elements/model-selector.tsx +++ b/web/components/ai-elements/model-selector.tsx @@ -9,14 +9,14 @@ import { CommandItem, CommandList, CommandShortcut, -} from "@/components/ui/command"; +} from "@web/components/ui/command"; import { Dialog, DialogContent, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog"; -import { cn } from "@/lib/utils"; +} from "@web/components/ui/dialog"; +import { cn } from "@web/components/class-names"; export function ModelSelector(props: ComponentProps) { return ; diff --git a/src/components/ai-elements/prompt-input.tsx b/web/components/ai-elements/prompt-input.tsx similarity index 99% rename from src/components/ai-elements/prompt-input.tsx rename to web/components/ai-elements/prompt-input.tsx index 6ccfeb64..fc1e0612 100644 --- a/src/components/ai-elements/prompt-input.tsx +++ b/web/components/ai-elements/prompt-input.tsx @@ -8,38 +8,38 @@ import { CommandItem, CommandList, CommandSeparator, -} from "@/components/ui/command"; +} from "@web/components/ui/command"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; +} from "@web/components/ui/dropdown-menu"; import { HoverCard, HoverCardContent, HoverCardTrigger, -} from "@/components/ui/hover-card"; +} from "@web/components/ui/hover-card"; import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupTextarea, -} from "@/components/ui/input-group"; +} from "@web/components/ui/input-group"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import { Spinner } from "@/components/ui/spinner"; +} from "@web/components/ui/select"; +import { Spinner } from "@web/components/ui/spinner"; import { Tooltip, TooltipContent, TooltipTrigger, -} from "@/components/ui/tooltip"; -import { cn } from "@/lib/utils"; +} from "@web/components/ui/tooltip"; +import { cn } from "@web/components/class-names"; import type { ChatStatus, FileUIPart, SourceDocumentUIPart } from "ai"; import { CornerDownLeftIcon, diff --git a/src/components/ai-elements/question.tsx b/web/components/ai-elements/question.tsx similarity index 97% rename from src/components/ai-elements/question.tsx rename to web/components/ai-elements/question.tsx index 182ee7ed..f8c98aa7 100644 --- a/src/components/ai-elements/question.tsx +++ b/web/components/ai-elements/question.tsx @@ -8,9 +8,9 @@ import type { SubmitEvent, } from "react"; -import { Button } from "@/components/ui/button"; -import { Textarea } from "@/components/ui/textarea"; -import { cn } from "@/lib/utils"; +import { Button } from "@web/components/ui/button"; +import { Textarea } from "@web/components/ui/textarea"; +import { cn } from "@web/components/class-names"; import { createContext, useCallback, diff --git a/src/components/ai-elements/reasoning.tsx b/web/components/ai-elements/reasoning.tsx similarity index 98% rename from src/components/ai-elements/reasoning.tsx rename to web/components/ai-elements/reasoning.tsx index 99bd4cb1..59c7a345 100644 --- a/src/components/ai-elements/reasoning.tsx +++ b/web/components/ai-elements/reasoning.tsx @@ -4,8 +4,8 @@ import { Collapsible, CollapsibleContent, CollapsibleTrigger, -} from "@/components/ui/collapsible"; -import { cn } from "@/lib/utils"; +} from "@web/components/ui/collapsible"; +import { cn } from "@web/components/class-names"; import { cjk } from "@streamdown/cjk"; import { code } from "@streamdown/code"; import { math } from "@streamdown/math"; diff --git a/src/components/ai-elements/shimmer.tsx b/web/components/ai-elements/shimmer.tsx similarity index 97% rename from src/components/ai-elements/shimmer.tsx rename to web/components/ai-elements/shimmer.tsx index 3acc74b1..1dd0eeda 100644 --- a/src/components/ai-elements/shimmer.tsx +++ b/web/components/ai-elements/shimmer.tsx @@ -2,7 +2,7 @@ /* oxlint-disable hooks/static-components -- AI Elements supports a caller-selected intrinsic motion element. */ -import { cn } from "@/lib/utils"; +import { cn } from "@web/components/class-names"; import { LazyMotion, domAnimation, m } from "motion/react"; import { type ElementType, memo, useMemo } from "react"; diff --git a/src/components/ai-elements/tests/message-response.test.tsx b/web/components/ai-elements/tests/message-response.test.tsx similarity index 97% rename from src/components/ai-elements/tests/message-response.test.tsx rename to web/components/ai-elements/tests/message-response.test.tsx index 0b9a98c5..7d9a8547 100644 --- a/src/components/ai-elements/tests/message-response.test.tsx +++ b/web/components/ai-elements/tests/message-response.test.tsx @@ -4,7 +4,7 @@ import { renderToStaticMarkup } from "react-dom/server"; import { ArtifactMessageImage, MessageResponse, -} from "@/components/ai-elements/message"; +} from "@web/components/ai-elements/message"; describe("message response rendering", () => { it("uses the synchronous renderer for settled text", () => { diff --git a/src/components/ai-elements/tests/prompt-input.test.tsx b/web/components/ai-elements/tests/prompt-input.test.tsx similarity index 98% rename from src/components/ai-elements/tests/prompt-input.test.tsx rename to web/components/ai-elements/tests/prompt-input.test.tsx index 5aa61f78..9e12a01c 100644 --- a/src/components/ai-elements/tests/prompt-input.test.tsx +++ b/web/components/ai-elements/tests/prompt-input.test.tsx @@ -65,7 +65,7 @@ import { PromptInputFooter, PromptInputSubmit, PromptInputTextarea, -} from "@/components/ai-elements/prompt-input"; +} from "@web/components/ai-elements/prompt-input"; describe("prompt input", () => { it("anchors the compact submit button without dropping footer children", () => { diff --git a/src/components/ai-elements/tool.tsx b/web/components/ai-elements/tool.tsx similarity index 98% rename from src/components/ai-elements/tool.tsx rename to web/components/ai-elements/tool.tsx index 4d037f94..78f7b127 100644 --- a/src/components/ai-elements/tool.tsx +++ b/web/components/ai-elements/tool.tsx @@ -4,8 +4,8 @@ import { Collapsible, CollapsibleContent, CollapsibleTrigger, -} from "@/components/ui/collapsible"; -import { cn } from "@/lib/utils"; +} from "@web/components/ui/collapsible"; +import { cn } from "@web/components/class-names"; import type { DynamicToolUIPart } from "ai"; import { CheckCircleIcon, diff --git a/src/components/browser/activity-duration-breakdown.tsx b/web/components/browser/activity-duration-breakdown.tsx similarity index 98% rename from src/components/browser/activity-duration-breakdown.tsx rename to web/components/browser/activity-duration-breakdown.tsx index a1f6f066..19470d67 100644 --- a/src/components/browser/activity-duration-breakdown.tsx +++ b/web/components/browser/activity-duration-breakdown.tsx @@ -2,7 +2,7 @@ import { browserActivityKinds, type BrowserActivityDurations, type BrowserActivityKind, -} from "@/lib/browser-activity"; +} from "@web/browser/activity"; const activityPresentation: Record< BrowserActivityKind, diff --git a/src/lib/utils.ts b/web/components/class-names.ts similarity index 100% rename from src/lib/utils.ts rename to web/components/class-names.ts diff --git a/src/components/ui/alert.tsx b/web/components/ui/alert.tsx similarity index 98% rename from src/components/ui/alert.tsx rename to web/components/ui/alert.tsx index 7c6e9ce3..875b3466 100644 --- a/src/components/ui/alert.tsx +++ b/web/components/ui/alert.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils"; +import { cn } from "@web/components/class-names"; const alertVariants = cva( "group/alert type-supporting-body relative grid w-full gap-0.5 rounded-lg border px-2.5 py-2 text-left has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4", diff --git a/src/components/ui/badge.tsx b/web/components/ui/badge.tsx similarity index 97% rename from src/components/ui/badge.tsx rename to web/components/ui/badge.tsx index 3f83ae18..9f6aca04 100644 --- a/src/components/ui/badge.tsx +++ b/web/components/ui/badge.tsx @@ -2,7 +2,7 @@ import { mergeProps } from "@base-ui/react/merge-props"; import { useRender } from "@base-ui/react/use-render"; import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils"; +import { cn } from "@web/components/class-names"; const badgeVariants = cva( "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 type-caption whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!", diff --git a/src/components/ui/button-group.tsx b/web/components/ui/button-group.tsx similarity index 95% rename from src/components/ui/button-group.tsx rename to web/components/ui/button-group.tsx index b939dc87..ce735962 100644 --- a/src/components/ui/button-group.tsx +++ b/web/components/ui/button-group.tsx @@ -2,8 +2,8 @@ import { mergeProps } from "@base-ui/react/merge-props"; import { useRender } from "@base-ui/react/use-render"; import { cva, type VariantProps } from "class-variance-authority"; -import { Separator } from "@/components/ui/separator"; -import { cn } from "@/lib/utils"; +import { Separator } from "@web/components/ui/separator"; +import { cn } from "@web/components/class-names"; const buttonGroupVariants = cva( "type-label flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-lg [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1", diff --git a/src/components/ui/button.tsx b/web/components/ui/button.tsx similarity index 98% rename from src/components/ui/button.tsx rename to web/components/ui/button.tsx index 11b0ca21..a3459641 100644 --- a/src/components/ui/button.tsx +++ b/web/components/ui/button.tsx @@ -1,7 +1,7 @@ import { Button as ButtonPrimitive } from "@base-ui/react/button"; import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils"; +import { cn } from "@web/components/class-names"; const buttonVariants = cva( "group/button inline-flex shrink-0 cursor-pointer items-center justify-center rounded-lg border bg-clip-padding whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px motion-reduce:transition-none motion-reduce:active:translate-y-0 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", diff --git a/src/components/ui/card.tsx b/web/components/ui/card.tsx similarity index 98% rename from src/components/ui/card.tsx rename to web/components/ui/card.tsx index e5e580e4..dca39100 100644 --- a/src/components/ui/card.tsx +++ b/web/components/ui/card.tsx @@ -1,6 +1,6 @@ import * as React from "react"; -import { cn } from "@/lib/utils"; +import { cn } from "@web/components/class-names"; function Card({ className, diff --git a/src/components/ui/collapsible.tsx b/web/components/ui/collapsible.tsx similarity index 100% rename from src/components/ui/collapsible.tsx rename to web/components/ui/collapsible.tsx diff --git a/src/components/ui/command.tsx b/web/components/ui/command.tsx similarity index 96% rename from src/components/ui/command.tsx rename to web/components/ui/command.tsx index bf61a69f..2a19996d 100644 --- a/src/components/ui/command.tsx +++ b/web/components/ui/command.tsx @@ -10,9 +10,9 @@ import { DialogDescription, DialogHeader, DialogTitle, -} from "@/components/ui/dialog"; -import { InputGroup, InputGroupAddon } from "@/components/ui/input-group"; -import { cn } from "@/lib/utils"; +} from "@web/components/ui/dialog"; +import { InputGroup, InputGroupAddon } from "@web/components/ui/input-group"; +import { cn } from "@web/components/class-names"; function Command({ className, diff --git a/src/components/ui/dialog.tsx b/web/components/ui/dialog.tsx similarity index 98% rename from src/components/ui/dialog.tsx rename to web/components/ui/dialog.tsx index 17ba6ac2..1b060751 100644 --- a/src/components/ui/dialog.tsx +++ b/web/components/ui/dialog.tsx @@ -5,8 +5,8 @@ import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"; import { cva, type VariantProps } from "class-variance-authority"; import { XIcon } from "lucide-react"; -import { cn } from "@/lib/utils"; -import { Button } from "@/components/ui/button"; +import { cn } from "@web/components/class-names"; +import { Button } from "@web/components/ui/button"; function Dialog({ ...props }: DialogPrimitive.Root.Props) { return ; diff --git a/src/components/ui/dropdown-menu.tsx b/web/components/ui/dropdown-menu.tsx similarity index 99% rename from src/components/ui/dropdown-menu.tsx rename to web/components/ui/dropdown-menu.tsx index 01612479..b1e56e0d 100644 --- a/src/components/ui/dropdown-menu.tsx +++ b/web/components/ui/dropdown-menu.tsx @@ -4,7 +4,7 @@ import * as React from "react"; import { Menu as MenuPrimitive } from "@base-ui/react/menu"; import { CheckIcon, ChevronRightIcon } from "lucide-react"; -import { cn } from "@/lib/utils"; +import { cn } from "@web/components/class-names"; function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) { return ; diff --git a/src/components/ui/field.tsx b/web/components/ui/field.tsx similarity index 97% rename from src/components/ui/field.tsx rename to web/components/ui/field.tsx index 6a4951a2..63fd7b6a 100644 --- a/src/components/ui/field.tsx +++ b/web/components/ui/field.tsx @@ -3,9 +3,9 @@ import { useMemo } from "react"; import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils"; -import { Label } from "@/components/ui/label"; -import { Separator } from "@/components/ui/separator"; +import { cn } from "@web/components/class-names"; +import { Label } from "@web/components/ui/label"; +import { Separator } from "@web/components/ui/separator"; function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) { return ( diff --git a/src/components/ui/hover-card.tsx b/web/components/ui/hover-card.tsx similarity index 97% rename from src/components/ui/hover-card.tsx rename to web/components/ui/hover-card.tsx index 21d82ff2..ab449803 100644 --- a/src/components/ui/hover-card.tsx +++ b/web/components/ui/hover-card.tsx @@ -2,7 +2,7 @@ import { PreviewCard as PreviewCardPrimitive } from "@base-ui/react/preview-card"; -import { cn } from "@/lib/utils"; +import { cn } from "@web/components/class-names"; function HoverCard({ ...props }: PreviewCardPrimitive.Root.Props) { return ; diff --git a/src/components/ui/input-group.tsx b/web/components/ui/input-group.tsx similarity index 96% rename from src/components/ui/input-group.tsx rename to web/components/ui/input-group.tsx index d2a1d4fd..5ee69548 100644 --- a/src/components/ui/input-group.tsx +++ b/web/components/ui/input-group.tsx @@ -3,10 +3,10 @@ import * as React from "react"; import { cva, type VariantProps } from "class-variance-authority"; -import { Button, type ButtonProps } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Textarea } from "@/components/ui/textarea"; -import { cn } from "@/lib/utils"; +import { Button, type ButtonProps } from "@web/components/ui/button"; +import { Input } from "@web/components/ui/input"; +import { Textarea } from "@web/components/ui/textarea"; +import { cn } from "@web/components/class-names"; const inputGroupVariants = cva( "group/input-group relative flex w-full min-w-0 items-center rounded-lg border border-input transition-colors outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-disabled:bg-input/50 has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto dark:bg-input/30 dark:has-disabled:bg-input/80 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5", diff --git a/src/components/ui/input.tsx b/web/components/ui/input.tsx similarity index 97% rename from src/components/ui/input.tsx rename to web/components/ui/input.tsx index 473f8d38..2fae59f9 100644 --- a/src/components/ui/input.tsx +++ b/web/components/ui/input.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import { Input as InputPrimitive } from "@base-ui/react/input"; import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils"; +import { cn } from "@web/components/class-names"; const inputVariants = cva( "type-input h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:type-label file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40", diff --git a/src/components/ui/label.tsx b/web/components/ui/label.tsx similarity index 96% rename from src/components/ui/label.tsx rename to web/components/ui/label.tsx index b7393e51..caa221e8 100644 --- a/src/components/ui/label.tsx +++ b/web/components/ui/label.tsx @@ -4,7 +4,7 @@ import * as React from "react"; import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils"; +import { cn } from "@web/components/class-names"; const labelVariants = cva( "type-label flex items-center gap-2 select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50", diff --git a/src/components/ui/logo.tsx b/web/components/ui/logo.tsx similarity index 100% rename from src/components/ui/logo.tsx rename to web/components/ui/logo.tsx diff --git a/src/components/ui/select.tsx b/web/components/ui/select.tsx similarity index 99% rename from src/components/ui/select.tsx rename to web/components/ui/select.tsx index e5ca26c4..cc5d3252 100644 --- a/src/components/ui/select.tsx +++ b/web/components/ui/select.tsx @@ -5,7 +5,7 @@ import { Select as SelectPrimitive } from "@base-ui/react/select"; import { cva, type VariantProps } from "class-variance-authority"; import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"; -import { cn } from "@/lib/utils"; +import { cn } from "@web/components/class-names"; const Select = SelectPrimitive.Root; diff --git a/src/components/ui/separator.tsx b/web/components/ui/separator.tsx similarity index 95% rename from src/components/ui/separator.tsx rename to web/components/ui/separator.tsx index 4893f7f7..8b18fb3e 100644 --- a/src/components/ui/separator.tsx +++ b/web/components/ui/separator.tsx @@ -3,7 +3,7 @@ import { Separator as SeparatorPrimitive } from "@base-ui/react/separator"; import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils"; +import { cn } from "@web/components/class-names"; const separatorVariants = cva( "shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch", diff --git a/src/components/ui/sheet.tsx b/web/components/ui/sheet.tsx similarity index 97% rename from src/components/ui/sheet.tsx rename to web/components/ui/sheet.tsx index 5a581791..18042fa6 100644 --- a/src/components/ui/sheet.tsx +++ b/web/components/ui/sheet.tsx @@ -4,8 +4,8 @@ import * as React from "react"; import { Dialog as SheetPrimitive } from "@base-ui/react/dialog"; import { XIcon } from "lucide-react"; -import { cn } from "@/lib/utils"; -import { Button } from "@/components/ui/button"; +import { cn } from "@web/components/class-names"; +import { Button } from "@web/components/ui/button"; function Sheet({ ...props }: SheetPrimitive.Root.Props) { return ; diff --git a/src/components/ui/sidebar.tsx b/web/components/ui/sidebar.tsx similarity index 98% rename from src/components/ui/sidebar.tsx rename to web/components/ui/sidebar.tsx index 97561615..b5023d2f 100644 --- a/src/components/ui/sidebar.tsx +++ b/web/components/ui/sidebar.tsx @@ -7,24 +7,24 @@ import { mergeProps } from "@base-ui/react/merge-props"; import { useRender } from "@base-ui/react/use-render"; import { cva, type VariantProps } from "class-variance-authority"; -import { useIsMobile } from "@/hooks/use-mobile"; -import { cn } from "@/lib/utils"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Separator } from "@/components/ui/separator"; +import { useIsMobile } from "@web/hooks/use-mobile"; +import { cn } from "@web/components/class-names"; +import { Button } from "@web/components/ui/button"; +import { Input } from "@web/components/ui/input"; +import { Separator } from "@web/components/ui/separator"; import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, -} from "@/components/ui/sheet"; -import { Skeleton } from "@/components/ui/skeleton"; +} from "@web/components/ui/sheet"; +import { Skeleton } from "@web/components/ui/skeleton"; import { Tooltip, TooltipContent, TooltipTrigger, -} from "@/components/ui/tooltip"; +} from "@web/components/ui/tooltip"; import { PanelLeftIcon } from "lucide-react"; import { z } from "zod"; diff --git a/src/components/ui/skeleton.tsx b/web/components/ui/skeleton.tsx similarity index 84% rename from src/components/ui/skeleton.tsx rename to web/components/ui/skeleton.tsx index 4a665677..0109d26b 100644 --- a/src/components/ui/skeleton.tsx +++ b/web/components/ui/skeleton.tsx @@ -1,6 +1,6 @@ import * as React from "react"; -import { cn } from "@/lib/utils"; +import { cn } from "@web/components/class-names"; function Skeleton({ className, ...props }: React.ComponentProps<"div">) { return ( diff --git a/src/components/ui/spinner.tsx b/web/components/ui/spinner.tsx similarity index 85% rename from src/components/ui/spinner.tsx rename to web/components/ui/spinner.tsx index ffdaed5e..a4424da2 100644 --- a/src/components/ui/spinner.tsx +++ b/web/components/ui/spinner.tsx @@ -1,6 +1,6 @@ import { Loader2Icon } from "lucide-react"; -import { cn } from "@/lib/utils"; +import { cn } from "@web/components/class-names"; function Spinner({ className, ...props }: React.ComponentProps<"svg">) { return ( diff --git a/src/components/ui/switch.tsx b/web/components/ui/switch.tsx similarity index 97% rename from src/components/ui/switch.tsx rename to web/components/ui/switch.tsx index 78c251b2..782b57ae 100644 --- a/src/components/ui/switch.tsx +++ b/web/components/ui/switch.tsx @@ -2,7 +2,7 @@ import { Switch as SwitchPrimitive } from "@base-ui/react/switch"; -import { cn } from "@/lib/utils"; +import { cn } from "@web/components/class-names"; function Switch({ className, diff --git a/src/components/ui/table.tsx b/web/components/ui/table.tsx similarity index 98% rename from src/components/ui/table.tsx rename to web/components/ui/table.tsx index 32042e57..c6ea611b 100644 --- a/src/components/ui/table.tsx +++ b/web/components/ui/table.tsx @@ -3,7 +3,7 @@ import * as React from "react"; import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils"; +import { cn } from "@web/components/class-names"; function Table({ className, ...props }: React.ComponentProps<"table">) { return ( diff --git a/src/components/ui/textarea.tsx b/web/components/ui/textarea.tsx similarity index 96% rename from src/components/ui/textarea.tsx rename to web/components/ui/textarea.tsx index b28ea199..4afdfd6b 100644 --- a/src/components/ui/textarea.tsx +++ b/web/components/ui/textarea.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils"; +import { cn } from "@web/components/class-names"; const textareaVariants = cva( "type-input flex field-sizing-content min-h-16 w-full rounded-lg border border-input bg-transparent px-2.5 py-2 transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40", diff --git a/src/components/ui/tooltip.tsx b/web/components/ui/tooltip.tsx similarity index 98% rename from src/components/ui/tooltip.tsx rename to web/components/ui/tooltip.tsx index fee1cc38..19df9e26 100644 --- a/src/components/ui/tooltip.tsx +++ b/web/components/ui/tooltip.tsx @@ -2,7 +2,7 @@ import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip"; -import { cn } from "@/lib/utils"; +import { cn } from "@web/components/class-names"; function TooltipProvider({ delay = 0, diff --git a/src/hooks/use-mobile.ts b/web/hooks/use-mobile.ts similarity index 100% rename from src/hooks/use-mobile.ts rename to web/hooks/use-mobile.ts diff --git a/src/trpc/client.tsx b/web/trpc/client.tsx similarity index 100% rename from src/trpc/client.tsx rename to web/trpc/client.tsx diff --git a/src/trpc/context.ts b/web/trpc/context.ts similarity index 58% rename from src/trpc/context.ts rename to web/trpc/context.ts index fb33f775..03896d67 100644 --- a/src/trpc/context.ts +++ b/web/trpc/context.ts @@ -1,4 +1,4 @@ -import type { AccessScope } from "@/lib/access-scope"; +import type { AccessScope } from "@shared/identity/access-scope"; export interface TRPCContext { readonly origin: string; diff --git a/src/trpc/http-context.test.ts b/web/trpc/http-context.test.ts similarity index 95% rename from src/trpc/http-context.test.ts rename to web/trpc/http-context.test.ts index df8cfaf8..b91a654c 100644 --- a/src/trpc/http-context.test.ts +++ b/web/trpc/http-context.test.ts @@ -1,6 +1,6 @@ import type { TRPCError } from "@trpc/server"; import { describe, expect, it, vi } from "vitest"; -import { UnauthenticatedError } from "@/lib/request-scope"; +import { UnauthenticatedError } from "@web/auth/request-scope"; import { createHTTPContext } from "./http-context"; describe("createHTTPContext", () => { diff --git a/src/trpc/http-context.ts b/web/trpc/http-context.ts similarity index 77% rename from src/trpc/http-context.ts rename to web/trpc/http-context.ts index 910a7c99..f1ade901 100644 --- a/src/trpc/http-context.ts +++ b/web/trpc/http-context.ts @@ -1,6 +1,9 @@ import { TRPCError } from "@trpc/server"; -import { requireRequestScope, UnauthenticatedError } from "@/lib/request-scope"; -import { isSameOrigin } from "@/lib/same-origin"; +import { + requireRequestScope, + UnauthenticatedError, +} from "@web/auth/request-scope"; +import { isSameOrigin } from "@web/trpc/same-origin"; export async function createHTTPContext( request: Request, diff --git a/src/trpc/init.ts b/web/trpc/init.ts similarity index 100% rename from src/trpc/init.ts rename to web/trpc/init.ts diff --git a/src/trpc/router.test.ts b/web/trpc/router.test.ts similarity index 86% rename from src/trpc/router.test.ts rename to web/trpc/router.test.ts index 81085b9d..4d5df850 100644 --- a/src/trpc/router.test.ts +++ b/web/trpc/router.test.ts @@ -1,7 +1,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -import * as BrowserTraces from "@/db/services/browser-traces"; -import * as Chats from "@/db/services/chats"; -import type { AccessScope } from "@/lib/access-scope"; +import * as BrowserTraces from "@db/services/browser-traces"; +import * as Chats from "@db/services/chats"; +import type { AccessScope } from "@shared/identity/access-scope"; import { appRouter } from "./router"; const listBrowserTracesMock = vi.spyOn(BrowserTraces, "listBrowserTraces"); diff --git a/src/trpc/router.ts b/web/trpc/router.ts similarity index 85% rename from src/trpc/router.ts rename to web/trpc/router.ts index 62ce8846..a212069c 100644 --- a/src/trpc/router.ts +++ b/web/trpc/router.ts @@ -1,20 +1,23 @@ import { gateway } from "ai"; import { revokeToken, startAuthorization } from "@vercel/connect"; import { z } from "zod"; -import { listBrowserTraces } from "@/db/services/browser-traces"; -import { saveChat } from "@/db/services/chats"; -import { replaceUserProfile } from "@/db/services/user-profile"; -import { selectGatewayModel } from "@/db/services/settings"; -import { deleteVaultItem, saveVaultItem } from "@/db/services/vault"; -import type { AccessScope } from "@/lib/access-scope"; -import { saveChatSchema } from "@/lib/chat"; -import { env } from "@/env"; +import { listBrowserTraces } from "@db/services/browser-traces"; +import { saveChat } from "@db/services/chats"; +import { replaceUserProfile } from "@db/services/user-profile"; +import { selectGatewayModel } from "@db/services/settings"; +import { deleteVaultItem, saveVaultItem } from "@db/services/vault"; +import type { AccessScope } from "@shared/identity/access-scope"; +import { saveChatSchema } from "@shared/chat/schema"; +import { env } from "@shared/environment"; import { googleWorkspaceSubject, googleWorkspaceTokenParams, -} from "@/lib/google-workspace"; -import { userProfileSchema } from "@/lib/user-profile"; -import { vaultCreateItemSchema, vaultImportItemsSchema } from "@/lib/vault"; +} from "@shared/google-workspace/connection"; +import { userProfileSchema } from "@shared/user-profile/schema"; +import { + vaultCreateItemSchema, + vaultImportItemsSchema, +} from "@shared/vault/schema"; import { createTRPCRouter, protectedProcedure } from "./init"; export const appRouter = createTRPCRouter({ diff --git a/src/lib/same-origin.ts b/web/trpc/same-origin.ts similarity index 100% rename from src/lib/same-origin.ts rename to web/trpc/same-origin.ts diff --git a/src/trpc/types.ts b/web/trpc/types.ts similarity index 100% rename from src/trpc/types.ts rename to web/trpc/types.ts From 84196766733eaca03be4dcefc73360e61b93f123 Mon Sep 17 00:00:00 2001 From: Jason Hedman <40368124+jasonhedman@users.noreply.github.com> Date: Fri, 4 Sep 2026 11:39:36 -0400 Subject: [PATCH 2/2] test: update merged oxlint aliases --- tools/oxlint/anti-slop/tests/anti-slop-plugin.test.ts | 2 +- .../oxlint/anti-slop/tests/no-chained-type-assertions.cases.ts | 2 +- .../anti-slop/tests/no-conditional-empty-object-spread.cases.ts | 2 +- tools/oxlint/anti-slop/tests/no-known-value-widening.cases.ts | 2 +- tools/oxlint/anti-slop/tests/no-module-mocking.cases.ts | 2 +- tools/oxlint/anti-slop/tests/no-object-parameters.cases.ts | 2 +- tools/oxlint/anti-slop/tests/no-reflect-apply.cases.ts | 2 +- tools/oxlint/anti-slop/tests/no-reflect-get.cases.ts | 2 +- tools/oxlint/anti-slop/tests/no-runtime-typeof.cases.ts | 2 +- tools/oxlint/anti-slop/tests/no-shape-in-symbol-names.cases.ts | 2 +- tools/oxlint/anti-slop/tests/no-unknown-parameters.cases.ts | 2 +- tools/oxlint/anti-slop/tests/no-unknown-returns.cases.ts | 2 +- tools/oxlint/anti-slop/tests/no-unknown-type-aliases.cases.ts | 2 +- tools/oxlint/anti-slop/tests/no-unsafe-dictionary-type.cases.ts | 2 +- tools/oxlint/anti-slop/tests/no-widen-then-assert.cases.ts | 2 +- .../tests/require-safety-comment-for-type-assertion.cases.ts | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tools/oxlint/anti-slop/tests/anti-slop-plugin.test.ts b/tools/oxlint/anti-slop/tests/anti-slop-plugin.test.ts index 8003065e..b42204af 100644 --- a/tools/oxlint/anti-slop/tests/anti-slop-plugin.test.ts +++ b/tools/oxlint/anti-slop/tests/anti-slop-plugin.test.ts @@ -1,7 +1,7 @@ import assert from "node:assert/strict"; import { test } from "vitest"; -import plugin from "@/tools/oxlint/anti-slop/index.ts"; +import plugin from "@tools/oxlint/anti-slop/index.ts"; import "./no-chained-type-assertions.cases.ts"; import "./no-conditional-empty-object-spread.cases.ts"; diff --git a/tools/oxlint/anti-slop/tests/no-chained-type-assertions.cases.ts b/tools/oxlint/anti-slop/tests/no-chained-type-assertions.cases.ts index 605035db..72f30e5a 100644 --- a/tools/oxlint/anti-slop/tests/no-chained-type-assertions.cases.ts +++ b/tools/oxlint/anti-slop/tests/no-chained-type-assertions.cases.ts @@ -1,6 +1,6 @@ import { typescriptRuleTester as tester } from "./rule-tester.ts"; -import { noChainedTypeAssertionsRule } from "@/tools/oxlint/anti-slop/rules/no-chained-type-assertions.ts"; +import { noChainedTypeAssertionsRule } from "@tools/oxlint/anti-slop/rules/no-chained-type-assertions.ts"; const error = { messageId: "chained" }; diff --git a/tools/oxlint/anti-slop/tests/no-conditional-empty-object-spread.cases.ts b/tools/oxlint/anti-slop/tests/no-conditional-empty-object-spread.cases.ts index 3912420a..e6bb077b 100644 --- a/tools/oxlint/anti-slop/tests/no-conditional-empty-object-spread.cases.ts +++ b/tools/oxlint/anti-slop/tests/no-conditional-empty-object-spread.cases.ts @@ -1,6 +1,6 @@ import { typescriptRuleTester as tester } from "./rule-tester.ts"; -import { noConditionalEmptyObjectSpreadRule } from "@/tools/oxlint/anti-slop/rules/no-conditional-empty-object-spread.ts"; +import { noConditionalEmptyObjectSpreadRule } from "@tools/oxlint/anti-slop/rules/no-conditional-empty-object-spread.ts"; const error = { messageId: "avoid" }; diff --git a/tools/oxlint/anti-slop/tests/no-known-value-widening.cases.ts b/tools/oxlint/anti-slop/tests/no-known-value-widening.cases.ts index e3437ecc..5e187827 100644 --- a/tools/oxlint/anti-slop/tests/no-known-value-widening.cases.ts +++ b/tools/oxlint/anti-slop/tests/no-known-value-widening.cases.ts @@ -1,6 +1,6 @@ import { typescriptRuleTester as tester } from "./rule-tester.ts"; -import { noKnownValueWideningRule } from "@/tools/oxlint/anti-slop/rules/no-known-value-widening.ts"; +import { noKnownValueWideningRule } from "@tools/oxlint/anti-slop/rules/no-known-value-widening.ts"; const error = { messageId: "widening" }; diff --git a/tools/oxlint/anti-slop/tests/no-module-mocking.cases.ts b/tools/oxlint/anti-slop/tests/no-module-mocking.cases.ts index 5286daab..51ce68c7 100644 --- a/tools/oxlint/anti-slop/tests/no-module-mocking.cases.ts +++ b/tools/oxlint/anti-slop/tests/no-module-mocking.cases.ts @@ -1,6 +1,6 @@ import { typescriptRuleTester as tester } from "./rule-tester.ts"; -import { noModuleMockingRule } from "@/tools/oxlint/anti-slop/rules/no-module-mocking.ts"; +import { noModuleMockingRule } from "@tools/oxlint/anti-slop/rules/no-module-mocking.ts"; const error = { messageId: "moduleMock" }; diff --git a/tools/oxlint/anti-slop/tests/no-object-parameters.cases.ts b/tools/oxlint/anti-slop/tests/no-object-parameters.cases.ts index b2d20e7b..826b483d 100644 --- a/tools/oxlint/anti-slop/tests/no-object-parameters.cases.ts +++ b/tools/oxlint/anti-slop/tests/no-object-parameters.cases.ts @@ -1,6 +1,6 @@ import { typescriptRuleTester as tester } from "./rule-tester.ts"; -import { noObjectParametersRule } from "@/tools/oxlint/anti-slop/rules/no-object-parameters.ts"; +import { noObjectParametersRule } from "@tools/oxlint/anti-slop/rules/no-object-parameters.ts"; const error = { messageId: "objectParameter" }; diff --git a/tools/oxlint/anti-slop/tests/no-reflect-apply.cases.ts b/tools/oxlint/anti-slop/tests/no-reflect-apply.cases.ts index 8e173202..ec471144 100644 --- a/tools/oxlint/anti-slop/tests/no-reflect-apply.cases.ts +++ b/tools/oxlint/anti-slop/tests/no-reflect-apply.cases.ts @@ -1,6 +1,6 @@ import { typescriptRuleTester as tester } from "./rule-tester.ts"; -import { noReflectApplyRule } from "@/tools/oxlint/anti-slop/rules/no-reflect-apply.ts"; +import { noReflectApplyRule } from "@tools/oxlint/anti-slop/rules/no-reflect-apply.ts"; const error = { messageId: "reflectApply" }; diff --git a/tools/oxlint/anti-slop/tests/no-reflect-get.cases.ts b/tools/oxlint/anti-slop/tests/no-reflect-get.cases.ts index 2632914e..8dbaa97d 100644 --- a/tools/oxlint/anti-slop/tests/no-reflect-get.cases.ts +++ b/tools/oxlint/anti-slop/tests/no-reflect-get.cases.ts @@ -1,6 +1,6 @@ import { typescriptRuleTester as tester } from "./rule-tester.ts"; -import { noReflectGetRule } from "@/tools/oxlint/anti-slop/rules/no-reflect-get.ts"; +import { noReflectGetRule } from "@tools/oxlint/anti-slop/rules/no-reflect-get.ts"; const error = { messageId: "reflectGet" }; diff --git a/tools/oxlint/anti-slop/tests/no-runtime-typeof.cases.ts b/tools/oxlint/anti-slop/tests/no-runtime-typeof.cases.ts index 77580710..8527c80d 100644 --- a/tools/oxlint/anti-slop/tests/no-runtime-typeof.cases.ts +++ b/tools/oxlint/anti-slop/tests/no-runtime-typeof.cases.ts @@ -1,6 +1,6 @@ import { typescriptRuleTester as tester } from "./rule-tester.ts"; -import { noRuntimeTypeofRule } from "@/tools/oxlint/anti-slop/rules/no-runtime-typeof.ts"; +import { noRuntimeTypeofRule } from "@tools/oxlint/anti-slop/rules/no-runtime-typeof.ts"; const error = { messageId: "runtimeTypeof" }; const allowInTypeGuards = [{ allowInTypeGuards: true }]; diff --git a/tools/oxlint/anti-slop/tests/no-shape-in-symbol-names.cases.ts b/tools/oxlint/anti-slop/tests/no-shape-in-symbol-names.cases.ts index 18173b6e..c3b9cb40 100644 --- a/tools/oxlint/anti-slop/tests/no-shape-in-symbol-names.cases.ts +++ b/tools/oxlint/anti-slop/tests/no-shape-in-symbol-names.cases.ts @@ -1,6 +1,6 @@ import { typescriptRuleTester as tester } from "./rule-tester.ts"; -import { noForbiddenTermInSymbolNamesRule } from "@/tools/oxlint/anti-slop/rules/no-shape-in-symbol-names.ts"; +import { noForbiddenTermInSymbolNamesRule } from "@tools/oxlint/anti-slop/rules/no-shape-in-symbol-names.ts"; const error = { messageId: "forbiddenSymbolName" }; diff --git a/tools/oxlint/anti-slop/tests/no-unknown-parameters.cases.ts b/tools/oxlint/anti-slop/tests/no-unknown-parameters.cases.ts index 387e92d9..552f8c13 100644 --- a/tools/oxlint/anti-slop/tests/no-unknown-parameters.cases.ts +++ b/tools/oxlint/anti-slop/tests/no-unknown-parameters.cases.ts @@ -1,6 +1,6 @@ import { typescriptRuleTester as tester } from "./rule-tester.ts"; -import { noUnknownParametersRule } from "@/tools/oxlint/anti-slop/rules/no-unknown-parameters.ts"; +import { noUnknownParametersRule } from "@tools/oxlint/anti-slop/rules/no-unknown-parameters.ts"; const error = { messageId: "unknownParameter" }; diff --git a/tools/oxlint/anti-slop/tests/no-unknown-returns.cases.ts b/tools/oxlint/anti-slop/tests/no-unknown-returns.cases.ts index ea4a2ad7..a48fb6bc 100644 --- a/tools/oxlint/anti-slop/tests/no-unknown-returns.cases.ts +++ b/tools/oxlint/anti-slop/tests/no-unknown-returns.cases.ts @@ -1,6 +1,6 @@ import { typescriptRuleTester as tester } from "./rule-tester.ts"; -import { noUnknownReturnsRule } from "@/tools/oxlint/anti-slop/rules/no-unknown-returns.ts"; +import { noUnknownReturnsRule } from "@tools/oxlint/anti-slop/rules/no-unknown-returns.ts"; const error = { messageId: "unknownReturn" }; diff --git a/tools/oxlint/anti-slop/tests/no-unknown-type-aliases.cases.ts b/tools/oxlint/anti-slop/tests/no-unknown-type-aliases.cases.ts index d7d56484..bd3c38b8 100644 --- a/tools/oxlint/anti-slop/tests/no-unknown-type-aliases.cases.ts +++ b/tools/oxlint/anti-slop/tests/no-unknown-type-aliases.cases.ts @@ -1,6 +1,6 @@ import { typescriptRuleTester as tester } from "./rule-tester.ts"; -import { noUnknownTypeAliasesRule } from "@/tools/oxlint/anti-slop/rules/no-unknown-type-aliases.ts"; +import { noUnknownTypeAliasesRule } from "@tools/oxlint/anti-slop/rules/no-unknown-type-aliases.ts"; const error = { messageId: "unknownAlias" }; diff --git a/tools/oxlint/anti-slop/tests/no-unsafe-dictionary-type.cases.ts b/tools/oxlint/anti-slop/tests/no-unsafe-dictionary-type.cases.ts index 27961abd..287ff9c1 100644 --- a/tools/oxlint/anti-slop/tests/no-unsafe-dictionary-type.cases.ts +++ b/tools/oxlint/anti-slop/tests/no-unsafe-dictionary-type.cases.ts @@ -1,6 +1,6 @@ import { typescriptRuleTester as tester } from "./rule-tester.ts"; -import { noUnsafeDictionaryTypeRule } from "@/tools/oxlint/anti-slop/rules/no-unsafe-dictionary-type.ts"; +import { noUnsafeDictionaryTypeRule } from "@tools/oxlint/anti-slop/rules/no-unsafe-dictionary-type.ts"; const error = { messageId: "unsafeDictionary" }; diff --git a/tools/oxlint/anti-slop/tests/no-widen-then-assert.cases.ts b/tools/oxlint/anti-slop/tests/no-widen-then-assert.cases.ts index 634a6a39..9f2be92a 100644 --- a/tools/oxlint/anti-slop/tests/no-widen-then-assert.cases.ts +++ b/tools/oxlint/anti-slop/tests/no-widen-then-assert.cases.ts @@ -1,6 +1,6 @@ import { typescriptRuleTester as tester } from "./rule-tester.ts"; -import { noWidenThenAssertRule } from "@/tools/oxlint/anti-slop/rules/no-widen-then-assert.ts"; +import { noWidenThenAssertRule } from "@tools/oxlint/anti-slop/rules/no-widen-then-assert.ts"; const error = { messageId: "widenThenAssert" }; diff --git a/tools/oxlint/anti-slop/tests/require-safety-comment-for-type-assertion.cases.ts b/tools/oxlint/anti-slop/tests/require-safety-comment-for-type-assertion.cases.ts index 55c6a7ac..d16f21d3 100644 --- a/tools/oxlint/anti-slop/tests/require-safety-comment-for-type-assertion.cases.ts +++ b/tools/oxlint/anti-slop/tests/require-safety-comment-for-type-assertion.cases.ts @@ -1,6 +1,6 @@ import { typescriptRuleTester as tester } from "./rule-tester.ts"; -import { requireSafetyCommentForTypeAssertionRule } from "@/tools/oxlint/anti-slop/rules/require-safety-comment-for-type-assertion.ts"; +import { requireSafetyCommentForTypeAssertionRule } from "@tools/oxlint/anti-slop/rules/require-safety-comment-for-type-assertion.ts"; const error = { messageId: "missingSafetyComment" };