pyflyrail 0.1.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.
- pyflyrail-0.1.0/.gitignore +15 -0
- pyflyrail-0.1.0/CHANGELOG.md +25 -0
- pyflyrail-0.1.0/LICENSE +21 -0
- pyflyrail-0.1.0/PKG-INFO +122 -0
- pyflyrail-0.1.0/README.md +97 -0
- pyflyrail-0.1.0/hatch_build.py +21 -0
- pyflyrail-0.1.0/pyproject.toml +95 -0
- pyflyrail-0.1.0/runtime-tooling/package-lock.json +419 -0
- pyflyrail-0.1.0/runtime-tooling/package.json +1 -0
- pyflyrail-0.1.0/runtime-tooling/tsconfig.json +1 -0
- pyflyrail-0.1.0/spec/fixtures/bundles.json +173 -0
- pyflyrail-0.1.0/spec/fixtures/configurations.json +3616 -0
- pyflyrail-0.1.0/spec/fixtures/edits.json +1289 -0
- pyflyrail-0.1.0/spec/fixtures/hooks.json +1611 -0
- pyflyrail-0.1.0/spec/fixtures/translations.json +1114 -0
- pyflyrail-0.1.0/src/flyrail/__init__.py +231 -0
- pyflyrail-0.1.0/src/flyrail/_codec.py +109 -0
- pyflyrail-0.1.0/src/flyrail/_config_manifest.py +322 -0
- pyflyrail-0.1.0/src/flyrail/_filesystem.py +113 -0
- pyflyrail-0.1.0/src/flyrail/_hook_translation.py +346 -0
- pyflyrail-0.1.0/src/flyrail/_inventory.py +39 -0
- pyflyrail-0.1.0/src/flyrail/_json_document.py +240 -0
- pyflyrail-0.1.0/src/flyrail/_lifecycle.py +910 -0
- pyflyrail-0.1.0/src/flyrail/_manifest.py +71 -0
- pyflyrail-0.1.0/src/flyrail/_mcp_translation.py +169 -0
- pyflyrail-0.1.0/src/flyrail/_memory.py +37 -0
- pyflyrail-0.1.0/src/flyrail/_observation.py +177 -0
- pyflyrail-0.1.0/src/flyrail/_resource_io.py +264 -0
- pyflyrail-0.1.0/src/flyrail/_resource_models.py +333 -0
- pyflyrail-0.1.0/src/flyrail/_resource_plan.py +482 -0
- pyflyrail-0.1.0/src/flyrail/_resource_transaction.py +372 -0
- pyflyrail-0.1.0/src/flyrail/_schema.py +133 -0
- pyflyrail-0.1.0/src/flyrail/_security.py +318 -0
- pyflyrail-0.1.0/src/flyrail/_sources.py +276 -0
- pyflyrail-0.1.0/src/flyrail/_toml_document.py +691 -0
- pyflyrail-0.1.0/src/flyrail/_toml_layout.py +73 -0
- pyflyrail-0.1.0/src/flyrail/_validation.py +54 -0
- pyflyrail-0.1.0/src/flyrail/artifacts.py +279 -0
- pyflyrail-0.1.0/src/flyrail/authority.py +255 -0
- pyflyrail-0.1.0/src/flyrail/bundle.py +327 -0
- pyflyrail-0.1.0/src/flyrail/configuration.py +252 -0
- pyflyrail-0.1.0/src/flyrail/content.py +226 -0
- pyflyrail-0.1.0/src/flyrail/destinations.py +233 -0
- pyflyrail-0.1.0/src/flyrail/editors.py +1096 -0
- pyflyrail-0.1.0/src/flyrail/hooks.py +39 -0
- pyflyrail-0.1.0/src/flyrail/inspection.py +270 -0
- pyflyrail-0.1.0/src/flyrail/lifecycle.py +148 -0
- pyflyrail-0.1.0/src/flyrail/models.py +74 -0
- pyflyrail-0.1.0/src/flyrail/observations.py +193 -0
- pyflyrail-0.1.0/src/flyrail/py.typed +0 -0
- pyflyrail-0.1.0/src/flyrail/rendered.py +206 -0
- pyflyrail-0.1.0/src/flyrail/runtime/bridge.mts +145 -0
- pyflyrail-0.1.0/src/flyrail/runtime/process.mts +38 -0
- pyflyrail-0.1.0/src/flyrail/runtime/runner.mts +192 -0
- pyflyrail-0.1.0/src/flyrail/targets.py +197 -0
- pyflyrail-0.1.0/src/flyrail/translation.py +383 -0
- pyflyrail-0.1.0/src/flyrail/values.py +168 -0
- pyflyrail-0.1.0/tests/conformance.py +5 -0
- pyflyrail-0.1.0/tests/hook_host.mjs +21 -0
- pyflyrail-0.1.0/tests/hook_native_host.mjs +48 -0
- pyflyrail-0.1.0/tests/hook_runner.mjs +9 -0
- pyflyrail-0.1.0/tests/skill_helpers.py +39 -0
- pyflyrail-0.1.0/tests/test_authority.py +258 -0
- pyflyrail-0.1.0/tests/test_bundle.py +785 -0
- pyflyrail-0.1.0/tests/test_config_bundle.py +498 -0
- pyflyrail-0.1.0/tests/test_config_conformance.py +126 -0
- pyflyrail-0.1.0/tests/test_config_models.py +441 -0
- pyflyrail-0.1.0/tests/test_configuration_ancestors.py +383 -0
- pyflyrail-0.1.0/tests/test_configuration_boundaries.py +318 -0
- pyflyrail-0.1.0/tests/test_configuration_comparison.py +138 -0
- pyflyrail-0.1.0/tests/test_configuration_dependency_aliases.py +92 -0
- pyflyrail-0.1.0/tests/test_configuration_directories.py +114 -0
- pyflyrail-0.1.0/tests/test_configuration_io.py +292 -0
- pyflyrail-0.1.0/tests/test_configuration_lifecycle.py +328 -0
- pyflyrail-0.1.0/tests/test_configuration_races.py +166 -0
- pyflyrail-0.1.0/tests/test_configuration_recovery.py +320 -0
- pyflyrail-0.1.0/tests/test_configuration_recovery_api.py +322 -0
- pyflyrail-0.1.0/tests/test_configuration_regressions.py +410 -0
- pyflyrail-0.1.0/tests/test_configuration_result_failures.py +281 -0
- pyflyrail-0.1.0/tests/test_configuration_sections.py +59 -0
- pyflyrail-0.1.0/tests/test_configuration_security.py +320 -0
- pyflyrail-0.1.0/tests/test_configuration_state_guards.py +285 -0
- pyflyrail-0.1.0/tests/test_configuration_validation.py +434 -0
- pyflyrail-0.1.0/tests/test_configuration_vectors.py +168 -0
- pyflyrail-0.1.0/tests/test_configuration_windows.py +210 -0
- pyflyrail-0.1.0/tests/test_edit_conformance.py +111 -0
- pyflyrail-0.1.0/tests/test_editors.py +1660 -0
- pyflyrail-0.1.0/tests/test_filesystem.py +178 -0
- pyflyrail-0.1.0/tests/test_hook_environments.py +137 -0
- pyflyrail-0.1.0/tests/test_hook_execution.py +417 -0
- pyflyrail-0.1.0/tests/test_hook_lifecycle.py +492 -0
- pyflyrail-0.1.0/tests/test_hook_schema_handover.py +240 -0
- pyflyrail-0.1.0/tests/test_hook_validation.py +158 -0
- pyflyrail-0.1.0/tests/test_hooks.py +369 -0
- pyflyrail-0.1.0/tests/test_models.py +169 -0
- pyflyrail-0.1.0/tests/test_release_tooling.py +842 -0
- pyflyrail-0.1.0/tests/test_security.py +126 -0
- pyflyrail-0.1.0/tests/test_targets.py +130 -0
- pyflyrail-0.1.0/tests/test_translation.py +609 -0
- pyflyrail-0.1.0/tests/test_translation_boundaries.py +524 -0
- pyflyrail-0.1.0/uv.lock +1107 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable user-facing changes to Flyrail for Python. Package versions are independent from
|
|
4
|
+
configuration bundle labels and shared format schema versions.
|
|
5
|
+
|
|
6
|
+
## [0.1.0] - 2026-09-20
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
- Python prototype
|
|
12
|
+
- Add reversible agent configuration bundles
|
|
13
|
+
- Add Python release process
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
- Unblock Python release
|
|
19
|
+
- Initialize Windows lock files
|
|
20
|
+
- Separate Windows lock range
|
|
21
|
+
- Correct Windows filesystem semantics
|
|
22
|
+
- Ignore inherited git context in the release helper
|
|
23
|
+
|
|
24
|
+
[0.1.0]: https://github.com/nielsmadan/flyrail/tree/python-v0.1.0
|
|
25
|
+
|
pyflyrail-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Niels Madan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pyflyrail-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pyflyrail
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A typed library for reversible coding-agent configuration bundles.
|
|
5
|
+
Project-URL: Documentation, https://github.com/nielsmadan/flyrail/tree/main/python/docs
|
|
6
|
+
Project-URL: Issues, https://github.com/nielsmadan/flyrail/issues
|
|
7
|
+
Project-URL: Repository, https://github.com/nielsmadan/flyrail
|
|
8
|
+
Author: Niels Madan
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: MacOS
|
|
14
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: tomlkit==0.15.1
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# Flyrail for Python
|
|
27
|
+
|
|
28
|
+
A typed, synchronous library for coding-agent configuration bundles: skills,
|
|
29
|
+
instructions, MCP registrations, hooks and supporting assets. Requires Python
|
|
30
|
+
3.11+; TOML editing lazily imports pinned `tomlkit`. Windows mutations require
|
|
31
|
+
Python 3.11.10+, 3.12.4+, or 3.13+ for private directory creation.
|
|
32
|
+
|
|
33
|
+
## Install and use
|
|
34
|
+
|
|
35
|
+
Install the `pyflyrail` distribution from PyPI. The import package remains `flyrail`:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
python -m pip install pyflyrail
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
To install the current checkout instead, run `python -m pip install .` from `python/`.
|
|
42
|
+
The following example uses the same public import in either installation:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from flyrail import Bundle, Target, inspect, install, uninstall, update
|
|
46
|
+
|
|
47
|
+
bundle = Bundle.from_directory("examples/filesystem/bundle")
|
|
48
|
+
targets = [Target.directory(".cache/demo-skills")]
|
|
49
|
+
|
|
50
|
+
installed = install(bundle, targets)
|
|
51
|
+
current = all(result.observation.is_current for result in inspect(bundle, targets))
|
|
52
|
+
updated = update(bundle, targets, lock_timeout=0.25)
|
|
53
|
+
removed = uninstall(bundle.id, targets)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`Target.directory` names the skill container itself. This example installs
|
|
57
|
+
`.cache/demo-skills/notes-summary/SKILL.md`. Use `Bundle.from_package("your_package")`
|
|
58
|
+
for application resources with a `flyrail/` bundle directory. Both loaders snapshot
|
|
59
|
+
complete trees before returning, so later removal of the source does not invalidate
|
|
60
|
+
an already loaded bundle.
|
|
61
|
+
|
|
62
|
+
Presets cover Claude Code, Codex, OpenCode, Pi, Cursor and Copilot. For example,
|
|
63
|
+
`Target.user("codex")` selects a user installation and
|
|
64
|
+
`Target.project("claude", "./project")` selects a project installation. Hosts choose
|
|
65
|
+
explicit destinations; the library never selects agents, prints, prompts, exits,
|
|
66
|
+
executes skill scripts or requests the network.
|
|
67
|
+
|
|
68
|
+
Bundle version labels are independent of your application's version. Inspection
|
|
69
|
+
compares the label, recorded content and actual content separately. Updates can
|
|
70
|
+
change content under the same label or install an older-looking label. An intact
|
|
71
|
+
matching revision returns `UNCHANGED`.
|
|
72
|
+
|
|
73
|
+
Check every mutation result's status, errors and resource recovery paths. A
|
|
74
|
+
committed resource can still need cleanup; `PARTIAL` reports completed resource
|
|
75
|
+
commits followed by a failure. Own edits block replacement/removal unless
|
|
76
|
+
`replace_modified=True`; untracked and foreign-owned skills remain protected.
|
|
77
|
+
Uninstall uses the bundle ID and receipts, without requiring source files.
|
|
78
|
+
|
|
79
|
+
For portable instructions, MCP, hooks and supporting assets, use `render(bundle, context)`
|
|
80
|
+
with an explicit `RenderContext`. It returns a `RenderedBundle` for
|
|
81
|
+
`preview`/`apply_preview` or `sync` with an `InstallationTarget`.
|
|
82
|
+
[Translation](https://github.com/nielsmadan/flyrail/blob/main/python/docs/translation.md)
|
|
83
|
+
explains capabilities, native alternatives and exact unsupported boundaries.
|
|
84
|
+
`inspect_installation` and `remove` use the private index without source bytes.
|
|
85
|
+
For applications that select destinations from observed files, call source-free
|
|
86
|
+
`recover_installation` before re-reading those files and building a fresh immutable
|
|
87
|
+
preview. Recovery preserves healthy ownership and retains pending membership for
|
|
88
|
+
the subsequent update or removal.
|
|
89
|
+
Use `inspect_installation(bundle.id, target).matches(bundle, rendered)` to compare
|
|
90
|
+
the app's current bundle and rendering with intact installed content. The
|
|
91
|
+
source-free `is_current` field checks the recorded generation only. Neither check
|
|
92
|
+
establishes host trust, discovery or activation; inspect render notices separately.
|
|
93
|
+
The [configuration API](https://github.com/nielsmadan/flyrail/blob/main/python/docs/api.md)
|
|
94
|
+
shows an in-memory instruction example and explains explicit takeover/adoption.
|
|
95
|
+
|
|
96
|
+
## Documentation and examples
|
|
97
|
+
|
|
98
|
+
- [Public API](https://github.com/nielsmadan/flyrail/blob/main/python/docs/api.md)
|
|
99
|
+
- [Command hooks](https://github.com/nielsmadan/flyrail/blob/main/python/docs/hooks.md)
|
|
100
|
+
- [Destinations and inspection](https://github.com/nielsmadan/flyrail/blob/main/python/docs/inspection.md)
|
|
101
|
+
- [Lifecycle and recovery](https://github.com/nielsmadan/flyrail/blob/main/python/docs/lifecycle.md)
|
|
102
|
+
- [Examples](https://github.com/nielsmadan/flyrail/blob/main/python/docs/examples.md)
|
|
103
|
+
- [Support and limits](https://github.com/nielsmadan/flyrail/blob/main/python/docs/support.md)
|
|
104
|
+
- [Shared formats](https://github.com/nielsmadan/flyrail/tree/main/spec)
|
|
105
|
+
|
|
106
|
+
The repository's `examples/` contains two independently packaged host CLIs: notes
|
|
107
|
+
with an explicit filesystem bundle and checksum with packaged resources. They
|
|
108
|
+
include a combined checksum `config` interface with generated guidance, skills,
|
|
109
|
+
stdio/HTTP MCP environment references and a portable hook with packaged assets.
|
|
110
|
+
Native hook execution requires an explicitly selected Node 24+ executable;
|
|
111
|
+
OpenCode/Pi can use their existing host runtimes. Python package builds require
|
|
112
|
+
no JavaScript runtime or compiler.
|
|
113
|
+
|
|
114
|
+
Examples and development tooling live in the repository; the source distribution
|
|
115
|
+
contains library code, tests, shared fixtures, runtime test tooling, package
|
|
116
|
+
metadata and the license.
|
|
117
|
+
|
|
118
|
+
For repository development, run `just check` from `python/` or the repository root.
|
|
119
|
+
It checks formatting, lint/security, strict typing, tests with branch coverage,
|
|
120
|
+
built package contents and installed consumers. The repository CI matrix covers
|
|
121
|
+
Python 3.11 and 3.14 on macOS, Linux and Windows. See
|
|
122
|
+
[development](https://github.com/nielsmadan/flyrail/blob/main/python/docs/development.md).
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Flyrail for Python
|
|
2
|
+
|
|
3
|
+
A typed, synchronous library for coding-agent configuration bundles: skills,
|
|
4
|
+
instructions, MCP registrations, hooks and supporting assets. Requires Python
|
|
5
|
+
3.11+; TOML editing lazily imports pinned `tomlkit`. Windows mutations require
|
|
6
|
+
Python 3.11.10+, 3.12.4+, or 3.13+ for private directory creation.
|
|
7
|
+
|
|
8
|
+
## Install and use
|
|
9
|
+
|
|
10
|
+
Install the `pyflyrail` distribution from PyPI. The import package remains `flyrail`:
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
python -m pip install pyflyrail
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
To install the current checkout instead, run `python -m pip install .` from `python/`.
|
|
17
|
+
The following example uses the same public import in either installation:
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from flyrail import Bundle, Target, inspect, install, uninstall, update
|
|
21
|
+
|
|
22
|
+
bundle = Bundle.from_directory("examples/filesystem/bundle")
|
|
23
|
+
targets = [Target.directory(".cache/demo-skills")]
|
|
24
|
+
|
|
25
|
+
installed = install(bundle, targets)
|
|
26
|
+
current = all(result.observation.is_current for result in inspect(bundle, targets))
|
|
27
|
+
updated = update(bundle, targets, lock_timeout=0.25)
|
|
28
|
+
removed = uninstall(bundle.id, targets)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`Target.directory` names the skill container itself. This example installs
|
|
32
|
+
`.cache/demo-skills/notes-summary/SKILL.md`. Use `Bundle.from_package("your_package")`
|
|
33
|
+
for application resources with a `flyrail/` bundle directory. Both loaders snapshot
|
|
34
|
+
complete trees before returning, so later removal of the source does not invalidate
|
|
35
|
+
an already loaded bundle.
|
|
36
|
+
|
|
37
|
+
Presets cover Claude Code, Codex, OpenCode, Pi, Cursor and Copilot. For example,
|
|
38
|
+
`Target.user("codex")` selects a user installation and
|
|
39
|
+
`Target.project("claude", "./project")` selects a project installation. Hosts choose
|
|
40
|
+
explicit destinations; the library never selects agents, prints, prompts, exits,
|
|
41
|
+
executes skill scripts or requests the network.
|
|
42
|
+
|
|
43
|
+
Bundle version labels are independent of your application's version. Inspection
|
|
44
|
+
compares the label, recorded content and actual content separately. Updates can
|
|
45
|
+
change content under the same label or install an older-looking label. An intact
|
|
46
|
+
matching revision returns `UNCHANGED`.
|
|
47
|
+
|
|
48
|
+
Check every mutation result's status, errors and resource recovery paths. A
|
|
49
|
+
committed resource can still need cleanup; `PARTIAL` reports completed resource
|
|
50
|
+
commits followed by a failure. Own edits block replacement/removal unless
|
|
51
|
+
`replace_modified=True`; untracked and foreign-owned skills remain protected.
|
|
52
|
+
Uninstall uses the bundle ID and receipts, without requiring source files.
|
|
53
|
+
|
|
54
|
+
For portable instructions, MCP, hooks and supporting assets, use `render(bundle, context)`
|
|
55
|
+
with an explicit `RenderContext`. It returns a `RenderedBundle` for
|
|
56
|
+
`preview`/`apply_preview` or `sync` with an `InstallationTarget`.
|
|
57
|
+
[Translation](https://github.com/nielsmadan/flyrail/blob/main/python/docs/translation.md)
|
|
58
|
+
explains capabilities, native alternatives and exact unsupported boundaries.
|
|
59
|
+
`inspect_installation` and `remove` use the private index without source bytes.
|
|
60
|
+
For applications that select destinations from observed files, call source-free
|
|
61
|
+
`recover_installation` before re-reading those files and building a fresh immutable
|
|
62
|
+
preview. Recovery preserves healthy ownership and retains pending membership for
|
|
63
|
+
the subsequent update or removal.
|
|
64
|
+
Use `inspect_installation(bundle.id, target).matches(bundle, rendered)` to compare
|
|
65
|
+
the app's current bundle and rendering with intact installed content. The
|
|
66
|
+
source-free `is_current` field checks the recorded generation only. Neither check
|
|
67
|
+
establishes host trust, discovery or activation; inspect render notices separately.
|
|
68
|
+
The [configuration API](https://github.com/nielsmadan/flyrail/blob/main/python/docs/api.md)
|
|
69
|
+
shows an in-memory instruction example and explains explicit takeover/adoption.
|
|
70
|
+
|
|
71
|
+
## Documentation and examples
|
|
72
|
+
|
|
73
|
+
- [Public API](https://github.com/nielsmadan/flyrail/blob/main/python/docs/api.md)
|
|
74
|
+
- [Command hooks](https://github.com/nielsmadan/flyrail/blob/main/python/docs/hooks.md)
|
|
75
|
+
- [Destinations and inspection](https://github.com/nielsmadan/flyrail/blob/main/python/docs/inspection.md)
|
|
76
|
+
- [Lifecycle and recovery](https://github.com/nielsmadan/flyrail/blob/main/python/docs/lifecycle.md)
|
|
77
|
+
- [Examples](https://github.com/nielsmadan/flyrail/blob/main/python/docs/examples.md)
|
|
78
|
+
- [Support and limits](https://github.com/nielsmadan/flyrail/blob/main/python/docs/support.md)
|
|
79
|
+
- [Shared formats](https://github.com/nielsmadan/flyrail/tree/main/spec)
|
|
80
|
+
|
|
81
|
+
The repository's `examples/` contains two independently packaged host CLIs: notes
|
|
82
|
+
with an explicit filesystem bundle and checksum with packaged resources. They
|
|
83
|
+
include a combined checksum `config` interface with generated guidance, skills,
|
|
84
|
+
stdio/HTTP MCP environment references and a portable hook with packaged assets.
|
|
85
|
+
Native hook execution requires an explicitly selected Node 24+ executable;
|
|
86
|
+
OpenCode/Pi can use their existing host runtimes. Python package builds require
|
|
87
|
+
no JavaScript runtime or compiler.
|
|
88
|
+
|
|
89
|
+
Examples and development tooling live in the repository; the source distribution
|
|
90
|
+
contains library code, tests, shared fixtures, runtime test tooling, package
|
|
91
|
+
metadata and the license.
|
|
92
|
+
|
|
93
|
+
For repository development, run `just check` from `python/` or the repository root.
|
|
94
|
+
It checks formatting, lint/security, strict typing, tests with branch coverage,
|
|
95
|
+
built package contents and installed consumers. The repository CI matrix covers
|
|
96
|
+
Python 3.11 and 3.14 on macOS, Linux and Windows. See
|
|
97
|
+
[development](https://github.com/nielsmadan/flyrail/blob/main/python/docs/development.md).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
|
|
5
|
+
from hatchling.builders.sdist import SdistBuilderConfig
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CustomBuildHook(BuildHookInterface[SdistBuilderConfig]):
|
|
9
|
+
def initialize(self, version: str, build_data: dict[str, Any]) -> None:
|
|
10
|
+
root = Path(self.root)
|
|
11
|
+
fixtures = root / "spec/fixtures"
|
|
12
|
+
if not fixtures.is_dir():
|
|
13
|
+
fixtures = root.parent / "spec/fixtures"
|
|
14
|
+
for name in (
|
|
15
|
+
"bundles.json",
|
|
16
|
+
"configurations.json",
|
|
17
|
+
"edits.json",
|
|
18
|
+
"translations.json",
|
|
19
|
+
"hooks.json",
|
|
20
|
+
):
|
|
21
|
+
build_data["force_include"][str(fixtures / name)] = f"spec/fixtures/{name}"
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling==1.32.0"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pyflyrail"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A typed library for reversible coding-agent configuration bundles."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{ name = "Niels Madan" }]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Operating System :: MacOS",
|
|
18
|
+
"Operating System :: POSIX :: Linux",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Programming Language :: Python :: 3.14",
|
|
25
|
+
"Typing :: Typed",
|
|
26
|
+
]
|
|
27
|
+
dependencies = ["tomlkit==0.15.1"]
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Documentation = "https://github.com/nielsmadan/flyrail/tree/main/python/docs"
|
|
31
|
+
Issues = "https://github.com/nielsmadan/flyrail/issues"
|
|
32
|
+
Repository = "https://github.com/nielsmadan/flyrail"
|
|
33
|
+
|
|
34
|
+
[dependency-groups]
|
|
35
|
+
audit = ["pip-audit==2.10.1"]
|
|
36
|
+
dev = [
|
|
37
|
+
"hatchling==1.32.0",
|
|
38
|
+
"mypy==2.3.1",
|
|
39
|
+
"pytest==9.1.1",
|
|
40
|
+
"pytest-cov==7.1.0",
|
|
41
|
+
"ruff==0.16.7",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[tool.uv]
|
|
45
|
+
required-version = ">=0.12.13"
|
|
46
|
+
|
|
47
|
+
[tool.hatch.build.targets.wheel]
|
|
48
|
+
packages = ["src/flyrail"]
|
|
49
|
+
|
|
50
|
+
[tool.hatch.build.targets.sdist]
|
|
51
|
+
include = ["/src", "/tests", "/runtime-tooling", "/README.md", "/CHANGELOG.md", "/LICENSE", "/pyproject.toml", "/uv.lock", "/hatch_build.py", "/.gitignore"]
|
|
52
|
+
exclude = ["**/.git", "**/.cache", "**/.venv", "**/__pycache__", "**/*.py[cod]", "**/*.egg-info", "**/build", "**/dist", "**/.DS_Store", "**/*.log"]
|
|
53
|
+
|
|
54
|
+
[tool.hatch.build.targets.sdist.hooks.custom]
|
|
55
|
+
path = "hatch_build.py"
|
|
56
|
+
|
|
57
|
+
[tool.ruff]
|
|
58
|
+
target-version = "py311"
|
|
59
|
+
line-length = 100
|
|
60
|
+
cache-dir = ".cache/ruff"
|
|
61
|
+
extend-exclude = [".cache", "dist"]
|
|
62
|
+
|
|
63
|
+
[tool.ruff.lint]
|
|
64
|
+
select = ["E", "F", "I", "UP", "B", "S", "SIM", "RUF"]
|
|
65
|
+
|
|
66
|
+
[tool.ruff.lint.per-file-ignores]
|
|
67
|
+
"tests/**/*.py" = ["S101"]
|
|
68
|
+
"scripts/package_probe.py" = ["S101"]
|
|
69
|
+
"scripts/hook_package_probe.py" = ["S101"]
|
|
70
|
+
"scripts/configuration_package_probe.py" = ["S101"]
|
|
71
|
+
"scripts/typed_consumer.py" = ["S101"]
|
|
72
|
+
|
|
73
|
+
[tool.mypy]
|
|
74
|
+
python_version = "3.11"
|
|
75
|
+
strict = true
|
|
76
|
+
files = ["src", "tests", "scripts", "examples", "hatch_build.py"]
|
|
77
|
+
cache_dir = ".cache/mypy"
|
|
78
|
+
|
|
79
|
+
[tool.pytest.ini_options]
|
|
80
|
+
testpaths = ["tests"]
|
|
81
|
+
addopts = "--strict-config --strict-markers"
|
|
82
|
+
markers = [
|
|
83
|
+
"integration: exercises real runtimes, subprocesses or full on-disk lifecycles",
|
|
84
|
+
]
|
|
85
|
+
cache_dir = ".cache/pytest"
|
|
86
|
+
filterwarnings = ["error"]
|
|
87
|
+
|
|
88
|
+
[tool.coverage.run]
|
|
89
|
+
branch = true
|
|
90
|
+
source = ["flyrail"]
|
|
91
|
+
data_file = ".cache/coverage/.coverage"
|
|
92
|
+
|
|
93
|
+
[tool.coverage.report]
|
|
94
|
+
show_missing = true
|
|
95
|
+
skip_covered = false
|