@polterware/polterbase 0.1.2

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.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +283 -0
  3. package/dist/index.js +225 -0
  4. package/package.json +55 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Polterware
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,283 @@
1
+ # @polterware/polterbase
2
+
3
+ [![npm version](https://img.shields.io/npm/v/%40polterware%2Fpolterbase.svg)](https://www.npmjs.com/package/@polterware/polterbase)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Node.js](https://img.shields.io/badge/Node.js-18%2B-green.svg)](https://nodejs.org/)
6
+
7
+ An optimized interactive CLI for managing Supabase CLI workflows with more speed, consistency, and discoverability.
8
+
9
+ Polterbase is a productivity layer on top of the official `supabase` CLI. Instead of memorizing command trees, you choose categories, build commands interactively, attach global flags, and pin common workflows for one-click reuse.
10
+
11
+ ## Features
12
+
13
+ - **Interactive Command Builder**: Guided flow for command + subcommand + extra args
14
+ - **Supabase Command Discovery**: Organized by practical categories
15
+ - **Global Flags Picker**: Add common global flags in one step
16
+ - **Pinned Commands**: Save successful command combinations for faster repetition
17
+ - **Custom Command Mode**: Run raw Supabase arguments like `-v` or `status -o json`
18
+ - **Shell Execution**: Executes your local `supabase` binary directly
19
+ - **TypeScript-based CLI**: Strongly typed internal implementation
20
+
21
+ ---
22
+
23
+ ## Installation
24
+
25
+ ### Run without installing globally
26
+
27
+ ```bash
28
+ npx @polterware/polterbase
29
+ ```
30
+
31
+ ### Install globally
32
+
33
+ ```bash
34
+ npm install -g @polterware/polterbase
35
+ ```
36
+
37
+ Then run:
38
+
39
+ ```bash
40
+ polterbase
41
+ ```
42
+
43
+ `polterbase` is a global CLI tool. Do not add it to `dependencies` or `devDependencies` of app projects.
44
+
45
+ ---
46
+
47
+ ## Requirements
48
+
49
+ - **Node.js**: `>= 18`
50
+ - **Supabase CLI**: installed and available in `PATH`
51
+
52
+ Check your environment:
53
+
54
+ ```bash
55
+ node -v
56
+ supabase --version
57
+ ```
58
+
59
+ Install Supabase CLI (official docs):
60
+
61
+ - [Supabase CLI Guide](https://supabase.com/docs/guides/cli)
62
+
63
+ ---
64
+
65
+ ## Quick Reference
66
+
67
+ ### Execution Model
68
+
69
+ Polterbase always executes commands as:
70
+
71
+ ```bash
72
+ supabase <command> <extra-args> <global-flags>
73
+ ```
74
+
75
+ ### Typical Flow
76
+
77
+ 1. Choose a category
78
+ 2. Choose a base command
79
+ 3. Add optional extra args
80
+ 4. Pick optional global flags
81
+ 5. Confirm and execute
82
+ 6. Optionally pin command after success
83
+
84
+ ---
85
+
86
+ ## Command Categories
87
+
88
+ ### Quick Start
89
+
90
+ - `bootstrap` - Bootstrap a Supabase project from a starter template
91
+
92
+ ### Local Development
93
+
94
+ - `db` - Manage Postgres databases
95
+ - `gen` - Run code generation tools
96
+ - `init` - Initialize a local project
97
+ - `inspect` - Inspect Supabase project resources
98
+ - `link` - Link local project to remote Supabase project
99
+ - `login` - Authenticate with Supabase access token
100
+ - `logout` - Remove local auth token
101
+ - `migration` - Manage migration scripts
102
+ - `seed` - Seed project from `supabase/config.toml`
103
+ - `services` - Show local service versions
104
+ - `start` - Start local Supabase containers
105
+ - `status` - Show local container status
106
+ - `stop` - Stop local Supabase containers
107
+ - `test` - Run tests against local stack
108
+ - `unlink` - Unlink local project
109
+
110
+ ### Management APIs
111
+
112
+ - `backups`
113
+ - `branches`
114
+ - `config`
115
+ - `domains`
116
+ - `encryption`
117
+ - `functions`
118
+ - `network-bans`
119
+ - `network-restrictions`
120
+ - `orgs`
121
+ - `postgres-config`
122
+ - `projects`
123
+ - `secrets`
124
+ - `snippets`
125
+ - `ssl-enforcement`
126
+ - `sso`
127
+ - `storage`
128
+ - `vanity-subdomains`
129
+
130
+ ### Additional Commands
131
+
132
+ - `completion` - Generate shell completion script
133
+ - `help` - Show Supabase command help
134
+
135
+ ### Custom Command / Check Version
136
+
137
+ Use this mode for free-form args like:
138
+
139
+ - `-v`
140
+ - `status -o json`
141
+ - `db pull`
142
+ - `projects list`
143
+
144
+ ---
145
+
146
+ ## Global Flags
147
+
148
+ Available global flags in the interactive selector:
149
+
150
+ - `--create-ticket` - Create support ticket on error
151
+ - `--debug` - Enable debug logs
152
+ - `--experimental` - Enable experimental features
153
+ - `--yes` - Auto-confirm prompts
154
+
155
+ ---
156
+
157
+ ## Pinned Commands
158
+
159
+ After a successful execution, Polterbase can pin the command for quick reuse.
160
+
161
+ Pinned items appear at the top of the main menu and can be removed via:
162
+
163
+ - `Manage Pinned Commands`
164
+
165
+ Pins are persisted locally using OS-level app config storage.
166
+
167
+ ---
168
+
169
+ ## Usage Examples
170
+
171
+ ### Check Supabase CLI version
172
+
173
+ Interactive path:
174
+
175
+ 1. `Custom Command / Check Version`
176
+ 2. Input: `-v`
177
+
178
+ Executed command:
179
+
180
+ ```bash
181
+ supabase -v
182
+ ```
183
+
184
+ ### Start local stack with debug
185
+
186
+ Interactive path:
187
+
188
+ 1. `Local Development`
189
+ 2. Command: `start`
190
+ 3. Extra args: none
191
+ 4. Flags: `--debug`
192
+
193
+ Executed command:
194
+
195
+ ```bash
196
+ supabase start --debug
197
+ ```
198
+
199
+ ### List projects
200
+
201
+ Interactive path:
202
+
203
+ 1. `Management APIs`
204
+ 2. Command: `projects`
205
+ 3. Extra args: `list`
206
+
207
+ Executed command:
208
+
209
+ ```bash
210
+ supabase projects list
211
+ ```
212
+
213
+ ### Run DB pull and auto-confirm prompts
214
+
215
+ Interactive path:
216
+
217
+ 1. `Local Development`
218
+ 2. Command: `db`
219
+ 3. Extra args: `pull`
220
+ 4. Flags: `--yes`
221
+
222
+ Executed command:
223
+
224
+ ```bash
225
+ supabase db pull --yes
226
+ ```
227
+
228
+ ---
229
+
230
+ ## Troubleshooting
231
+
232
+ ### `supabase: command not found`
233
+
234
+ Supabase CLI is not installed or not in your `PATH`.
235
+
236
+ Fix:
237
+
238
+ 1. Install Supabase CLI
239
+ 2. Restart terminal
240
+ 3. Run `supabase --version`
241
+
242
+ ### Command exits with non-zero code
243
+
244
+ Polterbase forwards execution to Supabase CLI. Use `--debug` and re-run to inspect detailed logs.
245
+
246
+ ### Pinned commands are missing
247
+
248
+ Pins are only suggested after successful runs. Confirm the pin prompt after a successful command.
249
+
250
+ ### Interactive prompt did not open correctly
251
+
252
+ Ensure you are running in a terminal that supports interactive TTY prompts.
253
+
254
+ ---
255
+
256
+ ## Security Notes
257
+
258
+ - Polterbase executes local shell commands through your installed Supabase CLI.
259
+ - Keep Supabase tokens out of shared shells and CI logs.
260
+ - Prefer short-lived tokens and least-privileged project access.
261
+
262
+ ---
263
+
264
+ ## Contributing
265
+
266
+ 1. Fork the repository
267
+ 2. Create a feature branch
268
+ 3. Commit changes with clear messages
269
+ 4. Open a pull request
270
+
271
+ Repository:
272
+
273
+ - [polterware/polterbase](https://github.com/polterware/polterbase)
274
+
275
+ ---
276
+
277
+ ## License
278
+
279
+ MIT License - see the [LICENSE](LICENSE) file for details.
280
+
281
+ ## Author
282
+
283
+ [Polterware](https://www.polterware.com)
package/dist/index.js ADDED
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import * as p from "@clack/prompts";
5
+ import pc from "picocolors";
6
+ import { spawn } from "child_process";
7
+ import Conf from "conf";
8
+ var config = new Conf({ projectName: "polterbase" });
9
+ var supabaseCommands = {
10
+ "Quick Start": [
11
+ { value: "bootstrap", label: "bootstrap - Bootstrap a Supabase project from a starter template" }
12
+ ],
13
+ "Local Development": [
14
+ { value: "db", label: "db - Manage Postgres databases" },
15
+ { value: "gen", label: "gen - Run code generation tools" },
16
+ { value: "init", label: "init - Initialize a local project" },
17
+ { value: "inspect", label: "inspect - Tools to inspect your Supabase project" },
18
+ { value: "link", label: "link - Link to a Supabase project" },
19
+ { value: "login", label: "login - Authenticate using an access token" },
20
+ { value: "logout", label: "logout - Log out and delete access tokens locally" },
21
+ { value: "migration", label: "migration - Manage database migration scripts" },
22
+ { value: "seed", label: "seed - Seed a Supabase project from supabase/config.toml" },
23
+ { value: "services", label: "services - Show versions of all Supabase services" },
24
+ { value: "start", label: "start - Start containers for Supabase local development" },
25
+ { value: "status", label: "status - Show status of local Supabase containers" },
26
+ { value: "stop", label: "stop - Stop all local Supabase containers" },
27
+ { value: "test", label: "test - Run tests on local Supabase containers" },
28
+ { value: "unlink", label: "unlink - Unlink a Supabase project" }
29
+ ],
30
+ "Management APIs": [
31
+ { value: "backups", label: "backups - Manage Supabase physical backups" },
32
+ { value: "branches", label: "branches - Manage Supabase preview branches" },
33
+ { value: "config", label: "config - Manage Supabase project configurations" },
34
+ { value: "domains", label: "domains - Manage custom domain names for Supabase projects" },
35
+ { value: "encryption", label: "encryption - Manage encryption keys of Supabase projects" },
36
+ { value: "functions", label: "functions - Manage Supabase Edge functions" },
37
+ { value: "network-bans", label: "network-bans - Manage network bans" },
38
+ { value: "network-restrictions", label: "network-restrictions - Manage network restrictions" },
39
+ { value: "orgs", label: "orgs - Manage Supabase organizations" },
40
+ { value: "postgres-config", label: "postgres-config - Manage Postgres database config" },
41
+ { value: "projects", label: "projects - Manage Supabase projects" },
42
+ { value: "secrets", label: "secrets - Manage Supabase secrets" },
43
+ { value: "snippets", label: "snippets - Manage Supabase SQL snippets" },
44
+ { value: "ssl-enforcement", label: "ssl-enforcement - Manage SSL enforcement configuration" },
45
+ { value: "sso", label: "sso - Manage Single Sign-On (SSO) authentication for projects" },
46
+ { value: "storage", label: "storage - Manage Supabase Storage objects" },
47
+ { value: "vanity-subdomains", label: "vanity-subdomains - Manage vanity subdomains for Supabase projects" }
48
+ ],
49
+ "Additional Commands": [
50
+ { value: "completion", label: "completion - Generate the autocompletion script" },
51
+ { value: "help", label: "help - Help about any command" }
52
+ ]
53
+ };
54
+ var globalFlags = [
55
+ { value: "--create-ticket", label: "--create-ticket (Create support ticket on error)" },
56
+ { value: "--debug", label: "--debug (Output debug logs)" },
57
+ { value: "--experimental", label: "--experimental (Enable experimental features)" },
58
+ { value: "--yes", label: "--yes (Answer yes to all prompts)" }
59
+ ];
60
+ function getPinnedCommands() {
61
+ return config.get("pinnedCommands") || [];
62
+ }
63
+ function addPinnedCommand(cmd) {
64
+ const current = getPinnedCommands();
65
+ if (!current.includes(cmd)) {
66
+ config.set("pinnedCommands", [...current, cmd]);
67
+ }
68
+ }
69
+ function removePinnedCommand(cmd) {
70
+ const current = getPinnedCommands();
71
+ config.set("pinnedCommands", current.filter((c) => c !== cmd));
72
+ }
73
+ async function main() {
74
+ console.clear();
75
+ p.intro(`${pc.bgGreen(pc.black(" POLTERBASE "))} The ultimate modern CLI for Supabase`);
76
+ let shouldExit = false;
77
+ while (!shouldExit) {
78
+ const pinned = getPinnedCommands();
79
+ const mainOptions = [
80
+ { value: "Quick Start", label: "Quick Start (Bootstrap templates)" },
81
+ { value: "Local Development", label: "Local Development (db, init, start, etc.)" },
82
+ { value: "Management APIs", label: "Management APIs (projects, secrets, domains, etc.)" },
83
+ { value: "Additional Commands", label: "Additional Commands (help, completion)" },
84
+ { value: "Custom", label: "Custom Command / Check Version" }
85
+ ];
86
+ if (pinned.length > 0) {
87
+ mainOptions.unshift(
88
+ { value: "MANAGE_PINS", label: pc.magenta("\u2699\uFE0F Manage Pinned Commands") },
89
+ ...pinned.map((cmd) => ({ value: `PIN:${cmd}`, label: `${pc.cyan("\u{1F4CC}")} ${cmd}` })),
90
+ // @ts-ignore
91
+ { value: "SEPARATOR", label: pc.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"), disabled: true }
92
+ );
93
+ }
94
+ mainOptions.push({ value: "EXIT", label: pc.red("Exit Polterbase") });
95
+ const category = await p.select({
96
+ message: "What kind of Supabase command do you want to run?",
97
+ // @ts-ignore
98
+ options: mainOptions.filter((opt) => opt.value !== "SEPARATOR"),
99
+ maxItems: 12
100
+ });
101
+ if (p.isCancel(category) || category === "EXIT") {
102
+ p.cancel("See you later!");
103
+ process.exit(0);
104
+ }
105
+ if (category === "MANAGE_PINS") {
106
+ const toRemove = await p.multiselect({
107
+ message: "Select commands to remove from pins (Space to select):",
108
+ options: pinned.map((cmd) => ({ value: cmd, label: cmd })),
109
+ required: false
110
+ });
111
+ if (!p.isCancel(toRemove) && Array.isArray(toRemove)) {
112
+ toRemove.forEach((cmd) => removePinnedCommand(cmd));
113
+ p.log.success("Pins updated!");
114
+ }
115
+ continue;
116
+ }
117
+ let finalArgs = [];
118
+ let isPinnedExecution = false;
119
+ if (typeof category === "string" && category.startsWith("PIN:")) {
120
+ const cmdStr = category.replace("PIN:", "");
121
+ finalArgs = cmdStr.split(" ");
122
+ isPinnedExecution = true;
123
+ } else {
124
+ let commandValue = "";
125
+ if (category === "Custom") {
126
+ const custom = await p.text({
127
+ message: 'Enter your custom supabase command/flags (e.g., "-v" or "status -o json"):',
128
+ placeholder: "-v"
129
+ });
130
+ if (p.isCancel(custom)) continue;
131
+ commandValue = custom;
132
+ } else {
133
+ const options = [
134
+ { value: "BACK", label: pc.yellow("\u2190 Go Back") },
135
+ // @ts-ignore
136
+ ...supabaseCommands[category]
137
+ ];
138
+ const command = await p.select({
139
+ message: `Select a command from ${category}:`,
140
+ options,
141
+ maxItems: 11
142
+ });
143
+ if (p.isCancel(command) || command === "BACK") continue;
144
+ const extraArgs = await p.text({
145
+ message: `Any additional sub-commands or arguments for "supabase ${command}"?`,
146
+ placeholder: 'e.g., "push", "pull", "list" (Press Enter to skip)',
147
+ initialValue: ""
148
+ });
149
+ if (p.isCancel(extraArgs)) continue;
150
+ commandValue = `${command} ${extraArgs}`.trim();
151
+ }
152
+ const selectedFlags = await p.multiselect({
153
+ message: "Select any global flags you want to include (Space to select, Enter to confirm):",
154
+ options: globalFlags,
155
+ required: false
156
+ });
157
+ if (p.isCancel(selectedFlags)) continue;
158
+ finalArgs = commandValue.split(" ").filter(Boolean);
159
+ if (Array.isArray(selectedFlags) && selectedFlags.length > 0) {
160
+ finalArgs = finalArgs.concat(selectedFlags);
161
+ }
162
+ }
163
+ const finalCmdString = `supabase ${finalArgs.join(" ")}`;
164
+ const confirm2 = await p.confirm({
165
+ message: `Ready to execute: ${pc.cyan(finalCmdString)}. Continue?`,
166
+ initialValue: true
167
+ });
168
+ if (p.isCancel(confirm2)) continue;
169
+ if (!confirm2) {
170
+ const action = await p.select({
171
+ message: "Command cancelled. What next?",
172
+ options: [
173
+ { value: "RETRY", label: "Try another command" },
174
+ { value: "EXIT", label: "Exit" }
175
+ ]
176
+ });
177
+ if (action === "RETRY") continue;
178
+ break;
179
+ }
180
+ p.outro(`Executing: ${pc.cyan(finalCmdString)}`);
181
+ const child = spawn("supabase", finalArgs, {
182
+ stdio: "inherit",
183
+ shell: true
184
+ });
185
+ await new Promise((resolve) => {
186
+ child.on("error", (err) => {
187
+ console.error(pc.red(`Failed to start command: ${err.message}`));
188
+ resolve();
189
+ });
190
+ child.on("exit", (code) => {
191
+ if (code !== 0) {
192
+ console.log(pc.red(`
193
+ Command exited with code ${code}`));
194
+ } else {
195
+ console.log(pc.green("\nCommand finished successfully!"));
196
+ if (!isPinnedExecution && !getPinnedCommands().includes(finalArgs.join(" "))) {
197
+ setTimeout(async () => {
198
+ const shouldPin = await p.confirm({
199
+ message: pc.magenta("Pin this command for easy access next time?"),
200
+ initialValue: false
201
+ });
202
+ if (shouldPin && !p.isCancel(shouldPin)) {
203
+ addPinnedCommand(finalArgs.join(" "));
204
+ p.log.success("Pinned! You can find it at the top of the main menu.");
205
+ }
206
+ }, 100);
207
+ }
208
+ }
209
+ resolve();
210
+ });
211
+ });
212
+ const next = await p.confirm({
213
+ message: "Do you want to run another command?",
214
+ initialValue: true
215
+ });
216
+ if (!next || p.isCancel(next)) {
217
+ shouldExit = true;
218
+ } else {
219
+ console.clear();
220
+ p.intro(`${pc.bgGreen(pc.black(" POLTERBASE "))} Continue managing your Supabase project`);
221
+ }
222
+ }
223
+ p.outro("Thank you for using Polterbase!");
224
+ }
225
+ main().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@polterware/polterbase",
3
+ "version": "0.1.2",
4
+ "description": "A global CLI for managing Supabase CLI workflows.",
5
+ "type": "module",
6
+ "bin": {
7
+ "polterbase": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/polterware/polterbase.git"
17
+ },
18
+ "bugs": {
19
+ "url": "https://github.com/polterware/polterbase/issues"
20
+ },
21
+ "homepage": "https://github.com/polterware/polterbase#readme",
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "preferGlobal": true,
26
+ "scripts": {
27
+ "dev": "tsup src/index.ts --watch --format esm --dts",
28
+ "build": "tsup src/index.ts --format esm --clean",
29
+ "lint": "tsc --noEmit",
30
+ "test": "vitest run",
31
+ "test:watch": "vitest"
32
+ },
33
+ "keywords": [
34
+ "polterware",
35
+ "polterbase",
36
+ "cli",
37
+ "typescript"
38
+ ],
39
+ "author": "Polterware",
40
+ "license": "MIT",
41
+ "engines": {
42
+ "node": ">=18"
43
+ },
44
+ "dependencies": {
45
+ "@clack/prompts": "^1.1.0",
46
+ "conf": "^15.1.0",
47
+ "picocolors": "^1.1.1"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^22.13.10",
51
+ "tsup": "^8.3.6",
52
+ "typescript": "^5.8.2",
53
+ "vitest": "^3.0.7"
54
+ }
55
+ }