chore: documentation added and adapted to RuDS

This commit is contained in:
2026-07-20 13:02:34 +02:00
parent c82b790b82
commit 7887d02e0b
15 changed files with 507 additions and 20 deletions

124
CLI.md Normal file
View File

@@ -0,0 +1,124 @@
# RuDS Command Line, Headless Server, and Terminal UI
## In this article
- [What the CLI is](#what-the-cli-is)
- [Installing the CLI](#installing-the-cli)
- [Global flags and output](#global-flags-and-output)
- [Command reference](#command-reference)
- [Creating content from the command line](#creating-content-from-the-command-line)
- [Running the headless server](#running-the-headless-server)
- [Using the terminal UI](#using-the-terminal-ui)
- [How the CLI and the desktop app stay in sync](#how-the-cli-and-the-desktop-app-stay-in-sync)
## What the CLI is
`bds-cli` is the automation surface of RuDS. It runs the same engines against the same application database and the same projects as the desktop app — there is no separate state, no export/import step, and no second configuration. Anything the CLI changes shows up in an open desktop window automatically.
Typical uses: scripted rebuilds and site generation, publishing from CI or cron, creating posts from other tools, importing images in bulk, running utility Lua scripts, and starting the headless server or the terminal UI.
## Installing the CLI
Install the launcher from the desktop app under **Settings → Data**, or run `bds-cli install` from a packaged binary. Both place a small forwarding launcher in `~/.local/bin` that executes the packaged CLI next to the shared runtime. Make sure `~/.local/bin` is on your `PATH`.
## Global flags and output
| Flag | Effect |
|---|---|
| `--json` | Print a stable JSON result envelope instead of human-readable text |
| `--airplane` | Block network commands and route automatic AI work to the local (airplane) endpoint |
The JSON envelope always has the shape `{"ok": bool, "command": string, "message": string, "data": object, "progress": [string], "notices": [string]}`, which makes the CLI safe to drive from scripts and LLM agents. Errors exit with code 1 and a formatted message on stderr; unknown commands and invalid options do the same.
With `--airplane`, `upload`, `push`, and `pull` are refused, and AI-assisted steps (language detection, translation, image enrichment) use the configured airplane endpoint. When no local endpoint is configured, the CLI prints a notice and falls back to offline heuristics where they exist — the command-line equivalent of the desktop's airplane-mode toast.
## Command reference
All commands operate on the active project from the shared project registry unless stated otherwise.
| Command | What it does |
|---|---|
| `rebuild` | Rebuild the cache database from the active project's files. `--incremental` applies only detected differences and imports orphan files |
| `repair <part>` | Run one derived-data repair: `post-links`, `media-links`, `thumbnails`, `embeddings`, or `search` |
| `render` | Render the generated site. `--incremental` validates output and applies only differences; `--force` re-renders everything, ignoring content hashes |
| `upload` | Upload generated HTML, thumbnails, and media using the project publishing settings, waiting for the publish job |
| `push` | Push the project repository to origin |
| `pull` | Fast-forward pull, then reconcile the cache database with the pulled files |
| `post` | Create a post from flags or JSON on stdin (see below) |
| `media <file>` | Import one image with best-effort AI enrichment and translations. `--language` overrides detection |
| `gallery <images…>` | Create a post and import/link all supplied images through the shared gallery pipeline |
| `config get\|set\|list` | Read or update global application settings; `list` shows effective values with secrets redacted |
| `project list\|add\|switch` | List, add (`--name` optional), or switch projects in the shared registry |
| `lua <script> [args…]` | Run an enabled utility Lua script from the active project in the sandboxed runtime |
| `server` | Start the authenticated headless SSH server (see below) |
| `tui` | Start the interactive terminal UI locally |
| `install` | Install the forwarding launcher in `~/.local/bin` |
## Creating content from the command line
`post` accepts either flags or a JSON object on stdin:
```
bds-cli post --title "Release notes" --content "…" --tags releases,news
echo '{"title":"Release notes","content":"…","tags":["releases"]}' | bds-cli post --stdin
```
Available flags: `--title`, `--content`, `--excerpt`, `--author`, `--language`, `--template`, `--tags`, `--categories`, `--no-translate`, `--stdin`. When `--language` is omitted the language is auto-detected (AI endpoint when available, offline heuristic otherwise, with a printed notice). After creation the same automatic translation cascade as the desktop app is scheduled and awaited.
`gallery` takes the same post flags plus image paths; every image is imported, linked to the new post, AI-enriched, and translated like the desktop gallery workflow. `media` runs the same pipeline for a single image without creating a post.
## Running the headless server
`bds-cli server` runs RuDS without a window — same binary family, same database, same engines. Launching the desktop binary with `BDS_MODE=server` is equivalent.
| Flag | Effect |
|---|---|
| `--bind <ip>` | SSH listen address. Defaults to loopback; external access must be explicit |
| `--port <port>` | SSH listen port (default 2222) |
| `--database <path>` | Application database path override |
| `--data-dir <path>` | Private application data directory containing the SSH key material |
Only the SSH port is ever exposed. On first start the server generates a restrictive RSA host key and an empty `authorized_keys` file in an `ssh/` folder inside the private application data directory. Add one public key per line — standard OpenSSH format. `authorized_keys` is re-read on every authentication, so key changes need no restart. There are no passwords.
Clients connect in two ways:
- **Terminal**: `ssh -p 2222 user@server` opens the terminal UI directly in the SSH session. Each client gets its own session; all sessions share the server's data and UI language.
- **Desktop app**: **File → Connect to Server…** with `user@host` or `user@host:port`. The desktop uses its own generated Ed25519 identity and trust-on-first-use `known_hosts`, negotiates the native protocol over the same SSH connection, and shows the remote workspace in the window. **File → Disconnect from Server** returns to the local workspace.
All connected clients stay synchronized through ordered domain events: an edit in one session refreshes lists and closes deleted-entity tabs everywhere.
## Using the terminal UI
Start it locally with `bds-cli tui`, or get it automatically over `ssh` to a headless server. The status line at the bottom always shows the keys available in the current context.
### Views and navigation
| Key | View |
|---|---|
| `1` | Posts |
| `2` | Media |
| `3` | Templates |
| `4` | Scripts |
| `5` | Tags |
| `6` | Settings |
| `7` | Git |
`↑`/`↓` or `j`/`k` move the sidebar selection, `Enter` opens the selected entry, `Esc` goes back, `q` quits.
### Working with content
- Posts open in a syntax-highlighted, soft-wrapped editor. `n` creates a new post. `Ctrl+S` saves the draft, `Ctrl+P` saves and publishes, `Ctrl+E` toggles the rendered Markdown preview, `Ctrl+G` runs the one-shot AI post analysis (airplane-gated).
- Templates and scripts open with HTML+Liquid and Lua highlighting.
- Images open in the terminal image preview.
- `/` opens a live filter for the current view: plain words search text, `tag:x` and `category:x` filter like the desktop chips, and an ISO date (`yyyy-mm-dd`) narrows to that day. Tokens combine with AND; `Enter` keeps the filter, `Esc` clears it.
- `:` opens the command prompt with the parameterless Blog-menu commands (metadata diff, validate site, force render, rebuilds, reindex, translations, duplicates, upload, preview URL). `:?` shows the list as help. Completed metadata-diff and site-validation tasks open a report panel; `Enter` applies the whole report, `Esc` closes it.
- `p` opens the project switcher; `o` switches to a folder prompt with bash-style tab completion to open a folder as a new project (a full rebuild is queued automatically).
- In Tags: `n` create, `Enter` rename, `c` cycle color, `t` cycle template, `d` then `y` delete, `s` sync from posts; in Merge, `Space` marks and `m` merges.
- In Git: `c` commit (stage all), `u` pull (fast-forward only), `s` push, `Enter` jumps the diff to a file.
- Settings sections mirror the desktop editor; `Enter` edits a field in the status line, `Ctrl+S` saves the section.
## How the CLI and the desktop app stay in sync
Every CLI mutation writes a notification row into the shared database. A running desktop app watches for these, invalidates its caches, and refreshes the affected views within moments — no manual reload. Processed notifications are pruned automatically.
Because CLI, TUI, server, and desktop all use the same engines, invariants hold everywhere: published bodies live in files, metadata flushes to the filesystem, and rebuilds reconcile external changes.

View File

@@ -10,6 +10,9 @@
- [Working with pages](#working-with-pages) - [Working with pages](#working-with-pages)
- [Working with media](#working-with-media) - [Working with media](#working-with-media)
- [Working with translations](#working-with-translations) - [Working with translations](#working-with-translations)
- [Finding content and duplicates](#finding-content-and-duplicates)
- [Previewing your site](#previewing-your-site)
- [Editing site navigation](#editing-site-navigation)
- [Using macros](#using-macros) - [Using macros](#using-macros)
- [Using scripting](#using-scripting) - [Using scripting](#using-scripting)
- [Using the AI assistant](#using-the-ai-assistant) - [Using the AI assistant](#using-the-ai-assistant)
@@ -23,6 +26,8 @@
- [Generating and publishing](#generating-and-publishing) - [Generating and publishing](#generating-and-publishing)
- [Typical editorial workflows](#typical-editorial-workflows) - [Typical editorial workflows](#typical-editorial-workflows)
- [Working fully offline](#working-fully-offline) - [Working fully offline](#working-fully-offline)
- [Connecting external AI agents (MCP)](#connecting-external-ai-agents-mcp)
- [Using the command line](#using-the-command-line)
- [Running a headless server and the terminal UI](#running-a-headless-server-and-the-terminal-ui) - [Running a headless server and the terminal UI](#running-a-headless-server-and-the-terminal-ui)
- [Troubleshooting and recovery](#troubleshooting-and-recovery) - [Troubleshooting and recovery](#troubleshooting-and-recovery)
- [Team conventions](#team-conventions) - [Team conventions](#team-conventions)
@@ -81,7 +86,9 @@ Finally, define language and author defaults. These defaults reduce repetitive e
## Understanding the interface ## Understanding the interface
The RuDS interface is organized around workflows rather than isolated forms. The Activity Bar on the left moves between major areas such as Posts, Pages, Media, Tags, Import, Source Control, and Settings. The Sidebar changes with the active area and helps with filtering, selection, and navigation. The Editor area is where most work happens and supports tabbed editing for content, configuration, and analysis views. The RuDS interface is organized around workflows rather than isolated forms. The Activity Bar on the left moves between the major areas: Posts, Pages, Media, Scripts, Templates, Tags, Chat, Import, Source Control, and Settings. The Sidebar changes with the active area and helps with filtering, selection, and navigation. The Editor area is where most work happens and supports tabbed editing for content, configuration, and analysis views. When no tab is open, the editor area shows the Dashboard with project statistics, a posting timeline, a tag cloud, and recent posts.
The status bar at the bottom shows the active project and holds the airplane-mode switch that decides whether online AI endpoints may be used. It also shows the applied site theme and, during AI chat, running token totals.
The bottom panel and status area matter during longer operations such as imports, rebuild actions, metadata scans, and media work. Toasts provide quick feedback. The Output panel provides deeper detail when something needs attention. The bottom panel and status area matter during longer operations such as imports, rebuild actions, metadata scans, and media work. Toasts provide quick feedback. The Output panel provides deeper detail when something needs attention.
@@ -107,6 +114,8 @@ A reliable post workflow is: draft to completion, review structure and metadata,
When you want help refining post metadata, use Quick Actions in the post editor and review AI suggestions for title, summary, and slug. Treat this as editorial assistance, not an automatic rewrite. When you want help refining post metadata, use Quick Actions in the post editor and review AI suggestions for title, summary, and slug. Treat this as editorial assistance, not an automatic rewrite.
The post editor's links panel shows outgoing links to other posts and backlinks from posts that reference the current one. Use it to check context before restructuring or unpublishing, and click a linked post to open it directly.
### Key takeaways ### Key takeaways
- Use Posts for date-oriented and regularly updated content. - Use Posts for date-oriented and regularly updated content.
@@ -141,7 +150,7 @@ The Media section is where you import, describe, and maintain assets used by pos
When importing media, add metadata while context is still fresh. Alt text should describe meaning for accessibility. Captions should support reader understanding. Media tags should help later retrieval and reuse. When importing media, add metadata while context is still fresh. Alt text should describe meaning for accessibility. Captions should support reader understanding. Media tags should help later retrieval and reuse.
You can also drag image files into the post editor or paste screenshots from the clipboard. RuDS imports the image into the media library, links it to the current post, and inserts the Markdown image at the cursor position. From the post editor you can insert already-imported media at the cursor position, or use the Gallery workflow to import several images at once: RuDS imports them into the media library, links them to the current post, runs the optional AI enrichment for titles and alt text, and inserts the gallery block into the post.
### Key takeaways ### Key takeaways
@@ -173,12 +182,67 @@ Media items can have translated title, alt text, and caption values per language
When blog languages are configured, RuDS can fill missing translations for posts and linked media. Automatic translation respects airplane mode and the configured AI runtime. If an automatic action cannot run in the current AI mode, RuDS reports that through the UI instead of silently inventing a result. When blog languages are configured, RuDS can fill missing translations for posts and linked media. Automatic translation respects airplane mode and the configured AI runtime. If an automatic action cannot run in the current AI mode, RuDS reports that through the UI instead of silently inventing a result.
### Validation report
Use **Blog → Validate Translations** to open a completeness report across all configured languages. It lists missing and outdated translations for posts and media so you can close gaps deliberately instead of discovering them after generation.
### Key takeaways ### Key takeaways
- Post translations store title, excerpt, and content separately from the canonical post. - Post translations store title, excerpt, and content separately from the canonical post.
- Media translations store translated descriptive text while the asset stays shared. - Media translations store translated descriptive text while the asset stays shared.
- Automatic translation keeps posts and linked media aligned across configured languages. - Automatic translation keeps posts and linked media aligned across configured languages.
- Do Not Translate excludes content from multi-language workflows. - Do Not Translate excludes content from multi-language workflows.
- The translation validation report shows missing languages before they become visible gaps.
[↑ Back to In this article](#in-this-article)
---
## Finding content and duplicates
The sidebar search narrows the current list as you type. Posts, pages, and media support full-text search with language-aware stemming, and the filter panel adds calendar, tag, and category filters that combine with the text query.
When semantic similarity is enabled in the project settings, sidebar search also ranks results by meaning, not only by matching words. The same capability powers related-post ranking in the links panel and tag suggestions in the post editor.
Use **Blog → Find Duplicate Posts** to review pairs of posts with very similar or identical content. The review view pages through candidate pairs, lets you open both posts, and lets you dismiss a pair once you have decided it is intentional. Dismissals are remembered.
### Key takeaways
- Sidebar search combines full-text matching with calendar, tag, and category filters.
- Semantic similarity, when enabled, improves search, related posts, and tag suggestions.
- The duplicate review helps consolidate overlapping content deliberately.
[↑ Back to In this article](#in-this-article)
---
## Previewing your site
Preview renders through the same pipeline as site generation, so what you see is what will be published. The preview server runs only on your machine at `127.0.0.1:4123` and is never exposed to the network.
Open a post preview inside the app with **Blog → Preview Post** or view it in your default browser with **File → Open in Browser**. Draft posts have their own preview routes, so you can check work in progress without publishing anything.
### Key takeaways
- Preview and generation share one rendering pipeline; there are no preview-only differences.
- The preview server is local-only.
- Drafts can be previewed without publishing.
[↑ Back to In this article](#in-this-article)
---
## Editing site navigation
The site menu is stored as an OPML file in your project (`meta/menu.opml`) and edited visually in the Menu Editor (**Blog → Edit Menu**). The Home entry always stays first; below it you can add page links, submenus, and category entries, including categories that do not exist yet.
Reorder entries by dragging or with the equivalent keyboard controls, indent or unindent to build submenus, and save when the structure is right. The saved menu feeds the same renderer used by preview and generation, so the navigation you build is exactly what appears on the published site.
### Key takeaways
- The menu is a filesystem artifact (`meta/menu.opml`) and therefore Git-reviewable.
- Home is protected and always first.
- Preview, generation, and the editor all use the same menu structure.
[↑ Back to In this article](#in-this-article) [↑ Back to In this article](#in-this-article)
@@ -283,7 +347,9 @@ The assistant can present results as text, tables, cards, charts, metrics, lists
## Organizing with tags ## Organizing with tags
Tags are your precision taxonomy tool. Over time, even well-managed projects accumulate near-duplicate tags, naming inconsistencies, and labels that no longer help readers or editors. Use the Tags area to keep taxonomy useful. Tags are your precision taxonomy tool. Over time, even well-managed projects accumulate near-duplicate tags, naming inconsistencies, and labels that no longer help readers or editors. Use the Tags area to keep taxonomy useful: the tag cloud shows usage, the manage section covers create, rename, color, and template assignment, and the merge section consolidates overlapping tags.
When semantic similarity is enabled, the post editor suggests existing tags that fit the content you are writing, which helps keep the taxonomy consistent instead of growing new variants.
After significant taxonomy cleanup, create a focused commit that captures the change clearly. After significant taxonomy cleanup, create a focused commit that captures the change clearly.
@@ -363,7 +429,7 @@ Maintenance actions such as rebuilds and diff scans are repair tools for specifi
Over time, metadata stored in the database and metadata stored on disk can drift apart, especially after external edits, merges, or file operations. The Metadata Diff tool detects these inconsistencies and lets you repair them without rebuilding everything. Over time, metadata stored in the database and metadata stored on disk can drift apart, especially after external edits, merges, or file operations. The Metadata Diff tool detects these inconsistencies and lets you repair them without rebuilding everything.
The scan covers posts, media, scripts, and templates. Results are grouped by entity type, and field pills let you focus on one kind of difference at a time. The scan covers posts and their translations, media and their translated sidecars, scripts, templates, project metadata, and embedding state. Results are grouped by entity type, and field pills let you focus on one kind of difference at a time.
Use DB to File when the database is correct. Use File to DB when the filesystem is correct. Use DB to File when the database is correct. Use File to DB when the filesystem is correct.
@@ -444,21 +510,55 @@ When AI is involved, airplane mode determines which automatic actions are allowe
--- ---
## Connecting external AI agents (MCP)
RuDS can act as an MCP (Model Context Protocol) server so external AI tools such as Claude Code or GitHub Copilot can read your project and propose changes. Enable it under **Settings → MCP**, which also shows the endpoint status and offers guarded one-click configuration for supported agents.
Reads are direct: agents can browse posts, media, tags, categories, and statistics, and search your content. Writes never happen silently — every write an agent requests becomes a pending proposal that you review and accept or reject in **Settings → MCP**. Only an accepted proposal is applied, exactly once, through the same engines the editors use.
The full list of resources and tools is documented in **Help → MCP Server Documentation**.
### Key takeaways
- MCP is opt-in and configured under Settings → MCP.
- Agents read directly but can only write through proposals you approve.
- See Help → MCP Server Documentation for the complete surface.
[↑ Back to In this article](#in-this-article)
---
## Using the command line
RuDS ships a command-line interface for automation: rebuilds, rendering, publishing, Git sync, post and media creation, utility scripts, and more. Install the `bds-cli` launcher from **Settings → Data**; it runs the same engines and the same database as the desktop app, and the app picks up CLI changes automatically.
The complete command reference — including how to start the headless server and the terminal UI — is available in **Help → CLI Documentation**.
### Key takeaways
- The CLI shares engines and data with the desktop app; there is no separate state.
- Install it from Settings → Data.
- See Help → CLI Documentation for the full reference.
[↑ Back to In this article](#in-this-article)
---
## Running a headless server and the terminal UI ## Running a headless server and the terminal UI
RuDS can run without a window on a server (for example a Linux VPS) and be used from several places at once. Start it with `BDS_MODE=server`; the same release binary that runs the desktop app then runs headless. All clients connect through one SSH port (default 2222) — the web endpoint itself stays private on the server. RuDS can run without a window on a server (for example a Linux VPS) and be used from several places at once. Start it with `bds-cli server`, or launch the desktop binary with `BDS_MODE=server` — both run the same headless mode. All clients connect through one SSH port (default 2222); nothing else is exposed to the network.
Access is controlled by SSH keys, not passwords. On first start the server creates an `ssh/` folder next to its database (for example `~/Library/Application Support/bds/ssh/` on macOS) containing the host key and an empty `authorized_keys` file. Paste the public keys of every machine that may connect into `authorized_keys`, one per line — the same file format OpenSSH uses. Access is controlled by SSH keys, not passwords. On first start the server creates an `ssh/` folder next to its database (for example `~/Library/Application Support/bds/ssh/` on macOS) containing the host key and an empty `authorized_keys` file. Paste the public keys of every machine that may connect into `authorized_keys`, one per line — the same file format OpenSSH uses.
To work in a terminal, connect with plain `ssh -p 2222 user@server`: the terminal UI opens directly. You can browse posts, media, templates, scripts, and tags, create and edit posts, publish, preview images, and run the one-shot AI actions. The status line at the bottom always shows the available keys. To work in a terminal, connect with plain `ssh -p 2222 user@server`: the terminal UI opens directly. You can browse posts, media, templates, scripts, and tags, create and edit posts, publish, preview images, manage settings and Git, and run the one-shot AI actions. The status line at the bottom always shows the available keys. The same terminal UI also runs locally via `bds-cli tui` — see **Help → CLI Documentation** for the complete reference.
To work in the desktop app against a remote server, use **File → Connect to Server…** and enter `user@host` (or `user@host:port`). The app connects with the SSH key from its own local `ssh/` folder and shows the remote workspace in the window; **File → Disconnect from Server** returns to the local workspace. A plain browser works too, through a manual SSH tunnel (`ssh -p 2222 -L 4010:127.0.0.1:4010 user@server`, then open `http://127.0.0.1:4010`). To work in the desktop app against a remote server, use **File → Connect to Server…** and enter `user@host` (or `user@host:port`). The app connects with the SSH key from its own local `ssh/` folder and shows the remote workspace in the window; **File → Disconnect from Server** returns to the local workspace.
Everything you see stays synchronized: when a script, another client, or a pipeline changes content on the server, every connected terminal and window updates. The interface language is a server-side setting — changing it in any client changes it for all of them. Everything you see stays synchronized: when a script, another client, or a pipeline changes content on the server, every connected terminal and window updates. The interface language is a server-side setting — changing it in any client changes it for all of them.
### Key takeaways ### Key takeaways
- `BDS_MODE=server` runs the same app headless; only the SSH port is exposed. - `bds-cli server` (or `BDS_MODE=server`) runs the same app headless; only the SSH port is exposed.
- Access is public-key only: manage `authorized_keys` in the server's `ssh/` folder. - Access is public-key only: manage `authorized_keys` in the server's `ssh/` folder.
- `ssh` gives the terminal UI; **File → Connect to Server…** gives the desktop app; both use the same keys. - `ssh` gives the terminal UI; **File → Connect to Server…** gives the desktop app; both use the same keys.
- All connected clients stay synchronized and share one interface language. - All connected clients stay synchronized and share one interface language.

99
MCP.md Normal file
View File

@@ -0,0 +1,99 @@
# RuDS MCP Server
## In this article
- [What the MCP server is](#what-the-mcp-server-is)
- [Enabling and connecting](#enabling-and-connecting)
- [Security model](#security-model)
- [Resources](#resources)
- [Tools](#tools)
- [The proposal workflow](#the-proposal-workflow)
- [Configuring coding agents](#configuring-coding-agents)
## What the MCP server is
RuDS exposes your active project to external AI tools through the Model Context Protocol (MCP). An agent such as Claude Code or GitHub Copilot can browse posts, media, tags, categories, and statistics, run searches, and draft changes — while every write stays under your explicit control in the desktop app.
Two transports serve the same surface:
- **stdio**: the packaged `bds-mcp` executable speaks MCP over stdin/stdout. This is what coding agents launch directly.
- **HTTP**: a stateless localhost-only endpoint at `http://127.0.0.1:4124/mcp` (POST), started by the desktop app when enabled in **Settings → MCP**, and by the headless server for its loopback clients.
Both operate on the shared application database and the active project.
## Enabling and connecting
Open **Settings → MCP** in the desktop app to:
- enable or disable the HTTP endpoint and see its status and address,
- review pending write proposals (see below),
- install or remove ready-made agent configuration for supported tools.
The stdio binary needs no enablement; running it is the connection.
## Security model
- The HTTP endpoint binds to `127.0.0.1` only and validates the `Host` and `Origin` headers against localhost, so browsers cannot be tricked into calling it cross-origin. Only `POST` and `OPTIONS` are accepted.
- Reads are direct and read-only. Writes never take effect on their own: every write tool creates an inert, persisted proposal that a human must approve in the desktop app.
- Agent configuration written by RuDS never contains secrets.
## Resources
Resources use the `bds://` scheme and are read-only.
| Resource | Content |
|---|---|
| `bds://project` | Active project identity and metadata |
| `bds://posts` | Blog posts (paginated via `bds://posts{?cursor}`) |
| `bds://media` | Media items (paginated via `bds://media{?cursor}`) |
| `bds://tags` | All tags |
| `bds://categories` | All categories |
| `bds://stats` | Blog statistics |
| `bds://posts/{id}/media` | Media linked to one post |
| `bds://media/{id}/image` | The media image itself |
Post detail includes full content and metadata plus backlinks and outgoing links; published bodies are read from the canonical files.
## Tools
Read and search tools return results directly:
| Tool | Purpose |
|---|---|
| `check_term` | Check whether a term is a category, a tag, or both, with post counts |
| `search_posts` | Full-text and filtered post search with pagination, backlinks, and outgoing links |
| `count_posts` | Count filtered posts grouped by year, month, tag, category, or status |
| `read_post_by_slug` | Read full post content and metadata, optionally in a translated language |
| `get_post_translations` | List every translation for a post |
| `get_media_translations` | List every translated metadata record for a media item |
Write tools create proposals instead of writing:
| Tool | Proposes |
|---|---|
| `draft_post` | A new post (title, content, excerpt, tags, categories, author, language) |
| `propose_post_metadata` | Metadata changes to an existing post |
| `propose_media_metadata` | Title, alt text, caption, or tag changes for a media item |
| `upsert_media_translation` | Translated media metadata for one language |
| `propose_script` | A Lua script (validated before proposing) |
| `propose_template` | A Liquid template (validated before proposing) |
## The proposal workflow
1. An agent calls a write tool. RuDS validates the payload and stores it as a pending proposal; nothing else happens.
2. The proposal appears under **Settings → MCP** in the desktop app with its full payload.
3. You accept or reject it. Acceptance applies the change exactly once through the same engines the editors use — files, search indexes, embeddings, and domain events all behave like a normal edit. Rejection discards it.
4. Pending proposals expire automatically after 30 minutes. Concurrent resolution is safe: a proposal can only be applied once, and the agent can query the outcome.
This keeps agents useful for drafting and bulk suggestions while a human stays the only path to persistent change.
## Configuring coding agents
**Settings → MCP** can install a guarded configuration for:
| Agent | What is written |
|---|---|
| Claude Code | An entry in `~/.claude.json` launching the packaged `bds-mcp` stdio binary |
| GitHub Copilot | The equivalent MCP server entry in Copilot's configuration file |
Installation is opt-in per agent, shows what will be written, never stores secrets, and can be removed the same way.

View File

@@ -13,7 +13,7 @@ The project is under active development. Core blogging workflows are broadly ava
- Template and Lua script management with explicit syntax-check feedback, using a custom Ropey/Syntect/Cosmic Text editor and the documented, bDS2-signature-compatible project-scoped [`bds` host API](docs/scripting/API_REFERENCE.md) across utilities, rendered macros, and Blogmark transforms. - Template and Lua script management with explicit syntax-check feedback, using a custom Ropey/Syntect/Cosmic Text editor and the documented, bDS2-signature-compatible project-scoped [`bds` host API](docs/scripting/API_REFERENCE.md) across utilities, rendered macros, and Blogmark transforms.
- SQLite and filesystem persistence with frontmatter, sidecars, rebuild, metadata diff/repair, and FTS5 search. - SQLite and filesystem persistence with frontmatter, sidecars, rebuild, metadata diff/repair, and FTS5 search.
- Optional on-device multilingual semantic search and tag suggestions backed by a persistent USearch index, with duplicate-post review and dismissal in the desktop workspace. - Optional on-device multilingual semantic search and tag suggestions backed by a persistent USearch index, with duplicate-post review and dismissal in the desktop workspace.
- Read-only in-app browsers for the bundled global `DOCUMENTATION.md` and the generated Lua API reference, public types, and runnable examples, with safe GFM rendering and confirmed external links. - Read-only in-app browsers in the Help menu for the bundled global `DOCUMENTATION.md`, the generated Lua API reference with public types and runnable examples, the [CLI/server/TUI documentation](CLI.md), and the [MCP server documentation](MCP.md), with safe GFM rendering and confirmed external links.
- A localized OPML menu editor manages pages, submenus, and category archives with protected Home ordering, keyboard-accessible tree controls, drag-and-drop, and bDS2-compatible persistence. - A localized OPML menu editor manages pages, submenus, and category archives with protected Home ordering, keyboard-accessible tree controls, drag-and-drop, and bDS2-compatible persistence.
- Project-scoped typed domain events synchronize desktop views with shared-engine and future CLI mutations; persisted CLI notifications are consumed once, and the selected UI language is shared through settings. - Project-scoped typed domain events synchronize desktop views with shared-engine and future CLI mutations; persisted CLI notifications are consumed once, and the selected UI language is shared through settings.
- Headless `bds-cli` automation for rebuild/repair/render, publishing and Git sync, post/media/gallery creation, effective shared settings with secret-presence redaction, projects, utility Lua tasks, JSON I/O, airplane-mode AI routing, and guarded launcher installation from Settings → Data or `bds-cli install`. - Headless `bds-cli` automation for rebuild/repair/render, publishing and Git sync, post/media/gallery creation, effective shared settings with secret-presence redaction, projects, utility Lua tasks, JSON I/O, airplane-mode AI routing, and guarded launcher installation from Settings → Data or `bds-cli install`.
@@ -51,6 +51,9 @@ Local macOS packages are ad-hoc signed without hardened runtime. A Developer ID
## References ## References
- [Specification index](SPECIFICATION_INDEX.md) - [Specification index](SPECIFICATION_INDEX.md)
- [User guide](DOCUMENTATION.md)
- [CLI, headless server, and terminal UI](CLI.md)
- [MCP server](MCP.md)
- [UI style guide](docs/UI_STYLE_GUIDE.md) - [UI style guide](docs/UI_STYLE_GUIDE.md)
- `../bDS2` — reference implementation when an Allium contract is ambiguous - `../bDS2` — reference implementation when an Allium contract is ambiguous

View File

@@ -969,6 +969,8 @@ pub struct BdsApp {
duplicates_state: DuplicatesState, duplicates_state: DuplicatesState,
guide_documentation: DocumentationState, guide_documentation: DocumentationState,
api_documentation: DocumentationState, api_documentation: DocumentationState,
cli_documentation: DocumentationState,
mcp_documentation: DocumentationState,
metadata_diff_state: MetadataDiffState, metadata_diff_state: MetadataDiffState,
menu_editor_state: MenuEditorState, menu_editor_state: MenuEditorState,
translation_validation_state: crate::views::translation_validation::TranslationValidationState, translation_validation_state: crate::views::translation_validation::TranslationValidationState,
@@ -1144,6 +1146,8 @@ impl BdsApp {
duplicates_state: DuplicatesState::default(), duplicates_state: DuplicatesState::default(),
guide_documentation: DocumentationState::new(DocumentationKind::Guide), guide_documentation: DocumentationState::new(DocumentationKind::Guide),
api_documentation: DocumentationState::new(DocumentationKind::Api), api_documentation: DocumentationState::new(DocumentationKind::Api),
cli_documentation: DocumentationState::new(DocumentationKind::Cli),
mcp_documentation: DocumentationState::new(DocumentationKind::Mcp),
metadata_diff_state: MetadataDiffState::default(), metadata_diff_state: MetadataDiffState::default(),
menu_editor_state: MenuEditorState::default(), menu_editor_state: MenuEditorState::default(),
translation_validation_state: Default::default(), translation_validation_state: Default::default(),
@@ -1232,6 +1236,8 @@ impl BdsApp {
duplicates_state: DuplicatesState::default(), duplicates_state: DuplicatesState::default(),
guide_documentation: DocumentationState::new(DocumentationKind::Guide), guide_documentation: DocumentationState::new(DocumentationKind::Guide),
api_documentation: DocumentationState::new(DocumentationKind::Api), api_documentation: DocumentationState::new(DocumentationKind::Api),
cli_documentation: DocumentationState::new(DocumentationKind::Cli),
mcp_documentation: DocumentationState::new(DocumentationKind::Mcp),
metadata_diff_state: MetadataDiffState::default(), metadata_diff_state: MetadataDiffState::default(),
menu_editor_state: MenuEditorState::default(), menu_editor_state: MenuEditorState::default(),
translation_validation_state: Default::default(), translation_validation_state: Default::default(),
@@ -3127,6 +3133,8 @@ impl BdsApp {
match kind { match kind {
DocumentationKind::Guide => &self.guide_documentation, DocumentationKind::Guide => &self.guide_documentation,
DocumentationKind::Api => &self.api_documentation, DocumentationKind::Api => &self.api_documentation,
DocumentationKind::Cli => &self.cli_documentation,
DocumentationKind::Mcp => &self.mcp_documentation,
} }
} }
@@ -3134,6 +3142,8 @@ impl BdsApp {
match kind { match kind {
DocumentationKind::Guide => &mut self.guide_documentation, DocumentationKind::Guide => &mut self.guide_documentation,
DocumentationKind::Api => &mut self.api_documentation, DocumentationKind::Api => &mut self.api_documentation,
DocumentationKind::Cli => &mut self.cli_documentation,
DocumentationKind::Mcp => &mut self.mcp_documentation,
} }
} }
@@ -3144,6 +3154,8 @@ impl BdsApp {
tokio::task::spawn_blocking(move || match kind { tokio::task::spawn_blocking(move || match kind {
DocumentationKind::Guide => crate::views::documentation::load_user_guide(), DocumentationKind::Guide => crate::views::documentation::load_user_guide(),
DocumentationKind::Api => crate::views::documentation::load_api_document(), DocumentationKind::Api => crate::views::documentation::load_api_document(),
DocumentationKind::Cli => crate::views::documentation::load_cli_guide(),
DocumentationKind::Mcp => crate::views::documentation::load_mcp_guide(),
}) })
.await .await
.unwrap_or_else(|error| DocumentLoad::Malformed { .unwrap_or_else(|error| DocumentLoad::Malformed {
@@ -3160,6 +3172,8 @@ impl BdsApp {
for (tab_type, kind) in [ for (tab_type, kind) in [
(TabType::Documentation, DocumentationKind::Guide), (TabType::Documentation, DocumentationKind::Guide),
(TabType::ApiDocumentation, DocumentationKind::Api), (TabType::ApiDocumentation, DocumentationKind::Api),
(TabType::CliDocumentation, DocumentationKind::Cli),
(TabType::McpDocumentation, DocumentationKind::Mcp),
] { ] {
if !self.tabs.iter().any(|tab| tab.tab_type == tab_type) { if !self.tabs.iter().any(|tab| tab.tab_type == tab_type) {
continue; continue;
@@ -3413,6 +3427,8 @@ impl BdsApp {
&self.duplicates_state, &self.duplicates_state,
&self.guide_documentation, &self.guide_documentation,
&self.api_documentation, &self.api_documentation,
&self.cli_documentation,
&self.mcp_documentation,
&self.metadata_diff_state, &self.metadata_diff_state,
&self.menu_editor_state, &self.menu_editor_state,
&self.translation_validation_state, &self.translation_validation_state,
@@ -4349,6 +4365,14 @@ impl BdsApp {
self.open_singleton_tab(TabType::ApiDocumentation, "tabBar.apiDocumentation"); self.open_singleton_tab(TabType::ApiDocumentation, "tabBar.apiDocumentation");
self.start_documentation_load(DocumentationKind::Api) self.start_documentation_load(DocumentationKind::Api)
} }
MenuAction::OpenCliDocumentation => {
self.open_singleton_tab(TabType::CliDocumentation, "tabBar.cliDocumentation");
self.start_documentation_load(DocumentationKind::Cli)
}
MenuAction::OpenMcpDocumentation => {
self.open_singleton_tab(TabType::McpDocumentation, "tabBar.mcpDocumentation");
self.start_documentation_load(DocumentationKind::Mcp)
}
MenuAction::ViewOnGitHub => { MenuAction::ViewOnGitHub => {
let _ = open::that("https://github.com/nickarumern/bds"); let _ = open::that("https://github.com/nickarumern/bds");
Task::none() Task::none()
@@ -9164,6 +9188,34 @@ mod tests {
); );
} }
#[test]
fn help_menu_opens_cli_and_mcp_documentation_tabs() {
let (db, project, temp) = setup();
let mut app = BdsApp::new_for_tests(db, project, temp.path().to_path_buf());
let _ = app.dispatch_menu_action(MenuAction::OpenCliDocumentation);
assert!(
app.tabs
.iter()
.any(|tab| tab.tab_type == TabType::CliDocumentation)
);
assert_eq!(
app.cli_documentation.status,
crate::views::documentation::DocumentStatus::Loading
);
let _ = app.dispatch_menu_action(MenuAction::OpenMcpDocumentation);
assert!(
app.tabs
.iter()
.any(|tab| tab.tab_type == TabType::McpDocumentation)
);
assert_eq!(
app.mcp_documentation.status,
crate::views::documentation::DocumentStatus::Loading
);
}
#[test] #[test]
fn project_switch_keeps_global_documentation_loaded() { fn project_switch_keeps_global_documentation_loaded() {
let (db, project, temp) = setup(); let (db, project, temp) = setup();

View File

@@ -57,6 +57,8 @@ pub enum MenuAction {
About, About,
OpenDocumentation, OpenDocumentation,
OpenApiDocumentation, OpenApiDocumentation,
OpenCliDocumentation,
OpenMcpDocumentation,
ViewOnGitHub, ViewOnGitHub,
ReportIssue, ReportIssue,
} }
@@ -101,6 +103,8 @@ impl MenuAction {
MenuAction::About, MenuAction::About,
MenuAction::OpenDocumentation, MenuAction::OpenDocumentation,
MenuAction::OpenApiDocumentation, MenuAction::OpenApiDocumentation,
MenuAction::OpenCliDocumentation,
MenuAction::OpenMcpDocumentation,
MenuAction::ViewOnGitHub, MenuAction::ViewOnGitHub,
MenuAction::ReportIssue, MenuAction::ReportIssue,
]; ];
@@ -190,6 +194,8 @@ impl MenuAction {
Self::About => "menu.item.about", Self::About => "menu.item.about",
Self::OpenDocumentation => "menu.item.openDocumentation", Self::OpenDocumentation => "menu.item.openDocumentation",
Self::OpenApiDocumentation => "menu.item.openApiDocumentation", Self::OpenApiDocumentation => "menu.item.openApiDocumentation",
Self::OpenCliDocumentation => "menu.item.openCliDocumentation",
Self::OpenMcpDocumentation => "menu.item.openMcpDocumentation",
Self::ViewOnGitHub => "menu.item.viewOnGitHub", Self::ViewOnGitHub => "menu.item.viewOnGitHub",
Self::ReportIssue => "menu.item.reportIssue", Self::ReportIssue => "menu.item.reportIssue",
} }
@@ -562,6 +568,18 @@ pub fn build_menu_bar(locale: UiLocale) -> (Menu, MenuRegistry) {
locale, locale,
None, None,
)); ));
let _ = help_menu.append(&item(
&mut reg,
MenuAction::OpenCliDocumentation,
locale,
None,
));
let _ = help_menu.append(&item(
&mut reg,
MenuAction::OpenMcpDocumentation,
locale,
None,
));
let _ = help_menu.append(&item(&mut reg, MenuAction::ViewOnGitHub, locale, None)); let _ = help_menu.append(&item(&mut reg, MenuAction::ViewOnGitHub, locale, None));
let _ = help_menu.append(&item(&mut reg, MenuAction::ReportIssue, locale, None)); let _ = help_menu.append(&item(&mut reg, MenuAction::ReportIssue, locale, None));

View File

@@ -17,6 +17,8 @@ pub enum TabType {
Templates, Templates,
Documentation, Documentation,
ApiDocumentation, ApiDocumentation,
CliDocumentation,
McpDocumentation,
SiteValidation, SiteValidation,
TranslationValidation, TranslationValidation,
FindDuplicates, FindDuplicates,
@@ -25,9 +27,9 @@ pub enum TabType {
impl TabType { impl TabType {
/// Singleton tool tabs per tabs.allium: always one instance, id = type name. /// Singleton tool tabs per tabs.allium: always one instance, id = type name.
/// ///
/// Singleton types (10): settings, tags, style, menu_editor, /// Singleton types (12): settings, tags, style, menu_editor,
/// documentation, api_documentation, metadata_diff, site_validation, /// documentation, api_documentation, cli_documentation, mcp_documentation,
/// translation_validation, find_duplicates. /// metadata_diff, site_validation, translation_validation, find_duplicates.
/// ///
/// Entity types (keyed by external ID): post, media, scripts (keyed), /// Entity types (keyed by external ID): post, media, scripts (keyed),
/// templates (keyed), chat, import, git_diff. /// templates (keyed), chat, import, git_diff.
@@ -41,6 +43,8 @@ impl TabType {
| Self::MetadataDiff | Self::MetadataDiff
| Self::Documentation | Self::Documentation
| Self::ApiDocumentation | Self::ApiDocumentation
| Self::CliDocumentation
| Self::McpDocumentation
| Self::SiteValidation | Self::SiteValidation
| Self::TranslationValidation | Self::TranslationValidation
| Self::FindDuplicates | Self::FindDuplicates
@@ -57,6 +61,8 @@ impl TabType {
Self::MetadataDiff => "metadata_diff", Self::MetadataDiff => "metadata_diff",
Self::Documentation => "documentation", Self::Documentation => "documentation",
Self::ApiDocumentation => "api_documentation", Self::ApiDocumentation => "api_documentation",
Self::CliDocumentation => "cli_documentation",
Self::McpDocumentation => "mcp_documentation",
Self::SiteValidation => "site_validation", Self::SiteValidation => "site_validation",
Self::TranslationValidation => "translation_validation", Self::TranslationValidation => "translation_validation",
Self::FindDuplicates => "find_duplicates", Self::FindDuplicates => "find_duplicates",
@@ -76,6 +82,8 @@ impl TabType {
Self::MetadataDiff => Some("tabBar.metadataDiff"), Self::MetadataDiff => Some("tabBar.metadataDiff"),
Self::Documentation => Some("tabBar.documentation"), Self::Documentation => Some("tabBar.documentation"),
Self::ApiDocumentation => Some("tabBar.apiDocumentation"), Self::ApiDocumentation => Some("tabBar.apiDocumentation"),
Self::CliDocumentation => Some("tabBar.cliDocumentation"),
Self::McpDocumentation => Some("tabBar.mcpDocumentation"),
Self::SiteValidation => Some("tabBar.siteValidation"), Self::SiteValidation => Some("tabBar.siteValidation"),
Self::TranslationValidation => Some("tabBar.translationValidation"), Self::TranslationValidation => Some("tabBar.translationValidation"),
Self::FindDuplicates => Some("tabBar.findDuplicates"), Self::FindDuplicates => Some("tabBar.findDuplicates"),

View File

@@ -15,6 +15,8 @@ use crate::i18n::t;
const API_REFERENCE: &str = include_str!("../../../../docs/scripting/API_REFERENCE.md"); const API_REFERENCE: &str = include_str!("../../../../docs/scripting/API_REFERENCE.md");
const API_TYPES: &str = include_str!("../../../../docs/scripting/TYPES.md"); const API_TYPES: &str = include_str!("../../../../docs/scripting/TYPES.md");
const USER_GUIDE: &str = include_str!("../../../../DOCUMENTATION.md"); const USER_GUIDE: &str = include_str!("../../../../DOCUMENTATION.md");
const CLI_GUIDE: &str = include_str!("../../../../CLI.md");
const MCP_GUIDE: &str = include_str!("../../../../MCP.md");
const UTILITY_EXAMPLE: &str = include_str!("../../../../docs/scripting/examples/utility.lua"); const UTILITY_EXAMPLE: &str = include_str!("../../../../docs/scripting/examples/utility.lua");
const MACRO_EXAMPLE: &str = include_str!("../../../../docs/scripting/examples/macro.lua"); const MACRO_EXAMPLE: &str = include_str!("../../../../docs/scripting/examples/macro.lua");
const TRANSFORM_EXAMPLE: &str = include_str!("../../../../docs/scripting/examples/transform.lua"); const TRANSFORM_EXAMPLE: &str = include_str!("../../../../docs/scripting/examples/transform.lua");
@@ -24,6 +26,8 @@ pub const API_DOCUMENTATION_URL: &str = "https://ruds.invalid/api-documentation"
pub enum DocumentationKind { pub enum DocumentationKind {
Guide, Guide,
Api, Api,
Cli,
Mcp,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -136,6 +140,8 @@ pub fn scroll_id(kind: DocumentationKind) -> scrollable::Id {
scrollable::Id::new(match kind { scrollable::Id::new(match kind {
DocumentationKind::Guide => "user-documentation", DocumentationKind::Guide => "user-documentation",
DocumentationKind::Api => "api-documentation", DocumentationKind::Api => "api-documentation",
DocumentationKind::Cli => "cli-documentation",
DocumentationKind::Mcp => "mcp-documentation",
}) })
} }
@@ -143,10 +149,14 @@ pub fn view(state: &DocumentationState, locale: UiLocale) -> Element<'_, Message
let title_key = match state.kind { let title_key = match state.kind {
DocumentationKind::Guide => "documentation.title", DocumentationKind::Guide => "documentation.title",
DocumentationKind::Api => "documentation.apiTitle", DocumentationKind::Api => "documentation.apiTitle",
DocumentationKind::Cli => "documentation.cliTitle",
DocumentationKind::Mcp => "documentation.mcpTitle",
}; };
let subtitle_key = match state.kind { let subtitle_key = match state.kind {
DocumentationKind::Guide => "documentation.subtitle", DocumentationKind::Guide => "documentation.subtitle",
DocumentationKind::Api => "documentation.apiSubtitle", DocumentationKind::Api => "documentation.apiSubtitle",
DocumentationKind::Cli => "documentation.cliSubtitle",
DocumentationKind::Mcp => "documentation.mcpSubtitle",
}; };
let toolbar = inputs::toolbar( let toolbar = inputs::toolbar(
vec![ vec![
@@ -244,10 +254,21 @@ fn table_row<'a>(values: &'a [String], header: bool) -> Element<'a, Message> {
} }
pub fn load_user_guide() -> DocumentLoad { pub fn load_user_guide() -> DocumentLoad {
let path = user_guide_path(); load_embedded_document(&user_guide_path(), USER_GUIDE)
match load_document_file(&path) { }
pub fn load_cli_guide() -> DocumentLoad {
load_embedded_document(&root_document_path("CLI.md"), CLI_GUIDE)
}
pub fn load_mcp_guide() -> DocumentLoad {
load_embedded_document(&root_document_path("MCP.md"), MCP_GUIDE)
}
fn load_embedded_document(path: &Path, embedded: &str) -> DocumentLoad {
match load_document_file(path) {
DocumentLoad::Missing { signature } => DocumentLoad::Ready { DocumentLoad::Missing { signature } => DocumentLoad::Ready {
source: USER_GUIDE.to_string(), source: embedded.to_string(),
signature, signature,
}, },
load => load, load => load,
@@ -308,6 +329,8 @@ pub fn load_api_document() -> DocumentLoad {
pub fn current_signature(kind: DocumentationKind) -> u64 { pub fn current_signature(kind: DocumentationKind) -> u64 {
match kind { match kind {
DocumentationKind::Guide => file_signature(&user_guide_path()), DocumentationKind::Guide => file_signature(&user_guide_path()),
DocumentationKind::Cli => file_signature(&root_document_path("CLI.md")),
DocumentationKind::Mcp => file_signature(&root_document_path("MCP.md")),
DocumentationKind::Api => { DocumentationKind::Api => {
let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../docs/scripting"); let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../docs/scripting");
paths_signature( paths_signature(
@@ -325,7 +348,11 @@ pub fn current_signature(kind: DocumentationKind) -> u64 {
} }
fn user_guide_path() -> PathBuf { fn user_guide_path() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("../../DOCUMENTATION.md") root_document_path("DOCUMENTATION.md")
}
fn root_document_path(name: &str) -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("../..").join(name)
} }
pub fn parse_document(source: &str) -> ParsedDocument { pub fn parse_document(source: &str) -> ParsedDocument {

View File

@@ -134,6 +134,8 @@ pub fn view<'a>(
duplicates_state: &'a DuplicatesState, duplicates_state: &'a DuplicatesState,
guide_documentation: &'a DocumentationState, guide_documentation: &'a DocumentationState,
api_documentation: &'a DocumentationState, api_documentation: &'a DocumentationState,
cli_documentation: &'a DocumentationState,
mcp_documentation: &'a DocumentationState,
metadata_diff_state: &'a MetadataDiffState, metadata_diff_state: &'a MetadataDiffState,
menu_editor_state: &'a MenuEditorState, menu_editor_state: &'a MenuEditorState,
translation_validation_state: &'a TranslationValidationState, translation_validation_state: &'a TranslationValidationState,
@@ -168,6 +170,8 @@ pub fn view<'a>(
duplicates_state, duplicates_state,
guide_documentation, guide_documentation,
api_documentation, api_documentation,
cli_documentation,
mcp_documentation,
metadata_diff_state, metadata_diff_state,
menu_editor_state, menu_editor_state,
translation_validation_state, translation_validation_state,
@@ -414,6 +418,8 @@ fn route_content_area<'a>(
duplicates_state: &'a DuplicatesState, duplicates_state: &'a DuplicatesState,
guide_documentation: &'a DocumentationState, guide_documentation: &'a DocumentationState,
api_documentation: &'a DocumentationState, api_documentation: &'a DocumentationState,
cli_documentation: &'a DocumentationState,
mcp_documentation: &'a DocumentationState,
metadata_diff_state: &'a MetadataDiffState, metadata_diff_state: &'a MetadataDiffState,
menu_editor_state: &'a MenuEditorState, menu_editor_state: &'a MenuEditorState,
translation_validation_state: &'a TranslationValidationState, translation_validation_state: &'a TranslationValidationState,
@@ -507,6 +513,8 @@ fn route_content_area<'a>(
ContentRoute::FindDuplicates => duplicates::view(duplicates_state, locale), ContentRoute::FindDuplicates => duplicates::view(duplicates_state, locale),
ContentRoute::Documentation => documentation::view(guide_documentation, locale), ContentRoute::Documentation => documentation::view(guide_documentation, locale),
ContentRoute::ApiDocumentation => documentation::view(api_documentation, locale), ContentRoute::ApiDocumentation => documentation::view(api_documentation, locale),
ContentRoute::CliDocumentation => documentation::view(cli_documentation, locale),
ContentRoute::McpDocumentation => documentation::view(mcp_documentation, locale),
ContentRoute::MetadataDiff => metadata_diff::view(metadata_diff_state, locale), ContentRoute::MetadataDiff => metadata_diff::view(metadata_diff_state, locale),
ContentRoute::MenuEditor => menu_editor::view(menu_editor_state, locale), ContentRoute::MenuEditor => menu_editor::view(menu_editor_state, locale),
ContentRoute::TranslationValidation => { ContentRoute::TranslationValidation => {
@@ -546,6 +554,8 @@ enum ContentRoute<'a> {
FindDuplicates, FindDuplicates,
Documentation, Documentation,
ApiDocumentation, ApiDocumentation,
CliDocumentation,
McpDocumentation,
MetadataDiff, MetadataDiff,
MenuEditor, MenuEditor,
TranslationValidation, TranslationValidation,
@@ -638,6 +648,8 @@ fn route_kind<'a>(
TabType::FindDuplicates => ContentRoute::FindDuplicates, TabType::FindDuplicates => ContentRoute::FindDuplicates,
TabType::Documentation => ContentRoute::Documentation, TabType::Documentation => ContentRoute::Documentation,
TabType::ApiDocumentation => ContentRoute::ApiDocumentation, TabType::ApiDocumentation => ContentRoute::ApiDocumentation,
TabType::CliDocumentation => ContentRoute::CliDocumentation,
TabType::McpDocumentation => ContentRoute::McpDocumentation,
TabType::MenuEditor => ContentRoute::MenuEditor, TabType::MenuEditor => ContentRoute::MenuEditor,
TabType::Style => ContentRoute::Placeholder(&tab.title), TabType::Style => ContentRoute::Placeholder(&tab.title),
TabType::TranslationValidation => ContentRoute::TranslationValidation, TabType::TranslationValidation => ContentRoute::TranslationValidation,

View File

@@ -46,6 +46,10 @@ documentation-title = Dokumentation
documentation-apiTitle = Lua-API-Dokumentation documentation-apiTitle = Lua-API-Dokumentation
documentation-subtitle = Schreibgeschütztes, mitgeliefertes RuDS-Benutzerhandbuch. documentation-subtitle = Schreibgeschütztes, mitgeliefertes RuDS-Benutzerhandbuch.
documentation-apiSubtitle = Generierte Lua-Referenz, öffentliche Typen und ausführbare Beispiele. documentation-apiSubtitle = Generierte Lua-Referenz, öffentliche Typen und ausführbare Beispiele.
documentation-cliTitle = CLI-Dokumentation
documentation-cliSubtitle = Referenz für Kommandozeile, Headless-Server und Terminal-UI.
documentation-mcpTitle = MCP-Server-Dokumentation
documentation-mcpSubtitle = Ressourcen und Werkzeuge, die RuDS externen KI-Agenten bereitstellt.
documentation-loading = Dokumentation wird geladen… documentation-loading = Dokumentation wird geladen…
documentation-missing = Das RuDS-Benutzerhandbuch ist nicht verfügbar. documentation-missing = Das RuDS-Benutzerhandbuch ist nicht verfügbar.
documentation-malformed = Die Dokumentationsquelle konnte nicht als UTF-8-Text gelesen werden. documentation-malformed = Die Dokumentationsquelle konnte nicht als UTF-8-Text gelesen werden.
@@ -69,6 +73,8 @@ menu-item-uploadSite = Website hochladen
menu-item-about = Über Blogging Desktop Server menu-item-about = Über Blogging Desktop Server
menu-item-openDocumentation = Dokumentation öffnen menu-item-openDocumentation = Dokumentation öffnen
menu-item-openApiDocumentation = Lua-API-Dokumentation öffnen menu-item-openApiDocumentation = Lua-API-Dokumentation öffnen
menu-item-openCliDocumentation = CLI-Dokumentation öffnen
menu-item-openMcpDocumentation = MCP-Server-Dokumentation öffnen
menu-item-viewOnGitHub = Auf GitHub ansehen menu-item-viewOnGitHub = Auf GitHub ansehen
menu-item-reportIssue = Problem melden menu-item-reportIssue = Problem melden
activity-posts = Beiträge activity-posts = Beiträge
@@ -235,6 +241,8 @@ siteValidation-extra = Zusätzliche Dateien
siteValidation-stale = Veraltete Dateien siteValidation-stale = Veraltete Dateien
tabBar-documentation = Dokumentation tabBar-documentation = Dokumentation
tabBar-apiDocumentation = API-Dokumentation tabBar-apiDocumentation = API-Dokumentation
tabBar-cliDocumentation = CLI-Dokumentation
tabBar-mcpDocumentation = MCP-Dokumentation
tabBar-findDuplicates = Duplikate finden tabBar-findDuplicates = Duplikate finden
tabBar-tags = Tags tabBar-tags = Tags
tabBar-preview = Vorschau tabBar-preview = Vorschau

View File

@@ -46,6 +46,10 @@ documentation-title = Documentation
documentation-apiTitle = Lua API Documentation documentation-apiTitle = Lua API Documentation
documentation-subtitle = Read-only bundled RuDS user guide. documentation-subtitle = Read-only bundled RuDS user guide.
documentation-apiSubtitle = Generated Lua reference, public types, and runnable examples. documentation-apiSubtitle = Generated Lua reference, public types, and runnable examples.
documentation-cliTitle = CLI Documentation
documentation-cliSubtitle = Command line, headless server, and terminal UI reference.
documentation-mcpTitle = MCP Server Documentation
documentation-mcpSubtitle = Resources and tools RuDS provides to external AI agents.
documentation-loading = Loading documentation… documentation-loading = Loading documentation…
documentation-missing = The RuDS user guide is unavailable. documentation-missing = The RuDS user guide is unavailable.
documentation-malformed = The documentation source could not be read as UTF-8 text. documentation-malformed = The documentation source could not be read as UTF-8 text.
@@ -69,6 +73,8 @@ menu-item-uploadSite = Upload Site
menu-item-about = About Blogging Desktop Server menu-item-about = About Blogging Desktop Server
menu-item-openDocumentation = Open Documentation menu-item-openDocumentation = Open Documentation
menu-item-openApiDocumentation = Open Lua API Documentation menu-item-openApiDocumentation = Open Lua API Documentation
menu-item-openCliDocumentation = Open CLI Documentation
menu-item-openMcpDocumentation = Open MCP Server Documentation
menu-item-viewOnGitHub = View on GitHub menu-item-viewOnGitHub = View on GitHub
menu-item-reportIssue = Report Issue menu-item-reportIssue = Report Issue
activity-posts = Posts activity-posts = Posts
@@ -235,6 +241,8 @@ siteValidation-extra = Extra Files
siteValidation-stale = Stale Files siteValidation-stale = Stale Files
tabBar-documentation = Documentation tabBar-documentation = Documentation
tabBar-apiDocumentation = API Documentation tabBar-apiDocumentation = API Documentation
tabBar-cliDocumentation = CLI Documentation
tabBar-mcpDocumentation = MCP Documentation
tabBar-findDuplicates = Find Duplicates tabBar-findDuplicates = Find Duplicates
tabBar-tags = Tags tabBar-tags = Tags
tabBar-preview = Preview tabBar-preview = Preview

View File

@@ -46,6 +46,10 @@ documentation-title = Documentación
documentation-apiTitle = Documentación de la API de Lua documentation-apiTitle = Documentación de la API de Lua
documentation-subtitle = Guía del usuario de RuDS incluida y de solo lectura. documentation-subtitle = Guía del usuario de RuDS incluida y de solo lectura.
documentation-apiSubtitle = Referencia de Lua generada, tipos públicos y ejemplos ejecutables. documentation-apiSubtitle = Referencia de Lua generada, tipos públicos y ejemplos ejecutables.
documentation-cliTitle = Documentación de la CLI
documentation-cliSubtitle = Referencia de la línea de comandos, el servidor sin interfaz y la interfaz de terminal.
documentation-mcpTitle = Documentación del servidor MCP
documentation-mcpSubtitle = Recursos y herramientas que RuDS ofrece a agentes de IA externos.
documentation-loading = Cargando documentación… documentation-loading = Cargando documentación…
documentation-missing = La guía del usuario de RuDS no está disponible. documentation-missing = La guía del usuario de RuDS no está disponible.
documentation-malformed = No se pudo leer la fuente de documentación como texto UTF-8. documentation-malformed = No se pudo leer la fuente de documentación como texto UTF-8.
@@ -69,6 +73,8 @@ menu-item-uploadSite = Subir sitio
menu-item-about = Acerca de Blogging Desktop Server menu-item-about = Acerca de Blogging Desktop Server
menu-item-openDocumentation = Abrir documentación menu-item-openDocumentation = Abrir documentación
menu-item-openApiDocumentation = Abrir documentación de la API de Lua menu-item-openApiDocumentation = Abrir documentación de la API de Lua
menu-item-openCliDocumentation = Abrir documentación de la CLI
menu-item-openMcpDocumentation = Abrir documentación del servidor MCP
menu-item-viewOnGitHub = Ver en GitHub menu-item-viewOnGitHub = Ver en GitHub
menu-item-reportIssue = Reportar problema menu-item-reportIssue = Reportar problema
activity-posts = Entradas activity-posts = Entradas
@@ -235,6 +241,8 @@ siteValidation-extra = Archivos adicionales
siteValidation-stale = Archivos desactualizados siteValidation-stale = Archivos desactualizados
tabBar-documentation = Documentación tabBar-documentation = Documentación
tabBar-apiDocumentation = Documentación API tabBar-apiDocumentation = Documentación API
tabBar-cliDocumentation = Documentación CLI
tabBar-mcpDocumentation = Documentación MCP
tabBar-findDuplicates = Buscar duplicados tabBar-findDuplicates = Buscar duplicados
tabBar-tags = Etiquetas tabBar-tags = Etiquetas
tabBar-preview = Vista previa tabBar-preview = Vista previa

View File

@@ -46,6 +46,10 @@ documentation-title = Documentation
documentation-apiTitle = Documentation de lAPI Lua documentation-apiTitle = Documentation de lAPI Lua
documentation-subtitle = Guide utilisateur RuDS intégré en lecture seule. documentation-subtitle = Guide utilisateur RuDS intégré en lecture seule.
documentation-apiSubtitle = Référence Lua générée, types publics et exemples exécutables. documentation-apiSubtitle = Référence Lua générée, types publics et exemples exécutables.
documentation-cliTitle = Documentation de la CLI
documentation-cliSubtitle = Référence de la ligne de commande, du serveur sans interface et de linterface terminal.
documentation-mcpTitle = Documentation du serveur MCP
documentation-mcpSubtitle = Ressources et outils que RuDS fournit aux agents IA externes.
documentation-loading = Chargement de la documentation… documentation-loading = Chargement de la documentation…
documentation-missing = Le guide utilisateur RuDS nest pas disponible. documentation-missing = Le guide utilisateur RuDS nest pas disponible.
documentation-malformed = La source de documentation na pas pu être lue comme texte UTF-8. documentation-malformed = La source de documentation na pas pu être lue comme texte UTF-8.
@@ -69,6 +73,8 @@ menu-item-uploadSite = Publier le site
menu-item-about = À propos de Blogging Desktop Server menu-item-about = À propos de Blogging Desktop Server
menu-item-openDocumentation = Ouvrir la documentation menu-item-openDocumentation = Ouvrir la documentation
menu-item-openApiDocumentation = Ouvrir la documentation de lAPI Lua menu-item-openApiDocumentation = Ouvrir la documentation de lAPI Lua
menu-item-openCliDocumentation = Ouvrir la documentation de la CLI
menu-item-openMcpDocumentation = Ouvrir la documentation du serveur MCP
menu-item-viewOnGitHub = Voir sur GitHub menu-item-viewOnGitHub = Voir sur GitHub
menu-item-reportIssue = Signaler un problème menu-item-reportIssue = Signaler un problème
activity-posts = Articles activity-posts = Articles
@@ -235,6 +241,8 @@ siteValidation-extra = Fichiers supplémentaires
siteValidation-stale = Fichiers obsolètes siteValidation-stale = Fichiers obsolètes
tabBar-documentation = Documentation tabBar-documentation = Documentation
tabBar-apiDocumentation = Documentation API tabBar-apiDocumentation = Documentation API
tabBar-cliDocumentation = Documentation CLI
tabBar-mcpDocumentation = Documentation MCP
tabBar-findDuplicates = Trouver les doublons tabBar-findDuplicates = Trouver les doublons
tabBar-tags = Tags tabBar-tags = Tags
tabBar-preview = Aperçu tabBar-preview = Aperçu

View File

@@ -46,6 +46,10 @@ documentation-title = Documentazione
documentation-apiTitle = Documentazione API Lua documentation-apiTitle = Documentazione API Lua
documentation-subtitle = Guida utente RuDS inclusa e in sola lettura. documentation-subtitle = Guida utente RuDS inclusa e in sola lettura.
documentation-apiSubtitle = Riferimento Lua generato, tipi pubblici ed esempi eseguibili. documentation-apiSubtitle = Riferimento Lua generato, tipi pubblici ed esempi eseguibili.
documentation-cliTitle = Documentazione CLI
documentation-cliSubtitle = Riferimento per riga di comando, server headless e interfaccia terminale.
documentation-mcpTitle = Documentazione del server MCP
documentation-mcpSubtitle = Risorse e strumenti che RuDS offre agli agenti IA esterni.
documentation-loading = Caricamento della documentazione… documentation-loading = Caricamento della documentazione…
documentation-missing = La guida utente RuDS non è disponibile. documentation-missing = La guida utente RuDS non è disponibile.
documentation-malformed = Non è stato possibile leggere la documentazione come testo UTF-8. documentation-malformed = Non è stato possibile leggere la documentazione come testo UTF-8.
@@ -69,6 +73,8 @@ menu-item-uploadSite = Carica sito
menu-item-about = Informazioni su Blogging Desktop Server menu-item-about = Informazioni su Blogging Desktop Server
menu-item-openDocumentation = Apri documentazione menu-item-openDocumentation = Apri documentazione
menu-item-openApiDocumentation = Apri documentazione API Lua menu-item-openApiDocumentation = Apri documentazione API Lua
menu-item-openCliDocumentation = Apri documentazione CLI
menu-item-openMcpDocumentation = Apri documentazione del server MCP
menu-item-viewOnGitHub = Visualizza su GitHub menu-item-viewOnGitHub = Visualizza su GitHub
menu-item-reportIssue = Segnala problema menu-item-reportIssue = Segnala problema
activity-posts = Post activity-posts = Post
@@ -235,6 +241,8 @@ siteValidation-extra = File aggiuntivi
siteValidation-stale = File obsoleti siteValidation-stale = File obsoleti
tabBar-documentation = Documentazione tabBar-documentation = Documentazione
tabBar-apiDocumentation = Documentazione API tabBar-apiDocumentation = Documentazione API
tabBar-cliDocumentation = Documentazione CLI
tabBar-mcpDocumentation = Documentazione MCP
tabBar-findDuplicates = Trova duplicati tabBar-findDuplicates = Trova duplicati
tabBar-tags = Tag tabBar-tags = Tag
tabBar-preview = Anteprima tabBar-preview = Anteprima

View File

@@ -29,12 +29,13 @@ surface TabRuntimeSurface {
-- ─── Tab types ──────────────────────────────────────────────── -- ─── Tab types ────────────────────────────────────────────────
-- 17 distinct tab types, each routing to a matching editor view. -- 19 distinct tab types, each routing to a matching editor view.
-- Plus "dashboard" as the no-tab default view. -- Plus "dashboard" as the no-tab default view.
-- --
-- Tab types: post, media, settings, style, tags, chat, import, -- Tab types: post, media, settings, style, tags, chat, import,
-- menu_editor, metadata_diff, git_diff, documentation, -- menu_editor, metadata_diff, git_diff, documentation,
-- api_documentation, site_validation, translation_validation, -- api_documentation, cli_documentation, mcp_documentation,
-- site_validation, translation_validation,
-- scripts, templates, find_duplicates -- scripts, templates, find_duplicates
-- --
-- Editor routes: all of the above plus "dashboard" (shown when no tab is active). -- Editor routes: all of the above plus "dashboard" (shown when no tab is active).
@@ -61,9 +62,10 @@ surface TabSurface {
-- 1. Singleton tool tabs: always one instance, never transient, id = type name. -- 1. Singleton tool tabs: always one instance, never transient, id = type name.
-- settings, tags, style, scripts (bare), menu_editor, documentation, -- settings, tags, style, scripts (bare), menu_editor, documentation,
-- api_documentation, metadata_diff, site_validation, -- api_documentation, cli_documentation, mcp_documentation,
-- metadata_diff, site_validation,
-- translation_validation, find_duplicates -- translation_validation, find_duplicates
-- Total: 11 singleton types. -- Total: 13 singleton types.
-- 2. Entity tabs: keyed by external ID, support preview/pin intent. -- 2. Entity tabs: keyed by external ID, support preview/pin intent.
-- post (id = postId), media (id = mediaId) -- post (id = postId), media (id = mediaId)
@@ -162,6 +164,8 @@ rule ResolveEditorRoute {
-- git_diff: Git diff view (file or commit, keyed by tab id) -- git_diff: Git diff view (file or commit, keyed by tab id)
-- documentation: Rendered markdown (DOCUMENTATION.md) -- documentation: Rendered markdown (DOCUMENTATION.md)
-- api_documentation: Rendered markdown (API.md) -- api_documentation: Rendered markdown (API.md)
-- cli_documentation: Rendered markdown (CLI.md)
-- mcp_documentation: Rendered markdown (MCP.md)
-- site_validation: Generated site link/structure validation -- site_validation: Generated site link/structure validation
-- translation_validation: Translation completeness checks -- translation_validation: Translation completeness checks
-- scripts: Script editor (keyed by scriptId) -- scripts: Script editor (keyed by scriptId)