chore(deno): migrate toolchain from Node 24 + pnpm to Deno 2.9.7 + TypeScript 7.0.2 (W1.5)
- root deno.json workspace (nodeModulesDir auto), npm versions registered once in imports, deno.lock; remove pnpm-lock/pnpm-workspace/root package.json; members keep minimal package.json (name/type/exports) - tasks: dev, typecheck (tsc 7.0.2 per member + deno check), lint/fmt (biome, useImportExtensions), test (vitest via deno), check:tokens, build (web + deno compile), ci, db:migrate/reset, gen:types - tsconfig base moved to config/ (no root tsconfig.json); deno types -> types/deno.d.ts; web drops baseUrl - server: Deno.serve entry with graceful shutdown, --role migrate|preflight|probe, WEB_ROOT static SPA hosting; drop @hono/node-server, tsx, esbuild build.mjs - logger: redact child() bindings and serialize err by message/stack; sync stdout destination; tests - relative imports get explicit extensions (sites/mp-sync paths left for follow-up) - crash-recovery tests spawn `deno run -A`; tasks tests use unique per-file schemas - single-container Dockerfile + entrypoint (migrate -> preflight -> api+worker watchdog), docker-compose.yml - docs: README, runbook, ADR-001 superseded, plan §1 validation row Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
1 parent
d9f2af2f3c
commit
304feea141
226 files changed
+6601
-8620
No files matched your search
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { HealthStatus } from "@umt/contracts";
|
||||
import { apiData, TTL_SECOND } from "~/lib/api";
|
||||
import { apiData, TTL_SECOND } from "~/lib/api.ts";
|
||||
|
||||
/** 服务健康状态,15 秒轮询 */
|
||||
export function useHealth() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { KeyRound } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Button } from "~/components/ui/button.tsx";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -10,9 +10,9 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "~/components/ui/dialog";
|
||||
import { Input } from "~/components/ui/input";
|
||||
import { clearAuth, getToken, setToken } from "~/lib/api";
|
||||
} from "~/components/ui/dialog.tsx";
|
||||
import { Input } from "~/components/ui/input.tsx";
|
||||
import { clearAuth, getToken, setToken } from "~/lib/api.ts";
|
||||
|
||||
/** 设置本机使用的 API Key(存 localStorage,首版单管理员) */
|
||||
export function ApiKeyDialog() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { LucideIcon } from "lucide-react";
|
||||
import { Inbox } from "lucide-react";
|
||||
import type { ReactNode } from "react";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
/** 空态:图标 + 标题 + 说明 + 可选操作。用于"尚无数据"与"功能建设中"占位 */
|
||||
export function EmptyState({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { findNavItem, NAV_ITEMS } from "./nav";
|
||||
import { findNavItem, NAV_ITEMS } from "./nav.ts";
|
||||
|
||||
describe("控制台导航", () => {
|
||||
it("12 个工作区,路径唯一", () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
/** 控制台页面标题:标题 + 一句说明 + 右侧操作区 */
|
||||
export function PageHeader({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
export type StatusTone = "success" | "warning" | "destructive" | "neutral";
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Construction } from "lucide-react";
|
||||
import { useLocation } from "react-router";
|
||||
import { EmptyState } from "./empty-state";
|
||||
import { findNavItem } from "./nav";
|
||||
import { PageHeader } from "./page-header";
|
||||
import { EmptyState } from "./empty-state.tsx";
|
||||
import { findNavItem } from "./nav.ts";
|
||||
import { PageHeader } from "./page-header.tsx";
|
||||
|
||||
/** 工作区占位页:标题与说明取自导航表,正文为"建设中"空态 */
|
||||
export function WorkspacePlaceholder({ milestone = "W3" }: { milestone?: string }) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
/**
|
||||
* 全站背景上左上角那束淡淡的棱镜漏光(样式见 app.css 的 .prism-leak)。
|
||||
|
||||
@@ -3,8 +3,8 @@ import { useTheme } from "next-themes";
|
||||
import { useEffect, useState } from "react";
|
||||
import { flushSync } from "react-dom";
|
||||
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { Button } from "~/components/ui/button.tsx";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
export function ThemeToggle({ className }: { className?: string }) {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { AlertDialog as AlertDialogPrimitive } from "radix-ui";
|
||||
import type * as React from "react";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { Button } from "~/components/ui/button.tsx";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
function AlertDialog({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
|
||||
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { Avatar as AvatarPrimitive } from "radix-ui";
|
||||
import type * as React from "react";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
function Avatar({
|
||||
className,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { Slot } from "radix-ui";
|
||||
import type * as React from "react";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
const badgeVariants = cva(
|
||||
"inline-flex items-center justify-center rounded-full border border-transparent px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ChevronRight, MoreHorizontal } from "lucide-react";
|
||||
import { Slot } from "radix-ui";
|
||||
import type * as React from "react";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
function Breadcrumb({ ...props }: React.ComponentProps<"nav">) {
|
||||
return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { Slot } from "radix-ui";
|
||||
import type * as React from "react";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
const buttonVariants = cva(
|
||||
// 全站只有这一套按钮(与动漫站同一思路):形状一律胶囊 / 正圆,颜色与材质只由 variant 决定,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { zhCN } from "date-fns/locale";
|
||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||
import { DayPicker, type DayPickerProps } from "react-day-picker";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
// 日历(react-day-picker v10)的玻璃族皮肤:全部走语义 token + 玻璃 hover
|
||||
// 语言(中性灰纱、选中 primary 药丸 + 顶部内高光、今日描边)。键盘导航
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type * as React from "react";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
function Card({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { XIcon } from "lucide-react";
|
||||
import { Dialog as DialogPrimitive } from "radix-ui";
|
||||
import type * as React from "react";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { Button } from "~/components/ui/button.tsx";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
function Dialog({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
||||
return <DialogPrimitive.Root data-slot="dialog" {...props} />;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type * as React from "react";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
|
||||
return (
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { Label as LabelPrimitive } from "radix-ui";
|
||||
import type * as React from "react";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
function Label({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>) {
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from "lucide-react";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
const PAGE_SIZE_OPTIONS = [10, 15, 20, 50, 100];
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Popover as PopoverPrimitive } from "radix-ui";
|
||||
import type * as React from "react";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
function Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root>) {
|
||||
return <PopoverPrimitive.Root data-slot="popover" {...props} />;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
|
||||
import { Select as SelectPrimitive } from "radix-ui";
|
||||
import type * as React from "react";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
function Select({ ...props }: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
||||
return <SelectPrimitive.Root data-slot="select" {...props} />;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Separator as SeparatorPrimitive } from "radix-ui";
|
||||
import type * as React from "react";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
function Separator({
|
||||
className,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { XIcon } from "lucide-react";
|
||||
import { Dialog as SheetPrimitive } from "radix-ui";
|
||||
import type * as React from "react";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
|
||||
return <SheetPrimitive.Root data-slot="sheet" {...props} />;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Slider as SliderPrimitive } from "radix-ui";
|
||||
import * as React from "react";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
function Slider({
|
||||
className,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Switch as SwitchPrimitive } from "radix-ui";
|
||||
import type * as React from "react";
|
||||
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
function Switch({ className, ...props }: React.ComponentProps<typeof SwitchPrimitive.Root>) {
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// 由 scripts/gen-design-tokens.mjs 从 app/app.css 生成,不要手改;改了 app.css 跑 pnpm gen:tokens
|
||||
// 由 scripts/gen-design-tokens.mjs 从 app/app.css 生成,不要手改;改了 app.css 跑 deno task gen:tokens
|
||||
export const DESIGN_TOKENS = {
|
||||
"fontSizes": [
|
||||
"micro",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { type ClassValue, clsx } from "clsx";
|
||||
import { extendTailwindMerge } from "tailwind-merge";
|
||||
|
||||
import { DESIGN_TOKENS } from "./design-tokens.generated";
|
||||
import { DESIGN_TOKENS } from "./design-tokens.generated.ts";
|
||||
|
||||
/**
|
||||
* 自定义工具类的 token(字号 / 圆角 / 缓动 / 时长)要告诉 tailwind-merge 它们属于哪一组:
|
||||
|
||||
@@ -2,7 +2,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { ThemeProvider } from "next-themes";
|
||||
import { useState } from "react";
|
||||
import { isRouteErrorResponse, Links, Meta, Outlet, Scripts, ScrollRestoration } from "react-router";
|
||||
import { Toaster } from "~/components/ui/sonner";
|
||||
import { Toaster } from "~/components/ui/sonner.tsx";
|
||||
|
||||
import type { Route } from "./+types/root";
|
||||
import "@fontsource-variable/inter-tight";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Bot, Send } from "lucide-react";
|
||||
import { EmptyState } from "~/components/console/empty-state";
|
||||
import { PageHeader } from "~/components/console/page-header";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Input } from "~/components/ui/input";
|
||||
import { EmptyState } from "~/components/console/empty-state.tsx";
|
||||
import { PageHeader } from "~/components/console/page-header.tsx";
|
||||
import { Button } from "~/components/ui/button.tsx";
|
||||
import { Input } from "~/components/ui/input.tsx";
|
||||
|
||||
/** Agent 会话页占位:消息流 + 输入框骨架,W2/W3 接入 agent_run 与 SSE 增量 */
|
||||
export default function AgentSession() {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Activity, AlertTriangle, CircleCheck, HardDrive, ListTodo, Radio, Sparkles } from "lucide-react";
|
||||
import { useHealth } from "~/api/health";
|
||||
import { EmptyState } from "~/components/console/empty-state";
|
||||
import { PageHeader } from "~/components/console/page-header";
|
||||
import { StatusBadge } from "~/components/console/status-badge";
|
||||
import { formatDateTime } from "~/lib/utils";
|
||||
import { useHealth } from "~/api/health.ts";
|
||||
import { EmptyState } from "~/components/console/empty-state.tsx";
|
||||
import { PageHeader } from "~/components/console/page-header.tsx";
|
||||
import { StatusBadge } from "~/components/console/status-badge.tsx";
|
||||
import { formatDateTime } from "~/lib/utils.ts";
|
||||
|
||||
// 首页六区块(REQ §13.4.3),W3 接入正式状态投影
|
||||
const SECTIONS = [
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder";
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder.tsx";
|
||||
|
||||
// 占位:标题与说明取自 components/console/nav.ts
|
||||
export default function IdentityPage() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder";
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder.tsx";
|
||||
|
||||
// 占位:标题与说明取自 components/console/nav.ts
|
||||
export default function InboxPage() {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { ChevronLeft, ChevronRight, Clapperboard, Menu } from "lucide-react";
|
||||
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
||||
import { Link, NavLink, Outlet, useLocation } from "react-router";
|
||||
import { ApiKeyDialog } from "~/components/console/api-key-dialog";
|
||||
import { findNavItem, NAV_GROUPS, NAV_ITEMS, type NavGroup } from "~/components/console/nav";
|
||||
import PrismLeak from "~/components/prism-leak";
|
||||
import { ThemeToggle } from "~/components/theme-toggle";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "~/components/ui/sheet";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { ApiKeyDialog } from "~/components/console/api-key-dialog.tsx";
|
||||
import { findNavItem, NAV_GROUPS, NAV_ITEMS, type NavGroup } from "~/components/console/nav.ts";
|
||||
import PrismLeak from "~/components/prism-leak.tsx";
|
||||
import { ThemeToggle } from "~/components/theme-toggle.tsx";
|
||||
import { Button } from "~/components/ui/button.tsx";
|
||||
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "~/components/ui/sheet.tsx";
|
||||
import { cn } from "~/lib/utils.ts";
|
||||
|
||||
const PORTAL_NAME = "媒体自动化";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder";
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder.tsx";
|
||||
|
||||
// 占位:标题与说明取自 components/console/nav.ts
|
||||
export default function LibraryPage() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder";
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder.tsx";
|
||||
|
||||
// 占位:标题与说明取自 components/console/nav.ts
|
||||
export default function OrganizePage() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder";
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder.tsx";
|
||||
|
||||
// 占位:标题与说明取自 components/console/nav.ts
|
||||
export default function PreferencesPage() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder";
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder.tsx";
|
||||
|
||||
// 占位:标题与说明取自 components/console/nav.ts
|
||||
export default function SettingsPage() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder";
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder.tsx";
|
||||
|
||||
// 占位:标题与说明取自 components/console/nav.ts
|
||||
export default function SitesPage() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder";
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder.tsx";
|
||||
|
||||
// 占位:标题与说明取自 components/console/nav.ts
|
||||
export default function SourcesPage() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder";
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder.tsx";
|
||||
|
||||
// 占位:标题与说明取自 components/console/nav.ts
|
||||
export default function SubscriptionsPage() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder";
|
||||
import { WorkspacePlaceholder } from "~/components/console/workspace-placeholder.tsx";
|
||||
|
||||
// 占位:标题与说明取自 components/console/nav.ts
|
||||
export default function TasksPage() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Link } from "react-router";
|
||||
import { EmptyState } from "~/components/console/empty-state";
|
||||
import { buttonVariants } from "~/components/ui/button";
|
||||
import { EmptyState } from "~/components/console/empty-state.tsx";
|
||||
import { buttonVariants } from "~/components/ui/button.tsx";
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
|
||||
Reference in new issue
Block a user