Skip to content
Open
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
171 changes: 171 additions & 0 deletions plugins/Wzdhehe/mcode-webui/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# Contributing to Mcode Web UI

Thanks for your interest in Mcode Web UI! This document covers
the day-to-day contribution workflow. For the bigger picture (plugin
packaging, release process), see [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md)
and [`plugins/Wzdhehe/mcode-webui/README.md`](plugins/Wzdhehe/mcode-webui/README.md).

## Code of conduct

Be kind. We review for substance, not for style preferences. If a
change makes the webui more correct / faster / easier to use, it's
in scope.

## Development setup

Requirements:

- **Node 22.19+** (uses `node:test`, `URL.parse`, `Blob.stream`)
- **Mcode CLI 0.1.4+** on `PATH` (or `MCODE_CMD` pointing to it)
- A POSIX-like shell on Windows: PowerShell 7+ or Git Bash

Clone and run:

```bash
git clone https://github.com/Wzdhehe/Mcode-webui.git
cd Mcode-webui
npm install # only devDeps (eslint, prettier, c8)
npm test # 382 unit tests + 1 skipped (383 total)
npm run lint # eslint flat config, must be 0 warnings
npm run dev # node server.js
# → http://127.0.0.1:8080/
```

`npm test` and `npm run lint` **must pass** before opening a PR.

## Repository layout

This repo has a **dual layout** — both copies are kept in sync:

```
Mcode-webui/ # ← the development tree (root)
├── server/ public/ test/ # Node + frontend + tests
├── docs/ # ARCHITECTURE, API, CAPABILITIES, …
├── acp.mjs, server.js, package.json
└── plugins/Wzdhehe/mcode-webui/ # ← the plugin artifact
├── server/ public/ test/ # ↑ real copies, not symlinks
├── docs/ references/ skills/
├── plugin.json package.json LICENSE
├── README.md PR_DESCRIPTION.md
└── SKILL.md # lives at skills/mcode-webui/SKILL.md
```

**Why two copies?** The community plugin registry takes the
`plugins/.../Mcode-webui/` tree as the submission. We keep it as a
real directory copy (not a junction or symlink — those break
zip-packaging and confuse `git log`).

`npm run setup:plugin` is a no-op on the current layout (it used to
create junctions; the trees have been expanded since).

## Editing flow

1. **Edit at the repo root** (`server/`, `public/`, `test/`).
2. **Mirror the change to the plugin tree** — copy the changed files
from `<root>/server/...` to `plugins/Wzdhehe/mcode-webui/server/...`,
and the same for `public/`, `test/`, `docs/`.
(The `package:plugin` script does this for you, but a
per-PR manual sync is fine for small changes.)
3. **Run the gate**:
```bash
npm test
npm run lint
npm run validate:plugin
```
4. **Commit** with a conventional message (see below).
5. **Push** to a feature branch and open a PR.

## Commit message format

We loosely follow [Conventional Commits](https://www.conventionalcommits.org/):

```
<type>(<scope>): <subject>

<body — explain WHY, not what>
<footer — refs, BREAKING CHANGE, etc.>
```

Common types:

- `feat:` — new feature
- `fix:` — bug fix
- `refactor:` — internal change, no behavior diff
- `test:` — test-only change
- `docs:` — documentation only
- `chore:` — build / CI / tooling

Scope is the area (`server`, `public`, `plugin`, `acp`, `test`, `docs`).

Example:

```
fix(acp): retry session/fork once on "Method not found"

mcode 0.1.5 returns "Method not found" for session/fork on the
first attempt but accepts it on retry. One retry is enough in
practice; log + continue.
```

## Pull request checklist

- [ ] `npm test` passes (382 + 1 skipped)
- [ ] `npm run lint` is clean (0 warnings)
- [ ] `npm run validate:plugin` is clean (mirrors official gate)
- [ ] Plugin tree (`plugins/.../Mcode-webui/`) is in sync with root
- [ ] No personal data in commit content (no IPs, no usernames, no
real session IDs)
- [ ] New env vars documented in `docs/API.md` and `plugin.json`
- [ ] New endpoints / events documented in `docs/API.md`
- [ ] `CHANGELOG.md` updated under an "Unreleased" section
- [ ] If destructive behavior changes, the security note
`plugins/.../references/SECURITY-NOTES.md` is updated (and
`plugin.json`'s `extensions.securityNotes` summary stays in sync)

## Adding a new route / event / panel

See [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md) for recipes. The
short version:

- **Route**: drop a file in `server/routes/<name>.js` exporting
`(req, res, deps) => …`, register in `server/router.js`.
- **SSE event**: emit via `state-bus` in the route; consume in
`public/app/render.js`.
- **UI panel**: add a `state` slice in `public/app/state.js`,
a renderer in `public/app/render.js`, a handler in
`public/app/events.js`, and an i18n key in `public/app/i18n.js`.

## Style guide

- **ESM only** — no CommonJS, no `require()`.
- **No runtime npm deps** — only `devDependencies`. Everything
runtime must be Node 22+ stdlib.
- **No silent failures** — every catch either re-throws, returns
an explicit error response, or logs a warning with a `console.warn`
tag. No `try { … } catch {}` blocks.
- **No fake UI buttons** — if mcode acp doesn't support a method
(see `docs/CAPABILITIES.md`), don't render a button that
pretends to work. Use a toast + skip.
- **i18n first** — every user-visible string in the frontend goes
through `i18n.t()`. No inline English / Chinese literals.
- **Token-aware error messages** — never echo the request URL
or headers into error bodies (token leak risk).

## Release process

1. Bump `version` in `package.json` (root + plugin copy).
2. Move "Unreleased" section in `CHANGELOG.md` to a dated
versioned section.
3. `npm run package:plugin` — produces `dist/Wzdhehe/mcode-webui/`
+ `dist/Wzdhehe/Mcode-webui.zip`.
4. Open a PR to the community registry
[`MiniMax-AI/MiniMax-Code-Plugins`](https://github.com/MiniMax-AI/MiniMax-Code-Plugins)
adding only the `plugins/Wzdhehe/mcode-webui/` tree (per the
"one folder = one plugin" model — see the official README).
5. Tag the release: `git tag v1.X.Y && git push --tags`.

## Questions?

Open an issue. If it's about a plugin-submission process (reviewer
comments, manifest fields, etc.), tag it `plugin-registry`.
21 changes: 21 additions & 0 deletions plugins/Wzdhehe/mcode-webui/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Wzdhehe

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
154 changes: 154 additions & 0 deletions plugins/Wzdhehe/mcode-webui/PR_DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# PR Description — Mcode-webui plugin

> **Submission body for the upstream PR to the
> [MiniMax-Code-Plugins](https://github.com/MiniMax-AI/MiniMax-Code-Plugins)
> community registry. Use this as the PR body verbatim.**

## What this PR adds

- New plugin at `plugins/Wzdhehe/mcode-webui/` per Agent Plugins 1.0 spec
- `plugin.json` with the 10 white-listed top-level fields
- `skills/mcode-webui/SKILL.md` with `{name, description}` frontmatter (343 chars) + body (official skills/ layout)
- `LICENSE` (MIT)
- `README.md` (user-facing quick start)
- `references/SECURITY-NOTES.md` (canonical security disclosure)
- `docs/` (ARCHITECTURE, API, CAPABILITIES, DEVELOPMENT, TROUBLESHOOTING)
- `server/`, `public/`, `test/` (real directory copies, kept in sync with
the project root; packaged as-is into `dist/` for the release artifact)
- `package.json` (copy of project root, with `setup:plugin` and
`package:plugin` scripts)

## Why this plugin

A Kimi-Code-style web frontend for the `mcode` agent runtime. It lets
users open `mcode` sessions in a browser instead of the terminal,
stream real-time tool events, switch workspaces, and use the
`ask-user` modal — all without the Mcode TUI eating their terminal.

## Example prompts (with expected results)

**Prompt 1** — User: "open Mcode webui"

Expected:
1. Run `node server.js` (foreground or background, your call)
2. Wait for the SSE `open` log line on stdout
3. Tell the user: "webui running at http://127.0.0.1:8080/ (or http://<lan-ip>:8080/ for LAN)"

**Prompt 2** — User: "Mcode webui status"

Expected:
1. Check if port 8080 is in use
2. If listening: report "running" + URL; if not: report "not running"
3. Optionally read `.server.err` for last error

**Prompt 3** — User: "show Mcode webui url"

Expected:
1. Print `http://<lan-ip>:8080/`
2. (If `TOKEN` is set) also print the full URL with `?token=…`

Full trigger list in [`SKILL.md`](SKILL.md#when-to-use-this-skill).

## Dependencies

- **Runtime**: Node 22.19+ stdlib only (zero npm deps)
- **External binary**: `mcode` CLI 0.1.4+ (for `mcode acp` transport)
- **Optional**: `sqlite3` binary (for usage panel) — auto-detected via
`server/lib/config.js#detectSqlite3Bin`
- **Optional**: `mavis` 0.1.0+ (for real token usage; degrades to
estimates if missing)

## Network & data behavior

- **Binds `0.0.0.0:8080` by default** — loopback-only via `HOST=127.0.0.1`
- **`?token=` query string** supported (browser convenience);
`Authorization: Bearer` header also accepted
- **No outbound network** — only local subprocesses (`mcode`, `mmx quota`)
- **Reads**: `~/.minimax/v2/sqlite/runtime-state.sqlite` (read-only)
- **Writes**:
- `~/.minimax/v2/sqlite/runtime-state.sqlite` — only on
`DELETE /api/sessions/:id` (with `?dryRun=true` opt-in preview)
- `MCODE_WEBUI_UPLOAD_DIR` (default `.webui-uploads/`) for file uploads
- `~/.minimax-code/webui/.webui-sessions.json` for session store
- **No telemetry, no remote endpoints**

Full disclosure: [`references/SECURITY-NOTES.md`](references/SECURITY-NOTES.md).

## Automated test evidence

```
$ npm test
ℹ tests 291
ℹ suites 86
ℹ pass 290
ℹ fail 0
ℹ skipped 1
ℹ duration_ms ~550

$ npm run lint
> eslint server/ test/
(0 errors, 0 warnings)
```

Test breakdown:
- `lib-config.test.js` — 28 tests (constants, env loading, sqlite detection)
- `lib-lan.test.js` — local request detection, LAN IP detection
- `lib-db.test.js` — `deleteMcodeSessionFromDb` happy path + missing-table
tolerance, dryRun path
- `lib-state-bus.test.js` — per-cid state isolation, SSE channel mgmt
- `mavis-usage.test.js` — real sqlite3 fixture, per-turn context math
- `sessions.test.js` — `?dryRun=true` preview, route-level session
CRUD with rollback
- `chat.test.js`, `routes-*.test.js` — error path coverage

CI: GitHub Actions on Node 22 / Node 24, Windows + Linux + macOS.

## Manual test evidence

- Installed plugin via `mavis plugin install` (path mode)
- Set `TOKEN=$(openssl rand -hex 16)`
- Opened `http://127.0.0.1:8080/?token=…` in browser — SSE stream
connected, model stream rendered
- Opened same URL on phone (LAN) — token auth accepted, mobile
layout responsive
- Ran a multi-turn session with tool calls (Bash, Read, Edit) —
all events rendered, quota panel updated
- Toggled `lanBroadcast: false` — phone got 403 with friendly page
- Deleted a session — log shows rows removed from all session-keyed
tables. v1.0 E2E evidence: ran the real-delete path against a copy of
the production `runtime-state.sqlite` (713 MB) via
`MCODE_RUNTIME_DB=<copy>`; a session with 11,176 rows across 12 tables
was reduced to 7 rows (only `questionnaire_requests` remains, skipped
by design — not `local_runtime_*`-prefixed). The table list covers
32 of the 33 session-keyed tables in the Mcode schema.
- Re-ran delete with `?dryRun=true` — preview shows row count, no
modification
- Restarted server — orphan mcode acp child cleaned up via SIGTERM

## Red-line compliance (mcode-plugin-guide)

- **Red-line 1 (destructive ops)**: `DELETE /api/sessions/:id` has
`?dryRun=true` opt-in preview. Real delete runs in a SQLite
`transaction()` with per-table error tolerance.
- **Red-line 2 (cross-platform)**: sqlite3 binary is auto-detected via
`detectSqlite3Bin()` — no hardcoded host paths.
- **Red-line 3 (披露完整性)**: `references/SECURITY-NOTES.md` is the
single source of truth; `SKILL.md` (TL;DR + link), `plugin.json`
(`extensions.securityNotes`), this PR description, and the plugin
`README.md` all reference it.
- **Red-line 7 (披露完整性)**: 3-place consistency — README,
plugin.json description + `extensions.securityNotes`, PR template.

## Checklist

- [x] `plugin.json` validates against `https://agent-plugins.org/schemas/1.0.0/plugin.schema.json`
- [x] `npm run validate-plugin` (planned batch H) passes
- [x] `npm test` — 261 pass, 0 fail, 0 lint warning
- [x] `references/SECURITY-NOTES.md` covers all red-line 7 topics
- [x] LICENSE present (MIT)
- [x] README.md present and non-empty
- [x] No symlinks (release artifact expands junctions)
- [x] No UTF-8 BOM in any text file
- [x] No placeholder markers in shipped files
- [x] No `hooks` / unsupported capability fields
- [x] One plugin per PR (this PR is only `plugins/Wzdhehe/mcode-webui/`)
Loading