diff --git a/.project-docs/10-decisions/adr-005-learning-project-catalog.md b/.project-docs/10-decisions/adr-005-learning-project-catalog.md index 25010f7..782bf46 100644 --- a/.project-docs/10-decisions/adr-005-learning-project-catalog.md +++ b/.project-docs/10-decisions/adr-005-learning-project-catalog.md @@ -13,7 +13,7 @@ The integrated Learning module previously implemented course generation, an acco - Keep the existing authenticated Learning entry and `module_access.learning` policy. - Replace the old course model completely with a server-driven project list and README detail page; do not retain a compatibility API or local-course read path. - Works Square operations owns project name, cover, summary, tags, version, ordering, publication state, Markdown, ZIP, immutable size, and SHA-256 metadata. -- Publish-time processing mirrors acceptable remote HTTPS raster images and rewrites README image references to fixed project-media paths. Renderer disables raw Markdown HTML; Main fetches controlled media with authentication, MIME validation, and a 10 MiB limit. +- Publish-time processing removes raw Markdown HTML and validates image references as credential-free, default-port HTTPS URLs whose current DNS answers are public. It preserves those URLs instead of downloading, decoding, transcoding, or mirroring image bytes. The Learning detail Renderer opts only Markdown image nodes into the guarded direct-HTTPS image path; covers and historical release media keep their existing controlled-media handling. - Electron Main owns Works credentials, the native save dialog, archive request, redirect/origin policy, temporary file, 512 MiB limit, declared size, SHA-256, ZIP signature, and atomic final rename. Renderer receives only bounded project DTOs, media data, and `saved` or `cancelled`. - Remove course generation, progress, local library, OpenMAIC player, Agent, ASR, classroom runtime, Learning IPC channels, player packaging resources, and their tests. - Do not automatically delete historical downloaded course data. The new client never reads or migrates it. @@ -22,7 +22,7 @@ The integrated Learning module previously implemented course generation, an acco - The desktop client and package are substantially smaller and no longer depend on a production Stage player artifact. - The external Works Square operations/admin/API contract must be implemented and deployed before the new client can provide real catalog data. -- Remote README images depend on successful publish-time mirroring; unsupported or failed images remain local display failures rather than arbitrary privileged network requests. +- Remote README images depend on the third-party origin and Electron's supported image formats. Each image failure remains local to that image, while availability and requester network information are visible to the image origin. - A future historical-data cleanup must be an explicit, user-controlled maintenance feature. ## Supersedes @@ -35,6 +35,8 @@ The integrated Learning module previously implemented course generation, an acco - Source task: `20260819-learning-project-catalog-impl-4e9c71a2` - Source commit: `38db158` - Integration merge: `d967b0f` +- Direct-image server source: `65ea070` +- Direct-image client source: `9956739` ## Related diff --git a/.project-docs/10-decisions/decision-index.md b/.project-docs/10-decisions/decision-index.md index b0f929d..73d0dd2 100644 --- a/.project-docs/10-decisions/decision-index.md +++ b/.project-docs/10-decisions/decision-index.md @@ -8,7 +8,7 @@ | ADR-002 | Robot V1 采用 Main 门控的引导式热点配网并衔接现有六位 Binding | Accepted / implemented, default on | 2026-08-16 | Robot Renderer、Host API、Electron Main、现有固件热点入口 | `adr-002-robot-guided-hotspot-binding-v1.md` | | ADR-003 | Robot 配网页内扫描并连接 Windows/macOS 热点 | Accepted / implemented with physical release gates pending | 2026-08-16 | Robot Renderer、Host API、Electron Main、Windows WLAN、macOS CoreWLAN/CoreLocation | `adr-003-robot-in-app-hotspot-connection.md` | | ADR-004 | Works Square 统一拥有桌面认证生命周期边界 | Accepted / implemented | 2026-08-19 | Renderer、Host API、Electron Main、Works Square auth facade | `adr-004-square-auth-lifecycle-boundary.md` | -| ADR-005 | Learning 采用运营精选项目目录并退役课程运行时 | Accepted / implemented | 2026-08-20 | Learning Renderer、Host API、Electron Main、Works Square operations/API | `adr-005-learning-project-catalog.md` | +| ADR-005 | Learning 采用运营精选项目目录、直接渲染经校验的 HTTPS README 图片并退役课程运行时 | Accepted / implemented, amended 2026-08-20 | 2026-08-20 | Learning Renderer、Host API、Electron Main、Works Square operations/API | `adr-005-learning-project-catalog.md` | ## Superseded Decisions diff --git a/.project-docs/20-architecture/data-flow.md b/.project-docs/20-architecture/data-flow.md index 666f573..eeb157d 100644 --- a/.project-docs/20-architecture/data-flow.md +++ b/.project-docs/20-architecture/data-flow.md @@ -25,7 +25,7 @@ | 设计 Quote 编辑与重报价 | 当前 Conversation 的 active Quote | Renderer 修改最终 Prompt/参数 → Main Host API → Works Square Quote update → 当前 Conversation | 服务端返回最新参数与设计点;报价完成前不能确认,确认提交最新原值,客户端不自行计价 | | 设计项目删除 | Canvas 侧栏精确项目名确认 | Renderer → Main Host API → Works Square Workspace DELETE | 删除成功后清理当前 Workspace/Conversation/task stream 并选择最近更新的剩余项目;结算与软删除语义由服务端负责 | | Prompt Museum 浏览与使用 | Canvas 侧栏“获取灵感” | Renderer → Main Host API → Works Square list/detail;选中 Prompt → 进程内 pending state → 当前 Canvas 输入框 | 只发送白名单筛选/游标;Works Token 留在 Main,Prompt 不自动发送,Museum 不包含客户端静态数据集 | -| Learning 项目浏览 | Learning 项目列表 / README 详情 | Renderer → typed Host API → Main fixed list/detail routes → Works Square published projects | 保留登录与 `module_access.learning`;Main 严格投影分页项目 DTO,README 禁用原始 HTML,发布时镜像的远程 raster 图片通过固定项目媒体路由和 10 MiB 上限读取 | +| Learning 项目浏览 | Learning 项目列表 / README 详情 | Renderer → typed Host API → Main fixed list/detail routes → Works Square published projects;README 图片节点 → 远程 HTTPS origin | 保留登录与 `module_access.learning`;Main 严格投影分页项目 DTO,README 禁用原始 HTML,仅图片节点可直连无凭据 HTTPS URL;封面和历史媒体仍使用受控媒体读取 | | Learning 项目下载 | README 详情页“下载项目” | Renderer → Host API → Main 原生保存对话框 → Works archive stream → 临时文件 → 原子重命名 | 最大 512 MiB;最多五跳同 Works origin 重定向,重定向请求不携带 Bearer;实际字节、声明大小、SHA-256 与 ZIP 签名均匹配后才保存,Renderer 只得到 `saved` 或 `cancelled` | | Robot 引导式热点配网 V1(已实现、默认开启) | Robot Binding 页面 | 用户选择引导配网 → 进入固件配网模式 → Renderer 经 Host API 请求 Main 扫描 → 用户选择短效候选 → Windows/macOS Adapter 连接并核验当前 SSID → Main 打开固定 Portal → 用户在 Portal 配置 Wi-Fi → 电脑恢复互联网 → 现有六位 Binding | 精确环境值 `0` 或 capability 读取失败回退直接六位码;系统 Wi-Fi 保留兜底,Makelore 不收集 Wi-Fi 密码、不修改固件,热点发现/`bound` 都不等于可信身份或 online/ready | @@ -63,7 +63,7 @@ - 服务端安全投影后的公共 `play_url`;只接受同源 HTTPS、精确 App 路径和可信版本状态。 - Works Square Workspace/Conversation API、每个 Conversation 的持久 Agent Gateway Session、单次 WebSocket ticket、双向命令/事件帧与幂等 REST 传输回退。 - Works Square Prompt Museum list/detail API;Main 添加当前账号 Bearer Token,Renderer 只使用 Host API 投影。 -- Works Square Learning project list/detail/media/archive API;Main 添加当前账号 Bearer Token,并限制固定路径、DTO、媒体 MIME/大小、归档重定向、字节数和摘要。 +- Works Square Learning project list/detail/media/archive API;Main 添加当前账号 Bearer Token,并限制固定路径、DTO、封面/历史媒体 MIME/大小、归档重定向、字节数和摘要。README 中经服务端校验的无凭据 HTTPS 图片由 Renderer 图片节点直接请求。 - 已实现的本机 Robot provisioning capability、固定 portal-open 与 hotspot scan/connect Host API。它们是本地 Main 操作,不读取 Works access token、不调用上游,也不接受任意 URL/SSID/BSSID/interface/profile。 ## Last Updated diff --git a/.project-docs/20-architecture/module-map.md b/.project-docs/20-architecture/module-map.md index 78bc7b0..f5a664a 100644 --- a/.project-docs/20-architecture/module-map.md +++ b/.project-docs/20-architecture/module-map.md @@ -35,9 +35,9 @@ | `shared/image-prompt-museum.ts` | Prompt Museum 列表、分类、详情、署名与分页共享 DTO | 客户端不包含内容数据集,只定义服务端字段契约 | | `electron/api/routes/image-prompt-museum.ts` | Main-owned Museum 列表/详情代理与 Works 登录态 | 仅 GET 固定路径和白名单查询;Renderer 不获得 Bearer Token | | `src/pages/ImagePromptMuseum/index.tsx` / `src/lib/image-prompt-museum.ts` / `src/stores/image-prompt-museum.ts` | Museum 搜索/筛选/详情与一次性 Prompt 回填 | 原 Prompt 只带回 Canvas 输入框,不自动发送;页面不接受投稿或互动 | -| `shared/learning.ts` / `src/lib/learning.ts` | Learning 项目列表、详情、媒体和下载结果的共享 DTO/Renderer facade | 所有访问走固定 Host API;Renderer 不持有 Token、任意上游 URL、归档或本地路径 | -| `electron/api/routes/learning.ts` / `electron/services/learning-project-download.ts` | Main-owned Learning 项目代理、受控媒体读取和原生 ZIP 保存 | 固定 Works 路径、严格 DTO/MIME/大小边界、最多五跳同源重定向、SHA-256/ZIP 签名校验和原子重命名 | -| `src/pages/Learning/` / `src/components/layout/LearningSidebar.tsx` | 分页项目卡片、README 详情和下载入口 | 保留登录与 `module_access.learning`;README 禁用原始 HTML,图片使用受控媒体路径,旧生成/播放器入口不存在 | +| `shared/learning.ts` / `src/lib/learning.ts` | Learning 项目列表、详情、媒体和下载结果的共享 DTO/Renderer facade | 项目 API 访问走固定 Host API;Renderer 不持有 Token、任意归档 URL 或本地路径,README 仅接受无凭据 HTTPS 图片 URL | +| `electron/api/routes/learning.ts` / `electron/services/learning-project-download.ts` | Main-owned Learning 项目代理、封面/历史媒体读取和原生 ZIP 保存 | 固定 Works 路径、严格 DTO/MIME/大小边界、最多五跳同源重定向、SHA-256/ZIP 签名校验和原子重命名 | +| `src/pages/Learning/` / `src/components/layout/LearningSidebar.tsx` | 分页项目卡片、README 详情和下载入口 | 保留登录与 `module_access.learning`;README 禁用原始 HTML,仅图片节点直连无凭据 HTTPS URL,旧生成/播放器入口不存在 | | `src/pages/AiHardware/index.tsx` | Robot 管理、现有六位 Binding,以及已实现的 default-on 引导式热点配网状态机 | 只编排非敏感步骤;不接收 Wi-Fi 密码,不把 `bound` 展示为在线证明 | | `src/lib/ai-hardware.ts` | Renderer 侧 Robot Host API 类型、安全错误映射和稳定 Binding/hotspot facade | 读取 Main-owned capability,调用固定 portal-open,并只传递短效 hotspot candidate ID;不添加任意 URL、SSID 或 Renderer IPC | | `electron/api/routes/ai-hardware.ts` | Main-owned Robot 云端代理,以及本地 capability/portal/hotspot actions | 默认开启、精确环境值 `0` 回滚;所有本地操作必须在 Works token/上游访问前返回,且只投影稳定安全错误 | @@ -71,7 +71,7 @@ - 多 Conversation 事件处理必须区分对话快照与 Workspace 任务更新;不得用任务时间戳推进 Conversation 流水位,也不得让旧会话的迟到流覆盖当前会话。 - Quote 编辑、重报价、确认和项目删除都跨 Renderer/Main/Works Square。异步结果必须核对当前 Workspace + Conversation;删除当前项目时必须先使旧选择和事件流失效,再加载剩余 Workspace。 - Prompt Museum 图片和来源 URL 来自服务端数据。服务端必须完成内容授权/署名审核;若未来需要凭据化素材,应新增 Main-owned 媒体代理,不能把对象存储凭据放进 Renderer URL。 -- Learning 的远端 JSON、Markdown、媒体、错误和 ZIP 下载跨信任边界;必须保持严格 DTO、固定项目/媒体路径、可信 raster MIME、媒体/README/归档大小、同源重定向、声明字节数、SHA-256、ZIP 签名、一次 401 refresh 和固定安全错误,不能把 Renderer 或 README 变成任意 Works/网络/文件系统代理。 +- Learning 的远端 JSON、Markdown、媒体、错误和 ZIP 下载跨信任边界;必须保持严格 DTO、固定项目/封面/历史媒体路径、可信 raster MIME、媒体/README/归档大小、同源重定向、声明字节数、SHA-256、ZIP 签名、一次 401 refresh 和固定安全错误。README 仅允许图片节点直连经服务端校验的无凭据 HTTPS URL,不能扩展为任意 Works 下载或文件系统代理。 - Gateway 命令的 REST fallback 只处理 WebSocket 发送、断连和 ACK 超时,必须复用 `client_command_id`;业务错误回退会造成重复提交。Quote 任务恢复只更新 Workspace 所有的任务,不能覆盖当前 Conversation。 - `closeEventSessions` 只负责本地流和缓存生命周期;远端 Conversation Session 是服务端持久资源。 - 单图来源选择器当前仍由精确中文 quick reply 触发,并以 Brief medium 判断图生图或视频首帧用途;扩展更多输入用途前应先把消息协议升级为结构化 action/purpose,避免展示文案与行为继续耦合。 diff --git a/.project-docs/20-architecture/system-overview.md b/.project-docs/20-architecture/system-overview.md index 642706f..31cd2bb 100644 --- a/.project-docs/20-architecture/system-overview.md +++ b/.project-docs/20-architecture/system-overview.md @@ -25,7 +25,7 @@ Makelore 是 Electron 桌面客户端。Renderer 负责项目操作与状态展 | AI Design Quote & Task Controls | 当前 Conversation Quote 与 Workspace 任务 | 最终 Prompt/generation options 每次修改由服务端重新计价;任务结果在详情中预览并经 Main-owned asset download 保存 | | Prompt Museum | Canvas “获取灵感”页面 → Main Host API → Works Square | 服务端驱动的审核内容、筛选和分页;Renderer 不持有 Works Token 或内置数据集,“使用此 Prompt”只回填输入框 | | Learning Project Catalog | 服务端分页项目卡片、README 详情与用户选择的 ZIP 下载 | Renderer 只持有安全项目 DTO 和 Markdown;不提供生成、进度、本地课程库或播放器 | -| Learning Main Boundary | 固定 Host API → Works Square project list/detail/media/archive | Main 持有 Works Bearer、媒体代理、原生保存路径、受控重定向、临时文件、大小/SHA-256/ZIP 签名校验与原子落盘;Renderer 不获得任意 URL 或本地路径 | +| Learning Main Boundary | 固定 Host API → Works Square project list/detail/media/archive | Main 持有 Works Bearer、封面/历史媒体代理、原生保存路径、受控重定向、临时文件、大小/SHA-256/ZIP 签名校验与原子落盘;README 图片节点可直接加载无凭据 HTTPS URL,Renderer 不获得任意归档 URL 或本地路径 | | Robot Workspace | Account-scoped agent configuration, device activation/binding, assignment, and credential-recovery UI | Renderer receives only safe Works Square projections. Configuration choices come from the USER-scoped safe catalog; unavailable current values remain editable without exposing provider credentials or configuration internals. | | AI Hardware Main Route | Fixed `/api/works/ai-hardware` Host API to Works Square proxy | Main owns Bearer auth, stable operation IDs, bounded retry, ETag/If-Match, request/response limits, error redaction, and the fixed no-store configuration-catalog proxy. Versioned responses accept only canonical strong or weak numeric ETags that equal the DTO revision; mutations always emit strong `If-Match`. It never forwards Renderer authorization headers. | @@ -41,7 +41,7 @@ Makelore 是 Electron 桌面客户端。Renderer 负责项目操作与状态展 - Product UI language is Chinese-only. Unsupported system or persisted language values normalize to `zh`; removed locale files are not runtime fallbacks. - Packaged Canvas remains cloud-only with no local fallback. `pnpm run dev` now uses the cloud adapter; the local Workspace adapter requires the explicit development command and remains unpackaged-only. - Prompt Museum is a read-only curated inspiration surface, not a user-content community. Main owns Works authentication and forwards only the bounded list/detail routes; the client never bundles museum content or automatically submits a selected Prompt. -- Learning uses a Main-owned read-only project-catalog boundary. Renderer does not receive Works credentials, object-storage identifiers, arbitrary download URLs, temporary/final paths, or an arbitrary network proxy. README raw HTML is disabled; publish-time mirrored raster images use fixed project-media paths. Main validates media and streams a selected project ZIP through bounded same-origin redirects, declared size, SHA-256, ZIP signature, and atomic rename before returning only `saved` or `cancelled`. +- Learning uses a Main-owned read-only project-catalog boundary. Renderer does not receive Works credentials, object-storage identifiers, arbitrary archive URLs, temporary/final paths, or an arbitrary network proxy. README raw HTML is disabled; Markdown image nodes alone may load validated credential-free HTTPS URLs directly, including SVG and other formats Electron supports. Main continues to validate covers/historical media and streams a selected project ZIP through bounded same-origin redirects, declared size, SHA-256, ZIP signature, and atomic rename before returning only `saved` or `cancelled`. - AI hardware network access is Main-owned. Renderer cannot hold Works Square or Xiaozhi credentials and cannot select arbitrary upstream paths or headers. - Robot model, language, and voice choices are dynamically projected from the Xiaozhi USER catalog through Works Square and Electron Main; the catalog is bounded, account-scoped, and `private, no-store` at each public hop. - One local account maps to one server-side Xiaozhi account binding. Agents and devices are resources beneath that account binding, not separate Xiaozhi users. diff --git a/.project-docs/30-worklog/current-state.md b/.project-docs/30-worklog/current-state.md index 6bb850e..3492f7f 100644 --- a/.project-docs/30-worklog/current-state.md +++ b/.project-docs/30-worklog/current-state.md @@ -4,11 +4,17 @@ This file is the integrated default-branch snapshot. Feature tasks record progre ## Integrated Through +- Direct Learning README-image source commit `9956739` from feature task + `20260820-direct-readme-client-a4d8e2c7` is integrated by task + `20260820-integrate-direct-readme-client-b7e41c9d`. README Markdown image nodes now + load validated credential-free HTTPS URLs directly, including SVG, while raw HTML, + covers, historical media reads, and the Main-owned verified ZIP save path retain + their existing boundaries. The matching Works Square source is `65ea070`. - Learning project-catalog source commit `38db158` from feature task `20260819-learning-project-catalog-impl-4e9c71a2` was merged as `d967b0f` by integration task `20260820-integrate-learning-catalog-a73e91c4`. Learning keeps its login and `module_access.learning` gate but now contains only a server-driven project list, - safe README detail, controlled mirrored raster media, and a Main-owned verified + safe README detail, direct credential-free HTTPS Markdown images, and a Main-owned verified native ZIP save path. Course generation, progress, local library, OpenMAIC player, Agent/ASR/classroom runtime, Learning IPC and player-artifact packaging were removed without a compatibility read path. Historical course data is left untouched. The @@ -82,7 +88,7 @@ Canvas 侧栏提供“获取灵感”进入 Prompt Museum。列表、筛选、 Makelore 在会话恢复、登录和刷新后由 Electron Main 请求 Works `/api/auth/me`,Renderer 只获得 Code、Canvas、Learning、Robot 四个布尔权限。缺失 `module_access` 或任一字段时默认开启;服务端 `design` 显式映射客户端 `painting`。被关闭的模块卡片置灰且不可点击,根路由、深层路由和别名路由均在 `MainLayout` 或模块初始化前阻断。Code provider 等待认证权限加载完成;权限查询返回终止性 `401` 时同时清理 Main 和 Renderer 会话。`/settings` 是全局设置,不受 Code 入口策略阻断。该机制只是客户端入口策略,不代替服务端 API 授权。 -AI 学习现在是已启用的运营精选项目目录,并继续受登录和 `module_access.learning` 控制。Renderer 通过 Main-owned Host API 获取分页项目卡片和 README 详情;Markdown 支持 GFM、禁用原始 HTML,服务端发布时把通过 SSRF/重定向/大小/MIME 校验的远程 HTTPS raster 图片镜像并改写为固定项目媒体路径,Main 再以 Bearer、可信 MIME 和 10 MiB 上限代理。详情页的下载按钮打开系统保存对话框;Main 将最大 512 MiB 的 ZIP 流式写入临时文件,只允许最多五跳同 Works origin 重定向,校验声明字节数、SHA-256 和 ZIP 签名后原子保存,Renderer 只接收 `saved` 或 `cancelled`。课程生成、进度、本地课程库、OpenMAIC player、Agent、ASR、课堂 runtime、Learning IPC 和 player artifact 打包已删除且没有兼容读取路径;历史课程数据保留但不再读取。客户端契约已完成,不代表 Works Square 运营后台/API 或生产内容已经部署。 +AI 学习现在是已启用的运营精选项目目录,并继续受登录和 `module_access.learning` 控制。Renderer 通过 Main-owned Host API 获取分页项目卡片和 README 详情;Markdown 支持 GFM、禁用原始 HTML。服务端发布时只校验图片 URL 为无凭据、默认端口、无 fragment 且当前 DNS 结果全部为公网地址的 HTTPS URL,保留地址而不下载、识别格式、转码或镜像;客户端仅为 README 图片节点启用直连,因此 SVG 和 Electron 支持的其他格式可直接显示,单图失败不阻断详情。封面和历史发布媒体继续走受控路径。详情页的下载按钮打开系统保存对话框;Main 将最大 512 MiB 的 ZIP 流式写入临时文件,只允许最多五跳同 Works origin 重定向,校验声明字节数、SHA-256 和 ZIP 签名后原子保存,Renderer 只接收 `saved` 或 `cancelled`。课程生成、进度、本地课程库、OpenMAIC player、Agent、ASR、课堂 runtime、Learning IPC 和 player artifact 打包已删除且没有兼容读取路径;历史课程数据保留但不再读取。服务端和客户端源码契约已完成,不代表生产部署或真实账号安装包联调已经完成。 AI 编程首次发送在新建 OpenCode session 已知为空时不再等待冗余历史读取,prompt 可直接进入 Host API;普通历史会话仍刷新消息。每个 Session 独立持有 run、loading、error 与内部队列;一个 Session 的回复或终止不会锁住、改写或重放另一个 Session。Host 接受或用户消息落库不算启动确认,只有明确 busy/retry、assistant、question、permission 或 typed terminal event 才确认/终结启动;独立的 10 秒 watchdog 到期时仅以 `SESSION_START_UNCONFIRMED` 终止该 Session。Main 以 runtime generation provenance、Agent 内容 fingerprint 和 live registry id 共同验证项目 Agent,provider/runtime 或 Agent 未应用时在执行前返回 typed `409` 且 `promptSent:false`。普通 message、command、summarize 和后台 provider sync 不自动重启、reload 或 dispose 共享 runtime;只有显式用户 apply/lifecycle 操作可以推进运行时刷新。Main AI proxy 只把明确的上游分组饱和投影为当前 OpenCode 的终止状态,配额耗尽保持独立终止态,通用限速继续保留 `429`。上下文压缩以每个 Session 的持久时间线事件呈现:自动与手动压缩使用不同文案,运行态原位弱化显示,完成后静态保留并可从历史恢复;`session.compacted` 只完成对应事件,只有真实 idle 才结束 run 和释放排队消息。 @@ -92,7 +98,7 @@ Robot 绑定设备默认先显示“引导配网 / 已有激活码”路径选 ## Recently Completed -- 2026-08-20: Replaced AI Learning's course generation/player stack with the curated project catalog defined by ADR-005. The authenticated/module-gated client now renders project cards and safe README detail, proxies publish-time mirrored media through Main, and saves verified ZIP archives through the native dialog. Old course/runtime/player packaging was removed; full client verification passed before main promotion, while the external operations backend and real-account package smoke remain pending. +- 2026-08-20: Replaced AI Learning's course generation/player stack with the curated project catalog defined by ADR-005. The authenticated/module-gated client now renders project cards and safe README detail, loads validated credential-free HTTPS Markdown images directly, and saves verified ZIP archives through the native dialog. Old course/runtime/player packaging was removed; server/client regressions and full suites passed, while production deployment and real-account package smoke remain pending. - 2026-08-19: Integrated native password/SMS login, the temporary HTTP/2-disabled diagnostic bootstrap, and the AI Design freeze fix. Workspace JSON calls and shared token refresh now settle within 30 seconds, transport abort is paired with deterministic rejection, and implicit Electron-to-Node fallback no longer replays mutation requests. Installed-client Quote retry/confirm smoke and the final HTTP/2 policy decision remain pending. - 2026-08-17: Integrated application-side multi-Session isolation for AI Programming. Session A may remain busy while Session B is independently accepted or terminally rejected; errors, startup deadlines and uncertain-failure cleanup stay Session-scoped. Main now fail-closes stale Agent/provider runtime state before execution, applies bounded manager/project FIFO acceptance with revocable timeouts, and never refreshes the shared runtime automatically from ordinary execution paths. Full unit, typecheck, lint, build, focused Electron E2E and independent Sol review passed; a real paid-provider/bundled-runtime concurrency smoke remains pending. - 2026-08-17: Replaced the temporary coverless-first-create fallback with a required PNG/JPEG/WebP picker, preview, file name, reselect action, Renderer/Main signature and size validation, and one Main-owned multipart metadata-plus-cover create request. Create conflicts fail before version upload; existing project metadata and covers remain unchanged. @@ -128,7 +134,7 @@ Robot 绑定设备默认先显示“引导配网 / 已有激活码”路径选 1. 用包含本次修复的安装包和真实 Works 账号重复执行 Quote PATCH、重试报价与继续调整,确认任一超时在 30 秒内释放 UI、其他请求可继续、服务端不收到隐式重复 mutation;确认后单独恢复 HTTP/2 再对照 smoke,决定是否移除临时 `disable-http2`。 2. 部署 Works `module_access` migration 与 `/api/auth/me` 权限 API,打包新 Makelore 客户端,再用真实账号分别关闭 Code、Canvas、Learning、Robot 执行卡片、根/深层/别名路由 smoke;同时独立验证模块 API 服务端授权。 -3. 实现并部署 Works Square Learning 项目管理、对象存储、远程图片镜像和 list/detail/media/archive API,再使用真实账号验证发布/下架、分页、README 图片、ZIP 校验/保存以及 Windows 与签名 macOS 安装包。 +3. 部署 Works Square Learning 项目管理、对象存储、README HTTPS URL 校验和 list/detail/media/archive API,再使用真实账号验证发布/下架、分页、远程 README 图片(含 SVG、失效 origin 和隐私提示)、ZIP 校验/保存以及 Windows 与签名 macOS 安装包。 4. 对 default-on Guided Hotspot Binding 核对指定固件镜像与六位码发行/消费契约,补齐 Windows 真机热点连接、签名 macOS x64/arm64 CoreWLAN/CoreLocation/worker 打包验证、真实 Host API/native seam Electron E2E 和完整真机 smoke;发布支持保留精确 `=0` 回滚,不把缺失证据表述为已验收。 5. 成组核对客户端 source+built+contract 上传 → 服务端逐字节校验 → OSS immutable Release → CDN/Edge 的发布契约与客户端 `play_url` 消费契约。 @@ -140,7 +146,7 @@ Robot 绑定设备默认先显示“引导配网 / 已有激活码”路径选 - 四模块权限只控制 Makelore 客户端入口和初始化,不是 API 授权边界。不得因卡片置灰或路由阻断而放宽 Works/模块服务端的身份与权限校验;旧服务端缺少对象/字段时默认开启是显式兼容策略。 - Prompt Museum 相对媒体必须保持固定的服务端路径并由 Main 处理;如果服务端增加媒体变体,需同步维护 entry/path 语法、Works Bearer 所有权、单次刷新、10 MiB 限制、可信 raster MIME 白名单与 Renderer data URL 校验。HTTPS 直连媒体必须继续无凭据,图片失败必须局限在卡片/详情视图。 -- Learning 项目目录依赖真实 Works 运营发布和固定 API 契约;README 远程图片必须在发布时镜像为固定媒体路径,客户端不得接受任意媒体/下载代理。Main 必须保持 Bearer 所有权、一次 401 refresh、可信 raster MIME、10 MiB 图片上限、同源最多五跳、512 MiB ZIP、声明大小/SHA-256/ZIP 签名和原子保存;不得把上游错误、Token、对象存储 URL 或本地路径投影到 Renderer。历史课程数据不再读取但也不得被隐式删除。 +- Learning 项目目录依赖真实 Works 运营发布和固定 API 契约;README 图片只允许服务端校验后的无凭据 HTTPS URL,并由 Markdown 图片节点直接加载,不得扩展为任意网络或归档代理。第三方 origin 的可用性、格式支持和请求隐私是已接受边界。Main 必须保持 Bearer 所有权、封面/历史媒体受控读取、一次 401 refresh、同源最多五跳、512 MiB ZIP、声明大小/SHA-256/ZIP 签名和原子保存;不得把上游错误、Token、对象存储 URL 或本地路径投影到 Renderer。历史课程数据不再读取但也不得被隐式删除。 - Works Project 首次封面已由服务端源 `407c883`(本地 merge `0cedfc4`)提供单请求原子绑定与失败补偿,客户端源 `145a6ce` 因此要求首次发布上传 PNG/JPEG/WebP 封面;部署、安装包和真实账号/对象存储 smoke 仍未完成。服务端仍没有已有 metadata 的 revision/ETag 与 draft-only 条件写,因此已有 draft/published 继续只允许 version-only,客户端不得以无条件 PATCH 替代。 - Guided Hotspot Binding 默认开启并提供未经认证的热点扫描/显式连接,但当前 Hotspot/portal 仍是开放 SoftAP + 明文 HTTP,且精确出货镜像、激活码发行契约、签名 macOS、Windows 真机与完整整链尚未验证。界面必须保留环境警告,异常发布可用精确环境值 `0` 回滚;不得把 SSID 前缀宣称为可信设备发现、自动认领或在线证明。 - 一键提交已成功但本机 submission binding 落盘失败时必须保持提交成功、显示固定 `binding_warning` 并继续轮询,避免用户误判上传失败。 diff --git a/.project-docs/30-worklog/tasks/20260820-integrate-direct-readme-client-b7e41c9d.md b/.project-docs/30-worklog/tasks/20260820-integrate-direct-readme-client-b7e41c9d.md new file mode 100644 index 0000000..1c97013 --- /dev/null +++ b/.project-docs/30-worklog/tasks/20260820-integrate-direct-readme-client-b7e41c9d.md @@ -0,0 +1,54 @@ +# Task: Integrate direct Learning README images + +## Identity + +- Task ID: 20260820-integrate-direct-readme-client-b7e41c9d +- Mode: Integration +- Branch: main +- Worktree: D:\Datas\OthersProjects\makelore +- Base commit: 99567396931882285fba19f8415e58e196db2c3c +- Owner: codex +- Status: Ready for Integration + +## Scope + +- Fast-forward the verified direct-README-image client source onto local `main`. +- Reconcile accepted Learning decisions, architecture/domain/current-state memory, + README, the Works Square collaboration contract, and the production commitment. +- Preserve the previously untracked packaging task record exactly as adopted by the + user's explicit merge confirmation. + +## Intent And Constraints + +- Implement the user's explicit replacement of publish-time image mirroring with direct + README Markdown image rendering. +- Keep raw HTML disabled, direct image URLs credential-free HTTPS only, and archive, + cover, historical-media, authentication, and module-access boundaries unchanged. +- Do not claim production deployment or signed-client smoke from source integration. + +## Outcome + +- Fast-forwarded client source `9956739` onto `main`. +- Updated canonical client documentation so Markdown image nodes directly load validated + credential-free HTTPS URLs, including SVG and other Electron-supported formats. +- Recorded that remote-origin availability, redirects, format support, and requester + network privacy are no longer controlled by Works Square image mirroring. +- Kept Main-owned verified ZIP saving plus controlled cover/historical-media handling. + +## Verification + +- Merged-default-branch Learning tests: `2` files, `5 passed`. +- Merged-default-branch TypeScript check: passed. +- Feature source verification remains `176` files / `2058 passed`, typecheck, lint, and + Vite production build passed. +- Canonical-document stale-mirroring scan and `git diff --check`: passed. + +## Follow-ups + +- Deploy matching Works Square source `65ea070` before distributing the matching client. +- Smoke real remote SVG/raster URLs, an unavailable origin, and privacy messaging in + Windows and signed macOS packages with a real entitled account. + +## Promotion Candidates + +- None recorded. diff --git a/.project-docs/40-domain/business-rules.md b/.project-docs/40-domain/business-rules.md index 276c717..e94df05 100644 --- a/.project-docs/40-domain/business-rules.md +++ b/.project-docs/40-domain/business-rules.md @@ -41,7 +41,7 @@ - 产品界面当前只支持中文;系统语言与历史持久设置中的其他值必须归一为 `zh`,不得保留不可达的伪语言选择。 - Learning 是登录必需且受 `module_access.learning` 控制的运营精选项目目录。客户端只提供项目列表、README 详情和用户触发的 ZIP 下载,不提供课程生成、进度、本地课程库、OpenMAIC 播放、Agent、ASR 或课堂 runtime,也不保留旧 API/数据兼容读取路径。 - Works Square 运营后台拥有项目名称、摘要、封面、标签、版本、排序、状态、Markdown、ZIP、声明字节数和 SHA-256。只有冻结了元数据、媒体和归档校验结果的 `published` 项目可被客户端列表或详情读取;客户端不提供上传、编辑或发布入口。 -- README 使用安全 Markdown/GFM 并禁用原始 HTML。运营发布时必须解析 Markdown,把无凭据的远程 HTTPS raster 图片经过 DNS/私网、重定向、大小、MIME 和解码校验后镜像,再改写为固定 `/api/learning/projects/:projectId/media/:mediaId` 路径;Main 只代理可信 PNG/JPEG/WebP/GIF/AVIF 且单图最大 10 MiB。 +- README 使用安全 Markdown/GFM 并禁用原始 HTML。运营发布时必须解析 Markdown,只保留无凭据、默认端口、无 fragment 且当前 DNS 全部指向公网地址的 HTTPS 图片 URL;不得下载、识别格式、转码或镜像 README 图片。客户端仅允许 Markdown 图片节点直连这些 URL,支持范围和可用性由 Electron 与远程 origin 决定;封面和历史发布媒体继续走受控媒体路径。 - 项目 ZIP 最大 512 MiB。Main 打开原生保存对话框,将下载流写入临时文件,只允许无 userinfo、最多五跳且保持 Works origin 的重定向,重定向请求不携带 Bearer;实际字节数、声明大小、SHA-256 与 ZIP 签名全部匹配后才原子重命名。Renderer 不得获得 Works Token、对象存储地址、任意下载 URL、临时路径或最终本地路径。 - 新客户端不读取、迁移或展示历史下载课程,但也不自动删除用户现有课程数据。任何清理功能必须另行设计为用户明确控制的可恢复维护动作。 - `game-engine` 不再是内置 OpenCode Skill。`planning-with-files` 在复杂任务中把 `task_plan.md`、`findings.md`、`progress.md` 写到当前项目根目录;不得写入 Skill 安装目录或用户目录。 @@ -68,7 +68,7 @@ - AI Canvas 请求冻结修复仍需在安装包内用真实账号重复 Quote PATCH、重试报价和继续调整:确认超时在 30 秒内释放 UI、并行请求可继续、服务端没有隐式重复 mutation。临时 `disable-http2` 不构成根因结论;修复确认后应恢复 HTTP/2 做对照 smoke,再决定正式协议策略。 - Robot Guided Hotspot Binding default-on 发布仍需确认指定硬件/固件确实提供被审计的开放 Hotspot/Portal、部署端签发严格六位 ASCII 数字码且与 Works validator 的时效/消费语义一致,并完成 Windows 真机、签名 macOS x64/arm64 native worker/association 与真实设备端到端 smoke。 - Prompt Museum 客户端契约和页面完成不等于 Works Square 内容后台、审核数据或 CDN 已部署;上线前需以真实登录账号验证列表、详情、署名链接、分页、图片和 Prompt 回填。 -- Learning 客户端集成不等于 Works Square 运营后台、对象存储、远程图片镜像或项目 API 已部署;上线前需先部署服务端合同,再以真实账号验证发布/下架、分页、README 图片、保存取消、ZIP 大小/摘要/签名错误以及 Windows/签名 macOS 安装包。 +- Learning 客户端集成不等于 Works Square 运营后台、对象存储或项目 API 已部署;上线前需先部署服务端合同,再以真实账号验证发布/下架、分页、远程 HTTPS README 图片(含 SVG 与失败隔离)、保存取消、ZIP 大小/摘要/签名错误以及 Windows/签名 macOS 安装包。 - 四模块入口策略上线前需确认 Works `module_access` migration/API 已部署,安装包包含对应客户端,并用真实账号逐一关闭四个模块验证卡片、根/深层/别名路由和独立 API 授权。 ## Last Reviewed diff --git a/.project-docs/80-commitments/commitments.md b/.project-docs/80-commitments/commitments.md index 9574c1b..b7b5c38 100644 --- a/.project-docs/80-commitments/commitments.md +++ b/.project-docs/80-commitments/commitments.md @@ -7,7 +7,7 @@ Track future-facing memory: promised follow-ups, unfinished loops, timed checks, | 2026-08-19 | 验收 AI Design 有限请求生命周期并决定正式 HTTP/2 策略 | 发布包含源 `87e4140` 的正式安装包前 | 客户端/Works 服务端/发布集成 | Pending | 使用真实账号连续执行 Quote PATCH、重试报价与继续调整,制造或等待慢响应,确认 30 秒内稳定返回、其他请求不被共同挂住、服务端无隐式重复 mutation;随后恢复 HTTP/2 重新打包做同场景对照。只有证据确认后才能移除临时 `disable-http2` 或把协议策略固化为正式决定。 | | 2026-08-17 | 验收 AI 编程真实双 Session runtime/provider 行为与 Agent 刷新边界 | 升级 bundled OpenCode、改变 provider 并发策略,或对外宣称双会话真实并发/即时 Agent 热更新前 | 客户端/OpenCode/provider 集成 | Pending | 使用明确配置的测试 provider 运行 opt-in bundled OpenCode 双 Session smoke,区分应用隔离与上游并发/串行/限流;若要求运行期即时应用 Agent 编辑,先提供 directory-scoped authoritative invalidation 或 whole-instance quiescence oracle。在此之前只允许回复完成后的手动 runtime restart,不从 `/session/status` 推断 dispose/reload 安全。 | | 2026-08-17 | 验收用户级四模块入口策略的真实发布链 | 发布包含源 tip `3b799af` 的 Makelore 安装包前 | Works 服务端/客户端/发布集成 | Pending | 部署 `module_access` migration 和 `/api/auth/me` API,重新打包并安装 Makelore;使用真实账号依次关闭 Code、Canvas、Learning、Robot,重启后验证卡片置灰/不可点、根/深层/别名路由阻断、`/settings` 仍可访问和 terminal `401` 退出;另行以直接 API 请求确认服务端授权,不以 UI 置灰代替 | -| 2026-08-20 | 部署并验收 AI Learning 项目目录完整链路 | 发布包含源 `38db158` 的 Makelore 安装包前 | Works 运营后台/服务端/客户端/发布集成 | Pending | 实现并部署项目管理、对象存储、发布代际、远程 HTTPS raster 图片校验镜像、list/detail/media/archive API;以真实账号验证发布/下架、排序分页、README/GFM/图片、原生保存取消、同源重定向、512 MiB、声明大小、SHA-256、ZIP 签名失败和 Windows/签名 macOS 安装包。不得以客户端测试宣称运营后台或生产数据已上线 | +| 2026-08-20 | 部署并验收 AI Learning 项目目录完整链路 | 发布包含源 `38db158`、`9956739` 的 Makelore 安装包前 | Works 运营后台/服务端/客户端/发布集成 | Pending | 实现并部署项目管理、对象存储、发布代际、README HTTPS URL 校验、list/detail/media/archive API;以真实账号验证发布/下架、排序分页、README/GFM/远程图片(含 SVG、失效 origin 和请求隐私说明)、原生保存取消、同源重定向、512 MiB、声明大小、SHA-256、ZIP 签名失败和 Windows/签名 macOS 安装包。不得以客户端测试宣称运营后台或生产数据已上线 | | 2026-08-17 | 验收首次项目封面并补齐已有资料条件写 | 发布包含源 `145a6ce` 的 Makelore 前,或启用 draft/published metadata 编辑前 | Works 服务端/客户端发布集成 | Partial / Pending | 首次封面已由服务端源 `407c883` 与客户端源 `145a6ce` 通过单请求绑定和失败补偿落地;仍需先部署服务端、重新打包客户端,并以真实对象存储/账号验证 404→create 409、cover 失败和版本阻断。已有资料编辑继续等待 metadata revision/ETag 与 draft-only 条件写;在此之前保持 existing version-only。 | | 2026-08-16 | 验收 Prompt Museum 与 Canvas 删除/重报价的真实服务端链路 | 发布包含 `26b52d7` Canvas 行为的安装包前 | 客户端/服务端集成 | Pending | 使用真实 Works 账号核对 Museum 列表/详情/分页/筛选/署名/CDN/Prompt 回填,并确认固定相对媒体路径可经 Main Bearer 代理、401 刷新、10 MiB/可信 raster MIME 边界后在 Renderer 展示;核对最终 Prompt/options 重报价和确认设计点;删除 Workspace 后确认软删除可见性、未提交任务取消/预留积分释放、已运行任务结算。保留 Main 错误脱敏和严格 DTO/HTTPS 投影,不以客户端回归替代服务端验收 | | 2026-08-16 | 验收 default-on Robot Guided Hotspot Binding 的 Windows/macOS 真实设备链路 | 下一份包含页面内热点连接行为的安装包发布前 | 客户端/硬件/服务端集成 | Pending | 核对精确出货固件与固定 Portal、六位码发行/消费语义;执行 Windows Robot 真机扫描/连接、签名 macOS x64/arm64 CoreLocation/CoreWLAN/worker/ASAR/Koffi smoke,以及真实 Host/native Electron 端到端配网+Binding;保留 `NIANCODE_AI_HARDWARE_GUIDED_HOTSPOT_BINDING=0` 回滚并记录支持矩阵 | diff --git a/README.md b/README.md index 83959af..a011922 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Makelore 是一个面向软件、视觉创作、互动学习与智能机器人 - AI 绘画:每个设计项目固定一个设计 Agent,并可包含多条互相独立的设计会话。消息、Brief、Quote 和 `turnRevision` 属于 Conversation;图片/视频生成任务与资产属于 Workspace,切换或新建会话不会创建新项目,也不会隐藏项目任务。图片创作既支持文生图,也支持从当前项目已完成作品或本地上传中选择一张参考图继续生成;输入框支持直接上传参考图,上传后可在候选区点击或输入 `@` 选择,并将所选资产随消息提交;视频沿用同一单图选择器绑定首帧。每条 Conversation 复用服务端持久 Agent Gateway Session;已连接时 Agent 命令、流式回复和任务进度共用 WebSocket,断流时使用幂等 REST 提交与低频同步。确认栏展示并允许编辑服务端最终提示词和 generation options,分别展示清晰度、画幅和视频时长;每次修改都会按当前 Quote 重新报价、刷新设计点,报价完成前不能确认,确认时将最新提示词与参数原值提交给后端。客户端不计算百炼尺寸、供应商价格或积分价格,服务端 Quote 是唯一计费准则。确认结果会按 Quote 对账,即使 Run 在任务落库后异常结束,Workspace 任务仍会恢复到统一列表。生产环境使用 Works Square 云端 Workspace 契约,上游不可用时明确报错。 - AI 绘画项目栏会在当前项目下保留会话历史,默认显示最近五条消息摘要和更新时间,更多会话可展开;新建或点击历史条目都在同一项目中切换并恢复完整对话。 - AI 绘画项目支持从侧栏删除。确认删除时必须完整输入项目名称;删除后项目及其会话、任务、参考图和生成作品会从账户中隐藏且无法访问,不影响用户已另存到磁盘的副本。服务端采用软删除,数据库记录和对象存储暂不物理清理。未提交的任务会被取消并释放预留积分,已提交或运行中的任务继续后台结算但对用户隐藏;删除当前项目后自动打开最近更新的剩余项目,删除最后一个项目后进入空状态。 -- AI 学习:主区展示服务端分页项目卡片,详情页用安全 Markdown 渲染 README;原始远程图片由 Works Square 在发布时校验、镜像并改写为固定媒体路径,再由 Main 进行 Bearer 代理、可信 raster MIME 与 10 MiB 上限校验。下载按钮打开系统保存对话框,Main 流式校验声明大小、SHA-256 与 ZIP 签名后原子保存,单包最大 512 MiB。客户端不提供课程生成、课程播放器、本地课程库、Agent、ASR 或课堂 runtime。运营管理与接口字段见 [`docs/learning-project-catalog-server-contract.md`](docs/learning-project-catalog-server-contract.md)。 +- AI 学习:主区展示服务端分页项目卡片,详情页用安全 Markdown 渲染 README;原始 HTML 被禁用,Markdown 图片节点直接加载服务端校验后的无凭据 HTTPS URL,包括 SVG 和 Electron 支持的其他图片格式,不经过服务端下载、识别、转码或镜像。下载按钮打开系统保存对话框,Main 流式校验声明大小、SHA-256 与 ZIP 签名后原子保存,单包最大 512 MiB。客户端不提供课程生成、课程播放器、本地课程库、Agent、ASR 或课堂 runtime。运营管理与接口字段见 [`docs/learning-project-catalog-server-contract.md`](docs/learning-project-catalog-server-contract.md)。 - 提示词博物馆:只陈列经过审核的作品预览、Prompt、分类以及作者/来源/许可证信息,支持搜索、使用场景/风格/主体筛选和详情抽屉;“使用此 Prompt”只把原文带回当前 Canvas 会话输入框,不自动发送、不构成社区。列表和详情数据由服务端提供,客户端不打包数据集;服务端字段契约见 [`docs/prompt-museum-server-contract.md`](docs/prompt-museum-server-contract.md)。 - 视觉系统:单一浅色主题,品牌蓝 `#3A5578`、星火橙 `#F26A3D`、白色画布与低饱和蓝灰层级。 - 字体系统:Renderer UI 内嵌 Inter Variable 与经过字符子集化的 Source Han Sans SC WOFF2,按字符范围统一中英文并保留系统中文字体 fallback;代码、路径和日志使用独立等宽字体。 @@ -99,7 +99,7 @@ Windows 打包脚本会先准备目标架构所需的 Python、uv 与 OpenCode - AI 编程项目配置以项目内 `.niancode/project.json` 为准;项目文件和会话主数据保持本地,问答观察快照按个人资料同步规则单向上行。 - AI 绘画 Renderer 只调用 Main-owned Host API;Main 负责 Works Square Token 刷新、Conversation 所属的服务端持久 Agent Session、单次 WebSocket ticket、双向命令/事件帧、断点续传与契约映射,并通过本机 Host API 的 SSE 投影同步任务状态。切换会话只重连对应流;注销或退出时关闭本地流并清除本机 Session-id 缓存,不删除服务端持久 Conversation Session。远端 Token 与 ticket 不进入 Renderer。 - AI 绘画使用独立的云端 Workspace 边界,不回退到 AI 编程项目数据,也不向 Renderer 暴露 Provider、模型、Prompt、存储 URI 或远端登录 Token。 -- AI 学习只通过 Main-owned Host API 获取项目列表、README 详情和固定媒体路径;Renderer 不持有 Works Token、对象存储地址、任意下载 URL 或本地文件路径。项目 ZIP 只允许同 Works origin 最多五跳重定向,重定向请求不携带 Bearer;下载结果仅向 Renderer 返回 `saved` 或 `cancelled`。README 不执行原始 HTML,图片必须由服务端镜像为固定项目媒体路径。 +- AI 学习只通过 Main-owned Host API 获取项目列表、README 详情和封面/历史媒体路径;Renderer 不持有 Works Token、对象存储地址、任意归档 URL 或本地文件路径。项目 ZIP 只允许同 Works origin 最多五跳重定向,重定向请求不携带 Bearer;下载结果仅向 Renderer 返回 `saved` 或 `cancelled`。README 不执行原始 HTML,仅 Markdown 图片节点可直接加载服务端校验后的无凭据 HTTPS URL。 - Prompt Museum 使用独立的 Main-owned Host API 代理;Renderer 只接收分页卡片、详情和服务端返回的图片地址,Works Square Token 只由 Main 持有。发布记录必须由服务端完成作者、来源、许可证和素材授权审核,模块不提供投稿、点赞、评论或排行榜。 - AI 编程的 Agent 配置是项目所有的;稳定 id 用于保持会话兼容,显示名称可以修改。AI 绘画的设计 Agent 是固定产品能力,不作为用户可增删的项目实体。 diff --git a/docs/learning-project-catalog-server-contract.md b/docs/learning-project-catalog-server-contract.md index 169b32e..ab6ff86 100644 --- a/docs/learning-project-catalog-server-contract.md +++ b/docs/learning-project-catalog-server-contract.md @@ -26,20 +26,20 @@ Renderer 的固定链路为 `Renderer -> Host API -> Electron Main -> Works Squa | 排序 `sort_order` | 有界整数;列表默认按运营排序,再按发布时间稳定排序 | | 状态 `status` | `draft`、`published`、`archived` | -上传中的对象不能直接进入公开目录。发布必须在一个事务/发布代际中冻结元数据、README、封面、镜像图片和 ZIP 摘要;任一校验失败则整个发布失败,旧的已发布版本继续可读。下架后列表和详情立即不可见,但已有审计记录不能物理删除。 +上传中的对象不能直接进入公开目录。发布必须在一个事务/发布代际中冻结元数据、经过净化和 URL 校验的 README、封面及 ZIP 摘要;任一校验失败则整个发布失败,旧的已发布版本继续可读。下架后列表和详情立即不可见,但已有审计记录不能物理删除。 -后台必须记录操作人、时间、发布代际、变更摘要、归档 SHA-256/字节数和远程图片抓取结果。客户端不提供任何运营上传或发布入口。 +后台必须记录操作人、时间、发布代际、变更摘要、归档 SHA-256/字节数、README 警告和远程图片 URL 数量。客户端不提供任何运营上传或发布入口。 ## 3. README 远程图片发布规则 -README 中的远程图片在“发布”时由服务端解析 Markdown AST 并镜像,客户端不直接使用原始远程图片 URL。处理要求: +README 中的远程图片在“发布”时由服务端解析 Markdown,并保留通过校验的原始 HTTPS URL;服务端不下载或处理图片字节。处理要求: 1. 只接受无用户名/密码的 HTTPS URL;拒绝 `http:`、`data:`、`file:`、本地路径和协议相对地址。 -2. 每一跳重新解析 DNS,并拒绝 loopback、私网、链路本地、保留地址、云元数据地址和非公网目标;最多 5 次重定向。 -3. 单图最大 10 MiB,同时限制超时、并发数和 README 图片总量;响应必须是实际可解码的 PNG/JPEG/WebP/GIF/AVIF,拒绝 SVG、HTML、XML 和 MIME 欺骗。 -4. 将通过校验的字节写入受控对象存储,以内容摘要去重;发布记录引用不可变对象。 -5. 把 Markdown 图片地址改写为 `/api/learning/projects/:projectId/media/:mediaId`。详情接口只返回改写后的 Markdown,不返回原始远程 URL 或对象 key。 -6. Markdown 原始 HTML在客户端被禁用;服务端也应在预览与发布时提示被忽略的 HTML,避免运营误判展示效果。 +2. 只允许默认 HTTPS 端口且不允许 fragment;解析当前 DNS,任一结果属于 loopback、私网、链路本地、保留地址、云元数据或其他非公网地址时拒绝发布。 +3. 限制 README 图片总量;不请求远端响应,因此不校验重定向、响应大小、MIME、像素、实际格式或内容。SVG 及其他 Electron 可渲染格式可直接显示。 +4. 发布后的 Markdown 保留通过校验的 URL,不创建 README 图片 blob 或新 release-media 行;现有媒体路由继续用于封面和历史已镜像发布。 +5. Markdown 原始 HTML 在客户端被禁用;服务端也从发布内容中移除 HTML 并返回 warning,避免运营误判展示效果。 +6. 客户端请求会直接到第三方图片 origin;图片可用性、后续 DNS/重定向和格式支持由 origin 与 Electron 决定,origin 也会看到请求方网络信息。单图加载失败不得阻断 README 其余内容。 封面同样优先返回固定媒体路径。若返回 HTTPS CDN 地址,该地址必须无凭据、由 Works Square 控制且不包含用户隐私。 @@ -106,7 +106,7 @@ README 中的远程图片在“发布”时由服务端解析 Markdown AST 并 "archiveBytes": 12582912, "publishedAt": "2026-08-01T00:00:00Z", "updatedAt": "2026-08-18T00:00:00Z", - "readmeMarkdown": "# 桌面机械臂\n\n![接线图](/api/learning/projects/robot-arm/media/wiring)", + "readmeMarkdown": "# 桌面机械臂\n\n![接线图](https://docs.example.com/wiring.svg)", "archiveFileName": "makelore-robot-arm-1.2.0.zip", "archiveSha256": "64位小写十六进制SHA-256" } @@ -117,7 +117,7 @@ TypeScript 权威字段定义位于 [`shared/learning.ts`](../shared/learning.ts ### 媒体与归档响应 -- 媒体接口只返回受控 raster 内容,必须设置准确 `Content-Type` 与 `Content-Length`;Main 限制 10 MiB,并转换为 data URL给 Renderer。 +- 媒体接口只用于封面和历史已镜像内容,返回受控 raster 内容并设置准确 `Content-Type` 与 `Content-Length`;Main 限制 10 MiB,并转换为 data URL 给 Renderer。新发布 README 的 HTTPS 图片不经过该接口。 - 归档接口返回 `application/zip`、`application/x-zip-compressed` 或 `application/octet-stream`,设置准确 `Content-Length`。如需重定向,只能跳转到与 Works API 相同 origin 的 HTTP(S) 地址,最多 5 跳;Main 不向重定向目标转发 Bearer。 - 归档字节必须与详情中的 `archiveBytes` 和 `archiveSha256` 精确一致。客户端验证失败时删除临时文件,不留下部分下载。 @@ -131,6 +131,6 @@ TypeScript 权威字段定义位于 [`shared/learning.ts`](../shared/learning.ts - `LEARNING_CONFLICT`(409,发布代际变化); - `LEARNING_UNAVAILABLE`(429/502/503)。 -列表/详情可对发布代际生成 ETag;媒体和归档按内容摘要设置不可变缓存,但不得缓存带用户私有授权的响应到公共共享缓存。日志不得记录 Bearer、签名 URL、README 原始私有 URL或对象存储 key。 +列表/详情可对发布代际生成 ETag;媒体和归档按内容摘要设置不可变缓存,但不得缓存带用户私有授权的响应到公共共享缓存。日志不得记录 Bearer、签名 URL、完整 README 图片 URL 或对象存储 key;可记录规范化主机、URL 摘要和图片数量。 -上线顺序:先部署数据库/对象存储、运营后台、远程图片镜像和四个公开接口,并用真实账号完成发布/下架/图片/ZIP 联调;再发布新客户端。旧 `/api/learning/courses`、generation/progress/runtime 接口不在新客户端兼容范围内,可按服务端消费者盘点结果独立退役。 +上线顺序:先部署数据库/对象存储、运营后台、README HTTPS URL 校验和四个公开接口,再发布包含直连图片支持的新客户端;随后用真实账号完成发布/下架/远程图片(含 SVG、失效 origin 和隐私提示)/ZIP 联调。旧 `/api/learning/courses`、generation/progress/runtime 接口不在新客户端兼容范围内,可按服务端消费者盘点结果独立退役。