chore(memory): 同步 Claude auto-memory 到 .claude/memory/
便于在其他机器(公司电脑)拉取后恢复对项目的记忆。 .gitignore 改为 .claude/* + 排除 .claude/memory/,其余 .claude/ 子内容继续忽略。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Showing
15 changed files
with
512 additions
and
1 deletions
.claude/memory/MEMORY.md
0 → 100644
| 1 | # Memory Index | ||
| 2 | |||
| 3 | - [User: 跨平台 UI 一致性诉求](user_cross_platform_ui.md) — 用户强烈关注 macOS 和 Windows 两端视觉/交互的一致性 | ||
| 4 | - [User: 自主交付偏好](user_overnight_autonomy.md) — 大型重构允许"睡前授权 → 醒来 review 分支"模式 | ||
| 5 | - [Project: 珠宝壹佰 / 品牌色](project_zb100_brand.md) — 公司"珠宝壹佰",品牌色契合 Apple Blue | ||
| 6 | - [Project: UI 主题系统架构](project_theme_system.md) — (旧 QWidget 路线) theme.py 设计令牌,业务不写 inline setStyleSheet | ||
| 7 | - [Project: UI 迁移到 QML](project_qml_migration.md) — 当前活跃路线,feat/ui-qml-poc 分支,task #11/#12/#20 完成,#13-#19 待办 | ||
| 8 | - [Reference: QML PoC 结构](reference_qml_poc_structure.md) — qml_poc/ 文件结构 + Theme token + 组件 API | ||
| 9 | - [Reference: 业务桥层 bridges/](reference_bridges.md) — 5 个 Bridge QObject 的 Property/Signal/Slot 形状(task #13-#17 wiring 查) | ||
| 10 | - [Reference: core/ 业务模块](reference_core_modules.md) — image_generator.py 拆分后的业务核心目录 | ||
| 11 | - [Feedback: 拒绝路径盲从 / 第一性原理](feedback_first_principles.md) — 路径非最优时直接建议替代方案,不要按用户当下方案盲做 | ||
| 12 | - [Feedback: UI 迭代用 python 跑,别打包](feedback_dev_iter_via_python.md) — 调 UI 用 pythonw.exe 直接跑,PyInstaller 太慢 | ||
| 13 | - [Feedback: 旧代码多留几天](feedback_keep_legacy_code.md) — 重构 / 替换实现时默认 .txt 改名保留,不 git rm,等用户主动说删 | ||
| 14 | - [Reference: 项目入口和打包](reference_entry_and_build.md) — 主入口、打包脚本、PyInstaller spec 位置 | ||
| 15 | - [Reference: 打包当前形状 + 易踩坑](reference_packaging.md) — task #19 ZB100ImageGenerator.spec 现状(QML datas 路径 / pathex / Pillow) |
| 1 | --- | ||
| 2 | name: UI 迭代用 python 直接跑,别打包 | ||
| 3 | description: 调试 UI 改动时直接 python image_generator.py,不要 pyinstaller 打包 | ||
| 4 | type: feedback | ||
| 5 | originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077 | ||
| 6 | --- | ||
| 7 | 用户原话:"你直接启动py让我看效果好了,不要打包了,打包反而节奏慢了"。 | ||
| 8 | |||
| 9 | **Why**:PyInstaller 打包跑一次约 60-90 秒(包括 collect dynamic libs、PYZ、COLLECT),UI 调试每次改一个 padding / 字号都要重打,浪费时间。Python 直接跑只要 1-2 秒到登录页。 | ||
| 10 | |||
| 11 | **How to apply**: | ||
| 12 | - 当用户想"看效果"或快速验收 UI 改动时,用 `start "" .venv/Scripts/pythonw.exe image_generator.py`(Windows 后台启动,无 console 窗口) | ||
| 13 | - pythonw.exe 而不是 python.exe — 前者不弹黑色 console,跟打包后体验一致 | ||
| 14 | - 只在以下场景才打包: | ||
| 15 | - 任务结尾要交付产物(明天上班看 dist) | ||
| 16 | - 验证打包后的资源完整性(如确认 PIL 原生库进了包) | ||
| 17 | - 用户明确要求"打个新包" | ||
| 18 | - 不要在每次改完代码后默认打包 | ||
| 19 | |||
| 20 | **配套**:先 `tasklist | grep -i ZB100\|pythonw` 看有没有残留实例,有就 kill,避免端口/文件锁冲突。 |
.claude/memory/feedback_first_principles.md
0 → 100644
| 1 | --- | ||
| 2 | name: 第一性原理 / 拒绝路径盲从 | ||
| 3 | description: 用户期望在路径非最优或目标模糊时直接被建议替代方案,而不是被动执行 | ||
| 4 | type: feedback | ||
| 5 | originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077 | ||
| 6 | --- | ||
| 7 | 来自全局 CLAUDE.md(用户的私有规则): | ||
| 8 | > **第一性原理**:从原始需求出发,拒绝路径盲从。目标模糊时停下讨论,路径非最优时直接建议替代方案 | ||
| 9 | |||
| 10 | 实际验证过的应用场景(2026-05-09): | ||
| 11 | - 用户最初问"UI 有点丑丑的,你有啥建议"——这是个开放问题。我直接给三个方向 + 推荐方案 B(自己写 QSS),用户接受。 | ||
| 12 | - 用户在选第三方库 vs 自写 QSS 时也接受了我"先做 B"的推荐。 | ||
| 13 | - brainstorming 阶段每个决策都给"我的推荐 + 理由"作为第一项,用户选择速度很快。 | ||
| 14 | |||
| 15 | **Why**:用户技术判断力强,希望对话型协作而非"你说一我做一"的脚本式执行。给推荐 + 理由比给清单更省时间。 | ||
| 16 | |||
| 17 | **How to apply**: | ||
| 18 | - 用户描述任务时如果包含 "你觉得"/"建议"/"看看"等词,**先给推荐**再给替代 | ||
| 19 | - 给方案永远是 2-3 个选项 + 我的判断 + 一句话理由,不要列 10 个让他选 | ||
| 20 | - 如果发现用户提的实施路径有更好的替代(比如他说"加个 retry"但实际应该改架构),**先建议替代**而不是默默照做 | ||
| 21 | - 简单问题直接回答,不要套结构化模板(CLAUDE.md 明确说"仅在架构决策 / 方案评估 / 代码审查时使用结构化模板") |
.claude/memory/feedback_keep_legacy_code.md
0 → 100644
| 1 | --- | ||
| 2 | name: 重构时保留旧实现,多留几天 | ||
| 3 | description: 用户偏好在大重构 / 替换实现时保留旧代码作为回退参考,不急着删 | ||
| 4 | type: feedback | ||
| 5 | originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077 | ||
| 6 | --- | ||
| 7 | 重构、替换实现、删除老入口时,**默认先保留旧代码几天到几周**,不要在 PR 里同时删。 | ||
| 8 | |||
| 9 | **Why**:用户多次强调(2026-05-09 改 image_generator.py.txt 时、2026-05-11 重申"多留几天")。 | ||
| 10 | 理由是新实现刚跑通时未必稳定,"万一有问题还能翻翻老代码"。Linus 风格的"不破坏兼容" | ||
| 11 | 在这个项目里被延伸成"不要急着断老路"——回退点的存在比代码整洁更重要。 | ||
| 12 | |||
| 13 | **How to apply**: | ||
| 14 | - 老入口 / 老实现替换为新版后,git mv 改 `.txt` 后缀(Python 不加载 / PyInstaller 不扫) | ||
| 15 | 而不是 `git rm`。等用户主动说"删了吧"再删。 | ||
| 16 | - 类似 image_generator.py.txt 的情况:要重构的大文件别"一次干净到底", | ||
| 17 | 先把核心拆出去,老文件保留两版并存几天。 | ||
| 18 | - 在 PR 描述里指明老代码留作 fallback,预计何时清理(让 reviewer 知道"这不是漏删")。 | ||
| 19 | - 自己看见老代码躺着别"顺手 cleanup" — 没用户授权不删。 | ||
| 20 | |||
| 21 | **判断边界**: | ||
| 22 | - 真正过期、已破坏 API、有安全问题的老代码,可以删(这种情况会很明显)。 | ||
| 23 | - 普通的"功能重写、行为不变"的老代码,按本规则保留。 |
.claude/memory/project_qml_migration.md
0 → 100644
| 1 | --- | ||
| 2 | name: UI 迁移到 PySide6 + QML(QtQuick) | ||
| 3 | description: 2026-05-09 用户决定从 QWidget+QSS 转 QtQuick/QML,分支 feat/ui-qml-poc | ||
| 4 | type: project | ||
| 5 | originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077 | ||
| 6 | --- | ||
| 7 | **Why**:QWidget+QSS 视觉天花板低(layout 压缩 / sizeHint 不更新 / 字号溢出系列坑)。 | ||
| 8 | QML layout 引擎稳定,圆角 / 阴影 / 动效原生支持,跨 Mac+Windows 视觉一致。 | ||
| 9 | **Python 业务后端完全不动**,只换 UI 层。 | ||
| 10 | |||
| 11 | **分支**:`feat/ui-qml-poc`,独立于 master。 | ||
| 12 | |||
| 13 | **目录结构**: | ||
| 14 | ``` | ||
| 15 | core/ 业务核心(task #20 从 image_generator.py 拆出) | ||
| 16 | paths.py / database.py / history.py / generation.py / jewelry.py | ||
| 17 | runtime.py 启动期工具(crash diag / init_logging / cleanup / log_system_info) | ||
| 18 | bridges/ QML 桥层 | ||
| 19 | auth.py / imagegen.py / history.py / taskqueue.py / jewelry.py / _icons.py | ||
| 20 | qml_poc/main_qml.py 主入口(8-phase boot + setContextProperty 注入桥) | ||
| 21 | qml_poc/qml/ QML 文件 | ||
| 22 | Theme.qml (Singleton tokens) | ||
| 23 | Main.qml / LoginScreen.qml / MainWindow.qml | ||
| 24 | ImageGenTab.qml / StyleDesignerTab.qml / HistoryTab.qml | ||
| 25 | components/ (PrimaryButton / SecondaryButton / ThemedTextField / ThemedComboBox / Card / CaptionLabel) | ||
| 26 | image_generator.py.txt 老 QWidget 代码(git mv 改 .txt 不参与执行,保留扒老逻辑用) | ||
| 27 | task_queue.py / audit_logger.py / preflight.py / config_util.py 保持 master 一致,未改架构 | ||
| 28 | ``` | ||
| 29 | |||
| 30 | **已完成**(截至 2026-05-10): | ||
| 31 | - ✅ #11 PoC UI 视觉 / #20 image_generator.py 拆 core/ | ||
| 32 | - ✅ #12 桥层(5 QObject contextProperty)/ #13 db 登录 + 记住凭据 | ||
| 33 | - ✅ #14 图片生成 tab 完整(核心 / 参考图 / 收藏 / 下载 / Ctrl+V / 14 比例 + 自动切模式 / | ||
| 34 | 多任务 / 拖拽重排 DragHandler Finder 风格 / 跟手 ghost / 10MB 校验 / 编号 badge) | ||
| 35 | - ✅ #16 历史 tab(ListView + 详情面板 + 右键菜单 / 清空 / 复制 prompt / 在文件管理器中显示选中 | ||
| 36 | / 🔁 重做按钮回填到生成 tab 不带生成图) | ||
| 37 | - ✅ #17 任务队列 sidebar(taskQueue.model 增量 / 状态彩色 / 进度条 / 左键回填 loadTask / | ||
| 38 | 右键 Menu 取消任务) | ||
| 39 | - ✅ #15 款式设计 tab(8 字段 + 锁定 + 随机 + 字段右键恢复单类别默认 + 顶部全部恢复 + | ||
| 40 | inline ➕/🗑️ 词条 + 实时 Prompt 预览) | ||
| 41 | - ✅ 启动 8-phase boot:crash diag → RotatingFileHandler logs/app.log → 系统信息 → | ||
| 42 | cleanup_clipboard_tempfiles → preflight → 窗口图标 → 桥层 → QML | ||
| 43 | - ✅ 完整 logtrace:bridges/* + core/* 所有 except 用 logger.exception(...) | ||
| 44 | - ✅ 剪贴板三层 fallback + macOS osascript 兜底(避免 Qt clipboard native crash) | ||
| 45 | - ✅ 输入框右键菜单(剪切/复制/粘贴/全选,密码框禁复制剪切) | ||
| 46 | - ✅ #21 修右键粘贴(TextField MouseArea 替代 TapHandler)+ 8px ScrollBar + | ||
| 47 | 参考图双击 TapHandler.onDoubleTapped 系统查看器 | ||
| 48 | - ✅ #22 日志分级 fsync:TieredFsyncHandler(WARNING+ 同步 fsync / INFO buffered) | ||
| 49 | + 1s 周期 daemon 线程兜底 + macOS DiagnosticReports 提示写入 crash_log.txt | ||
| 50 | - ✅ #19 Windows 打包:ZB100ImageGenerator.spec 切 qml_poc/main_qml.py 入口, | ||
| 51 | pathex=项目根,datas qml_poc/qml→_MEIPASS/qml(不带 qml_poc/ 前缀! | ||
| 52 | PyInstaller 把入口平铺到 _MEIPASS 根,Path(__file__).parent/"qml" 找 _MEIPASS/qml) | ||
| 53 | 本地 dist/ZB100ImageGenerator/ZB100ImageGenerator.exe 验证 8 phases 全过 | ||
| 54 | |||
| 55 | **剩余待办**: | ||
| 56 | - #19 Mac build_mac_universal.sh 真机验证(含 .app + .dmg + Pillow .dylibs) | ||
| 57 | - #19 image_generator.py.txt 真正删除(用户要求暂留作扒老逻辑参考;确认稳定后再删) | ||
| 58 | - #18 系统暗色模式跟随(Theme.qml 加深色 token + Qt.styleHints.colorScheme 监听) | ||
| 59 | - 款式设计批量词库管理对话框(旧版有,新版只有 inline ➕/🗑️) | ||
| 60 | - 双击大图内嵌 viewer(当前 Qt.openUrlExternally 系统查看器替代,等价但 UX 不同) | ||
| 61 | |||
| 62 | **How to apply**: | ||
| 63 | - 业务代码改在 core/* + task_queue.py + audit_logger.py | ||
| 64 | - UI 改在 qml_poc/qml/*;桥层 API 形状见 reference_bridges.md | ||
| 65 | - 老逻辑参考 image_generator.py.txt(已重命名不参与执行) | ||
| 66 | - 完整启动序列、logtrace 在 main_qml.py + core/runtime.py | ||
| 67 | - 用户偏好:先做 #19 打包能交付给同事;#18 暗色等留以后单独迭代 |
.claude/memory/project_theme_system.md
0 → 100644
| 1 | --- | ||
| 2 | name: UI 主题系统架构 | ||
| 3 | description: theme.py 是设计系统单一真相源,业务代码不写 inline setStyleSheet | ||
| 4 | type: project | ||
| 5 | originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077 | ||
| 6 | --- | ||
| 7 | 2026-05-09 重构上线(分支 `feat/ui-redesign-apple-theme`): | ||
| 8 | |||
| 9 | **架构**: | ||
| 10 | - `theme.py` 包含 TOKENS_LIGHT / TOKENS_DARK(24 个语义颜色)/ SIZES(圆角/间距/字号)/ FONT_STACK | ||
| 11 | - `build_qss(mode)` 拼出完整 QSS 字符串 | ||
| 12 | - `ThemeManager(QObject)` 监听 `QGuiApplication.styleHints().colorSchemeChanged` 自动切换 | ||
| 13 | - `apply_theme(app)` 在 `image_generator.py main()` 创建 QApplication 后立即调用 | ||
| 14 | - `get_color(token, fallback)` 用于 QSS 命中不到的渲染层 API(如 `setForeground`) | ||
| 15 | |||
| 16 | **业务代码规则**: | ||
| 17 | - ❌ 不要写 `widget.setStyleSheet(...)` 装饰样式 | ||
| 18 | - ✅ 用 `setObjectName("xxx")` 命中 `#xxx` 选择器 | ||
| 19 | - ✅ 用 `setProperty("variant", "primary"|"danger"|"ghost"|"link"|"success-flash")` 命中 `[variant="..."]` 按钮变体 | ||
| 20 | - ✅ 用 `setProperty("status", "success"|"warning"|"danger"|"info"|"muted")` + `style().polish()` 命中 status label | ||
| 21 | - ✅ 用 `setProperty("role", "title"|"secondary"|"caption"|"muted"|"thumb"|"thumb_index")` 命中通用 label 角色 | ||
| 22 | - ✅ 用 `setProperty("drag_state", "idle"|"active")` 命中拖拽态 | ||
| 23 | - ✅ 用 `setProperty("has_image", "true"|"false")` 命中预览图占位/已显示 | ||
| 24 | |||
| 25 | **仅允许的 inline setStyleSheet**: | ||
| 26 | - 平台 hack(macOS 占位符颜色 etc.)— `image_generator.py` 1292/1356 | ||
| 27 | - 单点临时高亮反馈(< 3 秒自动恢复) | ||
| 28 | |||
| 29 | **Why**:之前 65 处零散 `setStyleSheet` 让深色模式无法实现,且改一个圆角要找十处。集中后一处改全局。 | ||
| 30 | |||
| 31 | **How to apply**:未来加新 widget / 改外观时: | ||
| 32 | 1. 优先看 `theme.py` 里有没有合适的现成 token / variant / role | ||
| 33 | 2. 如果没有,加到 `theme.py` 里(保持单一真相源),别再开 inline setStyleSheet 的口子 | ||
| 34 | 3. 状态切换(图标变化、颜色反馈)用 `setProperty + style().polish()`,不要 inline setStyleSheet |
.claude/memory/project_zb100_brand.md
0 → 100644
| 1 | --- | ||
| 2 | name: 珠宝壹佰品牌信息 | ||
| 3 | description: 公司名"珠宝壹佰",应用名"珠宝壹佰图像生成器",品牌色与 Apple Blue 契合 | ||
| 4 | type: project | ||
| 5 | originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077 | ||
| 6 | --- | ||
| 7 | 公司中文名"珠宝壹佰",英文/代码 namespace 用 ZB100(如 `ZB100ImageGenerator`、`zb100_windows.ico`、`zb100_mac.icns`、GitLab 域名 `gitlab.zb100.com`)。 | ||
| 8 | |||
| 9 | **品牌色**:用户选择 Apple Blue `#0071E3`(Light)/ `#0A84FF`(Dark)作为应用主色,理由是"跟品牌元素的颜色契合"。 | ||
| 10 | |||
| 11 | **Why**:避免后续给珠宝业品牌联想(金色 / 祖母绿)—— 这些在 brainstorming 时被讨论过但被用户主动否决,他想要的是工具感而不是行业感。 | ||
| 12 | |||
| 13 | **How to apply**: | ||
| 14 | - 如果未来需要"品牌色装饰"(市场物料、登录页背景图、欢迎页),用蓝色系而非金/绿 | ||
| 15 | - 涉及多色 chart / status indicator 时,主色固定 Apple Blue,状态色(success/warning/danger)用 Apple system colors | ||
| 16 | - 如果有客户提"想加点珠宝业色彩"的需求,先确认是否要打破当前的"工具感专注"原则,不要默默加金色 |
.claude/memory/reference_bridges.md
0 → 100644
| 1 | --- | ||
| 2 | name: QML 业务桥层 bridges/* API | ||
| 3 | description: 5 个 Bridge QObject 的 Property/Signal/Slot 形状(截至 2026-05-10) | ||
| 4 | type: reference | ||
| 5 | originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077 | ||
| 6 | --- | ||
| 7 | **目录**: | ||
| 8 | ``` | ||
| 9 | bridges/ | ||
| 10 | ├── _icons.py build_placeholder_icon | ||
| 11 | ├── auth.py AuthBridge (db_config, audit_logger, last_user, saved_password_hash, config_path) | ||
| 12 | ├── imagegen.py ImageGenBridge (TaskQueueManager, HistoryManager, AuthBridge, api_key, saved_prompts, config_path) | ||
| 13 | ├── history.py HistoryBridge (HistoryManager) | ||
| 14 | ├── taskqueue.py TaskQueueBridge (TaskQueueManager) | ||
| 15 | └── jewelry.py JewelryBridge (JewelryLibraryManager) | ||
| 16 | ``` | ||
| 17 | |||
| 18 | **main_qml.py contextProperty 名字**:`auth / imageGen / history / taskQueue / jewelry / appState` | ||
| 19 | |||
| 20 | --- | ||
| 21 | |||
| 22 | **AuthBridge**: | ||
| 23 | - Property: `loggedIn` / `currentUser` / `lastUser` (constant) / `hasSavedPassword` (constant) | ||
| 24 | - Slot: | ||
| 25 | - `login(user, pwd) → bool` 明文密码 | ||
| 26 | - `loginWithSavedPassword(user) → bool` 用已存 hash("记住密码"路径,跳过 hash) | ||
| 27 | - `saveCredentials(pwd, rememberUser, rememberPwd)` 写回 config.json(pwd="" 时保留旧 hash) | ||
| 28 | - `logout()` / `deviceName() → str` | ||
| 29 | - Signal: `loggedInChanged / currentUserChanged / loginFailed(str)` | ||
| 30 | - 内部:登录成功同步拿 public IP(3 API 兜底 3s timeout)走 audit log_login | ||
| 31 | |||
| 32 | **ImageGenBridge**: | ||
| 33 | - Property: `apiKey / busy / savedPrompts (list)` | ||
| 34 | - Slot: | ||
| 35 | - `submitTask(prompt, refs, aspect, size, mode) → task_id` (task_type=IMAGE_GENERATION) | ||
| 36 | - `submitStyleTask(prompt, refs, aspect, size, mode) → task_id` (task_type=STYLE_DESIGN) | ||
| 37 | - `cancelTask(task_id)` | ||
| 38 | - `pasteFromClipboard() → list[str]` 三层 fallback(hasUrls / mime raw bytes / imageData / clipboard.image) | ||
| 39 | + macOS osascript 兜底(避免 Qt clipboard NSPasteboard→NSImage native crash) | ||
| 40 | - `normalizeFileUrls(urls) → list` (内部走 _validate_image_file 校验扩展名 + ≤10MB + QPixmap) | ||
| 41 | - `validateImageFile(path) → {ok, reason}` / `validateImageFiles(paths) → list` | ||
| 42 | - `saveFile(src, dest) → bool` 下载图片 | ||
| 43 | - `addSavedPrompt(p) / removeSavedPrompt(p) / toggleSavedPrompt(p) → bool` (返回切换后的"已收藏"状态) | ||
| 44 | - `isSavedPrompt(p) → bool` | ||
| 45 | - Signal: `taskSubmitted(taskId)`, `taskCompleted(taskId, resultPath, prompt, model)`, | ||
| 46 | `taskFailed(taskId, error)`, `taskProgress(taskId, progress, statusText)`, | ||
| 47 | `apiKeyChanged / busyChanged / savedPromptsChanged` | ||
| 48 | - 内部:_on_completed 调 history.save_generation → 写 task.result_path → emit taskCompleted | ||
| 49 | |||
| 50 | **HistoryBridge**: | ||
| 51 | - Property: `model` (HistoryListModel QAbstractListModel) / `count` | ||
| 52 | - Slot: | ||
| 53 | - `refresh()` 整体 reset / `addNew(ts)` 增量插顶 | ||
| 54 | - `deleteItem(ts)` 增量删 / `clearAll() → bool` rmtree+重建 | ||
| 55 | - `getItem(ts) → dict` 详情 / `thumbnailPath(ts) → str` 缩略图路径 | ||
| 56 | - `revealInExplorer(path)` Windows explorer /select, / macOS open -R / Linux xdg-open | ||
| 57 | - `copyToClipboard(text) → bool` | ||
| 58 | - `redoToImageGen(ts)` → emit redoRequested 让 ImageGenTab 回填 prompt+参考图+设置 | ||
| 59 | - Signal: `itemAdded(ts) / itemRemoved(ts) / countChanged`, | ||
| 60 | `redoRequested(payload)` payload: {timestamp, prompt, referenceImages, aspectRatio, imageSize, mode} | ||
| 61 | - HistoryListModel.roleNames: display / decoration / toolTip / timestamp(=UserRole) | ||
| 62 | |||
| 63 | **TaskQueueBridge**: | ||
| 64 | - Property: `model` (_TaskListModel) / `pendingCount` / `runningCount` | ||
| 65 | - Slot: `cancelTask(task_id)`, `loadTask(task_id)` → emit taskLoadRequested 回填到对应 tab | ||
| 66 | - Signal: `pendingCountChanged / runningCountChanged`, | ||
| 67 | `taskLoadRequested(payload)` payload: {taskId, type ("image_gen"|"style_design"), | ||
| 68 | prompt, referenceImages, aspectRatio, imageSize, mode, resultPath (空字符串 if 未完成)} | ||
| 69 | - _TaskListModel.roleNames: `taskId / prompt / status / progress / statusText / elapsed` | ||
| 70 | - status 值: "pending" / "running" / "completed" / "failed" | ||
| 71 | |||
| 72 | **JewelryBridge**: | ||
| 73 | - Property: `categories` (list, 8 个类别) | ||
| 74 | - Slot: `getOptions(cat) → list`, `addItem(cat, val)`, `removeItem(cat, val)`, | ||
| 75 | `resetCategory(cat)`, `resetAll()`, `previewPrompt(formData) → str` | ||
| 76 | - Signal: `libraryChanged(category)` | ||
| 77 | |||
| 78 | --- | ||
| 79 | |||
| 80 | **主要 wiring 模式**(QML 端): | ||
| 81 | |||
| 82 | 1. ImageGenTab 接 `taskQueue.taskLoadRequested` → type=image_gen 时回填 + 切 tab 0 | ||
| 83 | 2. ImageGenTab 接 `history.redoRequested` → 回填(不带生成图)+ 切 tab 0 | ||
| 84 | 3. StyleDesignerTab 接 `taskQueue.taskLoadRequested` → type=style_design 时回填 assembledPrompt + 切 tab 1 | ||
| 85 | 4. ImageGenTab 接 `imageGen.taskCompleted/Failed/Progress` → 自己 myTaskIds 数组管理多任务 | ||
| 86 | |||
| 87 | **重要约束**: | ||
| 88 | - bytes 永远不传 QML,写盘 → 传文件路径 | ||
| 89 | - Path 对象转 `as_posix()`(防 Windows 反斜杠在 QML "file:///" + path 拼接异常) | ||
| 90 | - HistoryItem 等 dataclass 不直接暴露,用 getItem 转 dict | ||
| 91 | - 异常都用 `logger.exception(msg)` 写完整 stack 到 logs/app.log |
.claude/memory/reference_core_modules.md
0 → 100644
| 1 | --- | ||
| 2 | name: core/ 业务核心模块结构 | ||
| 3 | description: image_generator.py 5082 行拆解后的业务核心目录布局(task #20 完成) | ||
| 4 | type: reference | ||
| 5 | originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077 | ||
| 6 | --- | ||
| 7 | **背景**:image_generator.py 原本 5082 行混了 12 个类(数据库/历史/Worker/词库/UI), | ||
| 8 | QML 迁移期顺手拆出业务核心,UI 类留待 task #19 删除。 | ||
| 9 | |||
| 10 | **目录布局**(截至 2026-05-10): | ||
| 11 | ``` | ||
| 12 | core/ | ||
| 13 | ├── __init__.py | ||
| 14 | ├── paths.py get_app_data_path + save_png_with_validation + | ||
| 15 | _migrate_data_from_app_bundle | ||
| 16 | ├── database.py DatabaseManager + hash_password | ||
| 17 | (加了 authenticate_with_hash 走"记住密码"路径,跳过 hash) | ||
| 18 | ├── history.py HistoryItem + HistoryListModel + HistoryManager | ||
| 19 | HistoryListModel.roleNames 已扩展给 QML:display/decoration/toolTip/timestamp | ||
| 20 | ├── generation.py MODEL_BY_MODE / MODEL_PRO / FLASH_ONLY_ASPECT_RATIOS + ImageGenerationWorker | ||
| 21 | └── jewelry.py DEFAULT_JEWELRY_LIBRARY (8 类) + JewelryLibraryManager + PromptAssembler | ||
| 22 | |||
| 23 | core/runtime.py (新加,2026-05-09 抽出,2026-05-10 加日志兜底) | ||
| 24 | enable_crash_diagnostics(含 macOS DiagnosticReports 提示写入 crash_log.txt) | ||
| 25 | init_logging(用 TieredFsyncHandler 替代 RotatingFileHandler) | ||
| 26 | TieredFsyncHandler — WARNING+ 同步 fsync / INFO buffered | ||
| 27 | start_periodic_fsync — 1s 周期 daemon 线程兜底(INFO 最坏丢 1s) | ||
| 28 | log_system_info / cleanup_clipboard_tempfiles | ||
| 29 | flush_logs(升级为对所有 handlers 走 fsync) | ||
| 30 | get_crash_log_path | ||
| 31 | ``` | ||
| 32 | |||
| 33 | **image_generator.py.txt**(2026-05-10 重命名): | ||
| 34 | - git mv .py → .py.txt 保留全部历史;Python 不加载,PyInstaller 不扫 | ||
| 35 | - 内容是老 QWidget UI 类(LoginDialog / ImageGeneratorWindow / DraggableThumbnail / | ||
| 36 | DragDropScrollArea / StyleDesignerTab + main())和顶部已搬走的工具函数副本 | ||
| 37 | - 用户要求暂不删,留作扒老逻辑参考;task #19 真正"删掉"动作要等用户确认 QML 版稳定后 | ||
| 38 | |||
| 39 | **外部消费**: | ||
| 40 | - task_queue.py / temp_clean.py: `from core.generation import ImageGenerationWorker` | ||
| 41 | - bridges/*: `from core.history import HistoryManager / HistoryListModel`, | ||
| 42 | `from core.database import DatabaseManager`, `from core.jewelry import PromptAssembler` 等 | ||
| 43 | - image_generator.py 顶部 `from core.* import *` 是 re-export,让 LoginDialog / | ||
| 44 | ImageGeneratorWindow 内部代码无感知(仍按原名字调用,任务 #19 一起删) |
.claude/memory/reference_entry_and_build.md
0 → 100644
| 1 | --- | ||
| 2 | name: 项目入口、打包、远端 | ||
| 3 | description: 主入口、PyInstaller spec、打包脚本、Git 远端等关键定位 | ||
| 4 | type: reference | ||
| 5 | originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077 | ||
| 6 | --- | ||
| 7 | **主入口**: | ||
| 8 | - `image_generator.py` `main()` (Phase 1-6 启动序列) | ||
| 9 | - QApplication 创建在 Phase 4,主题应用在 Phase 4 同步 | ||
| 10 | - preflight 在 Phase 4.5,登录页在 Phase 6 | ||
| 11 | |||
| 12 | **打包**: | ||
| 13 | - spec 文件:`ZB100ImageGenerator.spec`(跨平台单一真相源) | ||
| 14 | - Windows 脚本:`build_windows.bat`(自动建 venv + pip install + pyinstaller,最后 pause) | ||
| 15 | - macOS 脚本:`build_mac_universal.sh` | ||
| 16 | - 直接命令:`.venv/Scripts/pyinstaller.exe ZB100ImageGenerator.spec` | ||
| 17 | - 产物:`dist/ZB100ImageGenerator/ZB100ImageGenerator.exe` (~134MB) | ||
| 18 | |||
| 19 | **Git 远端**: | ||
| 20 | - `origin: http://gitlab.zb100.com:10080/chaijin/GoogleNanoBananaApp.git` | ||
| 21 | - 默认主分支 `master` | ||
| 22 | - Git 用户 `chaijin` | ||
| 23 | |||
| 24 | **用户管理工具**(管理员): | ||
| 25 | - `python user_util.py [add|list|disable|enable|reset] <username> [<password>]` | ||
| 26 | - 操作 MySQL `nano_banana_users` 表(hash SHA256) | ||
| 27 | - 配置从 `config.json` 的 `db_config` 字段读取 |
.claude/memory/reference_packaging.md
0 → 100644
| 1 | --- | ||
| 2 | name: PyInstaller 打包配置 (task #19) | ||
| 3 | description: ZB100ImageGenerator.spec 当前形状 + 易踩坑(QML 路径 / Pillow / pathex) | ||
| 4 | type: reference | ||
| 5 | originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077 | ||
| 6 | --- | ||
| 7 | **spec 当前形状(2026-05-10)**: | ||
| 8 | |||
| 9 | ```python | ||
| 10 | a = Analysis( | ||
| 11 | ['qml_poc/main_qml.py'], # 入口(不是老 image_generator.py) | ||
| 12 | pathex=[str(Path('.').resolve())], # 项目根,让 PyInstaller 找 audit_logger 等顶层模块 | ||
| 13 | binaries=pil_native_libs, # Pillow .dylibs/.libs collect_dynamic_libs | ||
| 14 | datas=[ | ||
| 15 | ('config.json', '.'), | ||
| 16 | ('qml_poc/qml', 'qml'), # ← 目标路径不带 qml_poc/ 前缀! | ||
| 17 | ('jewelry_library.json', '.'), | ||
| 18 | ] + 平台特定: | ||
| 19 | IS_WIN: ('zb100_windows.ico', '.') | ||
| 20 | IS_MAC: ('zb100_mac.icns', '.') | ||
| 21 | hiddenimports=[ | ||
| 22 | 'PySide6.QtQml', 'PySide6.QtQuick', 'PySide6.QtQuickControls2', | ||
| 23 | ], | ||
| 24 | ) | ||
| 25 | ``` | ||
| 26 | |||
| 27 | **关键坑(踩过的)**: | ||
| 28 | |||
| 29 | 1. **QML datas 目标路径必须是 `qml/` 不是 `qml_poc/qml/`** | ||
| 30 | 原因:PyInstaller 把入口脚本 `qml_poc/main_qml.py` 平铺到 `_MEIPASS/main_qml.py` | ||
| 31 | (不是 `_MEIPASS/qml_poc/main_qml.py`),所以 `Path(__file__).parent / "qml"` | ||
| 32 | = `_MEIPASS/qml`。datas 写 `('qml_poc/qml', 'qml')` 才对得上。 | ||
| 33 | |||
| 34 | 2. **pathex 必须显式给项目根** | ||
| 35 | main_qml.py 顶部 `sys.path.insert(0, ROOT)` PyInstaller 静态分析看不到, | ||
| 36 | 不给 pathex → 打包后 `from audit_logger import ...` ModuleNotFoundError。 | ||
| 37 | |||
| 38 | 3. **Pillow .dylibs 在 macOS 上必须收集** | ||
| 39 | spec 里有完整逻辑(collect_dynamic_libs + 显式枚举),输出量在 console。 | ||
| 40 | macOS 验证打包要看 `[spec] 最终 Pillow 原生库数量: > 0`。 | ||
| 41 | |||
| 42 | **构建命令**: | ||
| 43 | - Windows: `build_windows.bat` 或 `.venv/Scripts/pyinstaller.exe ZB100ImageGenerator.spec --noconfirm` | ||
| 44 | - macOS: `bash build_mac_universal.sh` (顺便打 .dmg,含 drag-to-install 布局) | ||
| 45 | |||
| 46 | **产物路径**: | ||
| 47 | - Windows: `dist/ZB100ImageGenerator/ZB100ImageGenerator.exe` + `_internal/` | ||
| 48 | - macOS: `dist/ZB100ImageGenerator.app` + `dist/ZB100ImageGenerator.dmg` | ||
| 49 | |||
| 50 | **Windows 验证状态(2026-05-10)**: | ||
| 51 | 打包通过 → 启动 8 phases 全过 → QML 装载成功 → 进入主循环零警告。 | ||
| 52 | 日志在 `dist/ZB100ImageGenerator/logs/app.log`。 | ||
| 53 | |||
| 54 | **macOS 验证状态**:未做(开发机是 Windows)。明早起来 `bash build_mac_universal.sh` | ||
| 55 | 跑一遍验证,重点看 .dmg 在 NAS / 邮件传输后 PIL/.dylibs symlink 是否完整。 | ||
| 56 | |||
| 57 | **仍未删的旧入口**:`image_generator.py.txt`(2026-05-10 git mv 改 .txt,不参与打包扫描) | ||
| 58 | 用户要求确认 QML 版稳定后再删。 |
| 1 | --- | ||
| 2 | name: QML PoC 文件结构与设计系统 | ||
| 3 | description: feat/ui-qml-poc 分支的 QML 代码组织、Theme 令牌、组件 API | ||
| 4 | type: reference | ||
| 5 | originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077 | ||
| 6 | --- | ||
| 7 | **目录结构**: | ||
| 8 | ``` | ||
| 9 | qml_poc/ | ||
| 10 | ├── main_qml.py 入口:装配 5 桥 + audit_logger + history.refresh() | ||
| 11 | │ env 调试:QML_AUTO_LOGIN=1 / QML_DEBUG_TAB=0|1|2 | ||
| 12 | └── qml/ | ||
| 13 | ├── qmldir 模块声明(singleton Theme 1.0) | ||
| 14 | ├── Theme.qml Singleton 设计令牌 | ||
| 15 | ├── Main.qml ApplicationWindow(登录态切换尺寸 + 子页) | ||
| 16 | ├── LoginScreen.qml 登录页(接 auth.login,错误展示 + busy) | ||
| 17 | ├── MainWindow.qml 主窗口(下划线 TabBar + 任务队列 sidebar 接 taskQueue.model) | ||
| 18 | ├── ImageGenTab.qml 图片生成 tab(参考图录入/收藏/下载/预览全接 imageGen) | ||
| 19 | ├── HistoryTab.qml 历史记录 tab(ListView + 详情面板,接 history.model) | ||
| 20 | ├── StyleDesignerTab.qml 款式设计 tab(8 字段 + 实时 Prompt 预览 + 生成) | ||
| 21 | └── components/ | ||
| 22 | ├── Card.qml 圆角 + 极淡边框,default property 子元素 | ||
| 23 | ├── PrimaryButton.qml pill 圆角 + Apple Blue + 120ms ColorAnimation | ||
| 24 | ├── SecondaryButton.qml 圆角描边,hover 出灰底 | ||
| 25 | ├── ThemedTextField.qml 焦点 2px 蓝边动效 | ||
| 26 | ├── ThemedComboBox.qml 自定义 chevron + popup 圆角 | ||
| 27 | └── CaptionLabel.qml 12pt DemiBold,组上方标签 | ||
| 28 | ``` | ||
| 29 | |||
| 30 | **Theme.qml 暴露的 token**(singleton,QML import 后 `Theme.accent` 直接用): | ||
| 31 | - 颜色:bgCanvas/bgSurface/bgElevated/bgSubtle/bgHover, textPrimary/Secondary/Tertiary/OnAccent, | ||
| 32 | borderDefault/Strong, divider, accent/Hover/Pressed/Subtle, success/warning/danger | ||
| 33 | - 尺寸:radiusSm/Md/Lg/Pill, space1-6, controlHSm/Md/Lg, fontXs/Sm/Base/Lg/Xl/Xxl | ||
| 34 | - 字体:fontFamily(按 Qt.platform.os 自动选 SF Pro / Segoe UI Variable) | ||
| 35 | |||
| 36 | **关键设计规则**: | ||
| 37 | - 所有圆角用 `Theme.radiusXxx`,不要硬编码 | ||
| 38 | - 所有颜色用 `Theme.xxx`,不要硬编码 hex | ||
| 39 | - caption + control 用 ColumnLayout spacing 4-6,组之间 spacing 12-16 | ||
| 40 | - Card 内 anchors.margins 用 `Theme.space4 (16)` 保证一致 | ||
| 41 | - 主按钮(生成 / 登录 / 提交)一律 PrimaryButton(pill 圆角) | ||
| 42 | - 次按钮(添加 / 下载 / 取消)一律 SecondaryButton(描边圆角) | ||
| 43 | - 状态色(成功 / 失败 / 等待)用 `color: Theme.success/danger/warning` | ||
| 44 | |||
| 45 | **AppState QObject**(main_qml.py,作为 contextProperty 暴露): | ||
| 46 | - Property: `loggedIn` (bool), `currentTab` (int) | ||
| 47 | - Slot: `login(username, password) → bool`, `logout()`, `setTab(idx)` | ||
| 48 | - Signal: `loggedInChanged`, `currentTabChanged` | ||
| 49 | - 当前是 PoC 占位(login 接受任意非空),下一步要换成真实 db 认证 | ||
| 50 | |||
| 51 | **业务桥层 TODO**(task #12):除 AppState,还需要暴露: | ||
| 52 | - `imageGen`:参考图列表 / 提示词 / 生成方法 / 进度信号 | ||
| 53 | - `styleDesigner`:字段列表 / 词库管理 / Prompt 预览 | ||
| 54 | - `history`:QAbstractListModel(复用现有 HistoryListModel) | ||
| 55 | - `taskQueue`:QAbstractListModel for 任务列表 + 取消方法 | ||
| 56 | - `theme`:跟随系统 colorScheme,触发 QML Theme 切换 |
.claude/memory/user_cross_platform_ui.md
0 → 100644
| 1 | --- | ||
| 2 | name: 跨平台 UI 一致性诉求 | ||
| 3 | description: 用户强烈关注 macOS 和 Windows 两端的视觉与交互一致性,会优先选择能跨平台统一表现的方案 | ||
| 4 | type: user | ||
| 5 | originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077 | ||
| 6 | --- | ||
| 7 | 用户在选 UI 设计方向时明确说:"因为这个也跟我们的品牌元素的颜色契合"以及"可以统一 MacOS 与 Windows 的设计语言"。 | ||
| 8 | |||
| 9 | 在 dark mode 决策上他强调:"macos 会让软件跟随时间自由转换深浅主题,你可以不做深色主题,但是它变的时候就会巨丑巨难看,这个你应该知道的" — 说明他对系统级 OS 行为有深刻观察,期望应用级响应。 | ||
| 10 | |||
| 11 | **应用方式**:未来给这个项目提任何 UI / 视觉建议时: | ||
| 12 | - 优先选 platform-neutral 的设计语言(Apple HIG / Material Design)而不是单平台专属(Fluent UI / iOS-specific) | ||
| 13 | - 涉及 OS 行为(系统主题、字体、缩放、HiDPI)必须双平台都验证 | ||
| 14 | - 推荐第三方库前确认 Mac + Windows 都被支持 | ||
| 15 | - 字体栈用回退(SF Pro → 苹方 → Segoe UI Variable → 微软雅黑) |
.claude/memory/user_overnight_autonomy.md
0 → 100644
| 1 | --- | ||
| 2 | name: 自主交付偏好(overnight 模式) | ||
| 3 | description: 用户接受 "睡前授权 → 醒来在公司 review 分支" 的工作模式,前提是有清晰兜底 | ||
| 4 | type: user | ||
| 5 | originSessionId: 21abab40-0d6c-449a-ae72-9ca03205f077 | ||
| 6 | --- | ||
| 7 | 2026-05-09 凌晨用户 brainstorming 完 UI 重设计后说:"我去睡觉了,你搞好把 memory 啥的 save 一下,推送到一个新分支,我明天在公司看新的分支里的内容就行了"。 | ||
| 8 | |||
| 9 | 明确认可的工作流: | ||
| 10 | 1. 新分支隔离(不动 master) | ||
| 11 | 2. 分支根目录留 OVERNIGHT_SUMMARY.md 供醒来看进度 + 验收清单 | ||
| 12 | 3. 多次小颗粒 commit(不是一个大 commit),便于 cherry-pick 或单点 revert | ||
| 13 | 4. memory 同步保存 | ||
| 14 | 5. 推到 origin(GitLab) | ||
| 15 | |||
| 16 | **应用方式**:当他再次给出"你直接搞" / "我去睡了" 类指令,且任务符合"破坏性可控、有明确成功标准"时,可以走 overnight 模式: | ||
| 17 | - 先用 1-2 行确认范围 + 兜底(不动 master / 不破坏功能 / 仅视觉层 etc.) | ||
| 18 | - 不在中途追问澄清;保留为已知问题写在 SUMMARY 里 | ||
| 19 | - 全程小步 commit,每个 commit message 精确到"做了什么 / 为什么" | ||
| 20 | - 顺手提交的 untracked 文件要在 SUMMARY 里说明 | ||
| 21 | - 任务完成后必须打包/启动验证,让用户醒来直接能跑 | ||
| 22 | |||
| 23 | **不适用场景**:涉及数据库变更、生产部署、密钥/凭证、第三方 API 协议变更 — 这些必须等用户在场。 |
-
Please register or sign in to post a comment