remember 0.1__tar.gz → 0.3.0__tar.gz
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.
- remember-0.3.0/.gitignore +78 -0
- remember-0.3.0/PKG-INFO +106 -0
- remember-0.3.0/README.md +85 -0
- remember-0.3.0/pyproject.toml +53 -0
- remember-0.3.0/src/remember/__init__.py +77 -0
- remember-0.3.0/src/remember/cli.py +113 -0
- remember-0.3.0/src/remember/client.py +404 -0
- remember-0.3.0/src/remember/errors.py +76 -0
- remember-0.3.0/src/remember/models.py +211 -0
- remember-0.3.0/tests/test_cli.py +196 -0
- remember-0.3.0/tests/test_client.py +274 -0
- remember-0.3.0/tests/test_client_facade.py +195 -0
- remember-0.3.0/uv.lock +598 -0
- remember-0.1/PKG-INFO +0 -14
- remember-0.1/remember/dicts.py +0 -241
- remember-0.1/remember/memoize.py +0 -259
- remember-0.1/remember/test/__init__.py +0 -0
- remember-0.1/remember/test/test_dicts.py +0 -303
- remember-0.1/remember/test/test_memoize.py +0 -53
- remember-0.1/setup.py +0 -21
- /remember-0.1/remember/__init__.py → /remember-0.3.0/src/remember/py.typed +0 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
.loopy_loop/sessions/
|
|
2
|
+
.loopy_loop/traces/
|
|
3
|
+
.loopy_loop/trace_finalization_outbox/
|
|
4
|
+
.loopy_loop/repository.json
|
|
5
|
+
.loopy_loop/state.json
|
|
6
|
+
.loopy_loop/state.json.lock
|
|
7
|
+
.loopy_loop/state.json.archive_*.json
|
|
8
|
+
|
|
9
|
+
# Disposable external research checkouts (never vendored)
|
|
10
|
+
.research/
|
|
11
|
+
|
|
12
|
+
# Python environments and generated caches
|
|
13
|
+
.venv/
|
|
14
|
+
.pytest_cache/
|
|
15
|
+
.ruff_cache/
|
|
16
|
+
__pycache__/
|
|
17
|
+
*.py[cod]
|
|
18
|
+
|
|
19
|
+
# IDE state
|
|
20
|
+
.idea/
|
|
21
|
+
|
|
22
|
+
# Cloudflare edge local secrets (never commit tokens)
|
|
23
|
+
ops/cloudflare_edge/config.local.toml
|
|
24
|
+
infra/benchmark-host/config.local.toml
|
|
25
|
+
infra/disposable-dp-host/config.local.toml
|
|
26
|
+
|
|
27
|
+
# Frontend install/build artifacts (source lives in fe/)
|
|
28
|
+
fe/node_modules/
|
|
29
|
+
fe/.next/
|
|
30
|
+
fe/out/
|
|
31
|
+
fe/*.tsbuildinfo
|
|
32
|
+
fe/.pages-deploy.digest
|
|
33
|
+
fe/.agent-browser-shots/
|
|
34
|
+
fe/.pen-exports/
|
|
35
|
+
fe/playwright-report/
|
|
36
|
+
fe/test-results/
|
|
37
|
+
.e2e-runtime/
|
|
38
|
+
|
|
39
|
+
# Observability host — secret-bearing / generated deploy artifacts (never commit)
|
|
40
|
+
infra/obs/.env
|
|
41
|
+
infra/obs/purge/purge.env
|
|
42
|
+
infra/obs/purge/projects.env
|
|
43
|
+
infra/obs/vmauth.rendered.yaml
|
|
44
|
+
infra/obs/Caddyfile.rendered
|
|
45
|
+
infra/obs/certs/
|
|
46
|
+
|
|
47
|
+
# Generic secret / rendered shapes (F2 hygiene)
|
|
48
|
+
*.pem
|
|
49
|
+
.env
|
|
50
|
+
*.env
|
|
51
|
+
!*.env.example
|
|
52
|
+
!infra/obs/.env.example
|
|
53
|
+
# Reviewed non-secret image/address inventory; credentials are separate files.
|
|
54
|
+
!infra/storage-cell/runtime.env
|
|
55
|
+
*.rendered.yaml
|
|
56
|
+
Caddyfile.rendered
|
|
57
|
+
**/umcobs0.conf
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
fe/storybook-static/
|
|
61
|
+
infra/benchmark-host/config.beam.local.toml
|
|
62
|
+
|
|
63
|
+
# fe_admin (D34)
|
|
64
|
+
fe_admin/node_modules/
|
|
65
|
+
fe_admin/out/
|
|
66
|
+
fe_admin/.next/
|
|
67
|
+
fe_admin/.agent-browser-shots/
|
|
68
|
+
fe_admin/storybook-static/
|
|
69
|
+
.dual-review/
|
|
70
|
+
|
|
71
|
+
# Built client distributions (published via the release workflow, never committed).
|
|
72
|
+
client/dist/
|
|
73
|
+
client/.venv/
|
|
74
|
+
|
|
75
|
+
# RememberFS local native build products (source and lockfiles remain tracked).
|
|
76
|
+
rememberfs/target/
|
|
77
|
+
experiments/rememberfs/rust-spike/target/
|
|
78
|
+
experiments/rememberfs/go-spike/rememberfs-go-spike
|
remember-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: remember
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Official Python client for the remember.dev managed memory service.
|
|
5
|
+
Project-URL: Homepage, https://remember.dev
|
|
6
|
+
Project-URL: Documentation, https://remember.dev/docs
|
|
7
|
+
Project-URL: Source, https://github.com/writeitai/ultimate-memory-cloud
|
|
8
|
+
Author-email: "WriteIt.ai s.r.o." <info@writeit.ai>
|
|
9
|
+
License: Apache-2.0
|
|
10
|
+
Keywords: agents,memory,remember.dev,rememberstack
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Requires-Dist: httpx>=0.27
|
|
19
|
+
Requires-Dist: rememberstack>=0.8.1
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# remember
|
|
23
|
+
|
|
24
|
+
Official Python SDK for the [remember.dev](https://remember.dev) managed memory service.
|
|
25
|
+
|
|
26
|
+
This distribution provides:
|
|
27
|
+
- **`remember.Client`** (D65): The primary ergonomic client for memory operations. Connects directly to your dedicated tenant deployment ingress with a single deployment API token (`umc_dp_…`).
|
|
28
|
+
- **`remember.CloudClient`** (D53): The control-plane client for checking deployment readiness, credit balances, and spend gates using a control-plane token (`umc_cp_…`).
|
|
29
|
+
- **`remember-status`**: CLI tool for quick control-plane status checks.
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
```console
|
|
34
|
+
pip install remember
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
This automatically installs `rememberstack` (which provides the `remember` CLI tool on `PATH`).
|
|
38
|
+
|
|
39
|
+
## Quickstart: Memory Operations (`Client`)
|
|
40
|
+
|
|
41
|
+
Mint an **API Token** (`umc_dp_…`) from your dashboard at **Settings → API Tokens**, then initialize `Client`:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
import remember
|
|
45
|
+
|
|
46
|
+
# Client accepts a bare secret (umc_dp_...) or a full Bearer string,
|
|
47
|
+
# and converts string file paths automatically:
|
|
48
|
+
with remember.Client(
|
|
49
|
+
api_key="umc_dp_…",
|
|
50
|
+
base_url="https://<deployment-id>.dp.remember.dev",
|
|
51
|
+
) as memory:
|
|
52
|
+
landed = memory.ingest("notes/project.md")
|
|
53
|
+
print("Ingested version:", landed.version_id)
|
|
54
|
+
|
|
55
|
+
# Search claims or chunks
|
|
56
|
+
claims = memory.search_claims(query="architecture decisions")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Environment Variables
|
|
60
|
+
|
|
61
|
+
For zero-config agent setups, set `REMEMBER_API_KEY` and `REMEMBER_API_URL`:
|
|
62
|
+
|
|
63
|
+
```console
|
|
64
|
+
export REMEMBER_API_URL="https://<deployment-id>.dp.remember.dev"
|
|
65
|
+
export REMEMBER_API_KEY="umc_dp_…"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
import remember
|
|
70
|
+
|
|
71
|
+
with remember.Client.from_env() as memory:
|
|
72
|
+
landed = memory.ingest("notes/project.md")
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`Client` also automatically falls back to `REMEMBERSTACK_API_AUTHORIZATION` and `REMEMBERSTACK_API_URL` for seamless compatibility.
|
|
76
|
+
|
|
77
|
+
## Quickstart: Status & Balances (`CloudClient`)
|
|
78
|
+
|
|
79
|
+
To check billing balance and deployment readiness in CI or monitoring bots, use `CloudClient` with an organisation-scoped control-plane token (`umc_cp_…`).
|
|
80
|
+
|
|
81
|
+
Control tokens are read-only, expiring status credentials (D53/D65). Because they are an API-only operational surface, mint one via the control-plane endpoint while authenticated with an owner session:
|
|
82
|
+
- **Endpoint**: `POST /app/api/v1/orgs/{org_id}/control-tokens` (or `POST /v1/orgs/{org_id}/control-tokens` against the direct control-plane URL).
|
|
83
|
+
- **Body**: `{"label": "ci-monitor", "expires_in_days": 90}` (accepts `label` and optional `expires_in_days` up to 90).
|
|
84
|
+
|
|
85
|
+
```console
|
|
86
|
+
export REMEMBER_CLOUD_TOKEN='umc_cp_…'
|
|
87
|
+
export REMEMBER_CLOUD_ORG='your-organisation-id'
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from remember import CloudClient
|
|
92
|
+
|
|
93
|
+
with CloudClient.from_env() as cloud:
|
|
94
|
+
if cloud.is_ready():
|
|
95
|
+
print("Balance:", cloud.billing_status().balance)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
You can also run the status CLI:
|
|
99
|
+
|
|
100
|
+
```console
|
|
101
|
+
$ remember-status
|
|
102
|
+
deployment active bb81063d-6b7b-41d0-a1df-dc57d4f1fe87
|
|
103
|
+
endpoint live bb81063d-6b7b-41d0-a1df-dc57d4f1fe87.dp.remember.dev
|
|
104
|
+
billing active balance 42.10
|
|
105
|
+
spend allow
|
|
106
|
+
```
|
remember-0.3.0/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# remember
|
|
2
|
+
|
|
3
|
+
Official Python SDK for the [remember.dev](https://remember.dev) managed memory service.
|
|
4
|
+
|
|
5
|
+
This distribution provides:
|
|
6
|
+
- **`remember.Client`** (D65): The primary ergonomic client for memory operations. Connects directly to your dedicated tenant deployment ingress with a single deployment API token (`umc_dp_…`).
|
|
7
|
+
- **`remember.CloudClient`** (D53): The control-plane client for checking deployment readiness, credit balances, and spend gates using a control-plane token (`umc_cp_…`).
|
|
8
|
+
- **`remember-status`**: CLI tool for quick control-plane status checks.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```console
|
|
13
|
+
pip install remember
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This automatically installs `rememberstack` (which provides the `remember` CLI tool on `PATH`).
|
|
17
|
+
|
|
18
|
+
## Quickstart: Memory Operations (`Client`)
|
|
19
|
+
|
|
20
|
+
Mint an **API Token** (`umc_dp_…`) from your dashboard at **Settings → API Tokens**, then initialize `Client`:
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
import remember
|
|
24
|
+
|
|
25
|
+
# Client accepts a bare secret (umc_dp_...) or a full Bearer string,
|
|
26
|
+
# and converts string file paths automatically:
|
|
27
|
+
with remember.Client(
|
|
28
|
+
api_key="umc_dp_…",
|
|
29
|
+
base_url="https://<deployment-id>.dp.remember.dev",
|
|
30
|
+
) as memory:
|
|
31
|
+
landed = memory.ingest("notes/project.md")
|
|
32
|
+
print("Ingested version:", landed.version_id)
|
|
33
|
+
|
|
34
|
+
# Search claims or chunks
|
|
35
|
+
claims = memory.search_claims(query="architecture decisions")
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Environment Variables
|
|
39
|
+
|
|
40
|
+
For zero-config agent setups, set `REMEMBER_API_KEY` and `REMEMBER_API_URL`:
|
|
41
|
+
|
|
42
|
+
```console
|
|
43
|
+
export REMEMBER_API_URL="https://<deployment-id>.dp.remember.dev"
|
|
44
|
+
export REMEMBER_API_KEY="umc_dp_…"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
import remember
|
|
49
|
+
|
|
50
|
+
with remember.Client.from_env() as memory:
|
|
51
|
+
landed = memory.ingest("notes/project.md")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`Client` also automatically falls back to `REMEMBERSTACK_API_AUTHORIZATION` and `REMEMBERSTACK_API_URL` for seamless compatibility.
|
|
55
|
+
|
|
56
|
+
## Quickstart: Status & Balances (`CloudClient`)
|
|
57
|
+
|
|
58
|
+
To check billing balance and deployment readiness in CI or monitoring bots, use `CloudClient` with an organisation-scoped control-plane token (`umc_cp_…`).
|
|
59
|
+
|
|
60
|
+
Control tokens are read-only, expiring status credentials (D53/D65). Because they are an API-only operational surface, mint one via the control-plane endpoint while authenticated with an owner session:
|
|
61
|
+
- **Endpoint**: `POST /app/api/v1/orgs/{org_id}/control-tokens` (or `POST /v1/orgs/{org_id}/control-tokens` against the direct control-plane URL).
|
|
62
|
+
- **Body**: `{"label": "ci-monitor", "expires_in_days": 90}` (accepts `label` and optional `expires_in_days` up to 90).
|
|
63
|
+
|
|
64
|
+
```console
|
|
65
|
+
export REMEMBER_CLOUD_TOKEN='umc_cp_…'
|
|
66
|
+
export REMEMBER_CLOUD_ORG='your-organisation-id'
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from remember import CloudClient
|
|
71
|
+
|
|
72
|
+
with CloudClient.from_env() as cloud:
|
|
73
|
+
if cloud.is_ready():
|
|
74
|
+
print("Balance:", cloud.billing_status().balance)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
You can also run the status CLI:
|
|
78
|
+
|
|
79
|
+
```console
|
|
80
|
+
$ remember-status
|
|
81
|
+
deployment active bb81063d-6b7b-41d0-a1df-dc57d4f1fe87
|
|
82
|
+
endpoint live bb81063d-6b7b-41d0-a1df-dc57d4f1fe87.dp.remember.dev
|
|
83
|
+
billing active balance 42.10
|
|
84
|
+
spend allow
|
|
85
|
+
```
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "remember"
|
|
7
|
+
version = "0.3.0"
|
|
8
|
+
description = "Official Python client for the remember.dev managed memory service."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
license = { text = "Apache-2.0" }
|
|
12
|
+
authors = [{ name = "WriteIt.ai s.r.o.", email = "info@writeit.ai" }]
|
|
13
|
+
keywords = ["remember.dev", "rememberstack", "memory", "agents"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"Programming Language :: Python :: 3.13",
|
|
20
|
+
"Typing :: Typed",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
# D43 rule 1 & D65: the cloud distribution depends on rememberstack for the core
|
|
24
|
+
# memory client and engine wire models. This package exposes the ergonomic Client
|
|
25
|
+
# facade for data-plane memory operations and CloudClient for control-plane queries.
|
|
26
|
+
dependencies = [
|
|
27
|
+
"httpx>=0.27",
|
|
28
|
+
"rememberstack>=0.8.1",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://remember.dev"
|
|
33
|
+
Documentation = "https://remember.dev/docs"
|
|
34
|
+
Source = "https://github.com/writeitai/ultimate-memory-cloud"
|
|
35
|
+
|
|
36
|
+
# D43 rule 3: this project declares NO console script named `remember`. That
|
|
37
|
+
# entry point belongs to `rememberstack` alone, and colliding on it would be a
|
|
38
|
+
# PATH conflict between two installed distributions.
|
|
39
|
+
[project.scripts]
|
|
40
|
+
remember-status = "remember.cli:main"
|
|
41
|
+
|
|
42
|
+
[tool.hatch.build.targets.wheel]
|
|
43
|
+
packages = ["src/remember"]
|
|
44
|
+
|
|
45
|
+
# The client's tests are their own suite: the repository's root pytest run is
|
|
46
|
+
# scoped to ``src/tests`` and never collects them. Declaring the section here
|
|
47
|
+
# also makes ``client`` pytest's rootdir, so a run does not inherit the service's
|
|
48
|
+
# asyncio settings.
|
|
49
|
+
[tool.pytest.ini_options]
|
|
50
|
+
testpaths = ["tests"]
|
|
51
|
+
|
|
52
|
+
[dependency-groups]
|
|
53
|
+
dev = ["pytest>=8.3", "respx>=0.21", "mypy>=1.14", "ruff>=0.9"]
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Python client library for the remember.dev managed memory service (D65).
|
|
2
|
+
|
|
3
|
+
PyPI project **`remember`**, import name **`remember`**.
|
|
4
|
+
|
|
5
|
+
What this package provides
|
|
6
|
+
--------------------------
|
|
7
|
+
|
|
8
|
+
1. **`Client`** (D65):
|
|
9
|
+
The primary developer memory client. Accepts a single deployment API token
|
|
10
|
+
(``umc_dp_…``) or bare secret, connects directly to tenant deployment ingress,
|
|
11
|
+
and provides ergonomic access to all memory operations (ingest, search,
|
|
12
|
+
pipeline readiness, and assured operations).
|
|
13
|
+
|
|
14
|
+
import remember
|
|
15
|
+
|
|
16
|
+
with remember.Client(
|
|
17
|
+
api_key="umc_dp_…",
|
|
18
|
+
base_url="https://<deployment-id>.dp.remember.dev",
|
|
19
|
+
) as memory:
|
|
20
|
+
landed = memory.ingest("guide.pdf")
|
|
21
|
+
|
|
22
|
+
Or zero-config from environment variables (``REMEMBER_API_KEY`` and ``REMEMBER_API_URL``):
|
|
23
|
+
|
|
24
|
+
memory = remember.Client.from_env()
|
|
25
|
+
|
|
26
|
+
2. **`CloudClient`** (D53):
|
|
27
|
+
The control-plane client. Uses an organisation-scoped control-plane token
|
|
28
|
+
(``umc_cp_…``) to inspect deployment readiness, credit balance, and spend gates.
|
|
29
|
+
|
|
30
|
+
from remember import CloudClient
|
|
31
|
+
|
|
32
|
+
with CloudClient.from_env() as cloud:
|
|
33
|
+
status = cloud.billing_status()
|
|
34
|
+
print(status.state, status.balance)
|
|
35
|
+
|
|
36
|
+
3. **Core Re-exports**:
|
|
37
|
+
Typed models and errors (:class:`Envelope`, :class:`ContextBundleV1`,
|
|
38
|
+
:class:`IngestedVersion`, :class:`ReadinessRequirements`, :class:`MemoryApiError`)
|
|
39
|
+
are re-exported directly from ``remember`` for convenient typing.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
from rememberstack.client import MemoryApiError
|
|
43
|
+
from rememberstack.client import ReadinessRequirements
|
|
44
|
+
from rememberstack.model import ContextBundleV1
|
|
45
|
+
from rememberstack.model import Envelope
|
|
46
|
+
from rememberstack.model import IngestedVersion
|
|
47
|
+
|
|
48
|
+
from remember.client import Client
|
|
49
|
+
from remember.client import CloudClient
|
|
50
|
+
from remember.errors import CloudError
|
|
51
|
+
from remember.errors import NotPermitted
|
|
52
|
+
from remember.errors import RateLimited
|
|
53
|
+
from remember.errors import Unauthenticated
|
|
54
|
+
from remember.models import BillingStatus
|
|
55
|
+
from remember.models import Deployment
|
|
56
|
+
from remember.models import LedgerEntry
|
|
57
|
+
from remember.models import SpendGate
|
|
58
|
+
|
|
59
|
+
__all__ = [
|
|
60
|
+
"BillingStatus",
|
|
61
|
+
"Client",
|
|
62
|
+
"CloudClient",
|
|
63
|
+
"CloudError",
|
|
64
|
+
"ContextBundleV1",
|
|
65
|
+
"Deployment",
|
|
66
|
+
"Envelope",
|
|
67
|
+
"IngestedVersion",
|
|
68
|
+
"LedgerEntry",
|
|
69
|
+
"MemoryApiError",
|
|
70
|
+
"NotPermitted",
|
|
71
|
+
"RateLimited",
|
|
72
|
+
"ReadinessRequirements",
|
|
73
|
+
"SpendGate",
|
|
74
|
+
"Unauthenticated",
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
__version__ = "0.3.0"
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""``remember-status`` — one command that answers the operator's question.
|
|
2
|
+
|
|
3
|
+
Named for what it does, and deliberately **not** ``remember``: that console
|
|
4
|
+
script belongs to ``rememberstack`` alone (D43 rule 3), and two installed
|
|
5
|
+
distributions competing for one name on ``PATH`` is a conflict no user should
|
|
6
|
+
have to debug.
|
|
7
|
+
|
|
8
|
+
$ remember-status
|
|
9
|
+
deployment active bb81063d-…dc57d4f1fe87
|
|
10
|
+
endpoint live bb81063d-….dp.remember.dev
|
|
11
|
+
billing active balance 42.10
|
|
12
|
+
spend allow
|
|
13
|
+
|
|
14
|
+
Exit status is meaningful, so a shell can branch: ``0`` ready, ``1`` not ready,
|
|
15
|
+
``2`` could not ask.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import argparse
|
|
21
|
+
from collections.abc import Sequence
|
|
22
|
+
import sys
|
|
23
|
+
|
|
24
|
+
from remember.client import CloudClient
|
|
25
|
+
from remember.errors import CloudError
|
|
26
|
+
from remember.errors import RateLimited
|
|
27
|
+
from remember.errors import Unauthenticated
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def main(argv: Sequence[str] | None = None) -> int:
|
|
31
|
+
"""Print one organisation's status; return an exit code a script can use."""
|
|
32
|
+
parser = argparse.ArgumentParser(
|
|
33
|
+
prog="remember-status",
|
|
34
|
+
description=(
|
|
35
|
+
"Report a remember.dev organisation's deployment, billing, and "
|
|
36
|
+
"spend state. Reads REMEMBER_CLOUD_TOKEN and REMEMBER_CLOUD_ORG."
|
|
37
|
+
),
|
|
38
|
+
)
|
|
39
|
+
parser.add_argument("--org", default=None, help="organisation id")
|
|
40
|
+
parser.add_argument("--url", default=None, help="control-plane base URL")
|
|
41
|
+
parser.add_argument(
|
|
42
|
+
"--quiet", action="store_true", help="print nothing; use the exit status only"
|
|
43
|
+
)
|
|
44
|
+
args = parser.parse_args(argv)
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
overrides = {}
|
|
48
|
+
if args.org:
|
|
49
|
+
overrides["org_id"] = args.org
|
|
50
|
+
if args.url:
|
|
51
|
+
overrides["base_url"] = args.url
|
|
52
|
+
with CloudClient.from_env(**overrides) as cloud:
|
|
53
|
+
return _report(cloud=cloud, quiet=bool(args.quiet))
|
|
54
|
+
except ValueError as error:
|
|
55
|
+
# Missing configuration: tell the user what to set, not a stack trace.
|
|
56
|
+
print(f"remember-status: {error}", file=sys.stderr)
|
|
57
|
+
return 2
|
|
58
|
+
except Unauthenticated as error:
|
|
59
|
+
print(
|
|
60
|
+
f"remember-status: credential rejected ({error}). "
|
|
61
|
+
"Mint a fresh control-plane token with "
|
|
62
|
+
"POST /v1/orgs/<org>/control-tokens while signed in.",
|
|
63
|
+
file=sys.stderr,
|
|
64
|
+
)
|
|
65
|
+
return 2
|
|
66
|
+
except RateLimited as error:
|
|
67
|
+
wait = f" retry in {error.retry_after:.0f}s" if error.retry_after else ""
|
|
68
|
+
print(f"remember-status: rate limited{wait}", file=sys.stderr)
|
|
69
|
+
return 2
|
|
70
|
+
except CloudError as error:
|
|
71
|
+
print(f"remember-status: {error}", file=sys.stderr)
|
|
72
|
+
return 2
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _report(*, cloud: CloudClient, quiet: bool) -> int:
|
|
76
|
+
"""Print the four facts worth knowing, and decide the exit code."""
|
|
77
|
+
deployment = cloud.deployment()
|
|
78
|
+
billing = cloud.billing_status()
|
|
79
|
+
gate = None
|
|
80
|
+
if deployment is not None:
|
|
81
|
+
gate = cloud.spend_gate(deployment_id=deployment.id)
|
|
82
|
+
|
|
83
|
+
if not quiet:
|
|
84
|
+
if deployment is None:
|
|
85
|
+
_line("deployment", "none", "no deployment provisioned yet")
|
|
86
|
+
else:
|
|
87
|
+
_line("deployment", deployment.state, deployment.id)
|
|
88
|
+
_line(
|
|
89
|
+
"endpoint",
|
|
90
|
+
"live" if deployment.hostname_live else "not serving",
|
|
91
|
+
deployment.hostname or "unknown",
|
|
92
|
+
)
|
|
93
|
+
balance = f"balance {billing.balance}" if billing.balance else ""
|
|
94
|
+
_line("billing", billing.state, balance)
|
|
95
|
+
if gate is not None:
|
|
96
|
+
_line("spend", gate.decision, gate.reason_code or "")
|
|
97
|
+
|
|
98
|
+
# Every fact printed above counts toward the exit code. A script that
|
|
99
|
+
# branches on `remember-status` is asking "can work run right now", and a
|
|
100
|
+
# zero exit while the spend gate says `park` would send it straight into a
|
|
101
|
+
# refusal. `is_ready` already covers endpoint liveness as well as state.
|
|
102
|
+
ready = (
|
|
103
|
+
deployment is not None
|
|
104
|
+
and deployment.is_ready
|
|
105
|
+
and billing.can_spend
|
|
106
|
+
and (gate is None or gate.allows_work)
|
|
107
|
+
)
|
|
108
|
+
return 0 if ready else 1
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _line(label: str, state: str, detail: str = "") -> None:
|
|
112
|
+
"""One aligned row, so several runs stack readably in a terminal."""
|
|
113
|
+
print(f"{label:<11} {state:<10} {detail}".rstrip())
|