Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
}
},
// Runs on the HOST before the container is created/started. Picks a
// free TCP port, writes it to .devcontainer/ports.env. The container
// runs with --network host (see runArgs) so the same port number is
// free TCP port and writes it to .devcontainer/ports.env. Launch and
// task configurations read that file directly. The container runs
// with --network host (see runArgs) so the same port number is
// both the in-container bind and the host-visible address — no port
// forwarding involved. See the wiki page
// [[preferences/devcontainer-ports]] for the full rationale and the
Expand Down Expand Up @@ -57,13 +58,10 @@
// server binds directly on the host's network namespace at whatever
// port initializeCommand picked.
//
// --env-file injects MIND_MAP_HOST_PORT into the container so the
// mind-map binary (which reads it via `serve --addr`) listens on
// the right port. host-side consumers (launch.json, scripts) read
// the same file directly.
// Consumers read .devcontainer/ports.env at execution time instead
// of relying on container environment captured only at creation.
"runArgs": [
"--network", "host",
"--env-file", ".devcontainer/ports.env"
"--network", "host"
],
"portsAttributes": {
"4242": {
Expand Down
13 changes: 5 additions & 8 deletions .devcontainer/initializeCommand.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
#!/usr/bin/env bash
# Runs on the HOST (not in the container) before docker run. Picks a
# free TCP port for the mind-map server and writes it to
# .devcontainer/ports.env. The value is consumed in two places:
#
# 1. Inside the container, via runArgs --env-file, so the mind-map
# binary's `serve --addr` reads $MIND_MAP_HOST_PORT.
# 2. On the host, by tools (launch.json, the screenshot harness,
# ad-hoc curl) that need to know what URL to hit.
# .devcontainer/ports.env. Launch configurations, tasks, the screenshot
# harness, and ad-hoc commands read the file when they run. Keeping the
# file as the single source of truth avoids stale container environment
# values when an existing devcontainer is restarted.
#
# Because the container runs with --network host (see devcontainer.json
# runArgs), there is no port forwarding involved — the container binds
Expand Down Expand Up @@ -47,8 +45,7 @@ PORT=$(pick_port)
# devcontainer CLI was invoked from.
cd "$(dirname "$0")"

# `--env-file` (used in runArgs) accepts bare KEY=VALUE lines. Don't
# quote the value — docker chokes on that.
# Keep this shell-sourceable for tasks and simple to parse from launch.json.
cat > ports.env <<EOF
MIND_MAP_HOST_PORT=$PORT
EOF
Expand Down
16 changes: 9 additions & 7 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@
// The devcontainer runs with --network host (see
// .devcontainer/devcontainer.json), so the in-container
// port IS the host port. initializeCommand.sh picks the
// value at create time and writes it to
// .devcontainer/ports.env; --env-file in runArgs makes
// $MIND_MAP_HOST_PORT available in the container's env.
// value at startup and writes it to
// .devcontainer/ports.env. Both the server and browser read
// the same file-backed input so container restarts cannot leave
// one side using a stale environment value.
// See [[preferences/devcontainer-ports]].
"name": "mind-map Server",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/cmd/mind-map",
"args": ["serve", "--addr", "0.0.0.0:${env:MIND_MAP_HOST_PORT}", "--webui", "${workspaceFolder}/webui/dist"],
"args": ["serve", "--addr", "0.0.0.0:${input:mindMapHostPort}", "--webui", "${workspaceFolder}/webui/dist"],
"preLaunchTask": "build-webui"
},
{
Expand All @@ -33,7 +34,7 @@
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/cmd/mind-map",
"args": ["serve", "--addr", "0.0.0.0:${env:MIND_MAP_HOST_PORT}", "--webui", "${workspaceFolder}/webui/dist"],
"args": ["serve", "--addr", "0.0.0.0:${input:mindMapHostPort}", "--webui", "${workspaceFolder}/webui/dist"],
},
{
"name": "mind-map (stdio)",
Expand All @@ -49,10 +50,11 @@
// .devcontainer/ports.env so the URL tracks whatever value
// initializeCommand picked.
"name": "WebUI",
"type": "chrome",
// Uses VS Code's built-in JavaScript debugger. The legacy
// msjsdiag.debugger-for-chrome extension is not required.
"type": "pwa-chrome",
"request": "launch",
"browserLaunchLocation": "ui",
"runtimeExecutable": "stable",
"url": "http://localhost:${input:mindMapHostPort}",
"webRoot": "${workspaceFolder}/webui",
"preLaunchTask": "waitForServer",
Expand Down
5 changes: 2 additions & 3 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,8 @@
// runs with --network host (see devcontainer.json), so
// the host and container see the same port number —
// whatever value initializeCommand.sh wrote to
// .devcontainer/ports.env and propagated into the
// container via --env-file. Sourcing the file in the
// shell command is the simplest portable way to read it;
// .devcontainer/ports.env. Sourcing the file in the shell
// command is the simplest portable way to read it;
// it avoids the need for the tasks-shell-input extension
// for tasks (the input is only used by launch.json's
// Chrome URL). See [[preferences/devcontainer-ports]].
Expand Down
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Both modes use the same wiki engine and the same wiki directory (`~/.mind-map/wi
| `get_backlinks` | Get all pages that link to a given page |
| `register_sync` | Register a wiki path prefix to sync with a git remote |
| `reindex_wiki` | Force a reindex pass against on-disk markdown (rarely needed; useful after edits made outside the wiki API) |
| `export_pages` | Export a page (and linked pages up to N hops) as zip or PDF |
| `export_pages` | Export a page (and linked pages up to N hops) as Markdown zip, PDF, or Word document |

## Wiki Features

Expand All @@ -111,7 +111,7 @@ Both modes use the same wiki engine and the same wiki directory (`~/.mind-map/wi
- **Full-text search**: SQLite FTS5 with ranked results and snippets
- **Multi-process safe**: SQLite page locking for concurrent agent access
- **Git sync**: sync wiki pages to GitHub repo wikis via configurable mappings
- **Export / Share**: export pages as zip or PDF — see below
- **Export / Share**: export pages as a Markdown zip, PDF, or Word document — see below

## Export & Share

Expand All @@ -133,8 +133,11 @@ Export is **pluggable** — formats register themselves at startup:
| Format | Description | Requirements |
|--------|-------------|--------------|
| **zip** | Archive of markdown files + assets | None |
| **docx** | Microsoft Word document with rendered Markdown, contents, and embedded images | None |
| **pdf** | Multi-page PDF with table of contents | Chrome, Edge, or Chromium on `$PATH` |

DOCX export uses the MIT-licensed [docxgo](https://github.com/mmonterroca/docxgo) library, with no Word installation or external converter required. It preserves headings, emphasis, lists, task lists, quotes, code blocks, tables, and PNG/JPEG/GIF images. External links remain clickable; wikilinks to exported pages become in-document hyperlinks, while wikilinks outside the export are shown as non-clickable dark gray underlined text. Mermaid blocks are rendered as embedded PNGs when Chromium and the local Mermaid bundle are available, with a code-block fallback otherwise.

PDF export uses [chromedp](https://github.com/chromedp/chromedp) to render markdown → HTML → PDF via a headless browser. It includes a clickable TOC, embedded images, and a print-friendly stylesheet. The PDF sharer only registers if a supported browser is detected — no browser, no PDF option.

### Using export
Expand All @@ -143,13 +146,13 @@ PDF export uses [chromedp](https://github.com/chromedp/chromedp) to render markd

**REST API**:
```
GET /api/export?format=zip&page=projects/my-project&depth=1
GET /api/export?format=docx&page=projects/my-project&depth=1
GET /api/export/formats # list available formats with settings schemas
```

**MCP tool**:
```
export_pages(format: "pdf", page: "architecture/auth", depth: -1)
export_pages(format: "docx", page: "architecture/auth", depth: -1)
```

### Adding new formats
Expand All @@ -164,7 +167,7 @@ The built-in web UI is a lightning-fast, Metro-inspired, chromeless Preact app:
- Markdown rendering with wikilinks as clickable links
- Backlinks section on every page
- Edit mode with raw markdown editor
- Export / share panel for zip and PDF export
- Export / share panel for Markdown zip, Word document, and PDF export
- Interactive graph view of the wiki link structure
- Dark / light theme toggle

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/chromedp/cdproto v0.0.0-20260321001828-e3e3800016bc
github.com/chromedp/chromedp v0.15.1
github.com/kardianos/service v1.2.4
github.com/mmonterroca/docxgo/v2 v2.14.0
github.com/modelcontextprotocol/go-sdk v1.5.0
github.com/spf13/cobra v1.10.2
github.com/yuin/goldmark v1.8.2
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kUL
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mmonterroca/docxgo/v2 v2.14.0 h1:dMsQ1VjwWKUawaFBlRHzIJkPDD6FLDjdJLGqV1GK+lo=
github.com/mmonterroca/docxgo/v2 v2.14.0/go.mod h1:Yc3h7M+sssxGMz51qQ8EHbfDb2NyleLbS+lZLH9Y0us=
github.com/modelcontextprotocol/go-sdk v1.5.0 h1:CHU0FIX9kpueNkxuYtfYQn1Z0slhFzBZuq+x6IiblIU=
github.com/modelcontextprotocol/go-sdk v1.5.0/go.mod h1:gggDIhoemhWs3BGkGwd1umzEXCEMMvAnhTrnbXJKKKA=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
Expand Down
Loading
Loading