oc-box 0.1.23__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.
- oc_box-0.1.23/.github/workflows/ci.yml +37 -0
- oc_box-0.1.23/.github/workflows/publish.yml +83 -0
- oc_box-0.1.23/AGENTS.md +110 -0
- oc_box-0.1.23/CONTRIBUTING.md +102 -0
- oc_box-0.1.23/LICENSE +674 -0
- oc_box-0.1.23/MANIFEST.in +7 -0
- oc_box-0.1.23/NOTICE +19 -0
- oc_box-0.1.23/PKG-INFO +407 -0
- oc_box-0.1.23/README.md +379 -0
- oc_box-0.1.23/SECURITY.md +141 -0
- oc_box-0.1.23/__init__.py +1 -0
- oc_box-0.1.23/__main__.py +5 -0
- oc_box-0.1.23/bootstrap.py +36 -0
- oc_box-0.1.23/build-info.json +6 -0
- oc_box-0.1.23/docs/cli.md +1352 -0
- oc_box-0.1.23/docs/oc-box.1 +812 -0
- oc_box-0.1.23/docs/oc-box.info +1567 -0
- oc_box-0.1.23/docs/oc-box.texi +826 -0
- oc_box-0.1.23/install.py +16 -0
- oc_box-0.1.23/install.sh +32 -0
- oc_box-0.1.23/installation.py +185 -0
- oc_box-0.1.23/oc_box.egg-info/PKG-INFO +407 -0
- oc_box-0.1.23/oc_box.egg-info/SOURCES.txt +74 -0
- oc_box-0.1.23/oc_box.egg-info/dependency_links.txt +1 -0
- oc_box-0.1.23/oc_box.egg-info/entry_points.txt +2 -0
- oc_box-0.1.23/oc_box.egg-info/top_level.txt +1 -0
- oc_box-0.1.23/oc_box.py +2425 -0
- oc_box-0.1.23/pyproject.toml +51 -0
- oc_box-0.1.23/setup.cfg +4 -0
- oc_box-0.1.23/setup.py +69 -0
- oc_box-0.1.23/status_report.py +485 -0
- oc_box-0.1.23/sync_config.py +192 -0
- oc_box-0.1.23/terminal_ui.py +193 -0
- oc_box-0.1.23/tests/fixture_services.py +64 -0
- oc_box-0.1.23/tests/smoke_mainline.py +761 -0
- oc_box-0.1.23/tests/test_documentation.py +237 -0
- oc_box-0.1.23/tests/test_oc_box.py +637 -0
- oc_box-0.1.23/tests/test_packaging.py +54 -0
- oc_box-0.1.23/tests/test_podman_options.py +384 -0
- oc_box-0.1.23/tests/test_process_io.py +36 -0
- oc_box-0.1.23/tests/test_session_import.py +453 -0
- oc_box-0.1.23/tests/test_stale_workspaces.py +245 -0
- oc_box-0.1.23/tests/test_startup.py +336 -0
- oc_box-0.1.23/tests/test_status.py +428 -0
- oc_box-0.1.23/tests/test_terminal.py +390 -0
- oc_box-0.1.23/tests/test_updater.py +526 -0
- oc_box-0.1.23/tests/test_version.py +137 -0
- oc_box-0.1.23/tests/test_workspace_identity.py +431 -0
- oc_box-0.1.23/tests/test_workspace_repair.py +312 -0
- oc_box-0.1.23/tools/build_docs.py +231 -0
- oc_box-0.1.23/tools/check_package.py +242 -0
- oc_box-0.1.23/tools/diagnose_import.py +126 -0
- oc_box-0.1.23/updater.py +255 -0
- oc_box-0.1.23/version_info.py +71 -0
- oc_box-0.1.23/workspace_identity.py +113 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Package and source checks
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
timeout-minutes: 15
|
|
15
|
+
strategy:
|
|
16
|
+
matrix:
|
|
17
|
+
python: ['3.10', '3.13']
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0
|
|
22
|
+
persist-credentials: false
|
|
23
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
24
|
+
with:
|
|
25
|
+
python-version: ${{ matrix.python }}
|
|
26
|
+
- name: Unit and documentation coverage checks
|
|
27
|
+
run: |
|
|
28
|
+
python -B -m unittest discover -s tests -v
|
|
29
|
+
python tools/build_docs.py --check
|
|
30
|
+
git diff --check
|
|
31
|
+
- name: Build Python distributions
|
|
32
|
+
run: |
|
|
33
|
+
python -m venv "$RUNNER_TEMP/build"
|
|
34
|
+
"$RUNNER_TEMP/build/bin/python" -m pip install build twine
|
|
35
|
+
"$RUNNER_TEMP/build/bin/python" -m build
|
|
36
|
+
"$RUNNER_TEMP/build/bin/python" -m twine check dist/*
|
|
37
|
+
python tools/check_package.py dist
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
name: Build and publish Python package
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
publish:
|
|
9
|
+
description: Publish to PyPI after checks (false builds only)
|
|
10
|
+
type: boolean
|
|
11
|
+
default: false
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
concurrency:
|
|
17
|
+
group: pypi-${{ github.ref }}
|
|
18
|
+
cancel-in-progress: false
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
build:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
timeout-minutes: 15
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
|
26
|
+
with:
|
|
27
|
+
fetch-depth: 0
|
|
28
|
+
persist-credentials: false
|
|
29
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
30
|
+
with:
|
|
31
|
+
python-version: '3.10'
|
|
32
|
+
- name: Create isolated build tools
|
|
33
|
+
run: |
|
|
34
|
+
python -m venv "$RUNNER_TEMP/oc-box-build"
|
|
35
|
+
"$RUNNER_TEMP/oc-box-build/bin/python" -m pip install build twine
|
|
36
|
+
- name: Validate source and release version
|
|
37
|
+
env:
|
|
38
|
+
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
|
39
|
+
run: |
|
|
40
|
+
python -m compileall -q oc_box.py bootstrap.py sync_config.py terminal_ui.py status_report.py workspace_identity.py installation.py updater.py version_info.py
|
|
41
|
+
python tools/build_docs.py --check
|
|
42
|
+
python - <<'PY'
|
|
43
|
+
import os
|
|
44
|
+
from version_info import get_version_info, VERSION_SERIES
|
|
45
|
+
build = get_version_info('.')
|
|
46
|
+
expected = f"v{VERSION_SERIES}.{build['commit_count']}"
|
|
47
|
+
assert not build['dirty'], 'Publish only a clean source commit'
|
|
48
|
+
if os.environ.get('RELEASE_TAG'):
|
|
49
|
+
assert os.environ['RELEASE_TAG'] == expected, f'Release tag must be {expected}'
|
|
50
|
+
print('Publishing/building', expected, 'from', build['commit'])
|
|
51
|
+
PY
|
|
52
|
+
- name: Run source regression tests
|
|
53
|
+
run: python -B -m unittest discover -s tests -v
|
|
54
|
+
- name: Build wheel and source distribution
|
|
55
|
+
run: |
|
|
56
|
+
"$RUNNER_TEMP/oc-box-build/bin/python" -m build
|
|
57
|
+
"$RUNNER_TEMP/oc-box-build/bin/python" -m twine check dist/*
|
|
58
|
+
- name: Verify isolated package installation and resources
|
|
59
|
+
run: python tools/check_package.py dist
|
|
60
|
+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
61
|
+
with:
|
|
62
|
+
name: python-distributions
|
|
63
|
+
path: dist/*
|
|
64
|
+
if-no-files-found: error
|
|
65
|
+
retention-days: 7
|
|
66
|
+
|
|
67
|
+
publish:
|
|
68
|
+
if: github.event_name == 'release' || inputs.publish
|
|
69
|
+
needs: build
|
|
70
|
+
runs-on: ubuntu-latest
|
|
71
|
+
timeout-minutes: 10
|
|
72
|
+
environment:
|
|
73
|
+
name: pypi
|
|
74
|
+
url: https://pypi.org/project/oc-box/
|
|
75
|
+
permissions:
|
|
76
|
+
id-token: write
|
|
77
|
+
steps:
|
|
78
|
+
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
|
79
|
+
with:
|
|
80
|
+
name: python-distributions
|
|
81
|
+
path: dist
|
|
82
|
+
- name: Publish with PyPI Trusted Publishing
|
|
83
|
+
uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # release/v1
|
oc_box-0.1.23/AGENTS.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# oc-box development
|
|
2
|
+
|
|
3
|
+
Run development commands from the repository root. Keep public documentation
|
|
4
|
+
portable: use example project paths and synthetic session IDs, not local data.
|
|
5
|
+
|
|
6
|
+
## Architecture
|
|
7
|
+
|
|
8
|
+
- `oc_box.py`: external rootless-Podman launcher and workspace lifecycle.
|
|
9
|
+
- `bootstrap.py`: baseline tools installed inside the container.
|
|
10
|
+
- `sync_config.py`: container-only config refresh with dependency-cache reuse.
|
|
11
|
+
- `terminal_ui.py`: native TUI relay and startup loading indicator.
|
|
12
|
+
- `status_report.py`: read-only host resource and storage reporting.
|
|
13
|
+
- `version_info.py`: commit-derived version and author/license information.
|
|
14
|
+
- `workspace_identity.py`: generic Linux VFS directory identity, capability-based
|
|
15
|
+
persistent handles and strict fallback; shared by lifecycle/status checks.
|
|
16
|
+
- `install.py`: copies the launcher to `~/.local/share/oc-box` and creates
|
|
17
|
+
`~/.local/bin/oc-box`.
|
|
18
|
+
- `installation.py`: staged immutable installed copies and launcher activation.
|
|
19
|
+
- `updater.py` / `install.sh`: public GitHub upgrades and one-line bootstrap.
|
|
20
|
+
- `pyproject.toml` / `setup.py`: Python distributions with an isolated `oc_box`
|
|
21
|
+
namespace, resources, public versions, and source metadata.
|
|
22
|
+
- `.github/workflows/publish.yml`: selected PyPI releases via Trusted Publishing.
|
|
23
|
+
- `tests/`: stdlib unit tests and bounded offline mainline integration fixtures.
|
|
24
|
+
- `docs/cli.md`: canonical command reference; `tools/build_docs.py` generates
|
|
25
|
+
the committed man/Texinfo/Info manuals from it.
|
|
26
|
+
|
|
27
|
+
OpenCode itself and its integrations run natively inside the container. Preserve
|
|
28
|
+
MCPs, formatters, language servers, and plugins. Do not return to replacing
|
|
29
|
+
built-in tools or disabling integrations for containment. Keep mainline OpenCode
|
|
30
|
+
unmodified. Live sessions persist in a private named volume, and host-side
|
|
31
|
+
history is synchronized with supported CLI export/import commands on exit.
|
|
32
|
+
|
|
33
|
+
## Git workflow
|
|
34
|
+
|
|
35
|
+
Commit completed changes after reviewing the diff and running the relevant
|
|
36
|
+
checks. The user explicitly requests automatic commits for work in this
|
|
37
|
+
repository. Stage intended source files explicitly; sandbox-generated empty
|
|
38
|
+
placeholder dotfiles are not project source. The user authorizes automatic
|
|
39
|
+
pushes of reviewed commits to an explicitly configured upstream, provided the
|
|
40
|
+
hosting service permits this AI-assisted project. Do not create a remote or
|
|
41
|
+
push to a service with incompatible policies. Do not store credentials in Git
|
|
42
|
+
URLs, config, source files, or command-line arguments.
|
|
43
|
+
|
|
44
|
+
The public upstream is `https://github.com/groopcd/oc-box.git`. Use only the
|
|
45
|
+
explicit `PERSONAL_GITHUB_TOKEN` for publication. Inherited `GITHUB_TOKEN` and
|
|
46
|
+
`GH_TOKEN` belong to a separate Microsoft/Copilot account and must not be used
|
|
47
|
+
for repository management or pushes. Give publishing subprocesses an isolated
|
|
48
|
+
GitHub CLI config and set their local `GH_TOKEN` from `PERSONAL_GITHUB_TOKEN`,
|
|
49
|
+
without modifying the parent environment. Verify `gh api user` reports
|
|
50
|
+
`groopcd` before publishing. Pass Git credential helpers per command rather
|
|
51
|
+
than storing tokens or changing global authentication settings.
|
|
52
|
+
|
|
53
|
+
Version `0.1.N+gHASH` is derived from the full Git history; every commit advances
|
|
54
|
+
N automatically. The installer embeds the source identity in its private
|
|
55
|
+
`build-info.json`. Original project code/documentation is GPL-3.0-or-later;
|
|
56
|
+
retain LICENSE and NOTICE when distributing/installing it.
|
|
57
|
+
PyPI uses the public `0.1.N` version; retain the full `+gHASH` identity in package
|
|
58
|
+
resources. Python-package installations upgrade through pipx/uv/pip, never the
|
|
59
|
+
GitHub self-updater. Preserve the normal curl/GitHub update path in parallel.
|
|
60
|
+
|
|
61
|
+
Update `docs/cli.md` when command-line behavior changes, then regenerate with
|
|
62
|
+
`python3 tools/build_docs.py` (requires GNU makeinfo). Prebuilt manuals ship in
|
|
63
|
+
the repository; installing oc-box must not require documentation build tools.
|
|
64
|
+
|
|
65
|
+
## Checks
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
python3 -B -m unittest discover -s tests -v
|
|
69
|
+
python3 -B tests/smoke_mainline.py
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The smoke test uses temporary databases and offline fixture services, with
|
|
73
|
+
bounded timeouts. It does not verify actual Podman isolation. Live Podman
|
|
74
|
+
verification must run on the host, outside another container/sandbox.
|
|
75
|
+
|
|
76
|
+
A host-terminal Tumbleweed container/OpenCode launch has succeeded. Full live
|
|
77
|
+
MCP, formatter, language-server, and stop/resume verification is still pending;
|
|
78
|
+
the automated integration checks use offline fixtures.
|
|
79
|
+
|
|
80
|
+
The host-terminal warm-start test is now effectively instant after retaining
|
|
81
|
+
the container-generated plugin SDK manifest, lockfiles, and dependency cache.
|
|
82
|
+
|
|
83
|
+
Host-session import and mapped NPU access have been exercised on Tumbleweed.
|
|
84
|
+
A native warm plugin-initialization probe completed in under one second.
|
|
85
|
+
New mounts use `:z`, and cold plugin resolution is timed before opening the TUI.
|
|
86
|
+
|
|
87
|
+
Container launches give Build mode allow-all OpenCode permissions through a
|
|
88
|
+
generated private config/plugin. Keep Plan/subagent rules and plain host
|
|
89
|
+
OpenCode permissions unchanged.
|
|
90
|
+
|
|
91
|
+
Do not treat a lost marker or changed filesystem device/inode as permission to
|
|
92
|
+
create a replacement workspace. Look up registered canonical paths, direct the
|
|
93
|
+
host operator to explicit `repair`, and never overwrite another workspace's
|
|
94
|
+
marker. Device-number changes may be accepted only against a recorded matching
|
|
95
|
+
filesystem ID, persistent directory handle, and inode; never infer a baseline
|
|
96
|
+
from an old device number and unchanged inode alone. Upgrade legacy records
|
|
97
|
+
under the workspace lock only after verification or explicit repair.
|
|
98
|
+
Use the common VFS APIs without filesystem-name branches. Do not promise
|
|
99
|
+
physical identity on unsupported drivers or replace it with a copyable marker.
|
|
100
|
+
Plain stale-workspace purge preserves project files, host history, and
|
|
101
|
+
private archive-origin evidence under `retired/`; keep that recovery path tested.
|
|
102
|
+
|
|
103
|
+
`terminal` is maintenance-only: no host credential/pass_env forwarding, no
|
|
104
|
+
OpenCode/auth/config refresh, startup profiles, or persistent shell history.
|
|
105
|
+
Keep its environment allowlisted and preserve the original container run state.
|
|
106
|
+
|
|
107
|
+
Updates fetch the fixed public HTTPS upstream anonymously with sanitized Git
|
|
108
|
+
configuration/environment. Never reuse publishing/provider credentials for
|
|
109
|
+
downloads. Keep automatic updating opt-in, preserve running release copies,
|
|
110
|
+
workspaces and source checkouts, and do not self-update from inside a container.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Use the full Git history: the release identity is `0.1.N+gHASH`, with the commit
|
|
4
|
+
count as N. Changes should keep mainline OpenCode unmodified and preserve MCPs,
|
|
5
|
+
formatters, language servers, plugins, and the host/container storage boundary.
|
|
6
|
+
|
|
7
|
+
## Checks
|
|
8
|
+
|
|
9
|
+
Python 3.10+ and stdlib are sufficient for unit tests. The mainline smoke test
|
|
10
|
+
also needs Git and OpenCode (integration checked with 1.19.5):
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
python3 -B -m unittest discover -s tests -v
|
|
14
|
+
python3 -B tests/smoke_mainline.py
|
|
15
|
+
python3 -B tools/build_docs.py --check
|
|
16
|
+
git diff --check
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Tests use isolated temporary app data. Mainline model/MCP/LSP/formatter fixtures
|
|
20
|
+
are local and bounded. These checks do not replace live host-side Podman tests.
|
|
21
|
+
Do not run host lifecycle tests from inside the project's running container.
|
|
22
|
+
|
|
23
|
+
## Manuals
|
|
24
|
+
|
|
25
|
+
Edit `docs/cli.md` when command-line behavior changes. Generate committed man,
|
|
26
|
+
Texinfo, and Info files with GNU makeinfo installed:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
python3 -B tools/build_docs.py
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
End-user installation copies prebuilt manuals and must not require build tools.
|
|
33
|
+
Optional man/Info rendering checks run when groff and GNU info are available.
|
|
34
|
+
Info output is byte-reproducible with the same makeinfo version. Different
|
|
35
|
+
Texinfo releases may change their banner, wrapping, typography, and tag offsets;
|
|
36
|
+
tests verify matching navigation across versions rather than requiring identical
|
|
37
|
+
binary output from every distribution's documentation toolchain.
|
|
38
|
+
|
|
39
|
+
## Source and release hygiene
|
|
40
|
+
|
|
41
|
+
- Stage intended files explicitly. Never commit auth files, tokens, private keys,
|
|
42
|
+
session databases/exports, registry metadata, caches, or sandbox placeholders.
|
|
43
|
+
- Review Git history as well as the working tree before a first public push.
|
|
44
|
+
With Gitleaks installed, run `gitleaks git --log-opts=--all --redact .` and
|
|
45
|
+
`gitleaks dir --redact .`. Scan reports belong outside the repository.
|
|
46
|
+
- Shell calls should use argument arrays. Forward credentials through the
|
|
47
|
+
process environment, never command-line arguments or credential-bearing URLs.
|
|
48
|
+
- Add regression tests for boundary changes, import compatibility, lifecycle
|
|
49
|
+
preservation, and actual command behavior rather than implementation mirrors.
|
|
50
|
+
- Keep examples portable and use synthetic session IDs.
|
|
51
|
+
- Disclose AI assistance honestly. Check each hosting service's policy before
|
|
52
|
+
publication; a GPL license does not override a service's content rules.
|
|
53
|
+
|
|
54
|
+
Original contributions are licensed GPL-3.0-or-later. Retain LICENSE and NOTICE.
|
|
55
|
+
|
|
56
|
+
## Python packages and PyPI releases
|
|
57
|
+
|
|
58
|
+
The wheel contains a namespaced `oc_box` package, runtime helper scripts,
|
|
59
|
+
prebuilt manuals, license/notice, and immutable source metadata. It has no
|
|
60
|
+
third-party runtime Python dependencies. GitHub source/curl installations stay
|
|
61
|
+
supported in parallel. Do not make a pip-managed launcher install through the
|
|
62
|
+
GitHub self-updater or write a global wrapper as an installation side effect.
|
|
63
|
+
|
|
64
|
+
Build in isolation (uv uses an ephemeral environment; no project/system pip
|
|
65
|
+
install is needed):
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
uv run --no-project --with build --with twine python -m build
|
|
69
|
+
uv run --no-project --with twine python -m twine check dist/*
|
|
70
|
+
python3 tools/check_package.py dist
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The last check installs only the wheel into a temporary virtual environment,
|
|
74
|
+
tests CLI commands/resources, and ensures package upgrades do not invoke the
|
|
75
|
+
GitHub installer. Standard build produces the wheel from the sdist to verify
|
|
76
|
+
that it works without Git. Do not publish a dirty working tree.
|
|
77
|
+
|
|
78
|
+
PyPI rejects local `+gHASH` version suffixes: the distribution version is
|
|
79
|
+
`0.1.N` from full-history commit count, and packaged `build-info.json` keeps
|
|
80
|
+
`0.1.N+gHASH` plus the full commit. Each selected release needs a unique version;
|
|
81
|
+
ordinary commits remain on GitHub without requiring a PyPI upload.
|
|
82
|
+
|
|
83
|
+
Trusted Publisher configuration in PyPI must match:
|
|
84
|
+
|
|
85
|
+
- Project: `oc-box` (pending publisher until its first successful publication).
|
|
86
|
+
- GitHub owner/repository: `groopcd/oc-box`.
|
|
87
|
+
- Workflow filename: `publish.yml`.
|
|
88
|
+
- GitHub environment: `pypi`.
|
|
89
|
+
|
|
90
|
+
No long-lived PyPI upload token belongs in GitHub or this repository. Only the
|
|
91
|
+
publish job receives `id-token: write`, and it downloads already-tested artifacts
|
|
92
|
+
rather than executing package build code with publishing credentials. GitHub
|
|
93
|
+
Actions are pinned by commit. The user must create/own the PyPI account and
|
|
94
|
+
configure the matching publisher; pending publishers do not reserve names.
|
|
95
|
+
|
|
96
|
+
First run the workflow with its `publish` input false to verify a build-only
|
|
97
|
+
run. A published GitHub release named `v0.1.N` (matching that commit's count)
|
|
98
|
+
builds, validates, and publishes to PyPI. Alternatively manually dispatch
|
|
99
|
+
`publish.yml` on a reviewed commit with `publish` true. Environment protection
|
|
100
|
+
rules may require owner approval. Do not publish from untrusted pull requests.
|
|
101
|
+
The repository's CI builds/verifies packages on Python 3.10 and 3.13; the full
|
|
102
|
+
mainline smoke fixture remains part of local verification with OpenCode.
|