boxyard 0.2.0__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.
- {boxyard-0.2.0 → boxyard-0.3.0}/.gitignore +3 -0
- boxyard-0.3.0/PKG-INFO +171 -0
- boxyard-0.3.0/README.md +156 -0
- {boxyard-0.2.0 → boxyard-0.3.0}/pyproject.toml +7 -5
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/_cli/app.py +1 -1
- boxyard-0.3.0/src/boxyard/_cli/main.py +2727 -0
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/_cli/multi_sync.py +80 -51
- boxyard-0.3.0/src/boxyard/_cli/path_tui.py +176 -0
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/_enums.py +1 -1
- boxyard-0.3.0/src/boxyard/_fast.py +274 -0
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/_models.py +206 -70
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/_remote_index.py +1 -16
- boxyard-0.3.0/src/boxyard/_shell_helper.py +94 -0
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/_tombstones.py +1 -17
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/_utils/base.py +63 -38
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/_utils/locking.py +35 -27
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/_utils/logical_expressions.py +13 -8
- boxyard-0.3.0/src/boxyard/_utils/perms.py +124 -0
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/_utils/rclone.py +132 -55
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/_utils/sync_helper.py +57 -51
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/cmds/__init__.py +1 -0
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/cmds/_copy_from_remote.py +28 -21
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/cmds/_create_user_symlinks.py +3 -4
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/cmds/_delete_box.py +27 -14
- boxyard-0.3.0/src/boxyard/cmds/_doctor.py +518 -0
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/cmds/_exclude_box.py +23 -10
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/cmds/_force_push_to_remote.py +32 -27
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/cmds/_get_box_sync_status.py +12 -8
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/cmds/_include_box.py +9 -8
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/cmds/_init_boxyard.py +19 -11
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/cmds/_modify_boxmeta.py +44 -13
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/cmds/_new_box.py +36 -33
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/cmds/_rename_box.py +35 -36
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/cmds/_sync_box.py +66 -48
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/cmds/_sync_missing_boxmetas.py +30 -22
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/cmds/_sync_name.py +12 -13
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/config.py +28 -19
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/const.py +8 -24
- boxyard-0.2.0/PKG-INFO +0 -65
- boxyard-0.2.0/README.md +0 -51
- boxyard-0.2.0/src/boxyard/_cli/main.py +0 -1656
- {boxyard-0.2.0 → boxyard-0.3.0}/LICENSE +0 -0
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/__init__.py +0 -0
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/_cli/__init__.py +0 -0
- {boxyard-0.2.0 → boxyard-0.3.0}/src/boxyard/_utils/__init__.py +0 -0
|
@@ -184,3 +184,6 @@ cython_debug/
|
|
|
184
184
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
185
185
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
186
186
|
#.idea/
|
|
187
|
+
|
|
188
|
+
# Personal agent notes (not shared)
|
|
189
|
+
AGENTS.local.md
|
boxyard-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: boxyard
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Requires-Dist: filelock>=3.12.0
|
|
8
|
+
Requires-Dist: pydantic>=2.12.4
|
|
9
|
+
Requires-Dist: python-ulid[pydantic]>=3.1.0
|
|
10
|
+
Requires-Dist: rich>=14.2.0
|
|
11
|
+
Requires-Dist: textual>=1.0.0
|
|
12
|
+
Requires-Dist: toml>=0.10.2
|
|
13
|
+
Requires-Dist: typer>=0.20.0
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# boxyard
|
|
17
|
+
|
|
18
|
+
A CLI tool for managing and syncing folders ("boxes") across local and remote storage using [rclone](https://rclone.org/). Track metadata, organize boxes into groups, and keep everything in sync with conflict detection.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install boxyard
|
|
24
|
+
# or
|
|
25
|
+
uv pip install boxyard
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Requires [rclone](https://rclone.org/downloads/) to be installed and configured.
|
|
29
|
+
|
|
30
|
+
## Quick start
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Initialize boxyard (creates config and data directories)
|
|
34
|
+
boxyard init
|
|
35
|
+
|
|
36
|
+
# Create a new box from an existing folder
|
|
37
|
+
boxyard new ~/projects/my-project
|
|
38
|
+
|
|
39
|
+
# Sync a box to remote storage
|
|
40
|
+
boxyard sync my-project
|
|
41
|
+
|
|
42
|
+
# Check sync status
|
|
43
|
+
boxyard yard-status
|
|
44
|
+
|
|
45
|
+
# List all boxes
|
|
46
|
+
boxyard list
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## What it does
|
|
50
|
+
|
|
51
|
+
Boxyard manages folders (called "boxes") that you want to keep synced between your local machine and remote storage (S3, SFTP, or any rclone-supported backend).
|
|
52
|
+
|
|
53
|
+
Each box has:
|
|
54
|
+
- **Data** (`data/`) - the actual folder contents
|
|
55
|
+
- **Metadata** (`boxmeta.toml`) - name, groups, storage location, creation info
|
|
56
|
+
- **Config** (`conf/`) - optional per-box configuration that controls how data is synced
|
|
57
|
+
- **Sync records** - track what's been synced and when, enabling conflict detection
|
|
58
|
+
|
|
59
|
+
### The `conf/` folder
|
|
60
|
+
|
|
61
|
+
Each box can optionally have a `conf/` folder containing rclone filter files that customize which files are included or excluded when syncing the box's data:
|
|
62
|
+
|
|
63
|
+
- `.rclone_include` - only sync files matching these patterns
|
|
64
|
+
- `.rclone_exclude` - skip files matching these patterns (if absent, the global default exclude list is used)
|
|
65
|
+
- `.rclone_filters` - combined include/exclude filter rules
|
|
66
|
+
|
|
67
|
+
During sync, the `conf/` folder is synced *before* the data, ensuring filter rules are up-to-date before they're applied. This means filter rules travel with the box across remotes -- if you want a box to always exclude `.venv/` or only include `*.csv`, put that in its `conf/` folder and it will apply everywhere the box is synced.
|
|
68
|
+
|
|
69
|
+
Boxes are identified by a unique ID (`{timestamp}_{subid}`, e.g. `20251122_143022_a7kx9`) and organized into groups via symlinks.
|
|
70
|
+
|
|
71
|
+
## Commands
|
|
72
|
+
|
|
73
|
+
| Command | Description |
|
|
74
|
+
|---------|-------------|
|
|
75
|
+
| `init` | Initialize boxyard config and data directories |
|
|
76
|
+
| `new` | Create a new box from a folder |
|
|
77
|
+
| `sync` | Sync a box with remote storage |
|
|
78
|
+
| `multi-sync` | Sync multiple boxes concurrently |
|
|
79
|
+
| `list` | List all boxes |
|
|
80
|
+
| `box-status` | Show sync status of a box |
|
|
81
|
+
| `yard-status` | Show sync status of all boxes |
|
|
82
|
+
| `doctor` | Read-only health check of the machine's boxyard state |
|
|
83
|
+
| `include` | Include a remote box in the local store |
|
|
84
|
+
| `exclude` | Exclude a box from the local store (keeps remote) |
|
|
85
|
+
| `delete` | Delete a box locally and/or remotely |
|
|
86
|
+
| `rename` | Rename a box locally, remotely, or both |
|
|
87
|
+
| `copy` | Copy a remote box to a local path without including it |
|
|
88
|
+
| `force-push` | Force push a local folder to a box's remote |
|
|
89
|
+
| `add-to-group` | Add a box to a group |
|
|
90
|
+
| `remove-from-group` | Remove a box from a group |
|
|
91
|
+
| `path` | Get the local path of a box |
|
|
92
|
+
| `which` | Identify which box a path belongs to |
|
|
93
|
+
|
|
94
|
+
### `doctor`
|
|
95
|
+
|
|
96
|
+
`boxyard doctor` runs a strictly read-only health check of the machine's boxyard state, so misuse and drift get caught mechanically. It never mutates or auto-fixes anything, and exits with code 0 when healthy and 1 when there is any finding — so it can run under cron/supervisors and be asserted by scripts and agents.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
boxyard doctor # full check, including remote storage
|
|
100
|
+
boxyard doctor --no-remote # offline: skip checks that access remote storage
|
|
101
|
+
boxyard doctor -o json # machine-readable report
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Checks:
|
|
105
|
+
|
|
106
|
+
| Check | What it flags |
|
|
107
|
+
|-------|---------------|
|
|
108
|
+
| `unregistered-folder` | Directories in `user_boxes_path` that are not registered boxes (e.g. hand-created instead of via `boxyard new`) |
|
|
109
|
+
| `malformed-name` | Entries in `user_boxes_path` whose names don't parse as `<timestamp>_<subid>__<name>` (legacy formats are accepted) |
|
|
110
|
+
| `broken-registration` | `local_store` registrations missing `boxmeta.toml`, or with one that fails to parse/validate |
|
|
111
|
+
| `duplicate-box-id` | The same box id registered more than once |
|
|
112
|
+
| `stale-cache` | `boxyard_meta.json` disagreeing with a fresh scan of `local_store` |
|
|
113
|
+
| `dangling-symlinks` | Group symlinks whose targets don't exist |
|
|
114
|
+
| `group-tree-debris` | Real (non-symlink) files in the group tree, which make `create-user-symlinks` raise |
|
|
115
|
+
| `orphaned-sync-records` | `sync_records/<index>/` with no matching registration |
|
|
116
|
+
| `interrupted-sync` | Local sync records left incomplete by an interrupted sync (the local copy may be incomplete), or that fail to parse |
|
|
117
|
+
| `unknown-storage-location` | `local_store` dirs and remote-index caches left over from removed/renamed storage locations |
|
|
118
|
+
| `rclone-config` | Unresolvable rclone binary, rclone storage locations with no remote in `boxyard_rclone.conf`, or a missing default exclude file |
|
|
119
|
+
| `stale-meta-mirror` | Remote boxmetas not mirrored locally (what `sync-missing-meta` would fetch); skipped with `--no-remote` |
|
|
120
|
+
| `tombstoned-box` | Locally registered boxes that were deleted (tombstoned) on the remote from another machine; skipped with `--no-remote` |
|
|
121
|
+
| `tree-orphans` | Boxmeta `parents` referencing unknown box ids |
|
|
122
|
+
|
|
123
|
+
Every finding comes with a one-line hint on how to fix it.
|
|
124
|
+
|
|
125
|
+
## Configuration
|
|
126
|
+
|
|
127
|
+
Config file: `~/.config/boxyard/config.toml`
|
|
128
|
+
|
|
129
|
+
```toml
|
|
130
|
+
default_storage_location = "my-remote"
|
|
131
|
+
boxyard_data_path = "~/.boxyard"
|
|
132
|
+
user_boxes_path = "~/boxes"
|
|
133
|
+
user_box_groups_path = "~/box-groups"
|
|
134
|
+
|
|
135
|
+
[storage_locations.my-remote]
|
|
136
|
+
storage_type = "rclone"
|
|
137
|
+
store_path = "boxyard"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Storage locations are defined as rclone remotes. Boxyard uses its own rclone config at `~/.config/boxyard/boxyard_rclone.conf`.
|
|
141
|
+
|
|
142
|
+
## Directory layout
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
~/.config/boxyard/
|
|
146
|
+
config.toml # Main config
|
|
147
|
+
boxyard_rclone.conf # rclone config for remotes
|
|
148
|
+
|
|
149
|
+
~/.boxyard/
|
|
150
|
+
local_store/{remote}/ # Local copies of box data
|
|
151
|
+
sync_records/ # Per-box sync state
|
|
152
|
+
locks/ # File locks for concurrent operations
|
|
153
|
+
|
|
154
|
+
~/boxes/ # Symlinks to box data folders
|
|
155
|
+
~/box-groups/ # Group symlinks (e.g. ~/box-groups/work/my-project)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Development
|
|
159
|
+
|
|
160
|
+
Boxyard uses [nblite](https://github.com/lukastk/nblite) for notebook-first development. Source files in `src/boxyard/` are autogenerated -- edit the `.pct.py` files in `pts/` instead.
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
uv sync # Install dependencies
|
|
164
|
+
nbl export --reverse # Sync pts -> nbs (after editing .pct.py files)
|
|
165
|
+
nbl export # Export nbs -> src/boxyard/
|
|
166
|
+
pytest src/tests/ # Run tests
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
MIT
|
boxyard-0.3.0/README.md
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# boxyard
|
|
2
|
+
|
|
3
|
+
A CLI tool for managing and syncing folders ("boxes") across local and remote storage using [rclone](https://rclone.org/). Track metadata, organize boxes into groups, and keep everything in sync with conflict detection.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install boxyard
|
|
9
|
+
# or
|
|
10
|
+
uv pip install boxyard
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Requires [rclone](https://rclone.org/downloads/) to be installed and configured.
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Initialize boxyard (creates config and data directories)
|
|
19
|
+
boxyard init
|
|
20
|
+
|
|
21
|
+
# Create a new box from an existing folder
|
|
22
|
+
boxyard new ~/projects/my-project
|
|
23
|
+
|
|
24
|
+
# Sync a box to remote storage
|
|
25
|
+
boxyard sync my-project
|
|
26
|
+
|
|
27
|
+
# Check sync status
|
|
28
|
+
boxyard yard-status
|
|
29
|
+
|
|
30
|
+
# List all boxes
|
|
31
|
+
boxyard list
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## What it does
|
|
35
|
+
|
|
36
|
+
Boxyard manages folders (called "boxes") that you want to keep synced between your local machine and remote storage (S3, SFTP, or any rclone-supported backend).
|
|
37
|
+
|
|
38
|
+
Each box has:
|
|
39
|
+
- **Data** (`data/`) - the actual folder contents
|
|
40
|
+
- **Metadata** (`boxmeta.toml`) - name, groups, storage location, creation info
|
|
41
|
+
- **Config** (`conf/`) - optional per-box configuration that controls how data is synced
|
|
42
|
+
- **Sync records** - track what's been synced and when, enabling conflict detection
|
|
43
|
+
|
|
44
|
+
### The `conf/` folder
|
|
45
|
+
|
|
46
|
+
Each box can optionally have a `conf/` folder containing rclone filter files that customize which files are included or excluded when syncing the box's data:
|
|
47
|
+
|
|
48
|
+
- `.rclone_include` - only sync files matching these patterns
|
|
49
|
+
- `.rclone_exclude` - skip files matching these patterns (if absent, the global default exclude list is used)
|
|
50
|
+
- `.rclone_filters` - combined include/exclude filter rules
|
|
51
|
+
|
|
52
|
+
During sync, the `conf/` folder is synced *before* the data, ensuring filter rules are up-to-date before they're applied. This means filter rules travel with the box across remotes -- if you want a box to always exclude `.venv/` or only include `*.csv`, put that in its `conf/` folder and it will apply everywhere the box is synced.
|
|
53
|
+
|
|
54
|
+
Boxes are identified by a unique ID (`{timestamp}_{subid}`, e.g. `20251122_143022_a7kx9`) and organized into groups via symlinks.
|
|
55
|
+
|
|
56
|
+
## Commands
|
|
57
|
+
|
|
58
|
+
| Command | Description |
|
|
59
|
+
|---------|-------------|
|
|
60
|
+
| `init` | Initialize boxyard config and data directories |
|
|
61
|
+
| `new` | Create a new box from a folder |
|
|
62
|
+
| `sync` | Sync a box with remote storage |
|
|
63
|
+
| `multi-sync` | Sync multiple boxes concurrently |
|
|
64
|
+
| `list` | List all boxes |
|
|
65
|
+
| `box-status` | Show sync status of a box |
|
|
66
|
+
| `yard-status` | Show sync status of all boxes |
|
|
67
|
+
| `doctor` | Read-only health check of the machine's boxyard state |
|
|
68
|
+
| `include` | Include a remote box in the local store |
|
|
69
|
+
| `exclude` | Exclude a box from the local store (keeps remote) |
|
|
70
|
+
| `delete` | Delete a box locally and/or remotely |
|
|
71
|
+
| `rename` | Rename a box locally, remotely, or both |
|
|
72
|
+
| `copy` | Copy a remote box to a local path without including it |
|
|
73
|
+
| `force-push` | Force push a local folder to a box's remote |
|
|
74
|
+
| `add-to-group` | Add a box to a group |
|
|
75
|
+
| `remove-from-group` | Remove a box from a group |
|
|
76
|
+
| `path` | Get the local path of a box |
|
|
77
|
+
| `which` | Identify which box a path belongs to |
|
|
78
|
+
|
|
79
|
+
### `doctor`
|
|
80
|
+
|
|
81
|
+
`boxyard doctor` runs a strictly read-only health check of the machine's boxyard state, so misuse and drift get caught mechanically. It never mutates or auto-fixes anything, and exits with code 0 when healthy and 1 when there is any finding — so it can run under cron/supervisors and be asserted by scripts and agents.
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
boxyard doctor # full check, including remote storage
|
|
85
|
+
boxyard doctor --no-remote # offline: skip checks that access remote storage
|
|
86
|
+
boxyard doctor -o json # machine-readable report
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Checks:
|
|
90
|
+
|
|
91
|
+
| Check | What it flags |
|
|
92
|
+
|-------|---------------|
|
|
93
|
+
| `unregistered-folder` | Directories in `user_boxes_path` that are not registered boxes (e.g. hand-created instead of via `boxyard new`) |
|
|
94
|
+
| `malformed-name` | Entries in `user_boxes_path` whose names don't parse as `<timestamp>_<subid>__<name>` (legacy formats are accepted) |
|
|
95
|
+
| `broken-registration` | `local_store` registrations missing `boxmeta.toml`, or with one that fails to parse/validate |
|
|
96
|
+
| `duplicate-box-id` | The same box id registered more than once |
|
|
97
|
+
| `stale-cache` | `boxyard_meta.json` disagreeing with a fresh scan of `local_store` |
|
|
98
|
+
| `dangling-symlinks` | Group symlinks whose targets don't exist |
|
|
99
|
+
| `group-tree-debris` | Real (non-symlink) files in the group tree, which make `create-user-symlinks` raise |
|
|
100
|
+
| `orphaned-sync-records` | `sync_records/<index>/` with no matching registration |
|
|
101
|
+
| `interrupted-sync` | Local sync records left incomplete by an interrupted sync (the local copy may be incomplete), or that fail to parse |
|
|
102
|
+
| `unknown-storage-location` | `local_store` dirs and remote-index caches left over from removed/renamed storage locations |
|
|
103
|
+
| `rclone-config` | Unresolvable rclone binary, rclone storage locations with no remote in `boxyard_rclone.conf`, or a missing default exclude file |
|
|
104
|
+
| `stale-meta-mirror` | Remote boxmetas not mirrored locally (what `sync-missing-meta` would fetch); skipped with `--no-remote` |
|
|
105
|
+
| `tombstoned-box` | Locally registered boxes that were deleted (tombstoned) on the remote from another machine; skipped with `--no-remote` |
|
|
106
|
+
| `tree-orphans` | Boxmeta `parents` referencing unknown box ids |
|
|
107
|
+
|
|
108
|
+
Every finding comes with a one-line hint on how to fix it.
|
|
109
|
+
|
|
110
|
+
## Configuration
|
|
111
|
+
|
|
112
|
+
Config file: `~/.config/boxyard/config.toml`
|
|
113
|
+
|
|
114
|
+
```toml
|
|
115
|
+
default_storage_location = "my-remote"
|
|
116
|
+
boxyard_data_path = "~/.boxyard"
|
|
117
|
+
user_boxes_path = "~/boxes"
|
|
118
|
+
user_box_groups_path = "~/box-groups"
|
|
119
|
+
|
|
120
|
+
[storage_locations.my-remote]
|
|
121
|
+
storage_type = "rclone"
|
|
122
|
+
store_path = "boxyard"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Storage locations are defined as rclone remotes. Boxyard uses its own rclone config at `~/.config/boxyard/boxyard_rclone.conf`.
|
|
126
|
+
|
|
127
|
+
## Directory layout
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
~/.config/boxyard/
|
|
131
|
+
config.toml # Main config
|
|
132
|
+
boxyard_rclone.conf # rclone config for remotes
|
|
133
|
+
|
|
134
|
+
~/.boxyard/
|
|
135
|
+
local_store/{remote}/ # Local copies of box data
|
|
136
|
+
sync_records/ # Per-box sync state
|
|
137
|
+
locks/ # File locks for concurrent operations
|
|
138
|
+
|
|
139
|
+
~/boxes/ # Symlinks to box data folders
|
|
140
|
+
~/box-groups/ # Group symlinks (e.g. ~/box-groups/work/my-project)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Development
|
|
144
|
+
|
|
145
|
+
Boxyard uses [nblite](https://github.com/lukastk/nblite) for notebook-first development. Source files in `src/boxyard/` are autogenerated -- edit the `.pct.py` files in `pts/` instead.
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
uv sync # Install dependencies
|
|
149
|
+
nbl export --reverse # Sync pts -> nbs (after editing .pct.py files)
|
|
150
|
+
nbl export # Export nbs -> src/boxyard/
|
|
151
|
+
pytest src/tests/ # Run tests
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## License
|
|
155
|
+
|
|
156
|
+
MIT
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "boxyard"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "Add your description here"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -9,6 +9,7 @@ dependencies = [
|
|
|
9
9
|
"pydantic>=2.12.4",
|
|
10
10
|
"python-ulid[pydantic]>=3.1.0",
|
|
11
11
|
"rich>=14.2.0",
|
|
12
|
+
"textual>=1.0.0",
|
|
12
13
|
"toml>=0.10.2",
|
|
13
14
|
"typer>=0.20.0",
|
|
14
15
|
]
|
|
@@ -28,7 +29,7 @@ dev = [
|
|
|
28
29
|
"git-cliff>=2.10.1",
|
|
29
30
|
"ipywidgets>=8.1.8",
|
|
30
31
|
"jupyterlab>=4.4.0",
|
|
31
|
-
"nblite>=1.
|
|
32
|
+
"nblite>=1.2.2", # 1.2.1 emits broken relative imports for function-export modules
|
|
32
33
|
"pytest>=9.0.0",
|
|
33
34
|
"python-dotenv>=1.2.1",
|
|
34
35
|
"ruff>=0.14.13",
|
|
@@ -37,6 +38,7 @@ dev = [
|
|
|
37
38
|
|
|
38
39
|
[project.scripts]
|
|
39
40
|
boxyard = "boxyard._cli.app:app"
|
|
41
|
+
boxyard-shell-helper = "boxyard._shell_helper:main"
|
|
40
42
|
|
|
41
43
|
[tool.pytest.ini_options]
|
|
42
44
|
testpaths = ["src/tests"]
|
|
@@ -86,11 +88,11 @@ ignore = [
|
|
|
86
88
|
# but trigger ruff warnings (unsorted imports, lambda assignments, etc.)
|
|
87
89
|
"src/boxyard/**/*.py" = [
|
|
88
90
|
"I001", "E731", "B904", "B905", "B018", "B006", "B007", "B020", "B023",
|
|
89
|
-
"C401", "C408", "C416", "C419",
|
|
91
|
+
"C401", "C408", "C416", "C419", "C420",
|
|
90
92
|
"F401", "F403", "F405", "F541", "F841",
|
|
91
|
-
"E721",
|
|
93
|
+
"E703", "E721",
|
|
92
94
|
"UP017", "UP024", "UP035", "UP041",
|
|
93
|
-
"W293",
|
|
95
|
+
"W291", "W293",
|
|
94
96
|
]
|
|
95
97
|
|
|
96
98
|
[tool.ruff.lint.isort]
|