worktree-runtime 0.1.0a3__tar.gz → 0.1.0a4__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.
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/Cargo.lock +3 -3
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/Cargo.toml +3 -3
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/LICENSE +7 -1
- worktree_runtime-0.1.0a4/PKG-INFO +127 -0
- worktree_runtime-0.1.0a4/README.md +102 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/AGENTS.md +50 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/crates/worktree_runtime_core/src/application/binding_lifecycle.rs +158 -82
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/src/application/git_worktree_service.rs +126 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/crates/worktree_runtime_core/src/application/validation.rs +39 -9
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/src/application.rs +4 -0
- worktree_runtime-0.1.0a3/crates/worktree_runtime_core/src/infrastructure/audit_record.rs → worktree_runtime-0.1.0a4/crates/worktree_runtime_core/src/domain/audit.rs +28 -49
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/crates/worktree_runtime_core/src/domain/paths.rs +13 -1
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/src/domain/porcelain.rs +132 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/src/domain.rs +7 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/src/infrastructure/audit_dir.rs +38 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/crates/worktree_runtime_core/src/infrastructure/audit_file_io.rs +82 -6
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/src/infrastructure/audit_reader.rs +80 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/src/infrastructure/audit_writer.rs +135 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/src/infrastructure/binding_store.rs +290 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/src/infrastructure/git_adapter.rs +190 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/src/infrastructure/github_policy_loader.rs +88 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/src/infrastructure/project_id_resolver.rs +133 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/crates/worktree_runtime_core/src/infrastructure/worktree_base_resolver.rs +5 -38
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/crates/worktree_runtime_core/src/infrastructure/worktree_config_loader.rs +16 -6
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/src/infrastructure/worktree_list_reader.rs +75 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/crates/worktree_runtime_core/src/infrastructure.rs +3 -1
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/crates/worktree_runtime_core/tests/common/mod.rs +103 -5
- {worktree_runtime-0.1.0a3/crates/worktree_runtime_core/tests → worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/e2e}/binding_lifecycle_tests.rs +113 -38
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/e2e/git_worktree_service_tests.rs +215 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/e2e/main.rs +8 -0
- {worktree_runtime-0.1.0a3/crates/worktree_runtime_core/tests → worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/e2e}/validation_tests.rs +51 -7
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/integration/audit_dir_tests.rs +84 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/integration/audit_file_io_tests.rs +169 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/integration/audit_reader_tests.rs +108 -0
- {worktree_runtime-0.1.0a3/crates/worktree_runtime_core/tests → worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/integration}/audit_writer_tests.rs +190 -213
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/integration/binding_store_tests.rs +354 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/integration/git_adapter_tests.rs +73 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/integration/github_policy_loader_tests.rs +177 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/integration/main.rs +17 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/integration/path_resolution_tests.rs +17 -0
- {worktree_runtime-0.1.0a3/crates/worktree_runtime_core/tests → worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/integration}/project_id_resolver_tests.rs +79 -176
- {worktree_runtime-0.1.0a3/crates/worktree_runtime_core/tests → worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/integration}/worktree_base_resolver_tests.rs +59 -29
- {worktree_runtime-0.1.0a3/crates/worktree_runtime_core/tests → worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/integration}/worktree_config_loader_tests.rs +39 -7
- {worktree_runtime-0.1.0a3/crates/worktree_runtime_core/tests → worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/integration}/worktree_list_reader_tests.rs +42 -86
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/unit/audit_tests.rs +125 -0
- {worktree_runtime-0.1.0a3/crates/worktree_runtime_core/tests → worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/unit}/binding_tests.rs +9 -3
- {worktree_runtime-0.1.0a3/crates/worktree_runtime_core/tests → worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/unit}/env_keys_tests.rs +4 -3
- {worktree_runtime-0.1.0a3/crates/worktree_runtime_core/tests → worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/unit}/git_worktree_tests.rs +7 -2
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/unit/github_policy_tests.rs +31 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/unit/main.rs +9 -0
- {worktree_runtime-0.1.0a3/crates/worktree_runtime_core/tests → worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/unit}/paths_tests.rs +33 -3
- worktree_runtime-0.1.0a4/crates/worktree_runtime_core/tests/unit/porcelain_tests.rs +82 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_pyo3/src/convert.rs +148 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_pyo3/src/functions.rs +446 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_pyo3/src/lib.rs +134 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_pyo3/src/types.rs +563 -0
- worktree_runtime-0.1.0a4/crates/worktree_runtime_pyo3/tests/pyo3_signature_freeze_tests.rs +173 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/pyproject.toml +19 -2
- worktree_runtime-0.1.0a4/src/worktree_runtime/AGENTS.md +21 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/src/worktree_runtime/SURFACE.yaml +23 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/src/worktree_runtime/api/__init__.py +16 -35
- worktree_runtime-0.1.0a4/src/worktree_runtime/api/__init__.pyi +356 -0
- worktree_runtime-0.1.0a4/src/worktree_runtime/presentation/audit_cli.py +91 -0
- worktree_runtime-0.1.0a3/PKG-INFO +0 -9
- worktree_runtime-0.1.0a3/crates/worktree_runtime_core/AGENTS.md +0 -9
- worktree_runtime-0.1.0a3/crates/worktree_runtime_core/src/application/audit_service.rs +0 -7
- worktree_runtime-0.1.0a3/crates/worktree_runtime_core/src/application/checkout_service.rs +0 -97
- worktree_runtime-0.1.0a3/crates/worktree_runtime_core/src/application.rs +0 -5
- worktree_runtime-0.1.0a3/crates/worktree_runtime_core/src/domain/porcelain.rs +0 -35
- worktree_runtime-0.1.0a3/crates/worktree_runtime_core/src/domain.rs +0 -6
- worktree_runtime-0.1.0a3/crates/worktree_runtime_core/src/infrastructure/audit_writer.rs +0 -184
- worktree_runtime-0.1.0a3/crates/worktree_runtime_core/src/infrastructure/binding_store.rs +0 -139
- worktree_runtime-0.1.0a3/crates/worktree_runtime_core/src/infrastructure/git_adapter.rs +0 -57
- worktree_runtime-0.1.0a3/crates/worktree_runtime_core/src/infrastructure/project_id_resolver.rs +0 -190
- worktree_runtime-0.1.0a3/crates/worktree_runtime_core/src/infrastructure/worktree_list_reader.rs +0 -178
- worktree_runtime-0.1.0a3/crates/worktree_runtime_core/tests/audit_file_io_tests.rs +0 -103
- worktree_runtime-0.1.0a3/crates/worktree_runtime_core/tests/audit_record_tests.rs +0 -45
- worktree_runtime-0.1.0a3/crates/worktree_runtime_core/tests/audit_service_tests.rs +0 -44
- worktree_runtime-0.1.0a3/crates/worktree_runtime_core/tests/binding_store_tests.rs +0 -215
- worktree_runtime-0.1.0a3/crates/worktree_runtime_core/tests/checkout_service_tests.rs +0 -124
- worktree_runtime-0.1.0a3/crates/worktree_runtime_pyo3/src/lib.rs +0 -1075
- worktree_runtime-0.1.0a3/crates/worktree_runtime_pyo3/tests/pyo3_signature_freeze_tests.rs +0 -31
- worktree_runtime-0.1.0a3/src/worktree_runtime/AGENTS.md +0 -14
- worktree_runtime-0.1.0a3/src/worktree_runtime/api/__init__.pyi +0 -144
- worktree_runtime-0.1.0a3/src/worktree_runtime/api.pyi +0 -144
- worktree_runtime-0.1.0a3/src/worktree_runtime/presentation/audit_cli.py +0 -68
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/crates/worktree_runtime_core/Cargo.toml +0 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/crates/worktree_runtime_core/src/domain/binding.rs +0 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/crates/worktree_runtime_core/src/domain/git_worktree.rs +0 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/crates/worktree_runtime_core/src/domain/github_policy.rs +0 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/crates/worktree_runtime_core/src/infrastructure/env_keys.rs +0 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/crates/worktree_runtime_core/src/infrastructure/path_resolution.rs +0 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/crates/worktree_runtime_core/src/lib.rs +0 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/crates/worktree_runtime_pyo3/AGENTS.md +0 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/crates/worktree_runtime_pyo3/Cargo.toml +0 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/src/_worktree_runtime_rust/__init__.py +0 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/src/worktree_runtime/__init__.py +0 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/src/worktree_runtime/presentation/__init__.py +0 -0
- {worktree_runtime-0.1.0a3 → worktree_runtime-0.1.0a4}/src/worktree_runtime/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# This file is automatically @generated by Cargo.
|
|
2
2
|
# It is not intended for manual editing.
|
|
3
|
-
version =
|
|
3
|
+
version = 4
|
|
4
4
|
|
|
5
5
|
[[package]]
|
|
6
6
|
name = "android_system_properties"
|
|
@@ -743,7 +743,7 @@ dependencies = [
|
|
|
743
743
|
|
|
744
744
|
[[package]]
|
|
745
745
|
name = "worktree_runtime_core"
|
|
746
|
-
version = "0.1.0-alpha.
|
|
746
|
+
version = "0.1.0-alpha.4"
|
|
747
747
|
dependencies = [
|
|
748
748
|
"chrono",
|
|
749
749
|
"fs2",
|
|
@@ -760,7 +760,7 @@ dependencies = [
|
|
|
760
760
|
|
|
761
761
|
[[package]]
|
|
762
762
|
name = "worktree_runtime_pyo3"
|
|
763
|
-
version = "0.1.0-alpha.
|
|
763
|
+
version = "0.1.0-alpha.4"
|
|
764
764
|
dependencies = [
|
|
765
765
|
"chrono",
|
|
766
766
|
"pyo3",
|
|
@@ -3,9 +3,9 @@ resolver = "2"
|
|
|
3
3
|
members = ["crates/worktree_runtime_core", "crates/worktree_runtime_pyo3"]
|
|
4
4
|
|
|
5
5
|
[workspace.package]
|
|
6
|
-
version = "0.1.0-alpha.
|
|
6
|
+
version = "0.1.0-alpha.4"
|
|
7
7
|
edition = "2021"
|
|
8
|
-
rust-version = "1.
|
|
8
|
+
rust-version = "1.85"
|
|
9
9
|
license = "LicenseRef-Proprietary"
|
|
10
10
|
publish = false
|
|
11
11
|
|
|
@@ -18,7 +18,7 @@ sha1 = "0.10"
|
|
|
18
18
|
fs2 = "0.4"
|
|
19
19
|
tempfile = "3.10"
|
|
20
20
|
wait-timeout = "0.2"
|
|
21
|
-
pyo3 = { version = "0.29", features = ["extension-module"] }
|
|
21
|
+
pyo3 = { version = "0.29", features = ["extension-module", "abi3-py310"] }
|
|
22
22
|
chrono = "0.4"
|
|
23
23
|
|
|
24
24
|
[profile.release]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Copyright (c) 2026
|
|
1
|
+
Copyright (c) 2026 bamboocity
|
|
2
2
|
All rights reserved.
|
|
3
3
|
|
|
4
4
|
This software and associated documentation files (the "Software") are
|
|
@@ -6,6 +6,12 @@ proprietary. Unauthorized copying, modification, distribution, or use of
|
|
|
6
6
|
the Software, via any medium, is strictly prohibited except as expressly
|
|
7
7
|
authorized in writing by the copyright holder.
|
|
8
8
|
|
|
9
|
+
The Software is distributed on the Python Package Index as binary wheels
|
|
10
|
+
and as a source distribution (sdist) that contains this source code. That
|
|
11
|
+
distribution is provided solely so the package can be installed and built;
|
|
12
|
+
it does not grant any right to copy, modify, or redistribute the source
|
|
13
|
+
beyond what is necessary to install the Software.
|
|
14
|
+
|
|
9
15
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
10
16
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
11
17
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: worktree-runtime
|
|
3
|
+
Version: 0.1.0a4
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: License :: Other/Proprietary License
|
|
6
|
+
Classifier: Operating System :: MacOS
|
|
7
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
8
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
11
|
+
Classifier: Programming Language :: Rust
|
|
12
|
+
Classifier: Typing :: Typed
|
|
13
|
+
Requires-Dist: pytest>=8.0 ; extra == 'dev'
|
|
14
|
+
Requires-Dist: pyyaml>=6.0 ; extra == 'dev'
|
|
15
|
+
Requires-Dist: mypy>=1.14 ; extra == 'dev'
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Summary: Worktree identity, binding persistence, and checkout substrate
|
|
19
|
+
Author: bamboocity
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
22
|
+
Project-URL: Changelog, https://github.com/bamboocity/worktree-runtime/blob/main/CHANGELOG.md
|
|
23
|
+
Project-URL: Repository, https://github.com/bamboocity/worktree-runtime
|
|
24
|
+
|
|
25
|
+
# worktree-runtime
|
|
26
|
+
|
|
27
|
+
Library for worktree **identity**, **binding persistence**, **checkout
|
|
28
|
+
validation**, and **path resolution**.
|
|
29
|
+
|
|
30
|
+
Consumers (adaptive-task / Noveler) call this so they do not each invent
|
|
31
|
+
project id, session↔worktree binding, main-vs-linked checks, or
|
|
32
|
+
state / shared paths. The public symbol list is
|
|
33
|
+
[`src/worktree_runtime/SURFACE.yaml`](src/worktree_runtime/SURFACE.yaml).
|
|
34
|
+
|
|
35
|
+
Binding store API: `register_binding`, `load_binding`, `recover_binding`,
|
|
36
|
+
`list_bindings`, and `remove_binding`. `git worktree remove` and vanish stay
|
|
37
|
+
in the consumer.
|
|
38
|
+
|
|
39
|
+
Rust is the implementation SSOT. Python is a shim, typing stubs, contract tests,
|
|
40
|
+
and a thin audit CLI. Missing native support is an install error; there is no
|
|
41
|
+
silent Python fallback in this project.
|
|
42
|
+
|
|
43
|
+
## Scope
|
|
44
|
+
|
|
45
|
+
This crate answers four questions and records consumer mutations:
|
|
46
|
+
|
|
47
|
+
| Responsibility | What the library does |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| Identity | Resolve project id, main branches, GitHub policy, and the `NOVELER_*` / location env catalog from cwd, env, git, and project config. |
|
|
50
|
+
| Binding | Persist, load, recover, and validate a session↔worktree record (`WorktreeBinding`). Reject before treating a cwd as bound. |
|
|
51
|
+
| Checkout | Resolve a `GitWorktree` (`rev-parse`), classify main vs linked, list porcelain entries, emit reason codes. |
|
|
52
|
+
| Path | Resolve worktree base / dir / state dir / known bases with fixed precedence. `NOVELER_WORKTREE_BASE` and `config/worktree.yaml` overrides apply only when `CI` / `GITHUB_ACTIONS` is set; elsewhere the base is `~/.adaptive-task/worktrees/<project_id>`. Normalize and fingerprint paths. |
|
|
53
|
+
|
|
54
|
+
Audit (`record_event` / `read_records` / rotation, plus
|
|
55
|
+
`presentation/audit_cli.py`) is append-only logging of consumer git
|
|
56
|
+
mutations (`worktree_remove`, `branch_delete`). It is not a session log.
|
|
57
|
+
|
|
58
|
+
### Out of scope
|
|
59
|
+
|
|
60
|
+
- **Agent isolation.** Codex Desktop, Cursor, and Claude Code create a
|
|
61
|
+
worktree (or checkout) so one chat does not dirty the user's main tree.
|
|
62
|
+
That sandbox is a different layer. This package does not replace it.
|
|
63
|
+
- **Session orchestration.** `adaptive-task init` / `next` / `report` stay
|
|
64
|
+
in the consumer.
|
|
65
|
+
- **Prep / vanish / cleanup hooks.** Detecting a disappeared worktree,
|
|
66
|
+
refusing cleanup, and running merge-cleanup tooling stay in adaptive-task.
|
|
67
|
+
- **`git worktree add` / `remove` as a product operation.** This crate
|
|
68
|
+
resolves locations and validates state. The consumer mutates git.
|
|
69
|
+
|
|
70
|
+
Using Codex Desktop only as an editor does not require importing this
|
|
71
|
+
package. Running adaptive-task identity, binding, or path policy still does.
|
|
72
|
+
Agent isolation worktrees and session worktrees can nest. Config may move
|
|
73
|
+
the session base when `CODEX_CLI` or `CLAUDE_CODE` is set. That override
|
|
74
|
+
exists because the two layers meet; it does not make this library redundant.
|
|
75
|
+
|
|
76
|
+
## Architecture
|
|
77
|
+
|
|
78
|
+
```mermaid
|
|
79
|
+
flowchart LR
|
|
80
|
+
callers["consumers"] -->|"worktree_runtime.api"| shim["Python shim and stubs"]
|
|
81
|
+
shim --> pyo3["PyO3 binding"]
|
|
82
|
+
pyo3 --> core["Rust core"]
|
|
83
|
+
contract["contract pytest"] -->|"black-box"| shim
|
|
84
|
+
cargo["cargo test"] --> core
|
|
85
|
+
release["maturin wheels"] --> callers
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Layout
|
|
89
|
+
|
|
90
|
+
Layout rationale is in [DESIGN.md](DESIGN.md).
|
|
91
|
+
|
|
92
|
+
- `crates/worktree_runtime_core/` — behavior SSOT
|
|
93
|
+
- `crates/worktree_runtime_pyo3/` — Python C-API translation only
|
|
94
|
+
- `src/worktree_runtime/` — `api` re-export, `.pyi`, `SURFACE.yaml`, `presentation/audit_cli.py`
|
|
95
|
+
- `src/_worktree_runtime_rust/` — placeholder package that hosts the cdylib built by maturin (`python-source = "src"`)
|
|
96
|
+
- `tests/contract/` — `from worktree_runtime.api import ...` only; `tests/cli/` — audit CLI exit codes
|
|
97
|
+
|
|
98
|
+
Distribution name is `worktree-runtime`. Import name is `worktree_runtime`.
|
|
99
|
+
`pyproject.toml` version and `Cargo.toml` `workspace.package.version` must match.
|
|
100
|
+
The crate is proprietary (`LICENSE`; all rights reserved). CI uses the `stable` toolchain with rustfmt and clippy.
|
|
101
|
+
|
|
102
|
+
## Change protocol
|
|
103
|
+
|
|
104
|
+
Multi-file, refactor, behavior, or core+pyo3+facade+contract work: run
|
|
105
|
+
`adaptive-gate` first ([AGENTS.md](AGENTS.md) Routing). Testing policy:
|
|
106
|
+
`.cursor/rules/testing.mdc`.
|
|
107
|
+
|
|
108
|
+
1. Behavior: add a failing cargo execution test, then implement in
|
|
109
|
+
`worktree_runtime_core` and run `cargo test`.
|
|
110
|
+
2. Public-surface shape only: update `SURFACE.yaml` and `.pyi`, plus a thin
|
|
111
|
+
contract assertion under `tests/contract/`. Do not put behavior suites in
|
|
112
|
+
pytest.
|
|
113
|
+
3. Export through PyO3; keep the shim as a re-export.
|
|
114
|
+
4. When the public surface changed, build a wheel and run the contract and
|
|
115
|
+
CLI pytest. `cargo fmt --check` and `clippy -D warnings` are required.
|
|
116
|
+
|
|
117
|
+
The verify loop (commands, hook setup, release steps) is defined once in
|
|
118
|
+
[BUILD.md](BUILD.md).
|
|
119
|
+
|
|
120
|
+
## Build
|
|
121
|
+
|
|
122
|
+
See [BUILD.md](BUILD.md). CI always runs fmt, clippy, cargo test, maturin,
|
|
123
|
+
contract+CLI pytest, `mypy.stubtest`, and an MSRV check, through
|
|
124
|
+
`.github/actions/rust-checks`.
|
|
125
|
+
Wheels are `abi3-py310` (CPython 3.10+) for Windows amd64, macOS x86_64 and
|
|
126
|
+
arm64, and manylinux x86_64 / aarch64. Pure-Python wheels are not published.
|
|
127
|
+
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# worktree-runtime
|
|
2
|
+
|
|
3
|
+
Library for worktree **identity**, **binding persistence**, **checkout
|
|
4
|
+
validation**, and **path resolution**.
|
|
5
|
+
|
|
6
|
+
Consumers (adaptive-task / Noveler) call this so they do not each invent
|
|
7
|
+
project id, session↔worktree binding, main-vs-linked checks, or
|
|
8
|
+
state / shared paths. The public symbol list is
|
|
9
|
+
[`src/worktree_runtime/SURFACE.yaml`](src/worktree_runtime/SURFACE.yaml).
|
|
10
|
+
|
|
11
|
+
Binding store API: `register_binding`, `load_binding`, `recover_binding`,
|
|
12
|
+
`list_bindings`, and `remove_binding`. `git worktree remove` and vanish stay
|
|
13
|
+
in the consumer.
|
|
14
|
+
|
|
15
|
+
Rust is the implementation SSOT. Python is a shim, typing stubs, contract tests,
|
|
16
|
+
and a thin audit CLI. Missing native support is an install error; there is no
|
|
17
|
+
silent Python fallback in this project.
|
|
18
|
+
|
|
19
|
+
## Scope
|
|
20
|
+
|
|
21
|
+
This crate answers four questions and records consumer mutations:
|
|
22
|
+
|
|
23
|
+
| Responsibility | What the library does |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| Identity | Resolve project id, main branches, GitHub policy, and the `NOVELER_*` / location env catalog from cwd, env, git, and project config. |
|
|
26
|
+
| Binding | Persist, load, recover, and validate a session↔worktree record (`WorktreeBinding`). Reject before treating a cwd as bound. |
|
|
27
|
+
| Checkout | Resolve a `GitWorktree` (`rev-parse`), classify main vs linked, list porcelain entries, emit reason codes. |
|
|
28
|
+
| Path | Resolve worktree base / dir / state dir / known bases with fixed precedence. `NOVELER_WORKTREE_BASE` and `config/worktree.yaml` overrides apply only when `CI` / `GITHUB_ACTIONS` is set; elsewhere the base is `~/.adaptive-task/worktrees/<project_id>`. Normalize and fingerprint paths. |
|
|
29
|
+
|
|
30
|
+
Audit (`record_event` / `read_records` / rotation, plus
|
|
31
|
+
`presentation/audit_cli.py`) is append-only logging of consumer git
|
|
32
|
+
mutations (`worktree_remove`, `branch_delete`). It is not a session log.
|
|
33
|
+
|
|
34
|
+
### Out of scope
|
|
35
|
+
|
|
36
|
+
- **Agent isolation.** Codex Desktop, Cursor, and Claude Code create a
|
|
37
|
+
worktree (or checkout) so one chat does not dirty the user's main tree.
|
|
38
|
+
That sandbox is a different layer. This package does not replace it.
|
|
39
|
+
- **Session orchestration.** `adaptive-task init` / `next` / `report` stay
|
|
40
|
+
in the consumer.
|
|
41
|
+
- **Prep / vanish / cleanup hooks.** Detecting a disappeared worktree,
|
|
42
|
+
refusing cleanup, and running merge-cleanup tooling stay in adaptive-task.
|
|
43
|
+
- **`git worktree add` / `remove` as a product operation.** This crate
|
|
44
|
+
resolves locations and validates state. The consumer mutates git.
|
|
45
|
+
|
|
46
|
+
Using Codex Desktop only as an editor does not require importing this
|
|
47
|
+
package. Running adaptive-task identity, binding, or path policy still does.
|
|
48
|
+
Agent isolation worktrees and session worktrees can nest. Config may move
|
|
49
|
+
the session base when `CODEX_CLI` or `CLAUDE_CODE` is set. That override
|
|
50
|
+
exists because the two layers meet; it does not make this library redundant.
|
|
51
|
+
|
|
52
|
+
## Architecture
|
|
53
|
+
|
|
54
|
+
```mermaid
|
|
55
|
+
flowchart LR
|
|
56
|
+
callers["consumers"] -->|"worktree_runtime.api"| shim["Python shim and stubs"]
|
|
57
|
+
shim --> pyo3["PyO3 binding"]
|
|
58
|
+
pyo3 --> core["Rust core"]
|
|
59
|
+
contract["contract pytest"] -->|"black-box"| shim
|
|
60
|
+
cargo["cargo test"] --> core
|
|
61
|
+
release["maturin wheels"] --> callers
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Layout
|
|
65
|
+
|
|
66
|
+
Layout rationale is in [DESIGN.md](DESIGN.md).
|
|
67
|
+
|
|
68
|
+
- `crates/worktree_runtime_core/` — behavior SSOT
|
|
69
|
+
- `crates/worktree_runtime_pyo3/` — Python C-API translation only
|
|
70
|
+
- `src/worktree_runtime/` — `api` re-export, `.pyi`, `SURFACE.yaml`, `presentation/audit_cli.py`
|
|
71
|
+
- `src/_worktree_runtime_rust/` — placeholder package that hosts the cdylib built by maturin (`python-source = "src"`)
|
|
72
|
+
- `tests/contract/` — `from worktree_runtime.api import ...` only; `tests/cli/` — audit CLI exit codes
|
|
73
|
+
|
|
74
|
+
Distribution name is `worktree-runtime`. Import name is `worktree_runtime`.
|
|
75
|
+
`pyproject.toml` version and `Cargo.toml` `workspace.package.version` must match.
|
|
76
|
+
The crate is proprietary (`LICENSE`; all rights reserved). CI uses the `stable` toolchain with rustfmt and clippy.
|
|
77
|
+
|
|
78
|
+
## Change protocol
|
|
79
|
+
|
|
80
|
+
Multi-file, refactor, behavior, or core+pyo3+facade+contract work: run
|
|
81
|
+
`adaptive-gate` first ([AGENTS.md](AGENTS.md) Routing). Testing policy:
|
|
82
|
+
`.cursor/rules/testing.mdc`.
|
|
83
|
+
|
|
84
|
+
1. Behavior: add a failing cargo execution test, then implement in
|
|
85
|
+
`worktree_runtime_core` and run `cargo test`.
|
|
86
|
+
2. Public-surface shape only: update `SURFACE.yaml` and `.pyi`, plus a thin
|
|
87
|
+
contract assertion under `tests/contract/`. Do not put behavior suites in
|
|
88
|
+
pytest.
|
|
89
|
+
3. Export through PyO3; keep the shim as a re-export.
|
|
90
|
+
4. When the public surface changed, build a wheel and run the contract and
|
|
91
|
+
CLI pytest. `cargo fmt --check` and `clippy -D warnings` are required.
|
|
92
|
+
|
|
93
|
+
The verify loop (commands, hook setup, release steps) is defined once in
|
|
94
|
+
[BUILD.md](BUILD.md).
|
|
95
|
+
|
|
96
|
+
## Build
|
|
97
|
+
|
|
98
|
+
See [BUILD.md](BUILD.md). CI always runs fmt, clippy, cargo test, maturin,
|
|
99
|
+
contract+CLI pytest, `mypy.stubtest`, and an MSRV check, through
|
|
100
|
+
`.github/actions/rust-checks`.
|
|
101
|
+
Wheels are `abi3-py310` (CPython 3.10+) for Windows amd64, macOS x86_64 and
|
|
102
|
+
arm64, and manylinux x86_64 / aarch64. Pure-Python wheels are not published.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# worktree_runtime_core
|
|
2
|
+
|
|
3
|
+
This crate is the behavior SSOT. Do not add PyO3 or Python dependencies.
|
|
4
|
+
Behavior changes belong here with `cargo test` (`.cursor/rules/testing.mdc`);
|
|
5
|
+
do not treat pytest as the SSOT.
|
|
6
|
+
|
|
7
|
+
## Layers
|
|
8
|
+
|
|
9
|
+
- `domain/` — value objects and pure rules (`binding`, `audit`, `paths`,
|
|
10
|
+
`porcelain`, `git_worktree`, `github_policy`). Today `paths::normalize_path`
|
|
11
|
+
still canonicalizes through the filesystem and `WorktreeBinding::new` calls
|
|
12
|
+
it; treat that as a known exception, do not add more I/O to `domain/`.
|
|
13
|
+
- `application/` — services that compose domain + infrastructure
|
|
14
|
+
(`binding_lifecycle`, `validation`, `git_worktree_service`). They own the
|
|
15
|
+
reason codes callers branch on.
|
|
16
|
+
- `infrastructure/` — filesystem, env, git subprocess, config readers.
|
|
17
|
+
|
|
18
|
+
## Conventions that are not obvious from the code
|
|
19
|
+
|
|
20
|
+
- **git**: every subprocess goes through `infrastructure::git_adapter`.
|
|
21
|
+
`git_output` returns `Result<String, GitInvokeError>`; `Exit` means the
|
|
22
|
+
repository state is unusable (not a repo, detached HEAD), every other
|
|
23
|
+
variant means git itself could not run and callers report
|
|
24
|
+
`WORKTREE_GIT_UNAVAILABLE`. Do not collapse errors to `""`. Tests
|
|
25
|
+
simulate a missing binary with `common::MissingGit` (thread-local
|
|
26
|
+
`override_git_program`), never by clearing `PATH`.
|
|
27
|
+
- **Reason codes** are a public contract (adaptive-task branches on them).
|
|
28
|
+
Adding one needs a CHANGELOG entry; renaming one is a breaking change.
|
|
29
|
+
- **Binding store** (`infrastructure::binding_store`) is locked
|
|
30
|
+
(`bindings.json.lock`) and fail-closed: a corrupt file is an error, never
|
|
31
|
+
an empty store.
|
|
32
|
+
- **Audit** (`infrastructure::audit_*`) is fail-open by design: a failed
|
|
33
|
+
write prints `[WORKTREE-AUDIT-FAILOPEN] ...` to stderr and returns
|
|
34
|
+
`Err(AuditWriteError)`; the PyO3 layer decides whether to raise
|
|
35
|
+
(`strict`). Rotation runs under the append lock; `read_records` reads
|
|
36
|
+
archives too. The only `unsafe` in the crate is `libc::gethostname` in
|
|
37
|
+
`audit_writer.rs` (unix).
|
|
38
|
+
- **Config precedence**: `NOVELER_WORKTREE_BASE` and
|
|
39
|
+
`config/worktree.yaml` overrides are honored only when `CI` or
|
|
40
|
+
`GITHUB_ACTIONS` is set (`worktree_base_resolver.rs`). Outside CI the
|
|
41
|
+
base is `~/.adaptive-task/worktrees/<project_id>`. Parse failures in
|
|
42
|
+
`pyproject.toml` / `config/worktree.yaml` log a warning and fall back to
|
|
43
|
+
defaults; they are not distinguishable from "file absent" to callers.
|
|
44
|
+
- **project_id**: `resolve_project_id` returns the declared value unchecked;
|
|
45
|
+
`resolve_project_id_checked` rejects invalid ids; every function that
|
|
46
|
+
turns an id into a directory name (`resolve_state_dir_name`) validates it
|
|
47
|
+
and falls back to `noveler`.
|
|
48
|
+
- **Logging**: `log::debug!` / `log::warn!` for diagnostics; the two
|
|
49
|
+
`eprintln!` breadcrumbs (`failopen_message`, `suspicious_extra_message`)
|
|
50
|
+
are frozen by tests and stay on stderr.
|