383e6f6b43
fix(db): expand source chain for all DB error logging
...
The previous fix only covered migration errors. The same truncation
affected two more places, both because tokio_postgres::Error's Display
prints only "db error" while the real message lives in source():
- api/error.rs: AppError::{db_conn,query,tx} logged with {e}, so every
runtime DB failure showed as "Query failed: db error". The
constructors' bound is tightened from impl Display+Debug to
impl std::error::Error so the source chain can be walked; the
user-facing message stays sanitized (existing tests still pass).
- db/pool.rs: ensure_database formatted tokio_postgres::Error directly
into the String returned to main.rs' exit(1) path, collapsing to
"failed to query pg_database: db error" etc.
Adds a shared crate::db::format_with_sources helper (walks source()
with de-dup of placeholder layers) and reuses it from MigrateError's
Display, the AppError constructors, and pool.rs.
2026-07-04 21:54:54 +08:00
e9f0b032b7
fix(db): expand migration error display to walk source chain
...
tokio_postgres::Error's Display prints only the placeholder "db error"
for DB-side failures; the actual message (e.g. column already exists,
SQLSTATE, constraint name) lives in source() as DbError. Without
traversing the chain, startup logs showed the useless
"migration 001 failed: db error", making failures impossible to
diagnose.
MigrateError::Display now appends each source layer with ": " and
exposes source() so error-reporting layers that walk the chain
themselves also benefit.
2026-07-04 21:47:24 +08:00
f3eb93f320
docs(agents): document code runner and fix clippy/biome lint
...
文档:
- AGENTS.md 新增「Code Runner」架构章节(三层架构 + WASM 可见性规则 +
governor 0.8 无 per_day 的处理 + runner 镜像契约)
- Environment 段补齐 CODE_RUNNER_* 与 RATE_LIMIT_CODE_EXEC_* 环境变量
Lint 修复(clippy --all-targets --all-features -D warnings 全绿):
- runner.rs/runner.rs: use_signal 冗余闭包 → 直接传 fn
- runner_config.rs: &*RUNNER_CONFIG 去 deref;assert_eq!(...false/true) → assert!
- markdown.rs: 局部变量 /// 改 //;Option.map().flatten() → and_then
- languages.rs: 删除从未读取的 LanguageDef.name 字段(语言名即 map key)
- docker.rs: start_container if let Err → ?;timeout match → is_err();
嵌套 if 合并(修 task 2 遗留 + clippy 1.96 新 lint)
- pages/admin/posts.rs: use_signal 冗余闭包(预存 lint,顺带修绿)
- codemirror editor.ts: biome format 重排 setSchema 单行
2026-07-03 18:57:25 +08:00
9851f98dc0
chore(docker): setup sandboxed runtime containers and build script
...
- runner-base: alpine 3.18 + 非 root 用户 1000:1000 + /code 工作目录
- runner-python: 基于 base, apk add python3 + python 符号链接(对齐 run_cmd 'python')
- runner-node: 基于 base, apk add nodejs
- runner.toml: 镜像自描述(运行时实际配置由 Rust LANGUAGES 注册表 + 环境变量决定)
- build-runners.sh: 按 base→python→node 顺序构建, tag 与 languages.rs 严格对齐
2026-07-03 18:48:03 +08:00
bbd4553467
feat(admin): add dedicated code-runner sandbox page at /admin/runner
...
不改动 852 行的 write.rs 编辑器布局,改为独立 admin 页面(与 posts/system 同款):
- runner.rs: Runner 页面(语言切换 join 按钮 + overrides JSON 输入 + CodeRunner 沙箱)
切换语言自动填充示例源码;overrides JSON 实时校验,畸形时提示并忽略
- mod.rs: 注册 runner 模块并导出 Runner
- router.rs: 新增 #[route("/runner")] Runner {} 嵌套在 /admin 下
- admin_layout.rs: 导航新增「试运行」入口
2026-07-03 18:41:05 +08:00
0e8b5fd7b7
feat(ui): scan and mount code-runner component client-side in reader
...
采用 Dioxus vdom 友好的片段拆分(避免篡改 dangerous_inner_html 产物导致 hydration 冲突):
- post_content.rs: split_content_fragments 把 content_html 拆成 Html/Runnable 片段,
Runnable 作为 <CodeRunner> 组件穿插渲染;HTML 实体解码还原源码;6 个单测
- markdown.rs: 可运行 pre 增加 data-source(转义后的原始源码), 供阅读器无损提取
- sanitizer.rs: 放行 pre 的 data-source 属性
(任务 7 的 data-source 增量一并在此提交)
2026-07-03 18:35:57 +08:00
6b875e6ba5
feat(ui): create CodeRunner Dioxus UI component with async polling
...
- runner.rs: CodeRunner 组件(源码展示 + Run 按钮 + 阶段/输出/错误区)
spawn 提交 StartExec 后用 sleep_ms(WASM 友好) 轮询 GetExecResult,MAX_POLLS 兜底
mut 信号加 cfg_attr 放行 server 的 unused_mut(AGENTS.md 约定)
提前克隆 source/language 给 move 闭包,避免 rsx! 二次借用 (E0382)
- execute.rs: 修正双目标可见性——server fn 模块不能 cfg-gate
共享类型 use 双目标可见,server-only 辅助 use 单独 gate(对齐 posts 模块约定)
- mod.rs: execute 不再 gate,languages/progress 仍 gate
2026-07-03 18:28:52 +08:00
576803302d
refactor(editor): support dynamic languages python/javascript in codemirror
...
- editor.ts: 新增 languageCompartment + buildLanguageExtension(lang, schema)
python → lang-python, node/javascript → lang-javascript, sql/缺省 → lang-sql
新增 setLanguage(lang) 热切换; setSchema 保留当前语言不被强制切回 sql
- package.json: +@codemirror/lang-python +lang-javascript
- codemirror_bridge.rs: EditorInstance 新增 set_language wasm-bindgen extern
(产物 public/codemirror/ 被 gitignore,本地已重建)
2026-07-03 18:22:21 +08:00
a77a2e3502
feat(markdown): support rendering and sanitizing runnable pre code-blocks
...
- markdown.rs: CodeBlock 处理识别 `runnable` 标记 + 受支持语言,在 <pre> 上
挂 data-runnable/data-lang/data-overrides;overrides JSON 经 escape_html 转义
防属性注入;非可运行围栏的 language-xxx 改取纯语言 token(首个空白前)
- sanitizer.rs: clean_html 放行 <pre> 的 data-runnable/data-lang/data-overrides
- 新增 4 个 markdown 测试 + 2 个 sanitizer 测试覆盖转义/白名单/字段顺序
2026-07-03 18:19:26 +08:00
9fe128d44d
feat(api): implement StartExec and GetExecResult server functions
...
- rate_limit.rs: 新增 CODE_EXEC 双层限流(per-second burst + 每日总额)
governor 0.8 无 per_day,用 with_period(24h)+allow_burst 模拟
- execute.rs: StartExec(IP 提取/语言白名单/源码大小/入队/并发信号量/clamp/容器执行)
+ GetExecResult(轮询读取 DashMap);系统异常脱敏,日志记详情
- .env.example: RATE_LIMIT_CODE_EXEC_PER_SEC 改为整数(governor 不支持小数)
2026-07-03 18:15:59 +08:00
3f3bbf284c
feat(api): add language registry and markdown fence info parser
2026-07-03 18:11:43 +08:00
9baa9da62f
feat(api): implement in-memory task registry with gc
2026-07-03 18:10:20 +08:00
60fd6378b6
feat(api): define shared serialized structs for code runner
...
Co-authored-by: plan docs/superpowers/plans/2026-07-03-code-runner.md Task 3
2026-07-03 18:09:27 +08:00
5fdc88a48c
fix(runner): resolve task 2 container runner review findings
2026-07-03 18:02:56 +08:00
f6042d23f6
chore(skill): add matt-pocock engineering skills
...
Add 20 engineering/productivity skills from mattpocock/skills:
ask-matt, code-review, codebase-design, diagnosing-bugs,
domain-modeling, grill-me, grill-with-docs, grilling, handoff,
implement, improve-codebase-architecture, prototype, research,
setup-matt-pocock-skills, tdd, teach, to-issues, to-prd, triage,
writing-great-skills.
Update skills-lock.json with corresponding source/hash entries.
2026-07-03 18:00:16 +08:00
d8d30df80c
feat(infra): implement Docker execution layer using bollard client
2026-07-03 17:59:52 +08:00
b0ebba3475
fix(runner_config): remove server gate on runner_config, safeguard clamp logic, and parse allow_network case-insensitively
2026-07-03 17:52:50 +08:00
60725053e4
feat(infra): implement runner config parsing and resource limits clamping
2026-07-03 17:50:42 +08:00
2fba43dc3f
chore(infra): add bollard dependency and modular structure
2026-07-03 17:49:08 +08:00
c85a898fbd
docs(skill): add yggdrasil-ui-design-taste skill
2026-07-03 17:43:19 +08:00
922d1d0755
fix(ui): apply border-radius to table corner cells to prevent background bleed
2026-07-03 17:31:05 +08:00
0dbbc9d813
fix(ui): remove display block from table to fix horizontal fill rendering
2026-07-03 17:29:52 +08:00
c7b11b7f04
style(ui): redesign markdown tables to match modern aesthetic
2026-07-03 17:27:54 +08:00
46860f7c41
fix(ui): apply mount animation inside each page component to avoid skeleton interception
2026-07-03 17:24:38 +08:00
d361bca220
feat(ui): add smooth mount animation for route transitions
2026-07-03 17:21:04 +08:00
197c08d258
style(ui): fix inconsistent padding on post card
2026-07-03 17:13:02 +08:00
34d1d65823
style(css): apply minimalist transparent scrollbar globally
2026-07-03 17:05:06 +08:00
e18fe18cc3
fix(admin/layout): move scrollbar to outer card edge for all admin pages
2026-07-03 16:53:10 +08:00
52b4f91622
fix(admin/write): restore scrollability by using overflow-y-auto and min-h-full
2026-07-03 16:50:53 +08:00
acfddb3e17
style(admin/write): overhaul write page to modern minimalist layout
2026-07-03 16:44:39 +08:00
d3a50728ed
style(admin): overhaul layout to modern minimalist sidebar design
2026-07-03 15:50:59 +08:00
38ba6692d3
style(admin): redesign admin UI with soft rounded corners and Catppuccin theme
2026-07-03 15:46:18 +08:00
9f69a132fa
refactor(admin): redesign write page for industrial aesthetic
2026-07-03 15:37:41 +08:00
cad0e3d83b
fix(admin): restrict write page width to match other pages
2026-07-03 15:35:06 +08:00
d1041a84dd
feat(admin): complete redesign of backend ui with industrial minimalist aesthetic
2026-07-03 15:32:02 +08:00
45f4e9cde0
refactor(ui): 去除 Rust 中硬编码颜色,统一语义色阶
...
跟随 Catppuccin 配色迁移,清理 src/ 中绕过 paper-* 语义 token 的
硬编码 dark:[#hex] 任意值,改用 Tailwind 默认灰阶(gray-700/800),
它们随主题切换自然适配。
- post.rs 状态徽章:dark:bg-[#333 ]/dark:text-[#9b9c9d] → gray-800/gray-400/500
(同步更新测试断言)
- comments/* 与 skeletons/* 的 dark:[#2a2a2a]/[#2e2e33]/[#333 ]/[#5a5a62]
→ 对应 gray-600/700/800
- trash.rs 状态灯发光圈 rgba 由旧鼠尾草绿(92,122,94) 改 Latte green(64,160,43)
- ui.rs BTN_SECONDARY 注释更新为新 Teal 强调色值
注:src/pages/admin/posts.rs 的 clippy redundant_closure 报错为既有问题,
与本次配色迁移无关,不在范围内。
2026-07-03 14:25:40 +08:00
90fc6977b0
feat(editor): Tiptap 编辑器配色迁移到 Catppuccin(Latte/Mocha)
...
编辑器 CSS 此前用硬编码 GitHub 风格色(#0366d6/#d73a49/#24292e 等),
独立于 paper-* 语义 token。逐元素重映射到 Catppuccin 调色板:
亮色 Latte:正文 text、标题 text、placeholder overlay0、
行内 code surface0/red、pre crust、blockquote surface1/subtext0、
hr surface1、链接 blue、selection surface0、表格 surface1/crust、
slash 弹层 mantle/surface0、checkbox/选中态 green(主强调)
暗色 Mocha:对应角色映射(text/cdd6f4 等)
上传遮罩的 rgba(255,255,255,*) 白字与 rgba(239,68,68,*) 红删除按钮
属中性覆盖层,保留不动。
2026-07-03 14:18:03 +08:00
385fb43516
feat(theme): 全站配色迁移到 Catppuccin(Latte/Mocha)
...
亮色 Latte、暗色 Mocha。语义 token 重新映射:
- theme/entry 背景用 base/mantle
- primary/secondary/content 文字用 text/subtext1/subtext0
- tertiary 占位符用 overlay0
- code-block/code-bg 用 crust/surface0
- border 用 surface1
- 主强调 accent 改 Green(#40a02b / #a6e3a1)
- 次强调 accent-2 改 Teal(#179299 / #94e2d5)
同步修正组件层硬编码字面量:
- md-content 链接 hover 改用 accent-2(Teal)
- copy-code 按钮用 paper-tertiary/paper-theme/accent 语义色
- blur-img 灰底去掉 fallback,直接用 paper-code-bg 变量
破坏性变更,不兼容旧色。
2026-07-03 14:11:07 +08:00
cb77d28a68
fix(theme): 跟随系统切换改为瞬切,放弃 VT 动画
...
诊断确认:跟随系统与手动点击的 VT 流程在 JS/CSS 层完全等价(animationName、
--tt-r、bg 翻转、clip-path 全部正确),但视觉上跟随系统场景下圆形展开动画
不显示,仅瞬切。系统偏好变化是后台事件,VT 在此上下文下动画不可靠。
改用设置语义的瞬切:JS 侧新增 applyResolvedTheme(isDark) 入口(非翻转语义,
直接 add/remove dark class),Rust effect 改调 __applyResolvedTheme 传实际
明暗值,移除圆心计算逻辑。职责清晰:
- 手动点击 → __startThemeTransition → VT 圆形展开(用户手势,动画可靠)
- 跟随系统 → __applyResolvedTheme → 瞬切(后台同步语义)
2026-07-03 13:42:17 +08:00
eb3087edf4
fix(theme): 跟随系统切换用主题按钮位置作为 VT 圆心
...
诊断发现跟随系统与手动点击的 JS 路径完全一致(__startViewTransition 全程
正常,无降级、无 reject),「看起来像淡入淡出」实为圆形展开动画在屏幕中心
圆心下的必然视觉效果:从中心向四周等距扩散,各方向同步推进,近似整体覆盖,
与手动点击(按钮在右上角,圆弧明显横扫)观感差异大。
改用 .theme-toggle 按钮的 getBoundingClientRect() 中心作为 VT 圆心,与手动
点击的动画起点一致;按钮不在 DOM 时回退到视口中心。同步更新注释说明。
2026-07-03 13:26:40 +08:00
740afca05a
chore: 在 lint 中添加类型检查并新增加载图标
...
- 在 Makefile 的 lint 目标中增加 `pnpm typecheck`
- 添加带渐变效果的旋转加载 SVG 图标
2026-07-03 11:36:24 +08:00
188fc464e2
fix(theme): System 模式下系统偏好变化时同步 dark class
...
原实现存在缺口:<html> 的 dark class 运行时写入点只有「首屏预加载脚本」与
「手动点击 ThemeToggle」两处,System 模式下系统颜色偏好自动变化时无人同步——
尽管 system_dark signal 与 resolved memo 都会更新,下游(CodeMirror 等)也
能跟随,但页面配色纹丝不动,与文件头注释承诺的「实时同步 .dark class」不符。
新增 use_effect 兜底:仅 System 模式下 resolved 实际翻转时,以视口中心为圆心
复用 __startThemeTransition 触发 VT 圆形展开动画。Light/Dark 显式模式由
ThemeToggle::onclick 全权负责,effect 不介入,避免重复触发;首次挂载通过
prev_resolved 信号记录基线,自然跳过(DOM 已由 ThemePreload 设好)。
2026-07-03 11:35:10 +08:00
c79c390482
fix(ui): ADMIN_TABLE_CLASS 去掉 overflow-hidden,修复 tooltip 被裁
...
overflow-hidden 用于圆角裁剪表格,但会硬裁掉行内按钮的 tooltip
(无论朝上朝下)。去掉后:表格行 hover 背景 (bg-paper-entry) 与
容器背景同色,圆角处无视觉差异,tooltip 可正常溢出表格边界。
全局生效,所有 admin 表格的 tooltip 不再被裁。
2026-07-03 11:15:48 +08:00
64ad40ca61
fix(admin/posts): Tooltip 包裹后操作按钮恢复垂直居中
...
- Tooltip 外层 div 由块级改为 inline-flex,作为行内伸缩盒参与
flex 行对齐,不再撑高或破坏基线
- 操作列容器补 items-center,显式锁定所有子项垂直居中
2026-07-03 11:08:04 +08:00
73b9cad550
refactor(ui): 抽取 Tooltip 组件,行内重建按钮补 tooltip
...
新增可复用 Tooltip 组件(group-hover 显现,支持 top/bottom 朝向),
消除顶部重建按钮手写的内联 tooltip div 重复,并为表格行内重建
按钮补上 tooltip(朝上,避免被表格容器的 overflow-hidden 裁掉)。
2026-07-03 11:03:56 +08:00
b6fe0ae082
style(admin/posts): 删除按钮 loading 用 spinner 覆盖文字
...
- 删除改为非乐观:点击后保留行并显示 loading,服务端成功才移除行、
失败保留行并弹提示(顺带修掉原先「删除失败行却没了」的隐患)
- deleting 信号由 Option<i32> 改为 HashSet<i32>,支持并发删除
- 删除按钮 loading 样式与重建一致:文案恒为「删除」,spinner
居中覆盖、文字 opacity-40 衬底
2026-07-03 10:51:16 +08:00
1530d3a2f4
style(admin/posts): 顶部重建按钮 loading 用 spinner 覆盖文字
...
工具条「重建内容」「重建全部」按钮 loading 时由「重建中...」文案
改为 spinner 居中覆盖、文字 opacity-40 衬底,与行内重建按钮的
loading 样式统一。
2026-07-03 10:46:57 +08:00
db87d3c886
fix(admin/posts): 重建支持并发 loading,spinner 覆盖文字
...
- rebuilding 信号由 Option<i32> 改为 HashSet<i32>,连续点击多篇
文章的重建按钮可同时处于 loading 态(单值会被后点的覆盖)
- loading 样式调整:按钮文案恒为「重建」,spinner 绝对定位覆盖在
文字上方居中,文字 opacity 调至 40% 衬底,不再切换文案
2026-07-03 10:40:11 +08:00
a5c00caa80
style(admin/posts): 操作列加宽横排,重建按钮 loading 用 spinner 图标
...
- 操作列宽 w-24 → w-44,三个按钮一行排开不换行
- 重建按钮 loading 态由「重建中...」文案改为 spinner 图标 + 「重建中」
- spinner 复用 public/icons/90-ring-with-gradient.svg,作为 SPINNER_SVG
常量收入 ui.rs(修正原 SVG 损坏的孤立 ':' 选择器,重命名 id/类名
避免多处内联时冲突),用 currentColor 继承按钮文字色
2026-07-03 10:26:14 +08:00
e55f2e12bd
refactor(admin/posts): 重建按钮文案改「重建」并去掉完成弹窗
...
按钮态文案与原有一致(「重建中...」);on_rebuild 改为静默执行,
仅按行切换 rebuilding 按钮态,完成后不再弹浏览器 alert。
2026-07-03 10:16:13 +08:00