shelfdb 2.0.0.dev0__tar.gz → 3.0.1__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.
- shelfdb-3.0.1/PKG-INFO +130 -0
- shelfdb-3.0.1/README.md +111 -0
- shelfdb-3.0.1/ai-skill/shelfdb-usage/SKILL.md +56 -0
- shelfdb-3.0.1/pyproject.toml +55 -0
- shelfdb-2.0.0.dev0/pyproject.toml → shelfdb-3.0.1/pyproject.toml.orig +17 -11
- shelfdb-3.0.1/src/shelfdb/__init__.py +0 -0
- shelfdb-3.0.1/src/shelfdb/__main__.py +5 -0
- shelfdb-3.0.1/src/shelfdb/cli.py +109 -0
- shelfdb-3.0.1/src/shelfdb/client/__init__.py +3 -0
- shelfdb-3.0.1/src/shelfdb/client/client.py +225 -0
- shelfdb-3.0.1/src/shelfdb/protocol/__init__.py +35 -0
- shelfdb-3.0.1/src/shelfdb/protocol/demo_poc.py +62 -0
- shelfdb-3.0.1/src/shelfdb/protocol/protocol.py +81 -0
- shelfdb-3.0.1/src/shelfdb/protocol/query_result.py +49 -0
- shelfdb-3.0.1/src/shelfdb/protocol/server.py +110 -0
- shelfdb-3.0.1/src/shelfdb/protocol/session.py +180 -0
- shelfdb-3.0.1/src/shelfdb/shelf/__init__.py +4 -0
- shelfdb-3.0.1/src/shelfdb/shelf/db.py +217 -0
- shelfdb-3.0.1/src/shelfdb/shelf/shelf/__init__.py +4 -0
- shelfdb-3.0.1/src/shelfdb/shelf/shelf/query.py +200 -0
- shelfdb-3.0.1/src/shelfdb/shelf/shelf/schema.py +55 -0
- shelfdb-3.0.1/src/shelfdb/shelf/shelf/shelf.py +209 -0
- shelfdb-3.0.1/src/shelfdb/target.py +30 -0
- shelfdb-2.0.0.dev0/PKG-INFO +0 -120
- shelfdb-2.0.0.dev0/README.md +0 -98
- shelfdb-2.0.0.dev0/src/shelfdb/__init__.py +0 -11
- shelfdb-2.0.0.dev0/src/shelfdb/ai_skill/__init__.py +0 -1
- shelfdb-2.0.0.dev0/src/shelfdb/ai_skill/shelfdb-usage/SKILL.md +0 -90
- shelfdb-2.0.0.dev0/src/shelfdb/ai_skill/shelfdb-usage/agents/openai.yaml +0 -4
- shelfdb-2.0.0.dev0/src/shelfdb/ai_skill/shelfdb-usage/references/docs/api-reference.md +0 -74
- shelfdb-2.0.0.dev0/src/shelfdb/ai_skill/shelfdb-usage/references/docs/embedded-mode.md +0 -155
- shelfdb-2.0.0.dev0/src/shelfdb/ai_skill/shelfdb-usage/references/docs/getting-started.md +0 -118
- shelfdb-2.0.0.dev0/src/shelfdb/ai_skill/shelfdb-usage/references/docs/index.md +0 -93
- shelfdb-2.0.0.dev0/src/shelfdb/ai_skill/shelfdb-usage/references/docs/protocol.md +0 -136
- shelfdb-2.0.0.dev0/src/shelfdb/ai_skill/shelfdb-usage/references/docs/query-model.md +0 -188
- shelfdb-2.0.0.dev0/src/shelfdb/ai_skill/shelfdb-usage/references/docs/security.md +0 -37
- shelfdb-2.0.0.dev0/src/shelfdb/ai_skill/shelfdb-usage/references/docs/server-mode.md +0 -181
- shelfdb-2.0.0.dev0/src/shelfdb/ai_skill/shelfdb-usage/references/docs/transactions.md +0 -120
- shelfdb-2.0.0.dev0/src/shelfdb/cli.py +0 -122
- shelfdb-2.0.0.dev0/src/shelfdb/client/__init__.py +0 -38
- shelfdb-2.0.0.dev0/src/shelfdb/client/_impl.py +0 -409
- shelfdb-2.0.0.dev0/src/shelfdb/log.py +0 -36
- shelfdb-2.0.0.dev0/src/shelfdb/protocol/__init__.py +0 -27
- shelfdb-2.0.0.dev0/src/shelfdb/protocol/codec.py +0 -32
- shelfdb-2.0.0.dev0/src/shelfdb/protocol/payload.py +0 -129
- shelfdb-2.0.0.dev0/src/shelfdb/protocol/query.py +0 -22
- shelfdb-2.0.0.dev0/src/shelfdb/protocol/schema.py +0 -70
- shelfdb-2.0.0.dev0/src/shelfdb/server/__init__.py +0 -10
- shelfdb-2.0.0.dev0/src/shelfdb/server/rpc.py +0 -35
- shelfdb-2.0.0.dev0/src/shelfdb/server/runtime.py +0 -144
- shelfdb-2.0.0.dev0/src/shelfdb/shelf/__init__.py +0 -18
- shelfdb-2.0.0.dev0/src/shelfdb/shelf/core.py +0 -349
- shelfdb-2.0.0.dev0/src/shelfdb/shelf/normalize.py +0 -26
- shelfdb-2.0.0.dev0/src/shelfdb/shelf/query.py +0 -76
- shelfdb-2.0.0.dev0/src/shelfdb/shelf/storage/__init__.py +0 -1
- shelfdb-2.0.0.dev0/src/shelfdb/shelf/storage/lmdb.py +0 -150
- shelfdb-2.0.0.dev0/src/shelfdb/util/__init__.py +0 -1
- shelfdb-2.0.0.dev0/src/shelfdb/util/transport.py +0 -31
- shelfdb-2.0.0.dev0/src/shelfdb/util/validation.py +0 -45
- {shelfdb-2.0.0.dev0 → shelfdb-3.0.1}/LICENSE +0 -0
shelfdb-3.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: shelfdb
|
|
3
|
+
Version: 3.0.1
|
|
4
|
+
Summary: A tiny database for Python
|
|
5
|
+
Author: Nitipit Nontasuwan
|
|
6
|
+
Author-email: Nitipit Nontasuwan <nitipit@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Dist: cyclopts>=4.10.2,<5
|
|
12
|
+
Requires-Dist: dill>=0.4.0,<0.5
|
|
13
|
+
Requires-Dist: lmdb>=1.7.3,<2
|
|
14
|
+
Requires-Dist: msgpack>=1.2.1,<2
|
|
15
|
+
Requires-Python: >=3.12
|
|
16
|
+
Project-URL: Documentation, https://keenlycode.github.io/shelfdb/
|
|
17
|
+
Project-URL: Repository, https://github.com/keenlycode/shelfdb
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# shelfdb
|
|
21
|
+
|
|
22
|
+
Tiny LMDB-backed shelf database utilities.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install shelfdb
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
> [!WARNING]
|
|
31
|
+
> The client/server protocol uses `dill` to support Python callables. Only use it
|
|
32
|
+
> between trusted processes; do not expose the server to untrusted clients or public
|
|
33
|
+
> networks.
|
|
34
|
+
|
|
35
|
+
## Development
|
|
36
|
+
|
|
37
|
+
Install development dependencies:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
uv sync --dev
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Run the complete non-publishing release gate:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
uv run python -m dev release-check
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The gate audits locked dependencies, checks formatting, linting, types, supported
|
|
50
|
+
Python versions, strict documentation, release artifacts, metadata, and a clean
|
|
51
|
+
wheel installation. GitHub Actions runs the same gate on pull requests, `main`,
|
|
52
|
+
and version tags.
|
|
53
|
+
|
|
54
|
+
Serve the docs locally:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
uv run python -m dev docs serve --port 9001 --livereload
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Publish the docs with mike to the `docs` branch:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
uv run python -m dev docs publish
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Override the publish target when needed:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
uv run python -m dev docs publish --publish-version 3.0.1 --alias latest --branch docs --remote origin
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Server
|
|
73
|
+
|
|
74
|
+
Run the protocol server:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
shelfdb server
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Run the protocol server on a custom address:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
shelfdb server --url "tcp://0.0.0.0:17001" --db-path ./db
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Client
|
|
87
|
+
|
|
88
|
+
Connect a client:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from shelfdb.client import Client
|
|
92
|
+
|
|
93
|
+
client = await Client.connect("tcp://127.0.0.1:31337")
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Unix sockets also work:
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
from shelfdb.client import Client
|
|
100
|
+
|
|
101
|
+
client = await Client.connect("unix:///tmp/shelfdb.sock")
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Example
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from shelfdb.client import Client
|
|
108
|
+
|
|
109
|
+
client = await Client.connect("tcp://127.0.0.1:31337")
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
async with client.transaction() as tx:
|
|
113
|
+
users = tx.shelf("users")
|
|
114
|
+
|
|
115
|
+
count = await users.count().query()
|
|
116
|
+
alice = await users.key("alice").item().query()
|
|
117
|
+
admins = await users.filter(
|
|
118
|
+
lambda item: item.value["role"] == "admin"
|
|
119
|
+
).sort(reverse=True).query()
|
|
120
|
+
|
|
121
|
+
async with client.transaction(write=True) as tx:
|
|
122
|
+
users = tx.shelf("users")
|
|
123
|
+
|
|
124
|
+
await users.put("eve", {"role": "user"}).query()
|
|
125
|
+
await users.key("eve").update(
|
|
126
|
+
lambda item: {**item.value, "role": "admin"}
|
|
127
|
+
).query()
|
|
128
|
+
finally:
|
|
129
|
+
await client.close()
|
|
130
|
+
```
|
shelfdb-3.0.1/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# shelfdb
|
|
2
|
+
|
|
3
|
+
Tiny LMDB-backed shelf database utilities.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install shelfdb
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
> [!WARNING]
|
|
12
|
+
> The client/server protocol uses `dill` to support Python callables. Only use it
|
|
13
|
+
> between trusted processes; do not expose the server to untrusted clients or public
|
|
14
|
+
> networks.
|
|
15
|
+
|
|
16
|
+
## Development
|
|
17
|
+
|
|
18
|
+
Install development dependencies:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
uv sync --dev
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Run the complete non-publishing release gate:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
uv run python -m dev release-check
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The gate audits locked dependencies, checks formatting, linting, types, supported
|
|
31
|
+
Python versions, strict documentation, release artifacts, metadata, and a clean
|
|
32
|
+
wheel installation. GitHub Actions runs the same gate on pull requests, `main`,
|
|
33
|
+
and version tags.
|
|
34
|
+
|
|
35
|
+
Serve the docs locally:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
uv run python -m dev docs serve --port 9001 --livereload
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Publish the docs with mike to the `docs` branch:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
uv run python -m dev docs publish
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Override the publish target when needed:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
uv run python -m dev docs publish --publish-version 3.0.1 --alias latest --branch docs --remote origin
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Server
|
|
54
|
+
|
|
55
|
+
Run the protocol server:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
shelfdb server
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Run the protocol server on a custom address:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
shelfdb server --url "tcp://0.0.0.0:17001" --db-path ./db
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Client
|
|
68
|
+
|
|
69
|
+
Connect a client:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from shelfdb.client import Client
|
|
73
|
+
|
|
74
|
+
client = await Client.connect("tcp://127.0.0.1:31337")
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Unix sockets also work:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from shelfdb.client import Client
|
|
81
|
+
|
|
82
|
+
client = await Client.connect("unix:///tmp/shelfdb.sock")
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Example
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from shelfdb.client import Client
|
|
89
|
+
|
|
90
|
+
client = await Client.connect("tcp://127.0.0.1:31337")
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
async with client.transaction() as tx:
|
|
94
|
+
users = tx.shelf("users")
|
|
95
|
+
|
|
96
|
+
count = await users.count().query()
|
|
97
|
+
alice = await users.key("alice").item().query()
|
|
98
|
+
admins = await users.filter(
|
|
99
|
+
lambda item: item.value["role"] == "admin"
|
|
100
|
+
).sort(reverse=True).query()
|
|
101
|
+
|
|
102
|
+
async with client.transaction(write=True) as tx:
|
|
103
|
+
users = tx.shelf("users")
|
|
104
|
+
|
|
105
|
+
await users.put("eve", {"role": "user"}).query()
|
|
106
|
+
await users.key("eve").update(
|
|
107
|
+
lambda item: {**item.value, "role": "admin"}
|
|
108
|
+
).query()
|
|
109
|
+
finally:
|
|
110
|
+
await client.close()
|
|
111
|
+
```
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: shelfdb-usage
|
|
3
|
+
description: Use when writing, reviewing, or explaining ShelfDB local database code, async client/server code, transactions, or fluent queries.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ShelfDB usage
|
|
7
|
+
|
|
8
|
+
Choose access mode from the deployment:
|
|
9
|
+
|
|
10
|
+
- Use `shelfdb.shelf.DB` when the process can open the LMDB database directly.
|
|
11
|
+
- Use `shelfdb.client.Client` when a separate trusted process runs `shelfdb server`.
|
|
12
|
+
|
|
13
|
+
## Safety boundary
|
|
14
|
+
|
|
15
|
+
The remote protocol uses `dill` so queries can contain Python callables. Deserializing a
|
|
16
|
+
request can execute arbitrary code in the server process. Never expose the server to
|
|
17
|
+
untrusted clients or public networks.
|
|
18
|
+
|
|
19
|
+
## Local API
|
|
20
|
+
|
|
21
|
+
Use synchronous transactions. Operations execute directly; do not add `.query()`.
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from shelfdb.shelf import DB
|
|
25
|
+
|
|
26
|
+
with DB("db") as db:
|
|
27
|
+
with db.transaction(write=False) as tx:
|
|
28
|
+
users = list(tx.shelf("users").items())
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Remote API
|
|
32
|
+
|
|
33
|
+
Connect asynchronously, use read transactions by default, and pass `write=True` for
|
|
34
|
+
mutations. Fluent operations only build a remote query; `await ...query()` sends it.
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from shelfdb.client import Client
|
|
38
|
+
|
|
39
|
+
client = await Client.connect("tcp://127.0.0.1:31337")
|
|
40
|
+
try:
|
|
41
|
+
async with client.transaction() as tx:
|
|
42
|
+
users = await tx.shelf("users").items().query()
|
|
43
|
+
finally:
|
|
44
|
+
await client.close()
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Rules
|
|
48
|
+
|
|
49
|
+
- Use `client.transaction()` for remote reads.
|
|
50
|
+
- Use `client.transaction(write=True)` for remote mutations.
|
|
51
|
+
- Always close a remote client with `await client.close()`.
|
|
52
|
+
- Keep local and remote terminal behavior distinct.
|
|
53
|
+
- In a ShelfDB source checkout, use `tests/usage/` as executable examples.
|
|
54
|
+
- Consult the current documentation before assuming unsupported query behavior.
|
|
55
|
+
|
|
56
|
+
Documentation: https://keenlycode.github.io/shelfdb/
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["uv_build>=0.11.3,<0.12"]
|
|
3
|
+
build-backend = "uv_build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "shelfdb"
|
|
7
|
+
version = "3.0.1"
|
|
8
|
+
description = "A tiny database for Python"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Programming Language :: Python :: 3.12",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
]
|
|
17
|
+
dependencies = [
|
|
18
|
+
"cyclopts>=4.10.2,<5",
|
|
19
|
+
"dill>=0.4.0,<0.5",
|
|
20
|
+
"lmdb>=1.7.3,<2",
|
|
21
|
+
"msgpack>=1.2.1,<2",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[[project.authors]]
|
|
25
|
+
name = "Nitipit Nontasuwan"
|
|
26
|
+
email = "nitipit@gmail.com"
|
|
27
|
+
|
|
28
|
+
[project.scripts]
|
|
29
|
+
shelfdb = "shelfdb.cli:main"
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Documentation = "https://keenlycode.github.io/shelfdb/"
|
|
33
|
+
Repository = "https://github.com/keenlycode/shelfdb"
|
|
34
|
+
|
|
35
|
+
[dependency-groups]
|
|
36
|
+
dev = [
|
|
37
|
+
"mike>=2.1.3,<3",
|
|
38
|
+
"mkdocs>=1.6.1,<2",
|
|
39
|
+
"mkdocs-shadcn>=0.10.4,<0.11",
|
|
40
|
+
"mkdocstrings[python]>=0.29.0,<0.30",
|
|
41
|
+
"pytest-cov>=7.0.0,<8",
|
|
42
|
+
"pymdown-extensions>=11.0.0,<12",
|
|
43
|
+
"pytest>=9.0.0,<10",
|
|
44
|
+
"ruff>=0.13.0,<0.14",
|
|
45
|
+
"tinydb>=4.8.2,<5",
|
|
46
|
+
"ty>=0.0.1a17,<0.0.2",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
[tool.uv.build-backend]
|
|
50
|
+
module-name = "shelfdb"
|
|
51
|
+
module-root = "src"
|
|
52
|
+
source-include = ["ai-skill/**"]
|
|
53
|
+
|
|
54
|
+
[tool.uv.build-backend.data]
|
|
55
|
+
data = "ai-skill"
|
|
@@ -4,8 +4,8 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "shelfdb"
|
|
7
|
-
version = "
|
|
8
|
-
description = "A tiny
|
|
7
|
+
version = "3.0.1"
|
|
8
|
+
description = "A tiny database for Python"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
11
11
|
license = "MIT"
|
|
@@ -13,34 +13,40 @@ license-files = ["LICENSE"]
|
|
|
13
13
|
authors = [
|
|
14
14
|
{ name = "Nitipit Nontasuwan", email = "nitipit@gmail.com" },
|
|
15
15
|
]
|
|
16
|
-
keywords = ["dict", "json", "database"]
|
|
17
16
|
classifiers = [
|
|
18
17
|
"Programming Language :: Python :: 3.12",
|
|
19
|
-
"License :: OSI Approved :: MIT License",
|
|
20
18
|
"Operating System :: OS Independent",
|
|
21
19
|
]
|
|
22
20
|
dependencies = [
|
|
23
|
-
"cyclopts>=4.10.2",
|
|
24
|
-
"dictify>=4.0.0,<4.1",
|
|
21
|
+
"cyclopts>=4.10.2,<5",
|
|
25
22
|
"dill>=0.4.0,<0.5",
|
|
26
23
|
"lmdb>=1.7.3,<2",
|
|
27
|
-
"msgpack>=1.1
|
|
28
|
-
"structlog>=25.1.0,<26",
|
|
29
|
-
"uvloop>=0.22.0,<0.23; platform_system == 'Linux'",
|
|
24
|
+
"msgpack>=1.2.1,<2",
|
|
30
25
|
]
|
|
31
26
|
|
|
32
27
|
[project.scripts]
|
|
33
28
|
shelfdb = "shelfdb.cli:main"
|
|
34
29
|
|
|
30
|
+
[project.urls]
|
|
31
|
+
Documentation = "https://keenlycode.github.io/shelfdb/"
|
|
32
|
+
Repository = "https://github.com/keenlycode/shelfdb"
|
|
33
|
+
|
|
35
34
|
[dependency-groups]
|
|
36
35
|
dev = [
|
|
37
|
-
"
|
|
36
|
+
"mike>=2.1.3,<3",
|
|
38
37
|
"mkdocs>=1.6.1,<2",
|
|
39
38
|
"mkdocs-shadcn>=0.10.4,<0.11",
|
|
40
39
|
"mkdocstrings[python]>=0.29.0,<0.30",
|
|
41
|
-
"pytest>=
|
|
40
|
+
"pytest-cov>=7.0.0,<8",
|
|
41
|
+
"pymdown-extensions>=11.0.0,<12",
|
|
42
|
+
"pytest>=9.0.0,<10",
|
|
43
|
+
"ruff>=0.13.0,<0.14",
|
|
44
|
+
"tinydb>=4.8.2,<5",
|
|
45
|
+
"ty>=0.0.1a17,<0.0.2",
|
|
42
46
|
]
|
|
43
47
|
|
|
44
48
|
[tool.uv.build-backend]
|
|
45
49
|
module-name = "shelfdb"
|
|
46
50
|
module-root = "src"
|
|
51
|
+
data = { data = "ai-skill" }
|
|
52
|
+
source-include = ["ai-skill/**"]
|
|
File without changes
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""Command-line interface for ShelfDB."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import shutil
|
|
6
|
+
import sysconfig
|
|
7
|
+
from contextlib import suppress
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from cyclopts import App
|
|
11
|
+
|
|
12
|
+
from shelfdb.protocol import serve, serve_unix
|
|
13
|
+
from shelfdb.shelf import DB
|
|
14
|
+
from shelfdb.target import parse_target, parse_tcp_location, parse_unix_location
|
|
15
|
+
|
|
16
|
+
app = App("shelfdb")
|
|
17
|
+
DEFAULT_AI_SKILL_INSTALL_PATH = ".agents/skills/shelfdb-usage"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def repo_root() -> Path:
|
|
21
|
+
return Path(__file__).resolve().parents[2]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def bundled_ai_skill_path() -> Path:
|
|
25
|
+
data_root = Path(sysconfig.get_path("data"))
|
|
26
|
+
installed_path = data_root / "shelfdb-usage"
|
|
27
|
+
if installed_path.exists():
|
|
28
|
+
return installed_path
|
|
29
|
+
|
|
30
|
+
repo_path = repo_root() / "ai-skill" / "shelfdb-usage"
|
|
31
|
+
if repo_path.exists():
|
|
32
|
+
return repo_path
|
|
33
|
+
|
|
34
|
+
raise FileNotFoundError("Bundled ShelfDB AI skill not found.")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def install_ai_skill(destination: Path, *, force: bool = False) -> Path:
|
|
38
|
+
source_file = bundled_ai_skill_path() / "SKILL.md"
|
|
39
|
+
if not source_file.is_file():
|
|
40
|
+
raise FileNotFoundError("Bundled ShelfDB SKILL.md not found.")
|
|
41
|
+
|
|
42
|
+
if destination.exists():
|
|
43
|
+
if not destination.is_dir():
|
|
44
|
+
raise NotADirectoryError(
|
|
45
|
+
f"AI skill destination is not a directory: {destination}"
|
|
46
|
+
)
|
|
47
|
+
if not force:
|
|
48
|
+
raise FileExistsError(
|
|
49
|
+
f"AI skill destination already exists: {destination}. Use --force to replace SKILL.md."
|
|
50
|
+
)
|
|
51
|
+
else:
|
|
52
|
+
destination.mkdir(parents=True)
|
|
53
|
+
|
|
54
|
+
shutil.copy2(source_file, destination / "SKILL.md")
|
|
55
|
+
return destination
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def prompt_ai_skill_install_path(
|
|
59
|
+
default_path: str = DEFAULT_AI_SKILL_INSTALL_PATH,
|
|
60
|
+
) -> Path:
|
|
61
|
+
response = input(f"Install ShelfDB AI skill to [{default_path}]: ").strip()
|
|
62
|
+
return Path(response or default_path)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
async def run_server(
|
|
66
|
+
*,
|
|
67
|
+
db_path: str,
|
|
68
|
+
url: str = "tcp://127.0.0.1:31337",
|
|
69
|
+
) -> None:
|
|
70
|
+
scheme, location = parse_target(url)
|
|
71
|
+
socket_path = None
|
|
72
|
+
|
|
73
|
+
with DB(db_path) as db:
|
|
74
|
+
if scheme == "tcp":
|
|
75
|
+
host, port = parse_tcp_location(location)
|
|
76
|
+
server = await serve(db, host=host, port=port)
|
|
77
|
+
else:
|
|
78
|
+
socket_path = str(Path(parse_unix_location(location)))
|
|
79
|
+
server = await serve_unix(db, path=socket_path)
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
await server.serve_forever()
|
|
83
|
+
finally:
|
|
84
|
+
server.close()
|
|
85
|
+
await server.wait_closed()
|
|
86
|
+
if socket_path is not None:
|
|
87
|
+
with suppress(FileNotFoundError):
|
|
88
|
+
Path(socket_path).unlink()
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@app.command
|
|
92
|
+
async def server(
|
|
93
|
+
db_path: str = "db",
|
|
94
|
+
url: str = "tcp://127.0.0.1:31337",
|
|
95
|
+
) -> None:
|
|
96
|
+
"""Run the ShelfDB protocol server."""
|
|
97
|
+
await run_server(db_path=db_path, url=url)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@app.command(name="ai-skill-install")
|
|
101
|
+
def ai_skill_install(path: str | None = None, force: bool = False) -> None:
|
|
102
|
+
"""Install the bundled ShelfDB AI skill to a local path."""
|
|
103
|
+
destination = Path(path) if path is not None else prompt_ai_skill_install_path()
|
|
104
|
+
installed = install_ai_skill(destination, force=force)
|
|
105
|
+
print(f"Installed ShelfDB AI skill to {installed}")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def main(argv: list[str] | None = None) -> None:
|
|
109
|
+
app(argv, backend="asyncio", result_action="return_none")
|