Skip to content

Feat/agent observability Improve agent observability and file sync resilience#6

Open
lvzhouyang wants to merge 7 commits intomarswaveai:mainfrom
lvzhouyang:feat/agent-observability
Open

Feat/agent observability Improve agent observability and file sync resilience#6
lvzhouyang wants to merge 7 commits intomarswaveai:mainfrom
lvzhouyang:feat/agent-observability

Conversation

@lvzhouyang
Copy link
Copy Markdown

@lvzhouyang lvzhouyang commented Apr 1, 2026

Summary

This PR improves ColaMD's agent-observability workflow and file-sync robustness.

  • hardens file-open and live-sync behavior with clearer error handling
  • improves renderer startup reliability and custom-theme loading behavior
  • adds a lightweight agent activity timeline with recent change summaries
  • lets recent agent changes jump to the changed content
  • tightens inline HTML sanitization for both rendering and export

Validation

  • npm run typecheck
  • npm run build
  • manual smoke testing for live file updates, timeline UI, recent-change jump navigation, and theme/error handling flows

Note

Medium Risk
Touches core file open/watch/save flows and renderer IPC/UI wiring; regressions could break live-sync or saving. Also changes security posture (CSP/sandbox/HTML sanitization), which is beneficial but can have compatibility edge cases.

Overview
Improves agent observability by adding a "Recent Changes" panel that tracks the last few external file updates, summarizes what changed, and lets users jump to the affected section; external updates now also trigger a short-lived in-editor diff highlight.

Hardens file-sync and UX resilience: centralizes file reads with size/type checks, handles atomic-save rename events, retries watcher failures, preserves scroll on external updates, and surfaces open/save/export/theme errors to the renderer via a new app-error IPC and toast UI.

Tightens security and export correctness by enabling Electron sandbox, strengthening the renderer CSP, sanitizing inline HTML node rendering, and sanitizing exported HTML; also adds CI/typecheck wiring (typecheck script + release workflow step) and ignores agent-loop logs.

Written by Cursor Bugbot for commit 6d5deda. This will update automatically on new commits. Configure here.

吕周洋 and others added 4 commits March 31, 2026 08:40
阶段一:安全加固
- 修复 load-theme-css 路径遍历漏洞(resolveThemePath 校验)
- CSP 补强:添加 script-src/object-src/base-uri/frame-src 指令
- IPC 输入校验:open-file-path/save-file/export-html 类型检查
- HTML 导出 sanitization:过滤 script/iframe/on* 事件属性
- html-view sanitization:白名单标签 + 移除危险属性

阶段二:文件同步健壮性
- fs.watch 处理 rename 事件(支持原子保存的编辑器)
- watcher error 事件监听 + 自动重建
- stopWatching 清理 debounceTimer
- 提取 readTextDocument 统一文件读取
- 添加 MAX_OPEN_FILE_SIZE 5MB 限制
- 提取 Agent 检测常量:AGENT_ACTIVE_GAP_MS 等

阶段三:Agent Diff View
- 节点级 diff:替换前快照 → 替换后比较 → 绿色高亮变更节点
- 5 秒自动淡出动画
- setMarkdown(content, showDiff) 新参数

阶段四:代码质量
- preload 事件返回 Unsubscribe 函数,支持注销
- 删除未使用的 scanCustomThemes 函数
- CI release.yml 添加 tsc 类型检查步骤

Co-Authored-By: Claude <noreply@anthropic.com>
Comment thread src/renderer/editor/sanitize.ts
Comment thread src/renderer/editor/editor.ts
Comment thread src/main/index.ts Outdated
1. sanitize.ts: 修复 replaceWith 后被提升子元素属性未清理的问题。
   之前 disallowed 标签被替换时,其子元素会被提升但属性未被 sanitize。
   现在先收集被提升的 Element 节点,替换后再对它们递归 walk。

2. base.css: 添加 agent-diff-added 和 agent-diff-fadeout CSS 规则,
   使 diff 高亮可见,并使 animationend 事件能正常触发。

3. main/index.ts: 修复 watchFile 中 fs.watch() 同步异常导致进程崩溃。
   用 try-catch 包裹 watch() 调用,异常时停止 watcher 并重试。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@lvzhouyang
Copy link
Copy Markdown
Author

已修复三个 review 问题:

1. sanitize.ts (High) - Sanitizer skips children of removed disallowed elements
修复:当 disallowed 标签被替换时,先收集被提升的子 Element 节点,替换后再对它们递归 walk 清理属性。

2. base.css (High) - Missing CSS for diff highlight classes
修复:添加 agent-diff-added(绿色背景高亮)和 agent-diff-fadeout(淡出动画)的 CSS 规则,使 animationend 事件能正常触发。

3. main/index.ts (Medium) - Uncaught exception in rename retry crashes main process
修复:用 try-catch 包裹 fs.watch() 调用,异常时停止 watcher 并延迟 500ms 重试,避免同步异常导致进程崩溃。

提交: 988f7d6

Comment thread src/main/index.ts
Comment thread src/main/index.ts
1. rename 后重新读取文件内容:atomic save 会替换文件,之前只重启
   watcher 但不读取内容,导致编辑器显示旧内容。现在立即读取并通知
   渲染器。

2. rename 时保留 agent 状态:之前调用 stopWatching() 会重置 agentState
   和 lastExternalChange,导致 agent dot 闪烁。改为只关闭 watcher,
   不重置 agent 状态。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@lvzhouyang
Copy link
Copy Markdown
Author

已修复另外两个 review 问题:

1. main/index.ts (High) - Rename handler omits file re-read after atomic save
修复:rename 事件后立即调用 readTextDocument() 读取文件内容并通知渲染器,不再只依赖 'change' 事件。

2. main/index.ts (Medium) - Rename handler resets agent activity detection state
修复:不再调用 stopWatching()(会重置 agentState 和 lastExternalChange),改为只关闭 watcher 并重启 watcher,保持 agent 状态连续性。

提交: b3649e4

Comment thread src/renderer/editor/sanitize.ts
Comment thread src/renderer/main.ts
1. sanitize.ts: 递归检查被提升元素的标签本身是否 allowed。
   之前内层 disallowed 标签被提升后不再检查,导致 <style> 等危险标签
   绕过检查。现在递归检查并持续提升直到只剩 allowed 标签或纯文本。

2. main.ts: 添加 stripMarkdown() 清理 targetText 中的格式字符。
   之前 targetText 保留 **bold**、[link](url) 等 markdown 语法,但比较
   时 DOM.textContent 是渲染后的纯文本,导致匹配失败。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@lvzhouyang
Copy link
Copy Markdown
Author

已修复另外两个 review 问题:

1. sanitize.ts (High) - Sanitizer allows disallowed tags promoted from nested context
修复:在递归检查被提升元素时,先检查其标签本身是否 allowed。若 disallowed,则继续提升其子节点而非直接 walk,防止 <style> 等危险标签绕过检查。

2. main.ts (Medium) - Jump navigation fails for markdown-formatted target text
修复:添加 stripMarkdown() 函数,移除 **[link](url)``` 等 markdown 格式字符,使 targetText 与 DOM.textContent 匹配。

提交: 6d5deda

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

'code', 'pre', 'b', 'i', 'u', 's', 'table', 'thead', 'tbody',
'tr', 'th', 'td', 'blockquote', 'ul', 'ol', 'li', 'p', 'a',
'img', 'figure', 'figcaption', 'ruby', 'rt', 'rp'
])
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sanitizer strips heading tags from HTML export

High Severity

ALLOWED_HTML_TAGS is missing h1 through h6. This set was designed for inline HTML sanitization in html-view.ts, but sanitizeHTMLFragment is now also applied to the full document HTML in the export path (sanitizeHTMLFragment(getHTML())). Since getHTML() serializes ProseMirror content using DOMSerializer which produces <h1><h6> tags, the sanitizer strips all headings from the exported HTML, replacing them with their unwrapped text content.

Additional Locations (1)
Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant