905527 × Alens 整合重构(2026-10-11)

边界

  • 905527 = Astro 公网站(${HOME}/dev/905527,Cloudflare Worker Static Assets)。
  • Alens = 个人节点后端(${HOME}/app/alens,端口 8000,Preact)。
  • 80 端口 = service-index.py 运维页,不是对外主站,不在整合范围。
  • 本轮不开放注册、不做节点联邦、不开发原生客户端。

已完成(Block 2/4/5)

  • 删除独立 Agent 页,导航只留 首页/探索/测试/关于。
  • Agent 卡片点击开详情面板:桌面侧栏 + 手机全屏,URL hash #agent=<name>,支持 Esc/返回键/深链。
  • Agent 介绍用 职责/能力/记忆机制/协作,去掉性格拟人化。
  • Explore 整合公开对象 + 工具:搜索、分类筛选(工具/收藏/kind)。
  • 对象独立详情页 /explore/<slug>/,构建期从 Alens 公开 API 生成。

关键实现决策

  1. 构建期快照:scripts/alens-snapshot.mjs 从 alens /api/v1/public/* 拉全部公开对象+评价,写 scripts/public-subjects.json(gitignore)。alens 不可达时保留旧快照,不阻塞构建。
  2. 封面本地化:构建期下载公开封面到 static/media/public/<uuid>.webp(gitignore,215M)。必须带 .webp 扩展名——无扩展名时 python http.server / Worker 返回 octet-stream,浏览器拒渲染。运行时引用本地相对路径,不依赖 alens 8000。
  3. 数据分离:只读 alens /api/v1/public/*(已做 NSFW 隐藏控制 subject_is_hidden + 字段白名单),绝不读私人接口。快照自动扫描内网地址/token 泄露。
  4. audit-public.py 修复:dist 加入 webp 封面后,原脚本对所有文件 read_text(utf-8) 崩溃于二进制 → fail-closed 报 INCOMPLETE。改为跳过二进制后缀(webp/png/字体等)+ try/except UnicodeDecodeError。
  5. 无障碍:subject-kind 标签 opacity: 0.8 导致对比度 3.82 < 4.5。改为 opacity: 1 + font-weight: 600(纯 —primary 6750a4)。

验收门禁(全过)

  • validate-content.mjs:4 Agent / 40 题 / 3 公开入口。
  • audit-public.py dist:3156 文本文件,privacy/nsfw/sensitive/boundary 全 0。
  • interaction-check.py:主题/侧栏/键盘/移动导航/过滤/对话框(依赖 playwright)。
  • accessibility.py:390/1440 × 明暗 × 4 页,16 项 0 违规。

环境坑

  • playwright 装在 /usr/bin/python3(系统 python3 无,venv 无 pip)。跑验收脚本用 /usr/bin/python3。
  • chromium 在 ${HOME}/.cache/ms-playwright/chromium-1243/。
  • 验收脚本连 http://${LOCALIP}:8895,需 python3 -m http.server 8895 起 dist。
  • astro dev 不热更 publicDir 深层新增文件(封面 404),验证用 build 产物 + 静态 server,别用 dev server 验封面。
  • browser_exec 的 js() 返回 {},用 cdp('Runtime.evaluate', expression=..., returnByValue=True)。

待办(未做)

  • Block 3 数据分离的更完整迁移、增量同步机制未做(本轮只做只读快照)。
  • Block 4 公开导出的媒体哈希去重/适配尺寸/Worker 静态资源优化未做(本轮封面直接下载原图)。
  • 未 push(9dee303 本地)。