Compare commits

..
Author SHA1 Message Date
dayuan.jiang 815db25784 chore: remove the sponsor material for Doubao and Atlas Cloud
The about pages lose the "Sponsored by ByteDance Doubao" card, the
promotional links in the provider list and the thanks paragraph; the
"bring your own key" note stays. The quota toast no longer shows the
Volcengine sign-up paragraph, and its messages in the four languages no
longer mention a sponsor. The provider guides lose the "free tokens"
promo line. The logo and invite images used only by that material are
deleted. Doubao and Atlas Cloud remain supported providers.
2026-10-10 08:17:15 +09:00
dayuan.jiang 26524276fd docs: keep the TrendShift badge under the language switch 2026-10-10 07:24:22 +09:00
dayuan.jiang 2a838b6670 docs: restructure the README around the new promo video
The three READMEs now follow the reader's path: what it is (video and
two paragraphs), highlights grouped as draw / edit / use, examples, how
to use it (demo, desktop app, MCP), how to self-host (local run, a
one-click deploy table, models and providers), and support.

Removed the table of contents, the sponsor blocks, the "How It Works"
section, the duplicated demo button and the model recommendation list.
The provider list now matches env.example (24 providers). The video is
the new 30-second promo. Bold markers inside the HTML example table are
now <strong> tags, so they render.
2026-10-10 07:20:15 +09:00
20 changed files with 2047 additions and 1798 deletions
+2 -2
View File
@@ -12,13 +12,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node.js
uses: actions/setup-node@v7
uses: actions/setup-node@v6
with:
node-version: '24'
+2 -2
View File
@@ -20,10 +20,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v7
uses: actions/setup-node@v6
with:
node-version: '24'
cache: 'npm'
+6 -6
View File
@@ -26,14 +26,14 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v7
uses: actions/checkout@v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v4
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -41,7 +41,7 @@ jobs:
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v6
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
@@ -54,7 +54,7 @@ jobs:
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v7
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
@@ -71,7 +71,7 @@ jobs:
# Push to AWS ECR for App Runner auto-deploy
- name: Configure AWS credentials
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
uses: aws-actions/configure-aws-credentials@v6
uses: aws-actions/configure-aws-credentials@v5
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+7 -7
View File
@@ -26,10 +26,10 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v7
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v7
uses: actions/setup-node@v6
with:
node-version: 24
cache: "npm"
@@ -50,10 +50,10 @@ jobs:
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v7
uses: actions/setup-node@v6
with:
node-version: 24
cache: "npm"
@@ -69,7 +69,7 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload unsigned artifacts for signing
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v6
id: upload-unsigned
with:
name: windows-unsigned
@@ -77,7 +77,7 @@ jobs:
retention-days: 1
- name: Sign with SignPath
uses: signpath/github-action-submit-signing-request@v3
uses: signpath/github-action-submit-signing-request@v2
with:
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
organization-id: '880a211d-2cd3-4e7b-8d04-3d1f8eb39df5'
@@ -89,7 +89,7 @@ jobs:
output-artifact-directory: release-signed
- name: Upload signed artifacts to release
uses: softprops/action-gh-release@v3
uses: softprops/action-gh-release@v2
with:
files: release-signed/*.exe
env:
+2 -2
View File
@@ -28,10 +28,10 @@ jobs:
working-directory: packages/mcp-server
steps:
- name: Checkout
uses: actions/checkout@v7
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v7
uses: actions/setup-node@v6
with:
node-version: 24
cache: "npm"
+8 -8
View File
@@ -11,12 +11,12 @@ jobs:
name: Lint & Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v7
uses: actions/setup-node@v6
with:
node-version: "24"
node-version: "20"
cache: "npm"
- name: Install dependencies
@@ -52,19 +52,19 @@ jobs:
matrix:
shard: [1, 2, 3, 4, 5, 6]
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v7
uses: actions/setup-node@v6
with:
node-version: "24"
node-version: "20"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Cache Playwright browsers
uses: actions/cache@v6
uses: actions/cache@v5
id: playwright-cache
with:
path: ~/.cache/ms-playwright
@@ -87,7 +87,7 @@ jobs:
CI: true
- name: Upload test results
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v6
if: always()
with:
name: playwright-report-${{ matrix.shard }}
+5 -5
View File
@@ -1,10 +1,10 @@
import {
ChevronDown,
Download,
FilePlus,
MessageSquareDashed,
PanelRightClose,
Settings,
Settings2,
SquarePen,
} from "lucide-react"
import { useRef } from "react"
import { DevXmlSimulator } from "@/components/dev-xml-simulator"
@@ -139,14 +139,14 @@ export function ChatPanel({
disabled={engine.isBusy}
data-testid="new-chat-button"
>
<FilePlus />
<SquarePen />
</IconButton>
<IconButton
label={dict.nav.settings}
onClick={() => openSettings()}
data-testid="settings-button"
>
<Settings />
<Settings2 />
</IconButton>
{!mobile && (
<IconButton
@@ -173,7 +173,7 @@ export function ChatPanel({
/>
)}
<div className="shrink-0 px-4 pt-1 pb-3">
<div className="shrink-0 p-2.5 pt-1">
<Composer
placeholder={
engine.messages.length > 0 &&
+42 -32
View File
@@ -18,18 +18,14 @@ interface Example {
file?: { path: string; name: string; type: string }
}
/** Secondary start buttons: outlined, so they read as clickable */
const startButtonClass =
"inline-flex h-8 items-center gap-1.5 rounded-lg border border-border bg-card px-3 text-[13px] text-foreground transition-colors hover:bg-accent [&_svg]:text-muted-foreground"
async function loadExampleFile(file: NonNullable<Example["file"]>) {
const response = await fetch(getAssetUrl(file.path))
const blob = await response.blob()
return new File([blob], file.name, { type: file.type })
}
/** One start-screen example: a small picture over its title */
function ExampleTile({
/** One start-screen choice: a small picture, a title and one line */
function ExampleCard({
onClick,
title,
description,
@@ -39,7 +35,6 @@ function ExampleTile({
}: {
onClick: () => void
title: string
/** Shown as the tooltip: the title alone names the example */
description: string
picture: React.ReactNode
/** An icon on a tinted tile instead of a diagram on paper */
@@ -50,20 +45,24 @@ function ExampleTile({
<button
type="button"
onClick={onClick}
title={description}
className="group/example flex min-w-0 flex-col gap-2 rounded-xl border border-border bg-card p-1.5 pb-2.5 text-left transition-colors hover:border-foreground/25"
className="group/example flex min-w-0 items-center gap-2.5 rounded-xl border border-border bg-card p-1.5 pr-2.5 text-left transition-colors hover:border-foreground/25"
data-testid={testId}
>
<span
className={cn(
"flex h-16 w-full items-center justify-center overflow-hidden rounded-lg",
"flex h-12 w-16 shrink-0 items-center justify-center overflow-hidden rounded-lg",
plain ? "bg-muted" : "sheet-light bg-white",
)}
>
{picture}
</span>
<span className="px-1 text-[13px] leading-snug font-medium text-foreground">
{title}
<span className="min-w-0 flex-1">
<span className="line-clamp-2 text-[13px] leading-snug font-medium text-foreground">
{title}
</span>
<span className="mt-0.5 block truncate text-xs text-muted-foreground">
{description}
</span>
</span>
</button>
)
@@ -93,7 +92,6 @@ export function LobbyHero({
key: "paper",
title: dict.examples.paperToDiagram,
description: dict.examples.paperDescription,
image: "/paper_demo.svg",
prompt: "Summarize this paper as a diagram",
file: {
path: "/chain-of-thought.txt",
@@ -187,12 +185,10 @@ export function LobbyHero({
placeholder={t.placeholder}
/>
{/* Examples: one row of tiles; the ways to bring your own
diagram follow as a separate group */}
<div
className={cn(
"mt-5 grid gap-2",
compact ? "grid-cols-1" : "grid-cols-5",
compact ? "grid-cols-1" : "grid-cols-3",
)}
>
{examples.map((example) =>
@@ -213,7 +209,7 @@ export function LobbyHero({
</span>
</button>
) : (
<ExampleTile
<ExampleCard
key={example.key}
onClick={() => pickExample(example)}
title={example.title}
@@ -225,7 +221,7 @@ export function LobbyHero({
<img
src={getAssetUrl(example.image)}
alt=""
className="max-h-14 max-w-[88%] object-contain transition-transform duration-300 group-hover/example:scale-[1.06]"
className="max-h-10 max-w-[56px] object-contain transition-transform duration-300 group-hover/example:scale-[1.06]"
/>
) : (
<FileText className="size-5 text-muted-foreground" />
@@ -235,34 +231,48 @@ export function LobbyHero({
/>
),
)}
{!compact && (
<ExampleCard
onClick={onOpenFile}
title={dict.workspace.openFile}
description={t.openFileHint}
picture={
<FileUp className="size-5 text-muted-foreground" />
}
plain
/>
)}
</div>
<p className="mt-2.5 text-center text-xs text-faint">
<p className="mt-3 text-center text-xs text-faint">
{dict.examples.cachedNote}
</p>
{/* Ways to start without an example, as plain buttons */}
<div className="mt-6 flex flex-wrap items-center justify-center gap-2">
<div className="mt-6 flex flex-wrap items-center justify-center gap-x-5 gap-y-2 text-[13px] text-muted-foreground">
{engine.sessions.length > 0 && (
<SessionMenu align="center" onOpenFile={onOpenFile}>
<button type="button" className={startButtonClass}>
<button
type="button"
className="inline-flex items-center gap-1.5 hover:text-foreground"
>
<History className="size-4" />
{t.recent}
</button>
</SessionMenu>
)}
<button
type="button"
onClick={onOpenFile}
className={startButtonClass}
data-testid="open-file"
>
<FileUp className="size-4" />
{dict.workspace.openFile}
</button>
{compact && (
<button
type="button"
onClick={onOpenFile}
className="inline-flex items-center gap-1.5 hover:text-foreground"
>
<FileUp className="size-4" />
{dict.workspace.openFile}
</button>
)}
<button
type="button"
onClick={onDrawYourself}
className={startButtonClass}
className="inline-flex items-center gap-1.5 hover:text-foreground"
data-testid="draw-yourself"
>
<Pencil className="size-4" />
+26 -26
View File
@@ -2,6 +2,7 @@ import {
AlertCircle,
Check,
ChevronDown,
Code2,
Copy,
Library,
PenTool,
@@ -179,23 +180,17 @@ function VersionCard({
</button>
)
// What the AI wrote: a text link in the summary line, so the card's
// only button is the action (undo or restore)
const summaryLine = (
<div className="text-xs text-muted-foreground">
{summary}
{/* The link wraps as one unit with its separator */}
<span className="whitespace-nowrap">
<span aria-hidden> · </span>
<button
type="button"
onClick={() => setShowCode((v) => !v)}
className="underline decoration-foreground/30 underline-offset-2 hover:text-foreground hover:decoration-foreground"
>
{showCode ? t.hideCode : t.showCode}
</button>
</span>
</div>
// What the AI wrote, on every card (main showed it on every tool call)
const codeButton = (
<button
type="button"
onClick={() => setShowCode((v) => !v)}
aria-label={showCode ? t.hideCode : t.showCode}
title={showCode ? t.hideCode : t.showCode}
className="inline-flex size-7 shrink-0 items-center justify-center rounded-lg text-muted-foreground hover:bg-accent hover:text-foreground"
>
<Code2 className="size-4" />
</button>
)
const codePanel = showCode && (
<div className="relative border-t border-border bg-surface-1 px-3 py-2.5">
@@ -236,12 +231,15 @@ function VersionCard({
/>
</button>
{badge}
<div className="min-w-0 flex-1">
<div className="min-w-0 flex-1" title={summary}>
<div className="truncate text-[13px] text-foreground">
{title}
</div>
{summaryLine}
<div className="truncate text-xs text-muted-foreground">
{summary}
</div>
</div>
{codeButton}
{restoreButton}
</div>
{codePanel}
@@ -273,12 +271,17 @@ function VersionCard({
{t.compare}
</span>
</button>
{/* Title row with the action; the summary runs under both */}
<div className="grid grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-x-2.5 px-3 py-2.5">
<div className="flex items-center gap-2.5 px-3 py-2.5">
{badge}
<div className="truncate text-[13px] font-medium text-foreground">
{title}
<div className="min-w-0 flex-1" title={summary}>
<div className="truncate text-[13px] font-medium text-foreground">
{title}
</div>
<div className="line-clamp-2 text-xs text-muted-foreground">
{summary}
</div>
</div>
{codeButton}
{canUndo ? (
<button
type="button"
@@ -297,9 +300,6 @@ function VersionCard({
) : (
restoreButton
)}
<div className="col-span-2 col-start-2 mt-0.5">
{summaryLine}
</div>
</div>
{codePanel}
</div>
+2 -2
View File
@@ -220,14 +220,14 @@ export function ModelSelector({
<span className="min-w-0 truncate text-xs">
{selectedModel
? shortModelName(selectedModel.modelId)
: dict.modelConfig.serverDefault}
: dict.modelConfig.default}
</span>
) : (
// Keep an sr-only label for screen readers when hidden
<span className="sr-only">
{selectedModel
? selectedModel.modelId
: dict.modelConfig.serverDefault}
: dict.modelConfig.default}
</span>
)}
<ChevronDown className="h-3 w-3 flex-shrink-0 text-muted-foreground" />
+2 -2
View File
@@ -1,6 +1,6 @@
"use client"
import { MessageSquare, PanelRightOpen, Settings, Shapes } from "lucide-react"
import { MessageSquare, PanelRightOpen, Settings2, Shapes } from "lucide-react"
import { usePathname, useRouter } from "next/navigation"
import { useEffect, useRef, useState } from "react"
import { CanvasStage } from "@/components/canvas/canvas-stage"
@@ -100,7 +100,7 @@ function StartBar({
onClick={() => openSettings()}
data-testid="settings-button"
>
<Settings />
<Settings2 />
</IconButton>
</div>
)
+4 -4
View File
@@ -72,7 +72,7 @@
"replicateDescription": "Upload and replicate an existing flowchart",
"creativeDrawing": "Creative drawing",
"creativeDescription": "Draw something fun and creative",
"cachedNote": "Examples use saved answers: they appear instantly and don't call the AI.",
"cachedNote": "Examples open instantly and don't use your model.",
"mcpServer": "MCP Server",
"mcpDescription": "Use in Claude Desktop, VS Code & Cursor"
},
@@ -96,7 +96,7 @@
"language": "Language",
"languageDescription": "Choose your interface language.",
"theme": "Theme",
"themeDescription": "Light or dark interface. The canvas follows the same theme.",
"themeDescription": "Light or dark interface. The diagram always stays on a white sheet, the way it exports.",
"diagramStyle": "Diagram style",
"diagramStyleDescription": "How the AI draws new diagrams: Styled uses colors and icons, Minimal keeps shapes plain.",
"sendShortcut": "Send shortcut",
@@ -399,7 +399,7 @@
"searchModels": "Search models...",
"noModelsFound": "No models found.",
"default": "Default",
"serverDefault": "Server model",
"serverDefault": "Server Default",
"serverModels": "Server Models",
"userModels": "User Models",
"configureModels": "Configure Models...",
@@ -694,7 +694,7 @@
},
"lobby": {
"title": "What would you like to draw?",
"lede": "Describe a diagram or upload a screenshot or PDF. You get a draw.io diagram you can keep editing and export.",
"lede": "Describe a diagram, or upload a screenshot or PDF. You get a regular draw.io diagram that you can keep editing and export.",
"placeholder": "For example: a login sequence diagram with SMS codes and retries",
"recent": "Recent diagrams",
"drawYourself": "Start with a blank canvas",
+4 -4
View File
@@ -72,7 +72,7 @@
"replicateDescription": "既存のフローチャートをアップロードして複製",
"creativeDrawing": "自由なイラスト",
"creativeDescription": "楽しくてクリエイティブなものを描く",
"cachedNote": "例は保存済みの回答を使うので、すぐに表示され、AI を呼び出しません。",
"cachedNote": "例はすぐに開き、モデルは使いません。",
"mcpServer": "MCP サーバー",
"mcpDescription": "Claude Desktop、VS Code、Cursor で使用"
},
@@ -96,7 +96,7 @@
"language": "言語",
"languageDescription": "インターフェース言語を選択します。",
"theme": "テーマ",
"themeDescription": "画面をライトにするかダークにするか。キャンバスも同じテーマになります。",
"themeDescription": "画面をライトにするかダークにするか。図はエクスポートしたときと同じく、常に白い用紙の上に表示されます。",
"diagramStyle": "図のスタイル",
"diagramStyleDescription": "AI が新しい図を描くときのスタイル。スタイル付きは色やアイコンを使い、ミニマルは素朴な図形だけにします。",
"sendShortcut": "送信のショートカット",
@@ -354,7 +354,7 @@
"searchModels": "モデルを検索...",
"noModelsFound": "モデルが見つかりません。",
"default": "デフォルト",
"serverDefault": "サーバーのモデル",
"serverDefault": "サーバーデフォルト",
"serverModels": "サーバーモデル",
"userModels": "ユーザーモデル",
"configureModels": "モデルを設定...",
@@ -694,7 +694,7 @@
},
"lobby": {
"title": "どんな図を描きますか?",
"lede": "図を説明するか、スクリーンショットや PDF をアップロードしてください。できあがるのは編集もエクスポートもできる draw.io の図です。",
"lede": "図の内容を説明するか、スクリーンショットや PDF をアップロードしてください。できあがるのは通常の draw.io の図なので、続けて編集もエクスポートもできます。",
"placeholder": "例:SMS 認証とリトライを含むログインのシーケンス図",
"recent": "最近の図",
"drawYourself": "白紙のキャンバスから始める",
+4 -4
View File
@@ -72,7 +72,7 @@
"replicateDescription": "上傳並複製現有流程圖",
"creativeDrawing": "創意繪畫",
"creativeDescription": "繪製有趣且富有創意的內容",
"cachedNote": "範例使用保存好的答案,立即顯示,不呼叫 AI。",
"cachedNote": "範例會立即開啟,不呼叫模型。",
"mcpServer": "MCP 伺服器",
"mcpDescription": "在 Claude Desktop、VS Code 和 Cursor 中使用"
},
@@ -96,7 +96,7 @@
"language": "語言",
"languageDescription": "選擇介面語言。",
"theme": "主題",
"themeDescription": "介面用淺色還是深色,畫布跟隨同一主題。",
"themeDescription": "介面用淺色還是深色。圖紙始終是白底,和匯出後的樣子一致。",
"diagramStyle": "圖形風格",
"diagramStyleDescription": "AI 畫新圖時的風格:精緻會用顏色和圖示,簡約只用樸素的圖形。",
"sendShortcut": "傳送快速鍵",
@@ -399,7 +399,7 @@
"searchModels": "搜尋模型...",
"noModelsFound": "未找到模型。",
"default": "預設",
"serverDefault": "伺服器模型",
"serverDefault": "伺服器預設",
"serverModels": "伺服器模型",
"userModels": "使用者模型",
"configureModels": "配置模型...",
@@ -694,7 +694,7 @@
},
"lobby": {
"title": "說說你要畫什麼",
"lede": "描述一張圖,或上傳截圖、PDF。得到的是可以繼續編輯和匯出的 draw.io 圖。",
"lede": "描述一張圖,或上傳截圖、PDF。畫出來的是標準的 draw.io 圖表,可以接著改,也可以匯出。",
"placeholder": "例如:使用者登入的時序圖,包含簡訊驗證碼和失敗重試",
"recent": "最近的圖紙",
"drawYourself": "從空白畫布開始",
+4 -4
View File
@@ -72,7 +72,7 @@
"replicateDescription": "上传并复制现有流程图",
"creativeDrawing": "创意绘画",
"creativeDescription": "绘制有趣且富有创意的内容",
"cachedNote": "示例使用保存好的答案,立即显示,不调用 AI。",
"cachedNote": "示例会立即打开,不调用模型。",
"mcpServer": "MCP 服务器",
"mcpDescription": "在 Claude Desktop、VS Code 和 Cursor 中使用"
},
@@ -96,7 +96,7 @@
"language": "语言",
"languageDescription": "选择界面语言。",
"theme": "主题",
"themeDescription": "界面用浅色还是深色,画布跟随同一主题。",
"themeDescription": "界面用浅色还是深色。图纸始终是白底,和导出后的样子一致。",
"diagramStyle": "图形风格",
"diagramStyleDescription": "AI 画新图时的风格:精致会用颜色和图标,简约只用朴素的图形。",
"sendShortcut": "发送快捷键",
@@ -399,7 +399,7 @@
"searchModels": "搜索模型...",
"noModelsFound": "未找到模型。",
"default": "默认",
"serverDefault": "服务器模型",
"serverDefault": "服务器默认",
"serverModels": "服务器模型",
"userModels": "用户模型",
"configureModels": "配置模型...",
@@ -694,7 +694,7 @@
},
"lobby": {
"title": "说说你要画什么",
"lede": "描述一张图,或上传截图、PDF。得到的是可以继续编辑和导出的 draw.io 图。",
"lede": "描述一张图,或者上传截图、PDF。画出来的是标准的 draw.io 图表,可以接着改,也可以导出。",
"placeholder": "比如:用户登录的时序图,包含短信验证码和失败重试",
"recent": "最近的图纸",
"drawYourself": "从空白画布开始",
+1689 -1139
View File
File diff suppressed because it is too large Load Diff
+17 -17
View File
@@ -45,11 +45,11 @@
"@aihubmix/ai-sdk-provider": "^2.2.1",
"@aws-sdk/client-dynamodb": "^3.957.0",
"@aws-sdk/credential-providers": "^3.943.0",
"@extractus/article-extractor": "^9.0.0",
"@extractus/article-extractor": "^8.0.18",
"@formatjs/intl-localematcher": "^0.9.0",
"@langfuse/client": "^5.0.0",
"@langfuse/otel": "^5.0.0",
"@langfuse/tracing": "^5.0.0",
"@langfuse/client": "^4.4.9",
"@langfuse/otel": "^4.4.4",
"@langfuse/tracing": "^4.4.9",
"@next/third-parties": "^16.0.6",
"@opennextjs/cloudflare": "^1.17.1",
"@openrouter/ai-sdk-provider": "^2.10.0",
@@ -74,13 +74,13 @@
"cmdk": "^1.1.1",
"idb": "^8.0.3",
"jsonrepair": "^3.13.1",
"lucide-react": "^1.0.0",
"motion": "^14.0.0",
"nanoid": "^6.0.0",
"lucide-react": "^0.577.0",
"motion": "^12.23.25",
"nanoid": "^5.0.0",
"negotiator": "^1.0.0",
"next": "^16.0.7",
"ollama-ai-provider-v2": "^3.6.0",
"pako": "^3.0.0",
"pako": "^2.1.0",
"prism-react-renderer": "^2.4.1",
"react": "^19.1.2",
"react-dom": "^19.1.2",
@@ -119,27 +119,27 @@
"@testing-library/user-event": "^14.6.1",
"@types/negotiator": "^0.6.4",
"@types/node": "^24.0.0",
"@types/pako": "^3.0.0",
"@types/pako": "^2.0.3",
"@types/react": "^19",
"@types/react-dom": "^19",
"@types/turndown": "^5.0.6",
"@vitejs/plugin-react": "^6.0.0",
"@vitest/coverage-v8": "^5.0.0",
"concurrently": "^10.0.0",
"@vitejs/plugin-react": "^5.1.2",
"@vitest/coverage-v8": "^4.0.16",
"concurrently": "^9.2.1",
"cross-env": "^10.1.0",
"electron": "^39.2.7",
"electron-builder": "^26.0.12",
"esbuild": "^0.28.0",
"eslint": "10.12.0",
"eslint": "9.39.5",
"eslint-config-next": "16.1.6",
"husky": "^9.1.7",
"jsdom": "^30.0.0",
"lint-staged": "^17.0.0",
"jsdom": "^27.4.0",
"lint-staged": "^16.2.7",
"shx": "^0.4.0",
"tailwindcss": "^4",
"typescript": "^7.0.0",
"typescript": "^5",
"vite-tsconfig-paths": "^6.0.3",
"vitest": "^5.0.0",
"vitest": "^4.0.16",
"wait-on": "^9.0.3",
"wrangler": "^4.60.0"
},
+217 -527
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -42,16 +42,16 @@
"@modelcontextprotocol/sdk": "^1.31.0",
"linkedom": "^0.18.0",
"open": "^11.0.0",
"pako": "^3.0.0",
"pako": "^2.2.0",
"saxes": "^6.0.0",
"zod": "^4.0.0"
},
"devDependencies": {
"@types/node": "^24.0.0",
"@types/pako": "^3.0.0",
"@types/pako": "^2.0.4",
"tsx": "^4.19.0",
"typescript": "^7.0.0",
"vitest": "^5.0.0"
"typescript": "^5",
"vitest": "^4.1.8"
},
"engines": {
"node": ">=18"
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 67 KiB