Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions .github/release-drafter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ header: |
`v$RESOLVED_VERSION`

## 下载地址 / Downloads
- macOS Apple Silicon: [点击下载 / Download](https://github.com/arnoldhao/dreamcreator/releases/download/v$RESOLVED_VERSION/dreamcreator-macos-arm64-$RESOLVED_VERSION.zip)
- macOS Intel: [点击下载 / Download](https://github.com/arnoldhao/dreamcreator/releases/download/v$RESOLVED_VERSION/dreamcreator-macos-x64-$RESOLVED_VERSION.zip)
- Windows 安装版 / Installer: [点击下载 / Download](https://github.com/arnoldhao/dreamcreator/releases/download/v$RESOLVED_VERSION/dreamcreator-windows-x64-$RESOLVED_VERSION-installer.exe)
- Windows 便携版 / Portable: [点击下载 / Download](https://github.com/arnoldhao/dreamcreator/releases/download/v$RESOLVED_VERSION/dreamcreator-windows-x64-$RESOLVED_VERSION.zip)
| 平台 / Platform | 官方下载 / Official | 镜像下载 / Mirror |
| --- | --- | --- |
| macOS Apple Silicon | [点击下载 / Download](https://github.com/arnoldhao/dreamcreator/releases/download/v$RESOLVED_VERSION/dreamcreator-macos-arm64-$RESOLVED_VERSION.zip) | [镜像下载 / Mirror](https://gh-proxy.com/https://github.com/arnoldhao/dreamcreator/releases/download/v$RESOLVED_VERSION/dreamcreator-macos-arm64-$RESOLVED_VERSION.zip) |
| macOS Intel | [点击下载 / Download](https://github.com/arnoldhao/dreamcreator/releases/download/v$RESOLVED_VERSION/dreamcreator-macos-x64-$RESOLVED_VERSION.zip) | [镜像下载 / Mirror](https://gh-proxy.com/https://github.com/arnoldhao/dreamcreator/releases/download/v$RESOLVED_VERSION/dreamcreator-macos-x64-$RESOLVED_VERSION.zip) |
| Windows 安装版 / Installer | [点击下载 / Download](https://github.com/arnoldhao/dreamcreator/releases/download/v$RESOLVED_VERSION/dreamcreator-windows-x64-$RESOLVED_VERSION-installer.exe) | [镜像下载 / Mirror](https://gh-proxy.com/https://github.com/arnoldhao/dreamcreator/releases/download/v$RESOLVED_VERSION/dreamcreator-windows-x64-$RESOLVED_VERSION-installer.exe) |
| Windows 便携版 / Portable | [点击下载 / Download](https://github.com/arnoldhao/dreamcreator/releases/download/v$RESOLVED_VERSION/dreamcreator-windows-x64-$RESOLVED_VERSION.zip) | [镜像下载 / Mirror](https://gh-proxy.com/https://github.com/arnoldhao/dreamcreator/releases/download/v$RESOLVED_VERSION/dreamcreator-windows-x64-$RESOLVED_VERSION.zip) |

## macOS 首次运行说明 / First Launch on macOS
将 `DreamCreator.app` 移动到“应用程序”目录后,若提示“无法打开”或“已损坏”,请在终端执行:
Expand Down
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,15 @@

### 一、下载安装

1. **获取安装包**:前往 [GitHub Releases](https://github.com/arnoldhao/dreamcreator/releases) 选择对应的安装包。macOS 用户使用 `.dmg`(Apple silicon 请选择 `arm64` 版本,Intel 请选择 `intel` 版本),Windows 用户根据需求选择 `.exe` 安装包或 `.zip` 便携版。
2. **通过系统安全提示**:
- macOS:右键应用选择“打开”,或执行 `sudo xattr -rd com.apple.quarantine /Applications/DreamCreator.app` 移除隔离。
- Windows:首次运行若出现 SmartScreen 提示,点击“更多信息 → 仍要运行”。

> 说明:当前 macOS 安装包可能尚未完成开发者签名与公证,首次运行时需要用户手动放行。
1. **下载对应安装包**:点击以下直链即可下载最新版本;如需查看历史版本,可前往 [GitHub Releases](https://github.com/arnoldhao/dreamcreator/releases):
- macOS Apple Silicon:[点击下载](https://updates.dreamapp.cc/dreamcreator/downloads/dreamcreator-macos-arm64-latest.zip)
- macOS Intel:[点击下载](https://updates.dreamapp.cc/dreamcreator/downloads/dreamcreator-macos-x64-latest.zip)
- Windows 安装版:[点击下载](https://updates.dreamapp.cc/dreamcreator/downloads/dreamcreator-windows-x64-latest-installer.exe)
- Windows 便携版:[点击下载](https://updates.dreamapp.cc/dreamcreator/downloads/dreamcreator-windows-x64-latest.zip)
2. **首次运行 macOS**:解压 `.zip` 后,将 `DreamCreator.app` 移动到“应用程序”目录。若系统提示“无法打开”或“已损坏”,请在终端执行:

`sudo xattr -rd com.apple.quarantine /Applications/DreamCreator.app`
3. **首次运行 Windows**:安装版双击 `.exe` 按提示安装;便携版解压 `.zip` 后直接运行。若首次启动出现 SmartScreen 提示,点击“更多信息 → 仍要运行”。


### 二、供应商 / Provider
Expand Down
15 changes: 9 additions & 6 deletions README_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,15 @@ Dream Creator is a cross-platform desktop application for macOS and Windows. It

### 1. Download and install

1. **Get the package**: go to [GitHub Releases](https://github.com/arnoldhao/dreamcreator/releases) and choose the package for your platform. On macOS, use the `.dmg` package (`arm64` for Apple silicon, `intel` for Intel Macs). On Windows, choose either the `.exe` installer or the portable `.zip` package.
2. **Handle system security prompts**:
- macOS: right-click the app and choose `Open`, or run `sudo xattr -rd com.apple.quarantine /Applications/DreamCreator.app`.
- Windows: if SmartScreen appears on first launch, choose `More info` and then `Run anyway`.

> Note: the current macOS package may not yet be fully signed and notarized, so manual approval may be required on first launch.
1. **Download the right package**: use the direct links below to download the latest build. If you need older releases, see [GitHub Releases](https://github.com/arnoldhao/dreamcreator/releases):
- macOS Apple Silicon: [Download](https://updates.dreamapp.cc/dreamcreator/downloads/dreamcreator-macos-arm64-latest.zip)
- macOS Intel: [Download](https://updates.dreamapp.cc/dreamcreator/downloads/dreamcreator-macos-x64-latest.zip)
- Windows Installer: [Download](https://updates.dreamapp.cc/dreamcreator/downloads/dreamcreator-windows-x64-latest-installer.exe)
- Windows Portable: [Download](https://updates.dreamapp.cc/dreamcreator/downloads/dreamcreator-windows-x64-latest.zip)
2. **First launch on macOS**: unzip the package, move `DreamCreator.app` to the Applications folder, and if macOS says the app can't be opened or is damaged, run:

`sudo xattr -rd com.apple.quarantine /Applications/DreamCreator.app`
3. **First launch on Windows**: double-click the `.exe` installer or unzip the portable `.zip` package and run it. If SmartScreen appears on first launch, choose `More info` and then `Run anyway`.

### 2. Providers

Expand Down
11 changes: 5 additions & 6 deletions frontend/src/app/main/MainApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import { AppShell } from "@/components/layout/AppShell";
import type { SidebarConfig } from "@/components/layout/AppSidebar";
import { PageHeader } from "@/shared/ui/PageHeader";
import { Button } from "@/shared/ui/button";
import { Separator } from "@/shared/ui/separator";
import { messageBus } from "@/shared/message";
import { useI18n } from "@/shared/i18n";
import { TaskDialog } from "@/features/library/components/TaskDialog";
Expand Down Expand Up @@ -354,15 +353,15 @@ export function MainApp() {
{isChatMenuOpen ? <ChevronUp className="h-4 w-4" /> : <ChevronDown className="h-4 w-4" />}
</Button>
{isChatMenuOpen ? (
<div className="absolute left-0 top-full z-50 mt-2 w-[220px] rounded-md border bg-popover p-1 text-sm shadow-md">
<div className="flex items-center gap-2 px-2 py-1.5 text-muted-foreground">
<div className="app-menu-content app-motion-surface absolute left-0 top-full z-50 mt-2 w-max min-w-fit text-sm animate-in fade-in-0 zoom-in-95">
<div className="app-menu-label flex items-center gap-2 text-sm text-muted-foreground">
<MessageCircle className="h-4 w-4" />
<span className="truncate">{resolvedChatSubtitle}</span>
</div>
<Separator className="my-1" />
<div className="app-menu-separator" />
<button
type="button"
className="flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50"
className="app-menu-item app-motion-color flex w-full items-center text-left text-sm outline-none hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50"
onClick={() => {
handleOpenWorkspace();
setIsChatMenuOpen(false);
Expand All @@ -374,7 +373,7 @@ export function MainApp() {
</button>
<button
type="button"
className="flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-destructive hover:bg-accent/60 hover:text-destructive"
className="app-menu-item app-motion-color flex w-full items-center text-left text-sm text-destructive outline-none hover:bg-accent hover:text-destructive"
onClick={() => {
handleDeleteThread();
setIsChatMenuOpen(false);
Expand Down
37 changes: 34 additions & 3 deletions frontend/src/app/providers/AppProviders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,30 @@ const upsertOperationListItem = (
return updated;
};

const shouldRefreshOperationListItem = (
current: OperationListItemDTO | undefined,
operation: LibraryOperationDTO
) => {
if (!current) {
return true;
}
const next = toOperationListItem(operation);
return (
current.libraryId !== next.libraryId ||
current.name !== next.name ||
current.kind !== next.kind ||
current.status !== next.status ||
current.domain !== next.domain ||
current.sourceIcon !== next.sourceIcon ||
current.platform !== next.platform ||
current.uploader !== next.uploader ||
current.publishTime !== next.publishTime ||
current.startedAt !== next.startedAt ||
current.finishedAt !== next.finishedAt ||
current.createdAt !== next.createdAt
);
};

const removeOperationListItem = (
previous: OperationListItemDTO[] | undefined,
operationId: string
Expand Down Expand Up @@ -486,9 +510,16 @@ export function AppProviders({ children }: PropsWithChildren) {
const operation = payload as LibraryOperationDTO;
store.upsertOperation(operation);
queryClient.setQueryData([...LIBRARY_OPERATIONS_QUERY_KEY, "detail", operation.id], operation);
queryClient.setQueriesData({ queryKey: LIBRARY_OPERATIONS_QUERY_KEY }, (current) =>
Array.isArray(current) ? upsertOperationListItem(current as OperationListItemDTO[], operation) : current
);
queryClient.setQueriesData({ queryKey: LIBRARY_OPERATIONS_QUERY_KEY }, (current) => {
if (!Array.isArray(current)) {
return current;
}
const items = current as OperationListItemDTO[];
const existing = items.find((item) => item.operationId === operation.id);
return shouldRefreshOperationListItem(existing, operation)
? upsertOperationListItem(items, operation)
: current;
});
if (isTerminalOperationStatus(operation.status)) {
scheduleLibraryResync(operation.libraryId);
}
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/layout/AppSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -207,14 +207,14 @@ function ThreadContextMenu({
}

const itemClassName =
"flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground";
"app-menu-item app-motion-color flex w-full items-center text-left text-sm outline-none hover:bg-accent hover:text-accent-foreground";

return createPortal(
<div
ref={menuRef}
role="menu"
className={cn(
"fixed z-[120] min-w-[10rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
"app-menu-content app-motion-surface fixed z-[120] w-max min-w-fit text-sm",
"animate-in fade-in-0 zoom-in-95"
)}
style={{ left: position.x, top: position.y }}
Expand All @@ -224,7 +224,7 @@ function ThreadContextMenu({
<Pencil className="h-4 w-4" />
<span>{labels.rename}</span>
</button>
<div className="-mx-1 my-1 h-px bg-border" />
<div className="app-menu-separator" />
<button type="button" role="menuitem" className={itemClassName} onClick={onArchiveToggle}>
{archived ? <ArchiveRestore className="h-4 w-4" /> : <Archive className="h-4 w-4" />}
<span>{archived ? labels.unarchive : labels.archive}</span>
Expand Down
17 changes: 14 additions & 3 deletions frontend/src/features/chat/components/ComposerBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,11 @@ const toFiniteTokenValue = (value: unknown): number => {
return Math.max(0, Math.floor(value));
};

const isCancelledErrorMessage = (error: unknown) => {
const message = error instanceof Error ? error.message : String(error ?? "");
return message.toLowerCase().includes("cancel");
};

const parseThreadContextSnapshot = (payload: unknown): ContextTokenSnapshot | null => {
if (!payload || typeof payload !== "object") {
return null;
Expand Down Expand Up @@ -641,14 +646,14 @@ function PermissionModeSelector({
style={PERMISSION_TRIGGER_MAX_WIDTH_STYLE}
>
<span className="inline-flex items-center justify-center">
<selected.Icon className="size-3.5 text-muted-foreground" />
<selected.Icon className="size-4 text-muted-foreground" />
</span>
</AuiSelectTrigger>
<AuiSelectContent align="center" className="max-w-[260px]">
{options.map((option) => (
<AuiSelectItem key={option.value} value={option.value}>
<span className="flex items-center gap-2 whitespace-nowrap">
<option.Icon className="size-3.5 text-muted-foreground" />
<option.Icon className="size-4 text-muted-foreground" />
<span className="truncate">{option.label}</span>
</span>
</AuiSelectItem>
Expand Down Expand Up @@ -837,8 +842,14 @@ export function ComposerBar({
t("chat.composer.attachDialogTitle")
);
const picked = (Array.isArray(selection) ? selection : []) as SelectedAttachmentFile[];
if (picked.length === 0) {
return;
}
await addSelectedAttachments(picked);
} catch (error) {
if (isCancelledErrorMessage(error)) {
return;
}
const message = error instanceof Error ? error.message : String(error);
messageBus.publishToast({
title: t("chat.composer.attachError"),
Expand Down Expand Up @@ -954,7 +965,7 @@ export function ComposerBar({
<ComposerPrimitive.AttachmentDropzone className="wails-no-drag">
<ComposerPrimitive.Root
data-file-drop-target="chat-composer"
className="flex w-full flex-col gap-2 rounded-2xl border border-border/60 bg-card/90 p-3 shadow-sm"
className="flex w-full flex-col gap-2 rounded-2xl border border-border/60 bg-card/90 p-[var(--app-sidebar-padding)] shadow-sm"
>
<ComposerAttachments />
<ComposerPrimitive.Input
Expand Down
Loading
Loading