pgserve 2.1.2 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +86 -0
- package/README.md +105 -1
- package/bin/autopg-wrapper.cjs +16 -0
- package/bin/pgserve-wrapper.cjs +31 -6
- package/bin/postgres-server.js +80 -7
- package/console/README.md +131 -0
- package/console/api.js +173 -0
- package/console/app.jsx +483 -0
- package/console/colors_and_type.css +227 -0
- package/console/components.jsx +167 -0
- package/console/console.css +1666 -0
- package/console/data.jsx +350 -0
- package/console/index.html +31 -0
- package/console/screens/databases.jsx +5 -0
- package/console/screens/health.jsx +5 -0
- package/console/screens/ingress.jsx +5 -0
- package/console/screens/optimizer.jsx +5 -0
- package/console/screens/rlm-sim.jsx +5 -0
- package/console/screens/rlm-trace.jsx +5 -0
- package/console/screens/security.jsx +5 -0
- package/console/screens/settings.jsx +611 -0
- package/console/screens/sql.jsx +5 -0
- package/console/screens/sync.jsx +5 -0
- package/console/screens/tables.jsx +5 -0
- package/console/tweaks-panel.jsx +425 -0
- package/package.json +11 -1
- package/src/cli-config.cjs +310 -0
- package/src/cli-install.cjs +98 -11
- package/src/cli-restart.cjs +228 -0
- package/src/cli-ui.cjs +580 -0
- package/src/cluster.js +43 -38
- package/src/postgres.js +141 -19
- package/src/settings-loader.cjs +235 -0
- package/src/settings-migrate.cjs +212 -0
- package/src/settings-pg-args.cjs +146 -0
- package/src/settings-schema.cjs +422 -0
- package/src/settings-validator.cjs +416 -0
- package/src/settings-writer.cjs +288 -0
- package/.claude/context/windows-debug.md +0 -119
- package/.genie/AGENTS.md +0 -15
- package/.genie/agents/README.md +0 -110
- package/.genie/agents/analyze.md +0 -176
- package/.genie/agents/forge.md +0 -290
- package/.genie/agents/garbage-cleaner.md +0 -324
- package/.genie/agents/garbage-collector.md +0 -596
- package/.genie/agents/github-issue-gc.md +0 -618
- package/.genie/agents/review.md +0 -380
- package/.genie/agents/semantic-analyzer/find-duplicates.md +0 -90
- package/.genie/agents/semantic-analyzer/find-orphans.md +0 -99
- package/.genie/agents/semantic-analyzer.md +0 -101
- package/.genie/agents/update.md +0 -182
- package/.genie/agents/wish.md +0 -357
- package/.genie/brainstorms/pgserve-v2/DESIGN.md +0 -174
- package/.genie/code/AGENTS.md +0 -694
- package/.genie/code/agents/audit/risk.md +0 -173
- package/.genie/code/agents/audit/security.md +0 -189
- package/.genie/code/agents/audit.md +0 -145
- package/.genie/code/agents/challenge.md +0 -230
- package/.genie/code/agents/change-reviewer.md +0 -295
- package/.genie/code/agents/code-garbage-collector.md +0 -425
- package/.genie/code/agents/code-quality.md +0 -410
- package/.genie/code/agents/commit-suggester.md +0 -255
- package/.genie/code/agents/commit.md +0 -124
- package/.genie/code/agents/consensus.md +0 -204
- package/.genie/code/agents/daily-standup.md +0 -722
- package/.genie/code/agents/docgen.md +0 -48
- package/.genie/code/agents/explore.md +0 -79
- package/.genie/code/agents/fix.md +0 -100
- package/.genie/code/agents/git/commit-advisory.md +0 -219
- package/.genie/code/agents/git/workflows/issue.md +0 -244
- package/.genie/code/agents/git/workflows/pr.md +0 -179
- package/.genie/code/agents/git/workflows/release.md +0 -460
- package/.genie/code/agents/git/workflows/report.md +0 -342
- package/.genie/code/agents/git.md +0 -432
- package/.genie/code/agents/implementor.md +0 -161
- package/.genie/code/agents/install.md +0 -515
- package/.genie/code/agents/issue-creator.md +0 -344
- package/.genie/code/agents/polish.md +0 -116
- package/.genie/code/agents/qa.md +0 -653
- package/.genie/code/agents/refactor.md +0 -294
- package/.genie/code/agents/release.md +0 -1129
- package/.genie/code/agents/roadmap.md +0 -885
- package/.genie/code/agents/tests.md +0 -557
- package/.genie/code/agents/tracer.md +0 -50
- package/.genie/code/agents/update/upstream-update.md +0 -85
- package/.genie/code/agents/update/versions/generic-update.md +0 -305
- package/.genie/code/agents/vibe.md +0 -1317
- package/.genie/code/spells/agent-configuration.md +0 -58
- package/.genie/code/spells/automated-rc-publishing.md +0 -106
- package/.genie/code/spells/branch-tracker-guidance.md +0 -28
- package/.genie/code/spells/debug.md +0 -320
- package/.genie/code/spells/emoji-naming-convention.md +0 -303
- package/.genie/code/spells/evidence-storage.md +0 -26
- package/.genie/code/spells/file-naming-rules.md +0 -35
- package/.genie/code/spells/forge-code-blueprints.md +0 -195
- package/.genie/code/spells/genie-integration.md +0 -153
- package/.genie/code/spells/publishing-protocol.md +0 -61
- package/.genie/code/spells/team-consultation-protocol.md +0 -284
- package/.genie/code/spells/tool-requirements.md +0 -20
- package/.genie/code/spells/triad-maintenance-protocol.md +0 -154
- package/.genie/code/teams/tech-council/council.md +0 -328
- package/.genie/code/teams/tech-council/jt.md +0 -352
- package/.genie/code/teams/tech-council/nayr.md +0 -305
- package/.genie/code/teams/tech-council/oettam.md +0 -375
- package/.genie/neurons/README.md +0 -193
- package/.genie/neurons/forge.md +0 -106
- package/.genie/neurons/genie.md +0 -63
- package/.genie/neurons/review.md +0 -106
- package/.genie/neurons/wish.md +0 -104
- package/.genie/product/README.md +0 -20
- package/.genie/product/cli-automation.md +0 -359
- package/.genie/product/environment.md +0 -60
- package/.genie/product/mission.md +0 -60
- package/.genie/product/roadmap.md +0 -44
- package/.genie/product/tech-stack.md +0 -34
- package/.genie/product/templates/context-template.md +0 -218
- package/.genie/product/templates/qa-done-report-template.md +0 -68
- package/.genie/product/templates/review-report-template.md +0 -89
- package/.genie/product/templates/wish-template.md +0 -120
- package/.genie/scripts/helpers/analyze-commit.js +0 -195
- package/.genie/scripts/helpers/bullet-counter.js +0 -194
- package/.genie/scripts/helpers/bullet-find.js +0 -289
- package/.genie/scripts/helpers/bullet-id.js +0 -244
- package/.genie/scripts/helpers/check-secrets.js +0 -237
- package/.genie/scripts/helpers/count-tokens.js +0 -200
- package/.genie/scripts/helpers/create-frontmatter.js +0 -456
- package/.genie/scripts/helpers/detect-markers.js +0 -293
- package/.genie/scripts/helpers/detect-todos.js +0 -267
- package/.genie/scripts/helpers/detect-unlabeled-blocks.js +0 -135
- package/.genie/scripts/helpers/embeddings.js +0 -344
- package/.genie/scripts/helpers/find-empty-sections.js +0 -158
- package/.genie/scripts/helpers/index.js +0 -319
- package/.genie/scripts/helpers/validate-frontmatter.js +0 -578
- package/.genie/scripts/helpers/validate-links.js +0 -207
- package/.genie/scripts/helpers/validate-paths.js +0 -373
- package/.genie/spells/README.md +0 -9
- package/.genie/spells/ace-protocol.md +0 -118
- package/.genie/spells/ask-one-at-a-time.md +0 -175
- package/.genie/spells/backup-analyzer.md +0 -542
- package/.genie/spells/blocker.md +0 -12
- package/.genie/spells/break-things-move-fast.md +0 -56
- package/.genie/spells/context-candidates.md +0 -72
- package/.genie/spells/context-critic.md +0 -51
- package/.genie/spells/defer-to-expertise.md +0 -278
- package/.genie/spells/delegate-dont-do.md +0 -292
- package/.genie/spells/error-investigation-protocol.md +0 -328
- package/.genie/spells/evidence-based-completion.md +0 -273
- package/.genie/spells/experiment.md +0 -65
- package/.genie/spells/file-creation-protocol.md +0 -229
- package/.genie/spells/forge-integration.md +0 -281
- package/.genie/spells/forge-orchestration.md +0 -514
- package/.genie/spells/gather-context.md +0 -18
- package/.genie/spells/global-health-check.md +0 -34
- package/.genie/spells/global-noop-roundtrip.md +0 -25
- package/.genie/spells/install-genie.md +0 -1232
- package/.genie/spells/install.md +0 -82
- package/.genie/spells/investigate-before-commit.md +0 -112
- package/.genie/spells/know-yourself.md +0 -288
- package/.genie/spells/learn.md +0 -828
- package/.genie/spells/mcp-diagnostic-protocol.md +0 -246
- package/.genie/spells/mcp-first.md +0 -124
- package/.genie/spells/multi-step-execution.md +0 -67
- package/.genie/spells/orchestration-boundary-protocol.md +0 -256
- package/.genie/spells/orchestrator-not-implementor.md +0 -189
- package/.genie/spells/prompt.md +0 -746
- package/.genie/spells/reflect.md +0 -404
- package/.genie/spells/routing-decision-matrix.md +0 -368
- package/.genie/spells/run-in-parallel.md +0 -12
- package/.genie/spells/session-state-updater-example.md +0 -196
- package/.genie/spells/session-state-updater.md +0 -220
- package/.genie/spells/track-long-running-tasks.md +0 -133
- package/.genie/spells/troubleshoot-infrastructure.md +0 -176
- package/.genie/spells/upgrade-genie.md +0 -415
- package/.genie/spells/url-presentation-protocol.md +0 -301
- package/.genie/spells/wish-initiation.md +0 -158
- package/.genie/spells/wish-issue-linkage.md +0 -410
- package/.genie/spells/wish-lifecycle.md +0 -100
- package/.genie/state/provider-status.json +0 -3
- package/.genie/state/version.json +0 -16
- package/.genie/wishes/canonical-pgserve-pm2-supervision/WISH.md +0 -290
- package/.genie/wishes/pgserve-v2/BRIEF-from-genie-pgserve.md +0 -99
- package/.genie/wishes/pgserve-v2/WISH.md +0 -442
- package/.genie/wishes/release-system-genie-pattern/WISH.md +0 -268
- package/.genie/wishes/release-system-genie-pattern/validation.md +0 -205
- package/.gitguardian.yaml +0 -29
- package/.gitguardianignore +0 -16
- package/.github/workflows/ci.yml +0 -122
- package/.github/workflows/release.yml +0 -289
- package/.github/workflows/version.yml +0 -228
- package/.husky/pre-commit +0 -2
- package/AGENTS.md +0 -433
- package/CLAUDE.md +0 -1
- package/Makefile +0 -285
- package/assets/icon.ico +0 -0
- package/bun.lock +0 -435
- package/bunfig.toml +0 -28
- package/ecosystem.config.cjs +0 -23
- package/eslint.config.js +0 -63
- package/examples/multi-tenant-demo.js +0 -104
- package/install.sh +0 -123
- package/knip.json +0 -9
- package/scripts/test-bun-self-heal.sh +0 -163
- package/scripts/test-npx.sh +0 -60
- package/tests/audit.test.js +0 -189
- package/tests/backpressure.test.js +0 -167
- package/tests/benchmarks/runner.js +0 -1197
- package/tests/benchmarks/vector-generator.js +0 -368
- package/tests/cli-install.test.js +0 -322
- package/tests/control-db.test.js +0 -285
- package/tests/daemon-control.test.js +0 -171
- package/tests/daemon-fingerprint-integration.test.js +0 -111
- package/tests/daemon-pr24-regression.test.js +0 -198
- package/tests/fingerprint.test.js +0 -263
- package/tests/fixtures/240-orphan-seed.sql +0 -30
- package/tests/multi-tenant.test.js +0 -374
- package/tests/orphan-cleanup.test.js +0 -390
- package/tests/pg-version-regex.test.js +0 -129
- package/tests/quick-bench.js +0 -135
- package/tests/router-handshake-retry.test.js +0 -119
- package/tests/router-handshake-watchdog.test.js +0 -110
- package/tests/sdk.test.js +0 -71
- package/tests/stale-postmaster-pid.test.js +0 -85
- package/tests/stress-test.js +0 -439
- package/tests/sync-perf-test.js +0 -150
- package/tests/tcp-listen.test.js +0 -368
- package/tests/tenancy.test.js +0 -403
- package/tests/wrapper-supervision.test.js +0 -107
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,92 @@ All notable changes to `pgserve` are documented here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres
|
|
5
5
|
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## Unreleased — autopg console settings
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Soft rename to `autopg`.** The npm package stays `pgserve` (no
|
|
12
|
+
`npm deprecate`); the package now also ships an `autopg` bin that
|
|
13
|
+
routes through the same dispatcher. Use either name interchangeably:
|
|
14
|
+
`autopg config list` and `pgserve config list` are byte-equivalent.
|
|
15
|
+
pm2 process name stays `pgserve` so existing supervised installs
|
|
16
|
+
upgrade cleanly with no migration step.
|
|
17
|
+
- **`~/.autopg/settings.json` (schema version 1).** Six sections —
|
|
18
|
+
`server`, `runtime`, `sync`, `supervision`, `postgres`, `ui` —
|
|
19
|
+
with a curated set of 15 PostgreSQL GUCs plus a `postgres._extra`
|
|
20
|
+
raw passthrough map. Every write is atomic (`tmp + rename`),
|
|
21
|
+
chmod 0600, and tagged with a sha256 etag for optimistic
|
|
22
|
+
concurrency control on the UI helper. Override the directory with
|
|
23
|
+
`AUTOPG_CONFIG_DIR`. See [`docs/settings-schema.md`](./docs/settings-schema.md)
|
|
24
|
+
for the full key reference.
|
|
25
|
+
- **`autopg config (list / get / set / edit / path / init)`** — manage
|
|
26
|
+
settings from the shell. `list` prints a `KEY VALUE SOURCE` table
|
|
27
|
+
showing where each leaf was resolved from (default / file / env).
|
|
28
|
+
`set` validates with a stable error format (`error: <field> — <CODE>:
|
|
29
|
+
<detail>`, exit code 2). Seven error codes: `INVALID_KEY`,
|
|
30
|
+
`INVALID_GUC_NAME`, `INVALID_GUC_VALUE`, `INVALID_TYPE`,
|
|
31
|
+
`OUT_OF_RANGE`, `READONLY`, `ETAG_MISMATCH`.
|
|
32
|
+
- **`autopg restart`** — pm2-aware. If the `pgserve` process appears
|
|
33
|
+
in `pm2 jlist`, calls `pm2 restart pgserve` (single-fire, respects
|
|
34
|
+
the hardened defaults registered at install time). Otherwise reads
|
|
35
|
+
the pidfile, sends SIGTERM, waits, and respawns the daemon
|
|
36
|
+
detached.
|
|
37
|
+
- **`autopg ui [--port N] [--no-open]`** — boots a local web console
|
|
38
|
+
on 127.0.0.1 (default port walk: 8433–8533). Single-user dev tool,
|
|
39
|
+
no auth, no TLS. Mounts four endpoints: `GET /api/settings` (returns
|
|
40
|
+
`{ settings, sources, etag }`), `PUT /api/settings` (requires
|
|
41
|
+
`If-Match`, returns 409 on stale etag), `POST /api/restart`,
|
|
42
|
+
`GET /api/status`. All handlers shell out to the CLI — the daemon
|
|
43
|
+
stays untouched, so the console works even with no daemon running.
|
|
44
|
+
- **Console scaffolding (`console/`).** React + Babel via CDN, no
|
|
45
|
+
build step. All 11 routes are registered; the **Settings** screen
|
|
46
|
+
is the first stateful one and renders the full 6-section schema
|
|
47
|
+
with type-aware controls, inline validation, an `OVERRIDDEN BY ENV`
|
|
48
|
+
chip on env-overridden rows, and an etag-mismatch reload banner.
|
|
49
|
+
The remaining 10 screens (Databases, Tables, SQL, Optimizer,
|
|
50
|
+
Security, Ingress, Health, Sync, RLM-trace, RLM-sim) render
|
|
51
|
+
`[ coming soon ]` placeholders — Health ships next.
|
|
52
|
+
- **Daemon now reads from settings.** `cluster.js` calls
|
|
53
|
+
`loadEffectiveConfig()` (env > file > defaults). `postgres.js`
|
|
54
|
+
emits `-c key=value` for every entry in `settings.postgres` and
|
|
55
|
+
`settings.postgres._extra`, with name regex (`^[a-z][a-z0-9_]*$`)
|
|
56
|
+
and scalar value validation enforced at boot — invalid GUCs are
|
|
57
|
+
dropped with a `logger.warn` so a typo in `_extra` doesn't crash
|
|
58
|
+
the daemon. Hardcoded `max_connections=1000` and the WAL
|
|
59
|
+
replication block (`wal_level=logical`,
|
|
60
|
+
`max_replication_slots=10`, `max_wal_senders=10`,
|
|
61
|
+
`wal_keep_size=512MB`) are now schema defaults — overridable
|
|
62
|
+
per-install via `autopg config set`.
|
|
63
|
+
- **`AUTOPG_*` env vars** as the new primary form. `PGSERVE_*` is
|
|
64
|
+
still honored at the daemon (one-time deprecation log per process
|
|
65
|
+
when `PGSERVE_*` is the only one set); `AUTOPG_*` wins on
|
|
66
|
+
conflict.
|
|
67
|
+
|
|
68
|
+
### Migrated
|
|
69
|
+
|
|
70
|
+
- **`~/.pgserve/` → `~/.autopg/` (one-shot, idempotent).** On first
|
|
71
|
+
run, if `~/.pgserve/` exists and `~/.autopg/` does not, the contents
|
|
72
|
+
are copied (preserving mtimes). A `MIGRATED-FROM-PGSERVE.md` marker
|
|
73
|
+
is dropped in the old directory so subsequent runs skip the copy
|
|
74
|
+
cleanly. If both directories exist, neither is touched and
|
|
75
|
+
`~/.autopg/` wins. No automatic merge.
|
|
76
|
+
|
|
77
|
+
### Notes for operators
|
|
78
|
+
|
|
79
|
+
- pm2 process name stays `pgserve`. Running `autopg install` on a
|
|
80
|
+
host that already has the legacy install is a no-op — pm2 sees the
|
|
81
|
+
same process name. Re-issue `pm2 save` if you want pm2 to persist
|
|
82
|
+
any settings changes through reboots.
|
|
83
|
+
- Local dev loop:
|
|
84
|
+
```bash
|
|
85
|
+
bun install && npm link && autopg install && autopg ui
|
|
86
|
+
```
|
|
87
|
+
Then edit `postgres.shared_buffers` in the UI, click Save & Restart,
|
|
88
|
+
and `psql -c "SHOW shared_buffers;"` reflects the new value.
|
|
89
|
+
- The npm package name is **not changing** — keep installing with
|
|
90
|
+
`npm install pgserve` (or `npx pgserve`); both `autopg` and
|
|
91
|
+
`pgserve` bins ship in the same tarball.
|
|
92
|
+
|
|
7
93
|
## 2.0.8
|
|
8
94
|
|
|
9
95
|
### Changed
|
package/README.md
CHANGED
|
@@ -37,6 +37,14 @@ psql postgresql://localhost:8432/myapp
|
|
|
37
37
|
|
|
38
38
|
> Note: v2 default is the Unix socket — see [Daemon mode](#daemon-mode). The TCP form above is the v1 compat path.
|
|
39
39
|
|
|
40
|
+
> **Naming.** The npm package stays `pgserve`. The CLI now also ships as
|
|
41
|
+
> `autopg` — both bins route to the same dispatcher. Use `autopg` for the
|
|
42
|
+
> new console (`autopg ui`) and configuration surface (`autopg config`,
|
|
43
|
+
> `autopg restart`); `pgserve <subcommand>` keeps working as a forever
|
|
44
|
+
> alias. Settings live at `~/.autopg/settings.json` and are migrated
|
|
45
|
+
> from `~/.pgserve/` automatically on first run. See
|
|
46
|
+
> [Console](#console-autopg-ui) and [Configuration](#configuration).
|
|
47
|
+
|
|
40
48
|
<br>
|
|
41
49
|
|
|
42
50
|
## Features
|
|
@@ -120,9 +128,25 @@ pgserve-windows-x64.exe --data C:\pgserve-data
|
|
|
120
128
|
|
|
121
129
|
## CLI Reference
|
|
122
130
|
|
|
131
|
+
`autopg` and `pgserve` are interchangeable — every subcommand routes
|
|
132
|
+
through the same dispatcher. Use whichever you prefer; new examples in
|
|
133
|
+
this README and in `console/` use `autopg`.
|
|
134
|
+
|
|
123
135
|
```
|
|
124
|
-
|
|
136
|
+
autopg [options] # foreground server (alias: pgserve)
|
|
137
|
+
autopg daemon # long-lived background daemon
|
|
138
|
+
autopg install [--port N] [--data P] # register pgserve under pm2
|
|
139
|
+
autopg uninstall # remove from pm2 (data dir kept)
|
|
140
|
+
autopg status # pm2 + on-disk config snapshot
|
|
141
|
+
autopg url | autopg port # canonical connection string / port
|
|
142
|
+
autopg config <list|get|set|edit|path|init> # manage ~/.autopg/settings.json
|
|
143
|
+
autopg restart # pm2-aware: pm2 restart pgserve, else SIGTERM+respawn
|
|
144
|
+
autopg ui [--port N] [--no-open] # local web console on 127.0.0.1
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Foreground options accepted by `autopg` / `pgserve` (no subcommand):
|
|
125
148
|
|
|
149
|
+
```
|
|
126
150
|
Options:
|
|
127
151
|
--port <number> PostgreSQL port (default: 8432)
|
|
128
152
|
--data <path> Data directory for persistence (default: in-memory)
|
|
@@ -351,6 +375,86 @@ agent state), not just for convenience.
|
|
|
351
375
|
|
|
352
376
|
<br>
|
|
353
377
|
|
|
378
|
+
## Console (`autopg ui`)
|
|
379
|
+
|
|
380
|
+
A local web console for inspecting and editing the running cluster.
|
|
381
|
+
Runs in-process via `node:http`, binds 127.0.0.1 only, single-user dev
|
|
382
|
+
tool — no auth, no TLS, never expose it.
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
autopg ui # walk 8433–8533 picking the first free port
|
|
386
|
+
autopg ui --port 8500 # bind exactly 8500
|
|
387
|
+
autopg ui --no-open # skip browser launch (CI / headless)
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
The first stateful screen — **Settings** — is functional today: it
|
|
391
|
+
renders the 6-section schema (server / runtime / sync / supervision /
|
|
392
|
+
postgres / ui), validates inline, and round-trips through
|
|
393
|
+
`~/.autopg/settings.json` with optimistic concurrency (sha256 etag +
|
|
394
|
+
`If-Match`). The other 10 screens (Databases, Tables, SQL, Optimizer,
|
|
395
|
+
Security, Ingress, Health, Sync, RLM-trace, RLM-sim) are scaffolded
|
|
396
|
+
as `[ coming soon ]` placeholders — Health ships next.
|
|
397
|
+
|
|
398
|
+
The UI shells out to the CLI for every mutation (`autopg config set`
|
|
399
|
+
under PUT, `autopg restart` under POST). The daemon stays untouched
|
|
400
|
+
— no HTTP API, no signal-based reload — so the console works even
|
|
401
|
+
when no daemon is running.
|
|
402
|
+
|
|
403
|
+
See [`console/README.md`](./console/README.md) for the local dev loop
|
|
404
|
+
and design-system source.
|
|
405
|
+
|
|
406
|
+
<br>
|
|
407
|
+
|
|
408
|
+
## Configuration
|
|
409
|
+
|
|
410
|
+
The CLI is the source of truth. Settings live at
|
|
411
|
+
`~/.autopg/settings.json` (override the directory with
|
|
412
|
+
`AUTOPG_CONFIG_DIR`; the legacy `PGSERVE_CONFIG_DIR` is still honored
|
|
413
|
+
and falls back to `~/.pgserve/`). Every write is atomic, chmod 0600,
|
|
414
|
+
and tagged with a sha256 etag for optimistic concurrency on the UI
|
|
415
|
+
helper's PUT path.
|
|
416
|
+
|
|
417
|
+
Schema sections (one per `~/.autopg/settings.json` top-level key):
|
|
418
|
+
|
|
419
|
+
| Section | Purpose |
|
|
420
|
+
|---------|---------|
|
|
421
|
+
| `server` | Router port/host, backend socket, superuser credentials |
|
|
422
|
+
| `runtime` | Log level, auto-provision, pgvector, data dir |
|
|
423
|
+
| `sync` | WAL-based logical replication toggle |
|
|
424
|
+
| `supervision` | pm2 hardening defaults (memory, restart, kill timeout) |
|
|
425
|
+
| `postgres` | 15 curated GUCs (`shared_buffers`, `wal_level`, …) + `_extra` raw passthrough |
|
|
426
|
+
| `ui` | Console theme / phosphor / density / CRT toggle |
|
|
427
|
+
|
|
428
|
+
```bash
|
|
429
|
+
autopg config init # write defaults
|
|
430
|
+
autopg config list # KEY VALUE SOURCE table
|
|
431
|
+
autopg config get postgres.shared_buffers # machine-friendly value
|
|
432
|
+
autopg config set postgres.shared_buffers 256MB # validates + atomic write
|
|
433
|
+
autopg config edit # opens $EDITOR on settings.json
|
|
434
|
+
autopg config path # absolute path (honors AUTOPG_CONFIG_DIR)
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
**Precedence:** `default < file < env`. `AUTOPG_*` env vars beat
|
|
438
|
+
`PGSERVE_*` (the legacy form is still honored with a one-time
|
|
439
|
+
deprecation log per process, so existing operators keep working).
|
|
440
|
+
The console shows a yellow `OVERRIDDEN BY ENV` chip on rows whose
|
|
441
|
+
env var is currently set.
|
|
442
|
+
|
|
443
|
+
**GUC passthrough:** `postgres._extra` is a free-form `{ gucName: scalar }`
|
|
444
|
+
map for any PostgreSQL setting outside the curated 15. Names must match
|
|
445
|
+
`^[a-z][a-z0-9_]*$`; values must be string / number / boolean (no
|
|
446
|
+
newlines, no leading `-`). Both layers are revalidated at boot, so a
|
|
447
|
+
typo logs a `logger.warn` and is dropped — postgres still starts.
|
|
448
|
+
|
|
449
|
+
**One-shot migration:** on first run, if `~/.pgserve/` exists and
|
|
450
|
+
`~/.autopg/` does not, the contents are copied (preserving mtimes)
|
|
451
|
+
and a `MIGRATED-FROM-PGSERVE.md` marker is dropped in the old dir.
|
|
452
|
+
Idempotent — second run is a no-op.
|
|
453
|
+
|
|
454
|
+
Full schema reference: [`docs/settings-schema.md`](./docs/settings-schema.md).
|
|
455
|
+
|
|
456
|
+
<br>
|
|
457
|
+
|
|
354
458
|
## Compat TCP via `--listen`
|
|
355
459
|
|
|
356
460
|
TCP is **off by default** in v2. Bring it back only when you need it
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* autopg wrapper — primary CLI bin name post soft-rename.
|
|
4
|
+
*
|
|
5
|
+
* autopg and pgserve route through the same dispatcher. The package
|
|
6
|
+
* stays published as `pgserve` on npm; this wrapper is the new
|
|
7
|
+
* preferred command, with `pgserve` retained as a forever alias.
|
|
8
|
+
*
|
|
9
|
+
* Implementation: delegate to pgserve-wrapper.cjs so dispatch logic
|
|
10
|
+
* stays single-sourced. argv[0]/argv[1] preservation is what matters
|
|
11
|
+
* for the inner module — node already wires argv correctly when
|
|
12
|
+
* require()'d at module load time, and the wrapper inspects
|
|
13
|
+
* process.argv directly.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
require('./pgserve-wrapper.cjs');
|
package/bin/pgserve-wrapper.cjs
CHANGED
|
@@ -29,14 +29,39 @@ const fs = require('fs');
|
|
|
29
29
|
// sees the original `daemon` token.
|
|
30
30
|
// ────────────────────────────────────────────────────────────────────────
|
|
31
31
|
const __subcommand = process.argv[2];
|
|
32
|
-
const __installSubcommands = new Set([
|
|
32
|
+
const __installSubcommands = new Set([
|
|
33
|
+
'install',
|
|
34
|
+
'uninstall',
|
|
35
|
+
'status',
|
|
36
|
+
'url',
|
|
37
|
+
'port',
|
|
38
|
+
// autopg-console-settings (Group 2): config / restart / ui are pure node
|
|
39
|
+
// wrappers that read/write `~/.autopg/settings.json` (and shell out to
|
|
40
|
+
// pm2 for restart). They don't need bun, so route them BEFORE the bun
|
|
41
|
+
// probe — same rationale as the wave-1 install commands.
|
|
42
|
+
'config',
|
|
43
|
+
'restart',
|
|
44
|
+
'ui',
|
|
45
|
+
]);
|
|
33
46
|
if (__subcommand && __installSubcommands.has(__subcommand)) {
|
|
34
47
|
const cli = require(path.join(__dirname, '..', 'src', 'cli-install.cjs'));
|
|
35
|
-
process.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
const result = cli.dispatch(__subcommand, process.argv.slice(3), {
|
|
49
|
+
scriptPath: path.join(__dirname, 'postgres-server.js'),
|
|
50
|
+
wrapperPath: __filename,
|
|
51
|
+
});
|
|
52
|
+
// `ui` returns a Promise that never resolves (the server parks on
|
|
53
|
+
// signals). Other subcommands return a number directly. Handle both.
|
|
54
|
+
if (result && typeof result.then === 'function') {
|
|
55
|
+
result.then(
|
|
56
|
+
(code) => process.exit(typeof code === 'number' ? code : 0),
|
|
57
|
+
(err) => {
|
|
58
|
+
process.stderr.write(`pgserve: ${err?.message ?? err}\n`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
process.exit(typeof result === 'number' ? result : 0);
|
|
40
65
|
}
|
|
41
66
|
if (__subcommand === 'serve') {
|
|
42
67
|
// Alias `serve` → `daemon` so the wish's canonical command name maps
|
package/bin/postgres-server.js
CHANGED
|
@@ -12,6 +12,7 @@ import path from 'path';
|
|
|
12
12
|
import os from 'os';
|
|
13
13
|
import { startMultiTenantServer } from '../src/index.js';
|
|
14
14
|
import { startClusterServer } from '../src/cluster.js';
|
|
15
|
+
import { loadEffectiveConfig as loadAutopgConfig } from '../src/settings-loader.cjs';
|
|
15
16
|
import {
|
|
16
17
|
PgserveDaemon,
|
|
17
18
|
stopDaemon,
|
|
@@ -132,6 +133,7 @@ function parseDaemonArgs(daemonArgs) {
|
|
|
132
133
|
autoProvision: true,
|
|
133
134
|
tcpListens: [],
|
|
134
135
|
enablePgvector: false,
|
|
136
|
+
maxConnections: null,
|
|
135
137
|
};
|
|
136
138
|
for (let i = 0; i < daemonArgs.length; i++) {
|
|
137
139
|
const arg = daemonArgs[i];
|
|
@@ -156,6 +158,21 @@ function parseDaemonArgs(daemonArgs) {
|
|
|
156
158
|
case '--pgvector':
|
|
157
159
|
opts.enablePgvector = true;
|
|
158
160
|
break;
|
|
161
|
+
case '--max-connections': {
|
|
162
|
+
// Accept the same flag the foreground/router mode takes so callers
|
|
163
|
+
// (genie's `getOrStartDaemon`, anything that spawns `pgserve daemon`
|
|
164
|
+
// with a tuned cap) can override the postmaster's `max_connections`.
|
|
165
|
+
// The `PgserveDaemon` constructor already honors `options.maxConnections`
|
|
166
|
+
// (see src/daemon.js — defaults to 1000); we just plumb it through.
|
|
167
|
+
const raw = daemonArgs[++i];
|
|
168
|
+
const parsed = Number.parseInt(raw, 10);
|
|
169
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
170
|
+
console.error(`--max-connections: expected a positive integer, got "${raw}"`);
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
opts.maxConnections = parsed;
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
159
176
|
case '--help':
|
|
160
177
|
console.log(`
|
|
161
178
|
pgserve daemon — singleton control-socket mode
|
|
@@ -167,13 +184,14 @@ USAGE:
|
|
|
167
184
|
pgserve daemon revoke-token <id>
|
|
168
185
|
|
|
169
186
|
OPTIONS:
|
|
170
|
-
--data <path>
|
|
171
|
-
--ram
|
|
172
|
-
--log <level>
|
|
173
|
-
--no-provision
|
|
174
|
-
--listen [host:]port
|
|
175
|
-
--pgvector
|
|
176
|
-
--
|
|
187
|
+
--data <path> Persistent data directory (default: in-memory)
|
|
188
|
+
--ram Use /dev/shm storage (Linux only)
|
|
189
|
+
--log <level> Log level: error|warn|info|debug (default: info)
|
|
190
|
+
--no-provision Disable auto-provisioning of databases
|
|
191
|
+
--listen [host:]port Bind opt-in TCP listener (repeatable)
|
|
192
|
+
--pgvector Auto-enable pgvector extension on new databases
|
|
193
|
+
--max-connections <n> Override the postmaster's max_connections (default: 1000)
|
|
194
|
+
--help Show this help
|
|
177
195
|
|
|
178
196
|
The daemon binds $XDG_RUNTIME_DIR/pgserve/control.sock (fallback /tmp/pgserve/control.sock).
|
|
179
197
|
A second invocation while the first is running exits with "already running".
|
|
@@ -370,8 +388,60 @@ FEATURES:
|
|
|
370
388
|
`);
|
|
371
389
|
}
|
|
372
390
|
|
|
391
|
+
/**
|
|
392
|
+
* Pull daemon options from ~/.autopg/settings.json (with env overlay).
|
|
393
|
+
* Returns a partial options patch — only keys that are present in the
|
|
394
|
+
* settings file or env override the hardcoded defaults. CLI flags layer
|
|
395
|
+
* on top of this in parseArgs().
|
|
396
|
+
*
|
|
397
|
+
* Failures (missing file, bad JSON) fall through to defaults silently —
|
|
398
|
+
* the daemon must remain runnable on a brand-new install before
|
|
399
|
+
* `autopg config init` has been called.
|
|
400
|
+
*/
|
|
401
|
+
function loadSettingsOverlay() {
|
|
402
|
+
try {
|
|
403
|
+
const cpuCount = os.cpus().length;
|
|
404
|
+
const isWindows = os.platform() === 'win32';
|
|
405
|
+
const { settings } = loadAutopgConfig();
|
|
406
|
+
const s = settings.server || {};
|
|
407
|
+
const r = settings.runtime || {};
|
|
408
|
+
const sy = settings.sync || {};
|
|
409
|
+
const pg = settings.postgres || {};
|
|
410
|
+
const overlay = {};
|
|
411
|
+
if (typeof s.port === 'number') overlay.port = s.port;
|
|
412
|
+
if (typeof s.host === 'string' && s.host) overlay.host = s.host;
|
|
413
|
+
if (typeof r.dataDir === 'string' && r.dataDir) overlay.dataDir = r.dataDir;
|
|
414
|
+
if (typeof r.ramMode === 'boolean') overlay.useRam = r.ramMode;
|
|
415
|
+
if (typeof r.logLevel === 'string' && r.logLevel) overlay.logLevel = r.logLevel;
|
|
416
|
+
if (typeof r.autoProvision === 'boolean') overlay.autoProvision = r.autoProvision;
|
|
417
|
+
if (typeof r.cluster === 'string') {
|
|
418
|
+
overlay.cluster = r.cluster === 'auto'
|
|
419
|
+
? (cpuCount > 1 && !isWindows)
|
|
420
|
+
: r.cluster === 'on';
|
|
421
|
+
}
|
|
422
|
+
if (typeof r.workers === 'number' && r.workers > 0) overlay.workers = r.workers;
|
|
423
|
+
if (typeof r.statsDashboard === 'boolean') overlay.showStats = r.statsDashboard;
|
|
424
|
+
if (typeof r.enablePgvector === 'boolean') overlay.enablePgvector = r.enablePgvector;
|
|
425
|
+
if (sy.enabled && typeof sy.url === 'string' && sy.url) overlay.syncTo = sy.url;
|
|
426
|
+
if (sy.enabled && typeof sy.databases === 'string' && sy.databases) overlay.syncDatabases = sy.databases;
|
|
427
|
+
// pgserve-side connection cap mirrors the postgres GUC unless the user
|
|
428
|
+
// has explicitly diverged via CLI flag (handled in parseArgs).
|
|
429
|
+
if (typeof pg.max_connections === 'number') overlay.maxConnections = pg.max_connections;
|
|
430
|
+
return overlay;
|
|
431
|
+
} catch {
|
|
432
|
+
// First run, no settings.json yet, or file parse error. Hardcoded
|
|
433
|
+
// defaults still produce a working daemon — nothing to do here.
|
|
434
|
+
return {};
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
373
438
|
/**
|
|
374
439
|
* Parse command line arguments
|
|
440
|
+
*
|
|
441
|
+
* Precedence (lowest → highest):
|
|
442
|
+
* 1. hardcoded defaults
|
|
443
|
+
* 2. ~/.autopg/settings.json (with env overlay via loadEffectiveConfig)
|
|
444
|
+
* 3. CLI flags ← explicit user intent always wins
|
|
375
445
|
*/
|
|
376
446
|
function parseArgs() {
|
|
377
447
|
// Auto-enable cluster mode on multi-core systems for best performance
|
|
@@ -395,6 +465,9 @@ function parseArgs() {
|
|
|
395
465
|
enablePgvector: false // Auto-enable pgvector extension on new databases
|
|
396
466
|
};
|
|
397
467
|
|
|
468
|
+
// Layer settings.json + env on top of defaults. CLI flags below win.
|
|
469
|
+
Object.assign(options, loadSettingsOverlay());
|
|
470
|
+
|
|
398
471
|
for (let i = 0; i < args.length; i++) {
|
|
399
472
|
const arg = args[i];
|
|
400
473
|
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# `console/` — autopg console
|
|
2
|
+
|
|
3
|
+
Local web console served by `autopg ui`. React + Babel via CDN, no build
|
|
4
|
+
step. Single-user dev tool — binds 127.0.0.1 only, no auth, no TLS.
|
|
5
|
+
|
|
6
|
+
## Run
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
autopg ui # walks 8433–8533 picking the first free port
|
|
10
|
+
autopg ui --port 8500 # bind exactly 8500 or fail
|
|
11
|
+
autopg ui --no-open # skip browser launch (CI / headless)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`pgserve ui …` is a forever alias of the same command.
|
|
15
|
+
|
|
16
|
+
The server boots in-process via `node:http` and serves this directory as
|
|
17
|
+
its document root. Four helper endpoints are mounted alongside the static
|
|
18
|
+
assets — every mutation shells out to the CLI rather than calling the
|
|
19
|
+
daemon directly, so the console works with or without a running daemon.
|
|
20
|
+
|
|
21
|
+
| Endpoint | Backed by |
|
|
22
|
+
|----------|-----------|
|
|
23
|
+
| `GET /api/settings` | `loadEffectiveConfig()` → `{ settings, sources, etag }` |
|
|
24
|
+
| `PUT /api/settings` | `writeSettings(body, { ifMatch })` (409 on stale `If-Match`) |
|
|
25
|
+
| `POST /api/restart` | `cli-restart.cjs` (pm2-aware) |
|
|
26
|
+
| `GET /api/status` | shells out to `autopg status --json` |
|
|
27
|
+
|
|
28
|
+
## Layout
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
console/
|
|
32
|
+
├── README.md # this file
|
|
33
|
+
├── index.html # entry — pinned React + Babel CDN scripts
|
|
34
|
+
├── app.jsx # shell + sidebar router (11 routes)
|
|
35
|
+
├── api.js # fetch wrapper, holds latest etag, surfaces ETAG_MISMATCH
|
|
36
|
+
├── components.jsx # shared widgets (Seg, Toggle, Field, …)
|
|
37
|
+
├── data.jsx # demo data fixtures (used by placeholder screens)
|
|
38
|
+
├── tweaks-panel.jsx # theme/phosphor/density/CRT toggles (persists to settings.ui)
|
|
39
|
+
├── colors_and_type.css # design tokens
|
|
40
|
+
├── console.css # layout + screen styles
|
|
41
|
+
└── screens/
|
|
42
|
+
├── settings.jsx # ✅ functional — 6-section schema editor
|
|
43
|
+
├── databases.jsx # [ coming soon ]
|
|
44
|
+
├── tables.jsx # [ coming soon ]
|
|
45
|
+
├── sql.jsx # [ coming soon ]
|
|
46
|
+
├── optimizer.jsx # [ coming soon ]
|
|
47
|
+
├── security.jsx # [ coming soon ]
|
|
48
|
+
├── ingress.jsx # [ coming soon ]
|
|
49
|
+
├── health.jsx # [ coming soon ] — next wish
|
|
50
|
+
├── sync.jsx # [ coming soon ]
|
|
51
|
+
├── rlm-trace.jsx # [ coming soon ]
|
|
52
|
+
└── rlm-sim.jsx # [ coming soon ]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Screen rollout
|
|
56
|
+
|
|
57
|
+
| Screen | Status | Notes |
|
|
58
|
+
|--------|--------|-------|
|
|
59
|
+
| Settings | ✅ functional | 6 sections, type-aware controls, raw GUC passthrough, etag concurrency, env-override chip |
|
|
60
|
+
| Health | 🟡 next | Live cluster health metrics — next wish |
|
|
61
|
+
| Databases | ⚪ placeholder | List + create + drop |
|
|
62
|
+
| Tables | ⚪ placeholder | Per-DB table inspector |
|
|
63
|
+
| SQL | ⚪ placeholder | Ad-hoc query runner |
|
|
64
|
+
| Optimizer | ⚪ placeholder | Plan inspector / GUC tuner suggestions |
|
|
65
|
+
| Security | ⚪ placeholder | Roles, RLS, audit log |
|
|
66
|
+
| Ingress | ⚪ placeholder | Listener / TLS / token surface |
|
|
67
|
+
| Sync | ⚪ placeholder | Replication-slot status |
|
|
68
|
+
| RLM-trace | ⚪ placeholder | RLM agent trace viewer (depends on rlmx) |
|
|
69
|
+
| RLM-sim | ⚪ placeholder | RLM scenario simulator (depends on rlmx) |
|
|
70
|
+
|
|
71
|
+
## Local dev loop
|
|
72
|
+
|
|
73
|
+
The console is shipped as static files — no build, no bundler. Edit the
|
|
74
|
+
`.jsx` files in place; refresh the browser tab to pick up the change
|
|
75
|
+
(Babel transpiles in the browser at load time). The CDN scripts are
|
|
76
|
+
pinned with SRI integrity hashes — bumping React or Babel requires
|
|
77
|
+
re-pinning the matching `integrity="sha384-…"` attribute in
|
|
78
|
+
[`index.html`](./index.html).
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
autopg ui --no-open --port 8500 &
|
|
82
|
+
open http://127.0.0.1:8500
|
|
83
|
+
# … edit screens/settings.jsx, refresh browser …
|
|
84
|
+
kill %1
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The Settings screen reads live state from `~/.autopg/settings.json`
|
|
88
|
+
through the helper endpoints, so changes survive reload and round-trip
|
|
89
|
+
through `autopg config get` from another shell.
|
|
90
|
+
|
|
91
|
+
### Concurrency model
|
|
92
|
+
|
|
93
|
+
`api.js` stores the etag returned by every successful GET and sends it
|
|
94
|
+
back as `If-Match` on the next PUT. If a parallel `autopg config set` (or
|
|
95
|
+
another browser tab) drifts the file, the PUT comes back as
|
|
96
|
+
`409 ETAG_MISMATCH` with a fresh `currentEtag`. The Settings screen
|
|
97
|
+
catches this and shows a "settings changed, reload?" banner instead of
|
|
98
|
+
overwriting the operator's other changes.
|
|
99
|
+
|
|
100
|
+
### Env-override chip
|
|
101
|
+
|
|
102
|
+
`GET /api/settings` returns a `sources` map (one entry per leaf:
|
|
103
|
+
`'default' | 'file' | 'env:<NAME>'`). Rows whose source starts with
|
|
104
|
+
`env:` render a yellow `OVERRIDDEN BY ENV` chip — Save still writes the
|
|
105
|
+
file, but `loadEffectiveConfig()` will keep returning the env value
|
|
106
|
+
until the env var is unset or the daemon is restarted with a clean
|
|
107
|
+
environment.
|
|
108
|
+
|
|
109
|
+
## Design system
|
|
110
|
+
|
|
111
|
+
The console UI is derived from the `pgserve-console` design kit at
|
|
112
|
+
`namastex-design-system/ui_kits/pgserve-console`. The CSS files
|
|
113
|
+
(`colors_and_type.css`, `console.css`) and the shared widgets
|
|
114
|
+
(`components.jsx`, `tweaks-panel.jsx`) are copied verbatim — the
|
|
115
|
+
soft rename only touches the topbar identity (`pgserve` → `autopg`)
|
|
116
|
+
and the Settings screen, which was rewritten to match the
|
|
117
|
+
6-section schema documented in
|
|
118
|
+
[`docs/settings-schema.md`](../docs/settings-schema.md).
|
|
119
|
+
|
|
120
|
+
## What's deliberately not here
|
|
121
|
+
|
|
122
|
+
- **No build step.** Pre-bundling is a future optimization. The CDN +
|
|
123
|
+
Babel-in-browser path is intentional for v1 — zero infrastructure.
|
|
124
|
+
- **No daemon HTTP API.** The CLI is the source of truth; every UI
|
|
125
|
+
mutation shells out. This means the UI works ahead of `autopg
|
|
126
|
+
install` (you can configure before the daemon ever runs) and
|
|
127
|
+
cannot leak privileges through a long-lived listening socket.
|
|
128
|
+
- **No multi-user / multi-machine access.** 127.0.0.1 only, by
|
|
129
|
+
design.
|
|
130
|
+
- **No telemetry, no analytics.** Static page + four endpoints, all
|
|
131
|
+
local.
|