powerbase-cli 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,141 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import ssl
5
+ import time
6
+ from contextlib import contextmanager
7
+ from dataclasses import replace
8
+ from datetime import datetime, timezone
9
+ from pathlib import Path
10
+ from typing import Iterator
11
+ from urllib import request
12
+ from urllib.error import HTTPError, URLError
13
+
14
+ from .config import BUNDLED_CA_CERT_SENTINEL, AuthState, ConfigStore, env_auth_state, load_bundled_ca_cert
15
+
16
+ try:
17
+ import fcntl
18
+ except ModuleNotFoundError: # pragma: no cover
19
+ fcntl = None # type: ignore[assignment]
20
+
21
+
22
+ class SessionError(RuntimeError):
23
+ """Raised when auth/session handling fails."""
24
+
25
+
26
+ class SessionManager:
27
+ def __init__(
28
+ self,
29
+ store: ConfigStore,
30
+ base_url: str | None,
31
+ anon_key: str | None,
32
+ *,
33
+ tls_insecure: bool = False,
34
+ ca_cert_file: str | None = None,
35
+ ) -> None:
36
+ self.store = store
37
+ self.base_url = base_url
38
+ self.anon_key = anon_key
39
+ self.tls_insecure = tls_insecure
40
+ self.ca_cert_file = ca_cert_file
41
+
42
+ def _urlopen(self, req: request.Request):
43
+ if self.tls_insecure:
44
+ context = ssl.create_default_context()
45
+ context.check_hostname = False
46
+ context.verify_mode = ssl.CERT_NONE
47
+ return request.urlopen(req, context=context)
48
+ if self.ca_cert_file:
49
+ if self.ca_cert_file == BUNDLED_CA_CERT_SENTINEL:
50
+ bundled_ca_cert = load_bundled_ca_cert()
51
+ if not bundled_ca_cert:
52
+ raise SessionError("Bundled test CA certificate is unavailable.")
53
+ context = ssl.create_default_context(cadata=bundled_ca_cert)
54
+ else:
55
+ context = ssl.create_default_context(cafile=self.ca_cert_file)
56
+ return request.urlopen(req, context=context)
57
+ return request.urlopen(req)
58
+
59
+ def get_auth_state(self) -> AuthState | None:
60
+ return env_auth_state() or self.store.load_auth()
61
+
62
+ def is_file_backed(self, auth: AuthState | None) -> bool:
63
+ return bool(auth and auth.source != "env")
64
+
65
+ def seconds_until_expiry(self, auth: AuthState | None) -> int | None:
66
+ if not auth or auth.session.expires_at is None:
67
+ return None
68
+ return auth.session.expires_at - int(time.time())
69
+
70
+ def ensure_valid(self, skew_seconds: int = 60) -> AuthState | None:
71
+ auth = self.get_auth_state()
72
+ if not auth:
73
+ return None
74
+ remaining = self.seconds_until_expiry(auth)
75
+ if remaining is None or remaining > skew_seconds:
76
+ return auth
77
+ if not auth.session.refresh_token:
78
+ return auth
79
+ return self.refresh(auth)
80
+
81
+ def refresh(self, auth: AuthState | None = None) -> AuthState:
82
+ auth = auth or self.get_auth_state()
83
+ if not auth:
84
+ raise SessionError("No authentication session available.")
85
+ if not auth.session.refresh_token:
86
+ raise SessionError("Current session has no refresh token. Please log in again.")
87
+ if not self.base_url or not self.anon_key:
88
+ raise SessionError("base_url and anon_key are required to refresh the session.")
89
+
90
+ payload = json.dumps({"refresh_token": auth.session.refresh_token}).encode("utf-8")
91
+ req = request.Request(
92
+ f"{self.base_url.rstrip('/')}/auth/v1/token?grant_type=refresh_token",
93
+ data=payload,
94
+ headers={
95
+ "apikey": self.anon_key,
96
+ "Content-Type": "application/json",
97
+ },
98
+ method="POST",
99
+ )
100
+ try:
101
+ with self._urlopen(req) as resp:
102
+ data = json.loads(resp.read().decode("utf-8"))
103
+ except HTTPError as exc: # pragma: no cover - exercised via tests with patched urlopen
104
+ body = exc.read().decode("utf-8", errors="replace")
105
+ raise SessionError(f"Failed to refresh session: {body}") from exc
106
+ except URLError as exc: # pragma: no cover - depends on runtime/network setup
107
+ raise SessionError(f"Failed to refresh session: {exc.reason}") from exc
108
+ except ssl.SSLError as exc: # pragma: no cover - depends on runtime/network setup
109
+ raise SessionError(f"Failed to refresh session: {exc}") from exc
110
+
111
+ new_auth = AuthState(
112
+ source=auth.source,
113
+ base_url=self.base_url,
114
+ anon_key=self.anon_key,
115
+ session=replace(
116
+ auth.session,
117
+ access_token=data["access_token"],
118
+ refresh_token=data.get("refresh_token", auth.session.refresh_token),
119
+ token_type=data.get("token_type", auth.session.token_type),
120
+ expires_at=data.get("expires_at"),
121
+ ),
122
+ user=data.get("user") or auth.user,
123
+ updated_at=datetime.now(timezone.utc).isoformat(),
124
+ )
125
+ if self.is_file_backed(auth):
126
+ with self.file_lock():
127
+ self.store.save_auth(new_auth)
128
+ return new_auth
129
+
130
+ @contextmanager
131
+ def file_lock(self) -> Iterator[None]:
132
+ self.store.ensure_base_dir()
133
+ lock_path = Path(self.store.base_dir) / ".auth.lock"
134
+ with lock_path.open("w", encoding="utf-8") as lock_file:
135
+ if fcntl is not None:
136
+ fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX)
137
+ try:
138
+ yield
139
+ finally:
140
+ if fcntl is not None:
141
+ fcntl.flock(lock_file.fileno(), fcntl.LOCK_UN)
@@ -0,0 +1,130 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import ssl
5
+ from dataclasses import dataclass
6
+ from typing import Any
7
+ from urllib import request
8
+ from urllib.error import HTTPError, URLError
9
+
10
+ from .config import BUNDLED_CA_CERT_SENTINEL, AppConfig, load_bundled_ca_cert
11
+ from .session import SessionError, SessionManager
12
+
13
+
14
+ class ApiError(RuntimeError):
15
+ def __init__(self, message: str, status: int | None = None) -> None:
16
+ super().__init__(message)
17
+ self.status = status
18
+
19
+
20
+ @dataclass
21
+ class RequestContext:
22
+ instance_id: str | None = None
23
+
24
+
25
+ class PowerbaseTransport:
26
+ def __init__(self, config: AppConfig, session_manager: SessionManager) -> None:
27
+ self.config = config
28
+ self.session_manager = session_manager
29
+
30
+ def _urlopen(self, req: request.Request):
31
+ if self.config.tls_insecure:
32
+ context = ssl.create_default_context()
33
+ context.check_hostname = False
34
+ context.verify_mode = ssl.CERT_NONE
35
+ return request.urlopen(req, context=context)
36
+ if self.config.ca_cert_file:
37
+ if self.config.ca_cert_file == BUNDLED_CA_CERT_SENTINEL:
38
+ bundled_ca_cert = load_bundled_ca_cert()
39
+ if not bundled_ca_cert:
40
+ raise ApiError("Bundled test CA certificate is unavailable.")
41
+ context = ssl.create_default_context(cadata=bundled_ca_cert)
42
+ else:
43
+ context = ssl.create_default_context(cafile=self.config.ca_cert_file)
44
+ return request.urlopen(req, context=context)
45
+ return request.urlopen(req)
46
+
47
+ def _build_headers(
48
+ self,
49
+ *,
50
+ auth_token: str | None,
51
+ headers: dict[str, str] | None,
52
+ instance_id: str | None,
53
+ ) -> dict[str, str]:
54
+ request_headers = {
55
+ "apikey": self.config.anon_key,
56
+ "Content-Type": "application/json",
57
+ }
58
+ if auth_token:
59
+ request_headers["Authorization"] = f"Bearer {auth_token}"
60
+ if instance_id:
61
+ request_headers["X-Instance-ID"] = instance_id
62
+ if headers:
63
+ request_headers.update(headers)
64
+ return request_headers
65
+
66
+ def _send(self, req: request.Request, *, stream: bool) -> Any:
67
+ resp = self._urlopen(req)
68
+ if stream:
69
+ return resp
70
+ raw = resp.read().decode("utf-8")
71
+ return json.loads(raw) if raw else {}
72
+
73
+ def _parse_http_error(self, exc: HTTPError) -> ApiError:
74
+ body_text = exc.read().decode("utf-8", errors="replace")
75
+ try:
76
+ data = json.loads(body_text)
77
+ except json.JSONDecodeError:
78
+ data = {"error": body_text}
79
+ return ApiError(data.get("error") or body_text or exc.reason, exc.code)
80
+
81
+ def invoke(
82
+ self,
83
+ function_path: str,
84
+ *,
85
+ method: str = "GET",
86
+ body: dict[str, Any] | None = None,
87
+ headers: dict[str, str] | None = None,
88
+ instance_id: str | None = None,
89
+ requires_auth: bool = True,
90
+ stream: bool = False,
91
+ ) -> Any:
92
+ if not self.config.base_url:
93
+ raise ApiError("Powerbase base URL is not configured.")
94
+ if not self.config.anon_key:
95
+ raise ApiError("Powerbase anon key is not configured.")
96
+
97
+ auth = self.session_manager.ensure_valid() if requires_auth else None
98
+ url = f"{self.config.base_url.rstrip('/')}/functions/v1/{function_path}"
99
+ payload = None if body is None else json.dumps(body).encode("utf-8")
100
+ request_headers = self._build_headers(
101
+ auth_token=auth.session.access_token if auth else None,
102
+ headers=headers,
103
+ instance_id=instance_id,
104
+ )
105
+ req = request.Request(url, data=payload, headers=request_headers, method=method.upper())
106
+
107
+ try:
108
+ return self._send(req, stream=stream)
109
+ except HTTPError as exc:
110
+ if exc.code == 401 and auth and auth.session.refresh_token:
111
+ try:
112
+ refreshed_auth = self.session_manager.refresh(auth)
113
+ except SessionError as refresh_error:
114
+ raise ApiError(str(refresh_error), 401) from refresh_error
115
+ retry_headers = self._build_headers(
116
+ auth_token=refreshed_auth.session.access_token,
117
+ headers=headers,
118
+ instance_id=instance_id,
119
+ )
120
+ retry_req = request.Request(url, data=payload, headers=retry_headers, method=method.upper())
121
+ try:
122
+ return self._send(retry_req, stream=stream)
123
+ except HTTPError as retry_exc:
124
+ raise self._parse_http_error(retry_exc) from retry_exc
125
+ raise self._parse_http_error(exc) from exc
126
+ except URLError as exc:
127
+ raise ApiError(f"Request failed: {exc.reason}") from exc
128
+ except ssl.SSLError as exc:
129
+ raise ApiError(f"Request failed: {exc}") from exc
130
+
@@ -0,0 +1,318 @@
1
+ Metadata-Version: 2.4
2
+ Name: powerbase-cli
3
+ Version: 0.1.0
4
+ Summary: CLI for operating Powerbase console workflows
5
+ Author: Powerbase
6
+ Requires-Python: >=3.11
7
+ Description-Content-Type: text/markdown
8
+
9
+ # powerbase-cli
10
+
11
+ Python CLI for automating Powerbase console operations, with a command shape designed for Openclaw and other LLM agents.
12
+
13
+ ## What It Covers
14
+
15
+ `powerbase-cli` mirrors the main console workflows with a user-mode auth model:
16
+
17
+ - browser login bridge for CLI use
18
+ - local session persistence and refresh
19
+ - config and context management
20
+ - organizations, databases, instances, branches
21
+ - SQL execution
22
+ - publish diff and publish run
23
+ - sandbox file operations
24
+ - sandbox agent provider config, chat, and login workflows
25
+
26
+ The CLI is optimized for agent use:
27
+
28
+ - stable command groups
29
+ - `--help` explains parameter source and format
30
+ - `--json` is available for machine-readable output
31
+ - context can be saved so later commands need fewer flags
32
+
33
+ Database model:
34
+
35
+ - default path: `powerbase instance create` uses the managed Powerbase database flow
36
+ - advanced path: `powerbase database create --dsn ...` registers an existing external database connection for later use with `--database-id`
37
+ - `powerbase database create` does not provision a new physical database
38
+
39
+ ## Install And Run
40
+
41
+ Install from PyPI:
42
+
43
+ ```bash
44
+ python -m pip install powerbase-cli
45
+ powerbase --help
46
+ ```
47
+
48
+ From the repository root during development:
49
+
50
+ ```bash
51
+ pip install -e .
52
+ ```
53
+
54
+ Or run directly during development:
55
+
56
+ ```bash
57
+ PYTHONPATH=src python3 -m powerbase_cli --help
58
+ ```
59
+
60
+ ## Configuration Model
61
+
62
+ Values are resolved in this order:
63
+
64
+ 1. command flags
65
+ 2. environment variables
66
+ 3. `~/.config/powerbase/`
67
+ 4. built-in defaults
68
+
69
+ Default local files:
70
+
71
+ ```text
72
+ ~/.config/powerbase/
73
+ config.toml
74
+ auth.json
75
+ context.json
76
+ ```
77
+
78
+ Most users do not need environment variables.
79
+
80
+ Optional advanced overrides:
81
+ - `POWERBASE_ACCESS_TOKEN` and `POWERBASE_REFRESH_TOKEN` for non-browser or pre-issued login flows
82
+ - `POWERBASE_INSTANCE_ID`, `POWERBASE_ORG_ID`, and `POWERBASE_BRANCH` to prefill local context
83
+ - `POWERBASE_CONFIG_DIR` to isolate local state, for example in tests or E2E runs
84
+ - `POWERBASE_OUTPUT` to default to `json`
85
+
86
+ ## Authentication
87
+
88
+ ### Browser Login
89
+
90
+ The preferred flow is:
91
+
92
+ ```bash
93
+ powerbase auth login
94
+ ```
95
+
96
+ The CLI now includes a built-in `base_url` and `anon_key` default for this deployment. The test package also bundles this environment's self-signed CA certificate, so most users can start with browser login directly and only use flags or environment variables when overriding that default.
97
+
98
+ The bundled CA is a test-only convenience for the current self-signed deployment. After the console moves to a publicly trusted TLS certificate, remove the bundled CA fallback and package resource, then keep only the built-in `base_url` and `anon_key` defaults.
99
+
100
+ This will:
101
+
102
+ 1. request a CLI login session from Powerbase
103
+ 2. print a browser URL
104
+ 3. poll until browser approval or until `--timeout` elapses (default **300** seconds, five minutes)
105
+ 4. save the resulting session to `~/.config/powerbase/auth.json`
106
+
107
+ Use `--timeout 0` to wait without a time limit. Use a larger value if users need more than five minutes to complete login.
108
+ If an agent or wrapper script is coordinating the workflow, it is still helpful
109
+ to tell the user: after browser approval, return to the current session so the
110
+ remaining steps can continue.
111
+
112
+ ### Manual Token Import
113
+
114
+ Use this when browser login is not available in the current agent environment:
115
+
116
+ ```bash
117
+ powerbase auth token-set \
118
+ --access-token ACCESS_TOKEN \
119
+ --refresh-token REFRESH_TOKEN \
120
+ --expires-at 1760000000
121
+ ```
122
+
123
+ Use `--base-url` or `--anon-key` here only when you intentionally want to override the built-in deployment defaults.
124
+
125
+ ### Check Auth State
126
+
127
+ ```bash
128
+ powerbase auth status --json
129
+ ```
130
+
131
+ ### Refresh A Saved Session
132
+
133
+ ```bash
134
+ powerbase auth refresh --json
135
+ ```
136
+
137
+ ## Context Workflow
138
+
139
+ For repeated agent workflows, save the current org, instance, and branch:
140
+
141
+ ```bash
142
+ powerbase context use-org ORG_ID
143
+ powerbase context use-instance INSTANCE_ID
144
+ powerbase context use-branch main
145
+ powerbase context show --json
146
+ ```
147
+
148
+ After that, many commands can omit `--instance-id`.
149
+
150
+ ## Common Workflows
151
+
152
+ ### Discover Resources
153
+
154
+ ```bash
155
+ powerbase org list --json
156
+ powerbase database list --json
157
+ powerbase instance list --json
158
+ powerbase branch list --instance-id INSTANCE_ID --json
159
+ ```
160
+
161
+ ### Create An Instance With The Managed Database Flow
162
+
163
+ This is the default and recommended path:
164
+
165
+ ```bash
166
+ powerbase org list --json
167
+ powerbase instance create --name todo-app --org-id ORG_ID --json
168
+ ```
169
+
170
+ `instance create` returns when provisioning starts, not necessarily when every
171
+ dependent resource is immediately readable. If `instance get`, `branch list`, or
172
+ sandbox commands briefly say the instance is missing or partial, retry after a
173
+ short wait.
174
+
175
+ ### Register And Reuse An External Database Connection
176
+
177
+ Use this only when you intentionally want the advanced bring-your-own-database flow:
178
+
179
+ ```bash
180
+ powerbase database create --name todo-db --dsn "mysql://user:pass@host:3306/db" --db-type mysql --json
181
+ powerbase instance create --name todo-app --database-id DATABASE_ID --org-id ORG_ID --json
182
+ ```
183
+
184
+ Notes for the advanced path:
185
+
186
+ - `powerbase database create` registers a DSN in Powerbase; it does not create a physical database server
187
+ - DSN credentials are sensitive and are stored by the platform
188
+ - branch and preview workflows may require SeekDB-compatible database behavior, not just generic MySQL wire compatibility
189
+ - deleting a Powerbase database record does not delete the external database itself
190
+
191
+ ### Switch To An Instance And Branch
192
+
193
+ ```bash
194
+ powerbase context use-instance INSTANCE_ID
195
+ powerbase branch switch feature/demo --instance-id INSTANCE_ID --json
196
+ powerbase context use-branch feature/demo
197
+ ```
198
+
199
+ When you create a branch with a name like `feature/demo`, later delete or SQL
200
+ commands should prefer the normalized slug returned by the API, such as
201
+ `feature-demo`, instead of assuming the original input string is still valid.
202
+
203
+ ### Run SQL
204
+
205
+ Inline SQL:
206
+
207
+ ```bash
208
+ powerbase sql run --instance-id INSTANCE_ID --branch main --sql "SELECT 1" --json
209
+ ```
210
+
211
+ From a file:
212
+
213
+ ```bash
214
+ powerbase sql run --instance-id INSTANCE_ID --sql-file ./query.sql --json
215
+ ```
216
+
217
+ ### Publish
218
+
219
+ ```bash
220
+ powerbase publish diff --instance-id INSTANCE_ID --json
221
+ powerbase publish run --instance-id INSTANCE_ID --json
222
+ ```
223
+
224
+ ### Sandbox Files
225
+
226
+ ```bash
227
+ powerbase sandbox files tree --instance-id INSTANCE_ID --root / --json
228
+ powerbase sandbox files read --instance-id INSTANCE_ID /src/app.tsx --json
229
+ powerbase sandbox files upload --instance-id INSTANCE_ID ./local.txt --target-path /tmp --json
230
+ ```
231
+
232
+ ### Sandbox Agent Providers
233
+
234
+ ```bash
235
+ powerbase agent providers --instance-id INSTANCE_ID --json
236
+ powerbase agent status --instance-id INSTANCE_ID --provider cursor --json
237
+ powerbase agent login-url --instance-id INSTANCE_ID --provider cursor --json
238
+ ```
239
+
240
+ ### Sandbox Agent Chat And Config
241
+
242
+ Send one prompt to the sandbox agent and stream events as JSONL:
243
+
244
+ ```bash
245
+ powerbase branch switch feature/demo --instance-id INSTANCE_ID --json
246
+
247
+ powerbase agent chat \
248
+ --instance-id INSTANCE_ID \
249
+ --provider cursor \
250
+ --message "Build a todo app with create, complete, and delete actions." \
251
+ --stream-jsonl
252
+ ```
253
+
254
+ `agent chat` follows the sandbox's current branch for the automatic preview build. Use
255
+ `powerbase branch switch ...` first when you want the generated preview to land on a
256
+ feature branch. `powerbase context use-branch ...` only changes the local default value;
257
+ it does not switch the remote sandbox by itself.
258
+
259
+ Read and update opencode provider config:
260
+
261
+ ```bash
262
+ powerbase agent opencode-config get --instance-id INSTANCE_ID --json
263
+ powerbase agent opencode-config set --instance-id INSTANCE_ID --provider anthropic --api-key API_KEY --json
264
+ powerbase agent opencode-config delete --instance-id INSTANCE_ID --provider anthropic --json
265
+ ```
266
+
267
+ Replace the sandbox `opencode.json` file:
268
+
269
+ ```bash
270
+ powerbase agent opencode-json set --instance-id INSTANCE_ID --file ./opencode.json --json
271
+ ```
272
+
273
+ ## Openclaw Usage Notes
274
+
275
+ When Openclaw or another LLM agent uses `powerbase`:
276
+
277
+ - prefer `--json` on all commands
278
+ - run discovery commands before write operations
279
+ - set context for long multi-step tasks
280
+ - use `auth status` before workflows that assume login
281
+ - use `auth token-set` if browser login is not practical in the current environment
282
+ - remember that `--json` overrides a saved `config output text` setting for that command
283
+
284
+ Recommended agent sequence:
285
+
286
+ 1. `powerbase auth status --json`
287
+ 2. If unauthenticated, run `powerbase auth login` or `powerbase auth token-set`
288
+ 3. `powerbase context show --json`
289
+ 4. If no instance is selected, run `powerbase instance list --json`
290
+ 5. If no suitable instance exists, prefer `powerbase instance create --name ... --org-id ... --json`
291
+ 6. Use `powerbase database ...` only for the advanced bring-your-own-database path
292
+ 7. Set context with `powerbase context use-instance ...`
293
+ 8. If you want the sandbox agent preview on a non-main branch, run `powerbase branch switch ...`
294
+ 9. Continue with `branch`, `sql`, `publish`, `sandbox files`, or `agent` commands
295
+
296
+ ## Testing
297
+
298
+ Run the full CLI test suite:
299
+
300
+ ```bash
301
+ PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=src python3 -m unittest discover -s tests -v
302
+ ```
303
+
304
+ Compile the modules:
305
+
306
+ ```bash
307
+ PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=src python3 -m py_compile src/powerbase_cli/*.py
308
+ ```
309
+
310
+ ## Project Skill
311
+
312
+ A project skill for Cursor/Openclaw-style agent usage lives in:
313
+
314
+ `./.cursor/skills/powerbase-cli-openclaw/SKILL.md`
315
+
316
+ Design and auth review notes live in:
317
+
318
+ `./docs/console-cli-plan.md`
@@ -0,0 +1,27 @@
1
+ powerbase_cli/__init__.py,sha256=EynUg4YKF7Qh1Hr8P1CbV8QyzMTU2jfqVE-Tfm8_ETw,79
2
+ powerbase_cli/__main__.py,sha256=PSQ4rpL0dG6f-qH4N7H-gD9igQkdHzH4yVZDcW8lfZo,80
3
+ powerbase_cli/api.py,sha256=F7TZzX7A2rl2j9Ecf1GG9kPowgdjADcKnefkuMz4WUw,12547
4
+ powerbase_cli/cli.py,sha256=Gc_tWlLI5CC3Nl3DhgomiHreqX7Im2jZ9T02-ZDZ08k,304
5
+ powerbase_cli/config.py,sha256=lqMUPQHaHlsr4hsYLVncMAOEM-z8WIhfdaJ9U491220,8588
6
+ powerbase_cli/session.py,sha256=1C5WbGN8ZAtx5miluJOn7Ll3nKw-EX-vKRCipd_yIx0,5492
7
+ powerbase_cli/transport.py,sha256=ObTjXn1DLZcysecIODqPiMBUg9yR_nxMIrR1I0PwQOo,4969
8
+ powerbase_cli/certs/powerbase-test-ca.pem,sha256=Pxtx-qkzTFign1vq7fPF_IrCTcue1Oqy2OQuVqeGk8o,1281
9
+ powerbase_cli/commands/__init__.py,sha256=OMk2nZXMUizPR1Ss7kCSRSEIiRnQYlOErYERGTe9Bqw,75
10
+ powerbase_cli/commands/agent.py,sha256=u6SvqwHA_rn_8NUAZZWxVxJSBHMjKtgqm7ySHpq-u4Q,8813
11
+ powerbase_cli/commands/auth.py,sha256=DTPnGEqE_NSmZO-3eVwP7757IvycDJgxu4Z1N2wvYZQ,6611
12
+ powerbase_cli/commands/branch.py,sha256=9PA2Dq510MUiPT2Zysa6OkfUH3D5VEfbdddUMzJn38E,3892
13
+ powerbase_cli/commands/config_cmd.py,sha256=LHGm3U9VwMquqyLqEjqqXUj57zte2v2qUTieFCbITCE,2613
14
+ powerbase_cli/commands/context.py,sha256=BbrdCcE_LcRP_skFJCW-NgflIoG3sBVHRUjpERS_S4s,3453
15
+ powerbase_cli/commands/database.py,sha256=JZPM7Gw3DECuyK93_oDwUIH7S8C6weS5PY_KnCqiUMQ,5011
16
+ powerbase_cli/commands/instance.py,sha256=o6E3UUSClfKqH2g-ijar9gbqlQyYB1U481yW4caXAuw,3424
17
+ powerbase_cli/commands/org.py,sha256=_VA9uyCCiK3UwkfXRhLJIUubj-hAyxGTIp1HZsjqPUQ,688
18
+ powerbase_cli/commands/parser.py,sha256=CGIEn2fwf-nO8P_gHm6mBSystl98NP2Zng0Se_-_JHM,3889
19
+ powerbase_cli/commands/publish.py,sha256=QTo2wmBTsTsXKu4vIur-IoJphbzRxi0ouFIcJYyVHbw,1985
20
+ powerbase_cli/commands/sandbox.py,sha256=fmGl4QpBr5bxVfjkmRoG0KtTWoWfEunek7EGb8ErcCI,4756
21
+ powerbase_cli/commands/shared.py,sha256=O8eVwnYIoWNpHD4doW_1a9FhGAL1PLuNkR-x7h9Z_w0,4833
22
+ powerbase_cli/commands/sql.py,sha256=T97TccsCylRRQ92bZEif_yHLDo5-qp6Xy161gkn-YYY,1417
23
+ powerbase_cli-0.1.0.dist-info/METADATA,sha256=tHC8wvMqsxP5TfpBQ4xtoyR0F_iynR2sQiRO6_7doNg,9607
24
+ powerbase_cli-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
25
+ powerbase_cli-0.1.0.dist-info/entry_points.txt,sha256=DPiHWLoDquxxsBfhtCbMTkjINlDZp06IO_nG5JMgUaY,53
26
+ powerbase_cli-0.1.0.dist-info/top_level.txt,sha256=mKtJfQ2PmKUb-g8K_D9JxAMEUwJA7poXura72Hh76nA,14
27
+ powerbase_cli-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ powerbase = powerbase_cli.cli:main
@@ -0,0 +1 @@
1
+ powerbase_cli