Skip to content

feat(mubu): add Mubu adapter with 5 commands#964

Open
SherlockSalvatore wants to merge 1 commit intojackwener:mainfrom
SherlockSalvatore:feat/mubu
Open

feat(mubu): add Mubu adapter with 5 commands#964
SherlockSalvatore wants to merge 1 commit intojackwener:mainfrom
SherlockSalvatore:feat/mubu

Conversation

@SherlockSalvatore
Copy link
Copy Markdown

Description

Adds a browser-based adapter for 幕布 (Mubu), a Chinese outliner and daily-notes app popular among knowledge workers and Obsidian users.

Type of Change

  • 🐛 Bug fix
  • ✨ New feature
  • 🌐 New site adapter
  • 📝 Documentation
  • ♻️ Refactor
  • 🔧 CI / build / tooling

Commands

Command Description
opencli mubu doc <id> Read a document as Markdown or plain text
opencli mubu docs List documents and folders in root (or a specific folder)
opencli mubu notes Read daily notes — today by default, or any date range
opencli mubu recent List recently edited documents
opencli mubu search <query> Full-text search across all documents and folders

Technical Notes

  • Auth: Strategy.COOKIE — reads Jwt-Token from localStorage and sends requests via in-page XHR (same pattern as the zsxq adapter), avoiding CORS issues and extension fetch interception.
  • Output formats: doc and notes support --output md (default, indented-list Markdown suitable for Obsidian import) and --output text (plain text for terminal reading).
  • Node rendering: utils.ts implements recursive renderers (nodesToMarkdown / nodesToText) that handle bold, italic, strikethrough, underline, node-mention links, hyperlinks, inline images, task checkboxes, deadline/reminder metadata (Obsidian Tasks/Reminder plugin format), and HTML tables → Markdown tables.
  • Daily notes (notes): Mubu stores daily notes as a year-doc tree (keyed in localStorage as daily_notes_doc_list). The adapter resolves year-doc IDs, fetches them in parallel for multi-year ranges, and filters day-nodes by date key. Supports --date, --month, --year, --from/--to, and --list (summary mode: date + entry count only).
  • Search: Uses the server-side /list/search API for full-text matching. Returns type, id, name, path (breadcrumb), hits (total matching nodes count), and snippet (up to 5 matching node previews joined by |).
  • Error handling: Auth failures (missing token or API code !== 0 with auth-related message) raise AuthRequiredError; other API errors raise CommandExecutionError.

Files

File Description
clis/mubu/doc.ts Read a single document (Markdown / plain text)
clis/mubu/docs.ts List documents and folders; --starred for quick-access list
clis/mubu/notes.ts Daily notes with flexible time range
clis/mubu/recent.ts Recently edited documents
clis/mubu/search.ts Full-text search with hit count and snippet preview
clis/mubu/utils.ts Shared API client, HTML→Markdown/Text renderers, type definitions
docs/adapters/browser/mubu.md Adapter documentation page
docs/adapters/index.md Added row to Browser Adapters table
docs/.vitepress/config.mts Added sidebar entry

Checklist

  • I ran the checks relevant to this PR
  • I updated tests or docs if needed
  • I included output or screenshots when useful

Documentation

  • Added doc page under docs/adapters/ (if new adapter)
  • Updated docs/adapters/index.md table (if new adapter)
  • Updated sidebar in docs/.vitepress/config.mts (if new adapter)
  • Updated README.md / README.zh-CN.md when command discoverability changed
  • Used positional args for the command's primary subject unless a named flag is clearly better
  • Normalized expected adapter failures to CliError subclasses instead of raw Error

Screenshots / Output

opencli mubu --help
Usage: opencli mubu [options] [command]

mubu commands

Options:
  -h, --help      display help for command

Commands:
  doc [options] <id>         读取幕布文档内容(默认输出 Markdown,可用 --output text 输出纯文本)
  docs [options]             列出幕布文档(默认根目录,--starred 查看快速访问列表)
  notes [options]            读取幕布速记(默认今天)。支持 --date/--month/--year/--from/--to 指定时间范围,--list 为概览模式(日期+条数)。
  recent [options]           最近编辑的幕布文档
  search [options] <query>   全局搜索幕布文档和文件夹(标题+内容,服务端全量匹配)。结果含 type/id/name/path/hits/snippet 字段。
  help [command]             display help for command
opencli mubu docs
type  id              name              updated               stared
────  ──────────────  ────────────────  ────────────────────  ──────
📁    xxxxxxxxxxxxxx  工作              2026-04-10 09:32      ★
📁    xxxxxxxxxxxxxx  个人              2026-04-09 21:15
📄    xxxxxxxxxxxxxx  每日复盘模板      2026-04-08 18:44      ★
📄    xxxxxxxxxxxxxx  项目计划          2026-04-07 11:20
opencli mubu notes --list --month 2026-04
date                content
──────────────────  ──────────
4 月 11 日,周五     8 条记录
4 月 10 日,周四     12 条记录
4 月 9 日,周三      5 条记录
opencli mubu search "AI"
type    id              name          path             hits  snippet
──────  ──────────────  ────────────  ───────────────  ────  ───────────────────────────────
doc     xxxxxxxxxxxxxx  AI 阅读笔记   个人 > 学习       5     大模型的涌现能力 | scaling law...
doc     xxxxxxxxxxxxxx  产品思考      工作 > 规划       1     AI 辅助设计流程
folder  xxxxxxxxxxxxxx  AI 资料       个人

@Astro-Han
Copy link
Copy Markdown
Contributor

Thanks for putting this together. I like the scope and the command set, but I think there are two merge blockers from my read.

The main one is that the new mubu adapter is added under clis/mubu/*.ts, while this repo now appears to load only .js adapters. src/discovery.ts skips .ts, and src/build-manifest.ts scans only .js, so I believe opencli mubu ... would never register after merge.

The other point is smaller but still worth fixing: the new commands use bare Error for expected user-input cases like invalid --output or bad date ranges. My suggestion would be to switch those to the usual CliError subclasses so the CLI behavior stays consistent.

@SherlockSalvatore
Copy link
Copy Markdown
Author

Thanks for putting this together. I like the scope and the command set, but I think there are two merge blockers from my read.

The main one is that the new mubu adapter is added under clis/mubu/*.ts, while this repo now appears to load only .js adapters. src/discovery.ts skips .ts, and src/build-manifest.ts scans only .js, so I believe opencli mubu ... would never register after merge.

The other point is smaller but still worth fixing: the new commands use bare Error for expected user-input cases like invalid --output or bad date ranges. My suggestion would be to switch those to the usual CliError subclasses so the CLI behavior stays consistent.

Thanks for the review~ I missed the recent refactor from .ts to .js and realized I haven't rebased against the latest code yet. I’ll rebase and make the necessary adjustments to the adapter and discovery logic ASAP. I'll also update the error handling to use CliError to keep it consistent with the project.

@SherlockSalvatore
Copy link
Copy Markdown
Author

Thanks for putting this together. I like the scope and the command set, but I think there are two merge blockers from my read.

The main one is that the new mubu adapter is added under clis/mubu/*.ts, while this repo now appears to load only .js adapters. src/discovery.ts skips .ts, and src/build-manifest.ts scans only .js, so I believe opencli mubu ... would never register after merge.

The other point is smaller but still worth fixing: the new commands use bare Error for expected user-input cases like invalid --output or bad date ranges. My suggestion would be to switch those to the usual CliError subclasses so the CLI behavior stays consistent.

@Astro-Han Thanks again for the review — both points are now addressed. Pushed the updated branch (force-push on feat/mubu).

1. .ts.js migration
Rebased onto latest main . All 6 files under clis/mubu/ are now .js with type annotations stripped. Verified locally: npm run build registers all 5 commands, and opencli mubu --help lists them.
correctly.

2. CliError subclasses for user-input errors
Replaced all 6 bare Error throws with ArgumentError. Auth and runtime errors in utils.js continue to use AuthRequiredError / CommandExecutionError.

Would appreciate another look when you get a chance 🙏

@Astro-Han
Copy link
Copy Markdown
Contributor

Thanks for the update. I reread the changes, and from my side the same three issues still look worth fixing:

  1. mubu doc should default to plain output. As written, the default path renders as a table, which does not match the command help or the expected Markdown export flow.
  2. htmlToMarkdown() should preserve <br> line breaks. Right now multiline nodes get flattened, so both doc and notes can lose structure in Markdown output.
  3. notes should reject impossible dates and months up front. Inputs like 2026-02-31 or 2026-13 currently come back as empty results, which reads like “no notes” instead of “invalid input.”

These are review notes from my side to help tighten the PR, not an attempt to block it. If you update those parts, I’m happy to take another look.

@SherlockSalvatore SherlockSalvatore force-pushed the feat/mubu branch 3 times, most recently from 138e1e2 to 43f1429 Compare April 12, 2026 13:39
@SherlockSalvatore
Copy link
Copy Markdown
Author

Thanks for the update. I reread the changes, and from my side the same three issues still look worth fixing:

  1. mubu doc should default to plain output. As written, the default path renders as a table, which does not match the command help or the expected Markdown export flow.
  2. htmlToMarkdown() should preserve <br> line breaks. Right now multiline nodes get flattened, so both doc and notes can lose structure in Markdown output.
  3. notes should reject impossible dates and months up front. Inputs like 2026-02-31 or 2026-13 currently come back as empty results, which reads like “no notes” instead of “invalid input.”

These are review notes from my side to help tighten the PR, not an attempt to block it. If you update those parts, I’m happy to take another look.

Hi @Astro-Han,

Thank you for your very thorough and responsible review! I really appreciate your attention to detail, which has significantly improved the robustness of this PR.

I have addressed all your comments in the latest commits. Here is a detailed summary of the improvements based on your feedback:

Preserved
and Multiline Structure:

Fixed the issue where multiline nodes were getting flattened. In htmlToMarkdown(),
tags are now explicitly converted to \n before the remaining HTML tags are stripped.

In nodesToMarkdown(), both text and note fields containing newlines are properly split and mapped with correct indentation. This ensures that multiline list items and blockquotes (>) fully retain their Markdown structure.

Strict Date Validation: Added robust date checks using dynamic day-of-month calculations (lastDayOfMonth). It now accurately throws errors for invalid leap years (e.g., 2025-02-29), non-existent days (e.g., 02-31), and out-of-bounds months/years.

Special Character Handling: Enhanced decodeHtmlEntities() to properly parse standard HTML entities (&, <, >, ", ', ) and Unicode sequences. This guarantees that symbols and consecutive spaces are correctly rendered without breaking Markdown elements like tables or bold texts.

I have verified these changes against 19 test cases covering extreme date inputs and complex string patterns. All tests passed successfully.

Please see the screenshots below for the formatting test results and date validation:

Test Cases for Formatting:
image
image

Date validation:
image

Looking forward to your further feedback!

@Astro-Han
Copy link
Copy Markdown
Contributor

Thanks for the update. I took another pass through the latest version, and the earlier issues I raised look addressed.

I only noticed one small edge case in htmlToMarkdown(): the node-mention conversion currently matches class="node-mention" exactly. If Mubu ever emits combined classes there, for example class="node-mention bold", that mention would fall through and render as plain text instead of a Markdown link. This feels minor, and it may be fine in practice if the markup is stable, but it is worth a quick check.

Other than that, this looks good to me. Overall LGTM.

@SherlockSalvatore
Copy link
Copy Markdown
Author

Thanks for the update. I took another pass through the latest version, and the earlier issues I raised look addressed.

I only noticed one small edge case in htmlToMarkdown(): the node-mention conversion currently matches class="node-mention" exactly. If Mubu ever emits combined classes there, for example class="node-mention bold", that mention would fall through and render as plain text instead of a Markdown link. This feels minor, and it may be fine in practice if the markup is stable, but it is worth a quick check.

Other than that, this looks good to me. Overall LGTM.

@Astro-Han Hi, the newest update might address your concern, please review. The test is below:
image
image

Commands: doc, docs, notes, recent, search.

- Uses COOKIE strategy; API calls via in-page XHR with Jwt-Token
  from localStorage (matches the web app's own mechanism).
- Renders node trees to Markdown (default) or plain text;
  supports tables, tasks, images, emoji, mentions, strikethrough,
  underline, and nested structures.
- notes supports flexible time ranges: single day, month, year,
  or custom --from/--to spans, plus a --list overview mode.
- search returns full-text matches with hit count and snippets
  for both folders and documents.
@Astro-Han
Copy link
Copy Markdown
Contributor

Thanks for checking this and for following up on the edge case.

I reviewed the latest update, and the node-mention handling looks good now. The earlier concerns I raised appear resolved.

LGTM from my side. Thanks again for the careful follow-through on the fixes and tests.

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.

2 participants