docs: refresh docs and add tunnel usage guide (#666)
Add a new tunnels page with verified, up-to-date CLI examples Remove deprecated `--daemon` usage and clarify QR/password behavior Add docs validation tooling and docs-source workflow for packaging and sync
This commit is contained in:
committed by
GitHub
parent
1f8e875357
commit
75c90d955c
@@ -0,0 +1,86 @@
|
||||
name: Docs Source
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "packages/docs/**"
|
||||
- "scripts/docs/**"
|
||||
- "package.json"
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag:
|
||||
description: "Optional existing tag to upload docs source archive"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
validate-and-package:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
archive_name: ${{ steps.archive.outputs.archive_name }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Validate docs source
|
||||
run: bun run docs:validate
|
||||
|
||||
- name: Build docs source archive
|
||||
id: archive
|
||||
run: |
|
||||
mkdir -p artifacts
|
||||
ARCHIVE_NAME="openchamber-docs-source-${GITHUB_SHA::8}.tar.gz"
|
||||
tar -czf "artifacts/${ARCHIVE_NAME}" -C packages/docs .
|
||||
echo "archive_name=${ARCHIVE_NAME}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Upload workflow artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: docs-source
|
||||
path: artifacts/${{ steps.archive.outputs.archive_name }}
|
||||
retention-days: 14
|
||||
|
||||
- name: Upload archive to release tag
|
||||
if: ${{ github.event_name == 'release' || github.event.inputs.release_tag != '' }}
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ github.event_name == 'release' && github.event.release.tag_name || github.event.inputs.release_tag }}
|
||||
files: artifacts/${{ steps.archive.outputs.archive_name }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Trigger openchamber-website docs sync (optional)
|
||||
if: ${{ github.event_name == 'release' || github.event_name == 'workflow_dispatch' }}
|
||||
env:
|
||||
WEBSITE_REPO: openchamber/openchamber-website
|
||||
WEBSITE_TOKEN: ${{ secrets.OPENCHAMBER_WEBSITE_REPO_TOKEN }}
|
||||
SOURCE_REF: ${{ github.event_name == 'release' && github.event.release.tag_name || github.ref_name }}
|
||||
run: |
|
||||
if [ -z "$WEBSITE_TOKEN" ]; then
|
||||
echo "OPENCHAMBER_WEBSITE_REPO_TOKEN not set; skip dispatch."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
curl -sS -X POST \
|
||||
-H "Authorization: Bearer $WEBSITE_TOKEN" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
https://api.github.com/repos/$WEBSITE_REPO/dispatches \
|
||||
-d @- <<JSON
|
||||
{
|
||||
"event_type": "docs_source_updated",
|
||||
"client_payload": {
|
||||
"source_repo": "${{ github.repository }}",
|
||||
"source_ref": "$SOURCE_REF",
|
||||
"archive_name": "${{ steps.archive.outputs.archive_name }}"
|
||||
}
|
||||
}
|
||||
JSON
|
||||
@@ -329,6 +329,8 @@ Independent project, not affiliated with the OpenCode team.
|
||||
|
||||
See [CONTRIBUTING.md](./CONTRIBUTING.md) for development setup and guidelines.
|
||||
|
||||
Docs source lives in [`packages/docs`](packages/docs/README.md).
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
"vscode:build": "bun run --cwd packages/vscode build",
|
||||
"vscode:package": "bun run --cwd packages/vscode package",
|
||||
"vscode:type-check": "bun run --cwd packages/vscode type-check",
|
||||
"docs:validate": "node scripts/docs/validate-docs.mjs",
|
||||
"icons:sprite": "node scripts/generate-file-type-sprite.mjs",
|
||||
"version:bump": "node scripts/bump-version.mjs",
|
||||
"release:prepare": "bun run build && bun run type-check && bun run lint",
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# Docs Authoring Guide
|
||||
|
||||
This package is docs content source-of-truth for OpenChamber.
|
||||
|
||||
## Add a new docs page
|
||||
|
||||
1. Create a new file in `packages/docs/content/docs/`.
|
||||
- Example: `packages/docs/content/docs/remote-access.mdx`
|
||||
2. Add frontmatter at top:
|
||||
|
||||
```mdx
|
||||
---
|
||||
title: Remote Access
|
||||
description: Access OpenChamber from outside your local network.
|
||||
---
|
||||
```
|
||||
|
||||
3. Use route-safe naming:
|
||||
- `foo.mdx` -> `/foo/`
|
||||
- `folder/index.mdx` -> `/folder/`
|
||||
- `folder/bar.mdx` -> `/folder/bar/`
|
||||
4. Run validation:
|
||||
|
||||
```bash
|
||||
bun run docs:validate
|
||||
```
|
||||
|
||||
## Add a new sidebar section
|
||||
|
||||
Edit `packages/docs/sidebar.config.json`.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"label": "Advanced",
|
||||
"items": [{ "label": "Remote Access", "link": "/remote-access/" }]
|
||||
}
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- use trailing slash in links (`/page/`)
|
||||
- every sidebar link must map to an existing MDX file
|
||||
- keep section labels short and task-oriented
|
||||
|
||||
## Sync into openchamber-website
|
||||
|
||||
`openchamber-website` renders/deploys docs via Starlight in `apps/docs`.
|
||||
|
||||
After docs content updates here:
|
||||
|
||||
1. copy `packages/docs/content/docs/*` -> `openchamber-website/apps/docs/src/content/docs/*`
|
||||
2. map `packages/docs/sidebar.config.json` into `openchamber-website/apps/docs/astro.config.mjs` sidebar
|
||||
3. run docs checks/build in website repo
|
||||
|
||||
Automation support exists in `.github/workflows/docs-source.yml` (release/manual packaging of docs source artifact).
|
||||
@@ -0,0 +1,42 @@
|
||||
# Docs Source Deployment
|
||||
|
||||
This repo publishes docs **source artifacts**.
|
||||
|
||||
Rendering and hosting still happen in `openchamber-website` (`apps/docs`).
|
||||
|
||||
## Workflow
|
||||
|
||||
Use `.github/workflows/docs-source.yml`.
|
||||
|
||||
Triggers:
|
||||
|
||||
- push to `main` when docs source changes
|
||||
- release published
|
||||
- manual `workflow_dispatch`
|
||||
|
||||
Outputs:
|
||||
|
||||
- validates docs (`bun run docs:validate`)
|
||||
- creates `openchamber-docs-source-<sha>.tar.gz`
|
||||
- uploads archive as workflow artifact
|
||||
- on release/manual with tag, uploads archive to release assets
|
||||
|
||||
## Optional cross-repo sync trigger
|
||||
|
||||
The workflow can trigger a `repository_dispatch` event in `openchamber-website`.
|
||||
|
||||
Set secret in this repo:
|
||||
|
||||
- `OPENCHAMBER_WEBSITE_REPO_TOKEN` (token with access to `openchamber/openchamber-website`)
|
||||
|
||||
Event sent:
|
||||
|
||||
- `event_type: docs_source_updated`
|
||||
|
||||
Payload includes:
|
||||
|
||||
- `source_repo`
|
||||
- `source_ref`
|
||||
- `archive_name`
|
||||
|
||||
`openchamber-website` can listen for this event and pull docs source from release artifacts.
|
||||
@@ -0,0 +1,31 @@
|
||||
# OpenChamber Docs Source
|
||||
|
||||
This package is the source-of-truth for OpenChamber public docs content.
|
||||
|
||||
## Layout
|
||||
|
||||
- `content/docs/*.mdx` - English docs pages
|
||||
- `sidebar.config.json` - docs navigation structure for Starlight sidebar
|
||||
- `CONTRIBUTING.md` - authoring guide for adding pages and sections
|
||||
- `DEPLOYMENT.md` - release/manual packaging and sync trigger model
|
||||
|
||||
## Local validation
|
||||
|
||||
Run from repo root:
|
||||
|
||||
```bash
|
||||
bun run docs:validate
|
||||
```
|
||||
|
||||
This validates:
|
||||
|
||||
- frontmatter (`title`, `description`) exists for every MDX page
|
||||
- sidebar links resolve to existing MDX routes
|
||||
|
||||
## Deployment model
|
||||
|
||||
This repo owns docs content.
|
||||
|
||||
Website rendering/deployment happens in `openchamber-website` (`apps/docs`).
|
||||
|
||||
Use `.github/workflows/docs-source.yml` to package docs source on release or manual trigger.
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
title: OpenChamber Docs
|
||||
description: Setup and operating guide for OpenChamber across web, desktop, and VS Code.
|
||||
---
|
||||
|
||||
# OpenChamber Docs
|
||||
|
||||
OpenChamber is the visual workspace around OpenCode.
|
||||
|
||||
Use these docs to:
|
||||
|
||||
- install the right surface for your workflow
|
||||
- expose OpenChamber safely for remote use
|
||||
- customize appearance and troubleshoot common issues
|
||||
|
||||
## Read this first
|
||||
|
||||
- [Install](/install/)
|
||||
- [Quickstart](/quickstart/)
|
||||
- [Tunnels](/tunnels/)
|
||||
- [Troubleshooting](/troubleshooting/)
|
||||
|
||||
## What OpenChamber is for
|
||||
|
||||
OpenChamber is for the parts of AI coding that benefit from a control room: branching sessions, reviewing diffs, managing terminals, watching tool progress, running project actions, and keeping the full board visible while the agent works.
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
title: Install
|
||||
description: Install OpenChamber for desktop, web, or VS Code.
|
||||
---
|
||||
|
||||
# Install
|
||||
|
||||
OpenChamber has three main surfaces:
|
||||
|
||||
- desktop app for macOS
|
||||
- CLI-hosted web app with installable PWA
|
||||
- VS Code extension
|
||||
|
||||
## Prerequisite
|
||||
|
||||
Install [OpenCode](https://opencode.ai) first.
|
||||
|
||||
## Web + PWA
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/openchamber/openchamber/main/scripts/install.sh | bash
|
||||
openchamber --ui-password be-creative-here
|
||||
```
|
||||
|
||||
Then open the URL printed by the CLI (usually `http://localhost:3000`).
|
||||
|
||||
## Desktop
|
||||
|
||||
Download the latest desktop build from the GitHub releases page or the OpenChamber download page.
|
||||
|
||||
## VS Code
|
||||
|
||||
Install from the VS Code Marketplace and sign into your usual OpenCode workflow.
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
title: Quickstart
|
||||
description: Start OpenChamber quickly and choose the right surface for the task.
|
||||
---
|
||||
|
||||
# Quickstart
|
||||
|
||||
## Fastest path
|
||||
|
||||
1. Install OpenCode.
|
||||
2. Install OpenChamber CLI.
|
||||
3. Run `openchamber --ui-password be-creative-here`.
|
||||
4. Open the web UI on your machine.
|
||||
5. If needed, start a tunnel and scan the QR code from your phone.
|
||||
|
||||
Use a strong UI password, especially if you plan to expose the instance remotely.
|
||||
|
||||
## Which surface should I use?
|
||||
|
||||
- use **desktop** for macOS-heavy daily driver workflows
|
||||
- use **web** for remote access and mobile review
|
||||
- use **VS Code** for editor-native sessions beside code
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
title: Themes
|
||||
description: Customize OpenChamber with built-in and user-defined themes.
|
||||
---
|
||||
|
||||
# Themes
|
||||
|
||||
OpenChamber supports built-in themes and custom theme JSON files.
|
||||
|
||||
## Add a custom theme
|
||||
|
||||
1. Create the themes directory:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/openchamber/themes
|
||||
```
|
||||
|
||||
2. Add your JSON file to that directory (for example `my-theme.json`).
|
||||
3. Open OpenChamber, then go to **Settings -> Theme -> Reload themes**.
|
||||
4. Pick your theme from the dropdown.
|
||||
|
||||
## Theme location
|
||||
|
||||
- macOS/Linux: `~/.config/openchamber/themes/`
|
||||
|
||||
## Full JSON format reference
|
||||
|
||||
Use the full format guide in the main repo docs:
|
||||
|
||||
- [`docs/CUSTOM_THEMES.md`](https://github.com/openchamber/openchamber/blob/main/docs/CUSTOM_THEMES.md)
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
title: Troubleshooting
|
||||
description: Common setup and runtime issues with quick fixes.
|
||||
---
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
## OpenChamber command exits or fails to start
|
||||
|
||||
- confirm Node.js `>=20`
|
||||
- run `openchamber --version`
|
||||
- reinstall latest CLI if needed
|
||||
|
||||
## Web UI is not reachable
|
||||
|
||||
- check server logs with `openchamber logs`
|
||||
- verify active port (default `3000`)
|
||||
- open `http://localhost:3000` directly first before testing tunnel links
|
||||
|
||||
## Remote/tunnel link does not work
|
||||
|
||||
- run `openchamber tunnel status --all`
|
||||
- restart tunnel from the same instance/port
|
||||
- regenerate connect link if previous token was already used
|
||||
|
||||
## VS Code extension does not connect
|
||||
|
||||
- confirm OpenChamber server is running
|
||||
- verify extension is updated
|
||||
- reload VS Code window and retry connection
|
||||
@@ -0,0 +1,77 @@
|
||||
---
|
||||
title: Tunnels
|
||||
description: Expose OpenChamber safely for remote and mobile access.
|
||||
---
|
||||
|
||||
# Tunnels
|
||||
|
||||
Use `openchamber tunnel` to expose a running OpenChamber instance.
|
||||
|
||||
## Quick start (Cloudflare quick mode)
|
||||
|
||||
1. Start OpenChamber:
|
||||
|
||||
```bash
|
||||
openchamber
|
||||
```
|
||||
|
||||
2. Start a tunnel:
|
||||
|
||||
```bash
|
||||
openchamber tunnel start --provider cloudflare --mode quick
|
||||
```
|
||||
|
||||
3. Check status:
|
||||
|
||||
```bash
|
||||
openchamber tunnel status
|
||||
```
|
||||
|
||||
By default, OpenChamber prints a QR code in interactive TTY sessions. Use `--qr` to force QR output, or `--no-qr` to disable it.
|
||||
|
||||
## Managed modes
|
||||
|
||||
### Managed remote
|
||||
|
||||
Use a token + hostname managed by Cloudflare:
|
||||
|
||||
```bash
|
||||
openchamber tunnel start --provider cloudflare --mode managed-remote --token-file ~/.secrets/cf-token --hostname app.example.com
|
||||
```
|
||||
|
||||
### Managed local
|
||||
|
||||
Use a local `cloudflared` config:
|
||||
|
||||
```bash
|
||||
openchamber tunnel start --provider cloudflare --mode managed-local --config ~/.cloudflared/config.yml
|
||||
```
|
||||
|
||||
## Profiles (managed-remote)
|
||||
|
||||
Save a reusable profile:
|
||||
|
||||
```bash
|
||||
openchamber tunnel profile add --provider cloudflare --mode managed-remote --name prod-main --hostname app.example.com --token-file ~/.secrets/cf-token
|
||||
```
|
||||
|
||||
Start using the saved profile:
|
||||
|
||||
```bash
|
||||
openchamber tunnel start --profile prod-main
|
||||
```
|
||||
|
||||
## Useful commands
|
||||
|
||||
```bash
|
||||
openchamber tunnel providers
|
||||
openchamber tunnel ready --provider cloudflare
|
||||
openchamber tunnel doctor --provider cloudflare
|
||||
openchamber tunnel stop --port 3000
|
||||
```
|
||||
|
||||
## Behavior notes
|
||||
|
||||
- one active tunnel per OpenChamber instance (port)
|
||||
- starting a new mode/provider on same instance replaces previous tunnel
|
||||
- generating a new connect link revokes previous unused one
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"sections": [
|
||||
{
|
||||
"label": "Start here",
|
||||
"items": [
|
||||
{ "label": "Overview", "link": "/" },
|
||||
{ "label": "Install", "link": "/install/" },
|
||||
{ "label": "Quickstart", "link": "/quickstart/" },
|
||||
{ "label": "Tunnels", "link": "/tunnels/" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "Customize",
|
||||
"items": [
|
||||
{ "label": "Themes", "link": "/themes/" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "Help",
|
||||
"items": [
|
||||
{ "label": "Troubleshooting", "link": "/troubleshooting/" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import { readdir, readFile } from "node:fs/promises"
|
||||
import path from "node:path"
|
||||
|
||||
const repoRoot = path.resolve(import.meta.dirname, "..", "..")
|
||||
const docsRoot = path.join(repoRoot, "packages", "docs")
|
||||
const contentRoot = path.join(docsRoot, "content", "docs")
|
||||
const sidebarPath = path.join(docsRoot, "sidebar.config.json")
|
||||
|
||||
async function walk(dir) {
|
||||
const entries = await readdir(dir, { withFileTypes: true })
|
||||
const files = await Promise.all(
|
||||
entries.map(async (entry) => {
|
||||
const target = path.join(dir, entry.name)
|
||||
if (entry.isDirectory()) return walk(target)
|
||||
return [target]
|
||||
}),
|
||||
)
|
||||
return files.flat()
|
||||
}
|
||||
|
||||
function toPosix(value) {
|
||||
return value.split(path.sep).join("/")
|
||||
}
|
||||
|
||||
function routeFromFile(filePath) {
|
||||
const relative = toPosix(path.relative(contentRoot, filePath))
|
||||
const withoutExt = relative.replace(/\.mdx$/, "")
|
||||
|
||||
if (withoutExt === "index") return "/"
|
||||
if (withoutExt.endsWith("/index")) {
|
||||
return `/${withoutExt.slice(0, -"/index".length)}/`
|
||||
}
|
||||
|
||||
return `/${withoutExt}/`
|
||||
}
|
||||
|
||||
function hasFrontmatterKey(content, key) {
|
||||
const hit = /^---\n([\s\S]*?)\n---\n/m.exec(content)
|
||||
if (!hit) return false
|
||||
return new RegExp(`^${key}:\\s*.+$`, "m").test(hit[1])
|
||||
}
|
||||
|
||||
async function run() {
|
||||
const filePaths = (await walk(contentRoot)).filter((p) => p.endsWith(".mdx"))
|
||||
const routeSet = new Set()
|
||||
const errors = []
|
||||
|
||||
for (const filePath of filePaths) {
|
||||
const body = await readFile(filePath, "utf8")
|
||||
const relative = toPosix(path.relative(repoRoot, filePath))
|
||||
const route = routeFromFile(filePath)
|
||||
routeSet.add(route)
|
||||
|
||||
if (!hasFrontmatterKey(body, "title")) {
|
||||
errors.push(`${relative}: missing frontmatter key 'title'`)
|
||||
}
|
||||
if (!hasFrontmatterKey(body, "description")) {
|
||||
errors.push(`${relative}: missing frontmatter key 'description'`)
|
||||
}
|
||||
}
|
||||
|
||||
const sidebarRaw = await readFile(sidebarPath, "utf8")
|
||||
const sidebar = JSON.parse(sidebarRaw)
|
||||
const links = (sidebar.sections ?? [])
|
||||
.flatMap((section) => section.items ?? [])
|
||||
.map((item) => item.link)
|
||||
|
||||
for (const link of links) {
|
||||
if (!routeSet.has(link)) {
|
||||
errors.push(`sidebar link has no page: ${link}`)
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
console.error("Docs validation failed:")
|
||||
for (const error of errors) {
|
||||
console.error(`- ${error}`)
|
||||
}
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log(`Docs validation passed: ${filePaths.length} pages, ${links.length} sidebar links.`)
|
||||
}
|
||||
|
||||
run().catch((error) => {
|
||||
console.error(error)
|
||||
process.exit(1)
|
||||
})
|
||||
Reference in New Issue
Block a user