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
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- 8 new describe commands: `\dP` (partitioned relations), `\dA`/`\dAc` (access methods / operator classes), `\dO` (collations), `\dF`/`\dFd`/`\dFp`/`\dFt` (text search objects) ([#806](https://github.com/NikolayS/rpg/pull/806))
- `standard_conforming_strings` GUC tracking — fixes backslash parsing in `E''` strings ([#808](https://github.com/NikolayS/rpg/pull/808))
- Async NOTICE/WARNING buffering for deterministic output ordering ([#807](https://github.com/NikolayS/rpg/pull/807))
- `rpg:file:line:` error location prefix matching psql's `-f` behaviour ([#803](https://github.com/NikolayS/rpg/pull/803))
- `rpg:file:line:` error location prefix matching psql's `-f` behavior ([#803](https://github.com/NikolayS/rpg/pull/803))
- Wrapped format trailing-space and padding fixes ([#809](https://github.com/NikolayS/rpg/pull/809))
- 3 previously skipped tests un-skipped: `copydml`, `transactions`, `plpgsql` ([#810](https://github.com/NikolayS/rpg/pull/810))
- **WASM browser build (experimental).** rpg compiles to `wasm32-unknown-unknown` for browser use via WebSocket proxy. SQL queries, most `\` meta-commands, `/version`, `/dba`, and error reporting all work. Line editing with arrow keys, history, and Ctrl-U/K/W supported. See [`docs/WASM.md`](docs/WASM.md). ([#759](https://github.com/NikolayS/rpg/pull/759))
Expand Down Expand Up @@ -239,7 +239,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- Connector config unified with daemon integration ([#481](https://github.com/NikolayS/rpg/pull/481))
- Per-feature autonomy granularity replaces single global setting ([#527](https://github.com/NikolayS/rpg/pull/527))
- Refactored to explicit Tokio runtime construction ([#541](https://github.com/NikolayS/rpg/pull/541))
- Removed module-level `dead_code` suppressions in favour of targeted attributes ([#535](https://github.com/NikolayS/rpg/pull/535))
- Removed module-level `dead_code` suppressions in favor of targeted attributes ([#535](https://github.com/NikolayS/rpg/pull/535))

### Fixed

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ Unit tests live next to the code they test (in `#[cfg(test)]` modules).
just test-integration
```

Integration tests require a running Postgres instance. Docker is used to spin up ephemeral containers. Tests in the `tests/` directory with the `integration` feature gate.
Integration tests require a running Postgres instance. Docker is used to spin up ephemeral containers. The tests live in the `tests/` directory behind the `integration` feature gate.

## Cross-compilation

Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
[![Rust](https://img.shields.io/badge/rust-1.88%2B-orange.svg)](https://www.rust-lang.org/)

A psql-compatible terminal written in Rust with built-in DBA diagnostics and AI assistant.
rpg is a psql-compatible Postgres terminal written in Rust, with built-in DBA diagnostics and an AI assistant.
Single binary, no dependencies, cross-platform.

## Features
Expand Down Expand Up @@ -73,7 +73,7 @@ Anything that works in psql works here unchanged. Everything rpg adds uses `/`.

## AI assistant

Integrates with OpenAI, Anthropic, and Ollama:
rpg integrates with OpenAI, Anthropic, and Ollama:

```sql
-- Ask questions about your database
Expand Down Expand Up @@ -102,7 +102,7 @@ select * from orders where status = 'pending';

### /text2sql — natural language to SQL

By default, the generated SQL is shown in a preview box and you confirm before it runs:
By default, rpg shows the generated SQL in a preview box and asks for confirmation before running it:

```
postgres=# /text2sql
Expand Down Expand Up @@ -392,9 +392,9 @@ rpg --ssh-tunnel user@bastion.example.com -h 10.0.0.5 -d mydb

Supports PostgreSQL 14–18.

rpg is tested against PostgreSQL's own regression test suite (unmodified `.sql` files from the postgres source tree) in CI on every push. Both psql and rpg execute the same queries against the same server; outputs are normalized and diff'dpass only if identical.
rpg is tested against PostgreSQL's own regression test suite (unmodified `.sql` files from the postgres source tree) in CI on every push. Both psql and rpg execute the same queries against the same server; outputs are normalized and diffeda test passes only if they are identical.

**222 of 232 PostgreSQL regression tests pass** (0 failures, 10 skipped) against a PostgreSQL 18 server. The skips are CI infrastructure limits, C extensions, or known parsing gaps — not core compatibility issues.
**222 of 232 PostgreSQL regression tests pass** (0 failures, 10 skipped) against a PostgreSQL 18 server. The skips are due to CI infrastructure limits, C extensions, or known parsing gaps — not core compatibility issues.

→ Full compatibility report: [`docs/psql-compat.md`](docs/psql-compat.md)

Expand Down
4 changes: 2 additions & 2 deletions docs/COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace is unambiguous: if it starts with `/`, it is an rpg extension.

## psql-compatible `\` commands (keep as-is)

These match psql behaviour and must not be changed:
These match psql behavior and must not be changed:

`\a`, `\c`, `\C`, `\cd`, `\copy`, `\d`, `\D`, `\db`, `\dc`, `\df`, `\di`,
`\dl`, `\dn`, `\do`, `\dp`, `\ds`, `\dt`, `\dT`, `\du`, `\dv`, `\e`, `\echo`,
Expand Down Expand Up @@ -79,7 +79,7 @@ These match psql behaviour and must not be changed:
| `/session resume <id>` | reconnect using a saved session |
| `/refresh` | reload schema cache for tab completion |
| `/log-file <path>` | start logging queries (no arg = stop) |
| `/explain-share <service>` | upload last EXPLAIN plan to external visualiser |
| `/explain-share <service>` | upload last EXPLAIN plan to external visualizer |
| `/commands` | list custom Lua meta-commands |
| `/version` | show rpg version and build information |
| `/f2` | toggle schema-aware tab completion |
Expand Down
6 changes: 3 additions & 3 deletions docs/GLOSSARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ point.
- **Module** — anything with an interface and an implementation: a function, a struct + its `impl`, a file, a `mod`, a crate.
- **Interface** — everything a caller must know to use the module: signatures, invariants, error modes, ordering, configuration. Not just types.
- **Implementation** — the code inside the module.
- **Depth** — leverage at the interface: lots of behaviour behind a small interface.
- **Depth** — leverage at the interface: lots of behavior behind a small interface.
- **Deep module** — small interface, large implementation. High leverage.
- **Shallow module** — interface nearly as complex as the implementation. Low leverage; usually a pass-through.
- **Seam** — where an interface lives; a place behaviour can be altered without editing in place.
- **Seam** — where an interface lives; a place behavior can be altered without editing in place.
- **Adapter** — a concrete type satisfying an interface at a seam.
- **Leverage** — what callers gain from depth: terse, intent-shaped call sites.
- **Locality** — what maintainers gain from depth: change, bugs, knowledge concentrated in one place.
Expand Down Expand Up @@ -64,7 +64,7 @@ design discussion and PR descriptions.
- **Command Registry** — the table that maps a parsed `Command` to its handler. Replaces the two `match` statements in today's dispatchers.
- **`CommandCtx`** — proposed bundle of execution dependencies (`client`, `params`, `settings`, `tx`) passed to every handler. Single place to extend handler capabilities.
- **`MetaResult`** — the existing handler return enum (`Continue` / `Quit` / `Reconnected` / `ClearBuffer` / `PrintBuffer` / …). Stays.
- **Category** — grouping of commands for behaviours that vary across them: AI, DBA, session, output, conditional, …. The token-budget gate becomes a property of the category, not a hand-curated list.
- **Category** — grouping of commands for behaviors that vary across them: AI, DBA, session, output, conditional, …. The token-budget gate becomes a property of the category, not a hand-curated list.

## REPL state

Expand Down
18 changes: 9 additions & 9 deletions docs/WASM.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<!-- Copyright 2026 Nikolay Samokhvalov / postgres.ai -->
<!-- SPDX-License-Identifier: Apache-2.0 -->

# rpg WASM — Browser Build (Experimental)
# rpg WASM: browser build (experimental)

> **Status: Experimental.** The WASM build is functional for interactive SQL
> and most meta-commands, but some features are unavailable due to platform
> constraints (no filesystem, no shell, no ratatui). See
> [Known Limitations](#known-limitations) below.
> [Known limitations](#known-limitations) below.

Run rpg in the browser as a WebAssembly module. SQL queries, meta-commands,
and rpg diagnostics work against a real Postgres server via a WebSocket proxy.
Expand Down Expand Up @@ -37,7 +37,7 @@ protocol negotiation. Because the underlying `WsIo` type is `!Send`, the
connection driver runs on `wasm_bindgen_futures::spawn_local` instead of
`tokio::spawn`.

## Quick Start
## Quick start

### 1. Install prerequisites

Expand Down Expand Up @@ -86,7 +86,7 @@ cd wasm && python3 -m http.server 8080
Navigate to `http://localhost:8080`. Enter connection details in the toolbar
and click **Connect**.

## What Works
## What works

- **SQL queries** with psql-style tabular formatting (`\x` expanded mode supported)
- **Meta-commands:** `\d`, `\dt`, `\dn`, `\du`, `\di`, `\dv`, `\df`, `\l`, `\conninfo`, `\timing`, `\x`, `\set`, `\echo`, `\?`
Expand All @@ -95,10 +95,10 @@ and click **Connect**.
- **Line editing:** arrow keys, command history (Up/Down), Ctrl-U/K/W/L, Home/End, Delete, Backspace
- **Connection** to any Postgres 14-18 server via the WebSocket proxy

## Known Limitations
## Known limitations

Commands that require native OS facilities show a friendly error message
instead of panicking — e.g. `\i: file include is not available on
instead of panicking, for example `\i: file include is not available on
wasm32-unknown-unknown (no filesystem)`.

| Feature | Reason |
Expand All @@ -121,7 +121,7 @@ wasm32-unknown-unknown (no filesystem)`.
| AI commands (`/ask`, `/fix`, `/explain`, `/optimize`) | Require `reqwest` streaming, which is limited on WASM |
| Multi-statement command tags | When multiple statements are sent in one line, the command tag from the first is reused for subsequent ones (cosmetic, queries execute correctly) |

## Output Routing
## Output routing

Standard `println!` / `eprintln!` write to file descriptors 1 and 2, which are
sinks on `wasm32-unknown-unknown` (there is no OS). rpg uses custom macros to
Expand Down Expand Up @@ -169,11 +169,11 @@ invisible to native `cargo check` / `cargo test`.
`wasm/build-rpg-wasm.sh` automates the full build:

1. Installs `wasm-pack` if missing
2. Ensures `wasm32-unknown-unknown` target is added
2. Ensures the `wasm32-unknown-unknown` target is added
3. Runs `wasm-pack build --target web --release --features wasm`
4. Optionally runs `wasm-opt -Oz` (from binaryen) for size optimization

## WebSocket Proxy
## WebSocket proxy

`wasm/ws-proxy.js` is a Node.js process that bridges WebSocket connections from
the browser to a Postgres TCP socket. One TCP connection is created per
Expand Down
6 changes: 3 additions & 3 deletions docs/psql-compat.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

**222 of 232 PostgreSQL regression tests pass** (0 failures, 10 skipped) against a PostgreSQL 18 server; the skips are CI infrastructure limits or C extensions — not core compatibility issues.

For everyday use — queries, `\d` commands, scripts, `\copy`, REPL — rpg is a safe drop-in.
For everyday use — queries, `\d` commands, scripts, `\copy`, the REPL — rpg is a safe drop-in.

---

Expand Down Expand Up @@ -88,7 +88,7 @@ CI server: `postgres:18`. The `SKIP_ALWAYS` list in `tests/compat/test-psql-regr

### Describe commands (`\d` family)

All describe commands produce output byte-identical to psql.
All describe commands produce output byte-identical to psql's.

| Command | Status | Tested | Description |
|---------|--------|--------|-------------|
Expand Down Expand Up @@ -256,7 +256,7 @@ This is the other side of the compatibility story — rpg is a superset in these

### Command namespace

rpg uses `/` for all its own commands and `\` exclusively for psql-compatible metacommands. This makes it unambiguous which commands are standard and which are extensions. `\dba`, `\sql`, `\plan` etc. are deprecated aliases that still work but print a migration hint.
rpg uses `/` for all its own commands and `\` exclusively for psql-compatible metacommands. This makes it unambiguous which commands are standard and which are extensions. `\dba`, `\sql`, `\plan`, etc. are deprecated aliases that still work but print a migration hint.

---

Expand Down
2 changes: 1 addition & 1 deletion src/ash/sampler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,7 @@ mod tests {
match result.unwrap() {
LiveSnapshotResult::Ok(snap) => {
// Snapshot should have valid structure (counts may be 0).
assert!(snap.active_count == snap.by_type.values().sum::<u32>());
assert_eq!(snap.active_count, snap.by_type.values().sum::<u32>());
}
LiveSnapshotResult::Missed => {
panic!("unexpected Missed with timeout disabled");
Expand Down
2 changes: 1 addition & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2068,7 +2068,7 @@ protected_tables = ["users", "payments", "audit_log"]
// when we are outside the home directory tree.
if let Some(path) = found {
// A .rpg.toml exists somewhere above the temp dir — that is fine.
assert!(path.file_name().unwrap() == ".rpg.toml");
assert_eq!(path.file_name().unwrap(), ".rpg.toml");
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ struct Cli {
#[arg(long, value_name = "LEVEL")]
log_level: Option<String>,

/// Generate `rpg_ops` wrapper SQL and exit. Specify PG version (e.g. 14, 16).
/// Generate `rpg_ops` wrapper SQL and exit. Specify PG version (e.g., 14, 16).
#[arg(long, value_name = "PG_VERSION", default_missing_value = "16", num_args = 0..=1)]
generate_wrappers: Option<String>,

Expand Down
3 changes: 2 additions & 1 deletion wasm/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<head>
<meta charset="UTF-8">
<title>rpg — browser terminal</title>
<meta name="description" content="Run rpg, a psql-compatible Postgres terminal with built-in DBA diagnostics, in your browser as a WebAssembly module connected to a Postgres server through a WebSocket proxy.">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@xterm/xterm@5.5.0/css/xterm.css">
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
Expand Down Expand Up @@ -266,7 +267,7 @@
// Load the WASM module.
term.writeln('Loading rpg.wasm...');
await init();
term.writeln('rpg.wasm loaded. Press \x1b[36mConnect\x1b[0m to start.');
term.writeln('rpg.wasm loaded. Click \x1b[36mConnect\x1b[0m to start.');

connectBtn.addEventListener('click', async () => {
connectBtn.disabled = true;
Expand Down
Loading