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.
Files changed (55) hide show
  1. oc_box-0.1.23/.github/workflows/ci.yml +37 -0
  2. oc_box-0.1.23/.github/workflows/publish.yml +83 -0
  3. oc_box-0.1.23/AGENTS.md +110 -0
  4. oc_box-0.1.23/CONTRIBUTING.md +102 -0
  5. oc_box-0.1.23/LICENSE +674 -0
  6. oc_box-0.1.23/MANIFEST.in +7 -0
  7. oc_box-0.1.23/NOTICE +19 -0
  8. oc_box-0.1.23/PKG-INFO +407 -0
  9. oc_box-0.1.23/README.md +379 -0
  10. oc_box-0.1.23/SECURITY.md +141 -0
  11. oc_box-0.1.23/__init__.py +1 -0
  12. oc_box-0.1.23/__main__.py +5 -0
  13. oc_box-0.1.23/bootstrap.py +36 -0
  14. oc_box-0.1.23/build-info.json +6 -0
  15. oc_box-0.1.23/docs/cli.md +1352 -0
  16. oc_box-0.1.23/docs/oc-box.1 +812 -0
  17. oc_box-0.1.23/docs/oc-box.info +1567 -0
  18. oc_box-0.1.23/docs/oc-box.texi +826 -0
  19. oc_box-0.1.23/install.py +16 -0
  20. oc_box-0.1.23/install.sh +32 -0
  21. oc_box-0.1.23/installation.py +185 -0
  22. oc_box-0.1.23/oc_box.egg-info/PKG-INFO +407 -0
  23. oc_box-0.1.23/oc_box.egg-info/SOURCES.txt +74 -0
  24. oc_box-0.1.23/oc_box.egg-info/dependency_links.txt +1 -0
  25. oc_box-0.1.23/oc_box.egg-info/entry_points.txt +2 -0
  26. oc_box-0.1.23/oc_box.egg-info/top_level.txt +1 -0
  27. oc_box-0.1.23/oc_box.py +2425 -0
  28. oc_box-0.1.23/pyproject.toml +51 -0
  29. oc_box-0.1.23/setup.cfg +4 -0
  30. oc_box-0.1.23/setup.py +69 -0
  31. oc_box-0.1.23/status_report.py +485 -0
  32. oc_box-0.1.23/sync_config.py +192 -0
  33. oc_box-0.1.23/terminal_ui.py +193 -0
  34. oc_box-0.1.23/tests/fixture_services.py +64 -0
  35. oc_box-0.1.23/tests/smoke_mainline.py +761 -0
  36. oc_box-0.1.23/tests/test_documentation.py +237 -0
  37. oc_box-0.1.23/tests/test_oc_box.py +637 -0
  38. oc_box-0.1.23/tests/test_packaging.py +54 -0
  39. oc_box-0.1.23/tests/test_podman_options.py +384 -0
  40. oc_box-0.1.23/tests/test_process_io.py +36 -0
  41. oc_box-0.1.23/tests/test_session_import.py +453 -0
  42. oc_box-0.1.23/tests/test_stale_workspaces.py +245 -0
  43. oc_box-0.1.23/tests/test_startup.py +336 -0
  44. oc_box-0.1.23/tests/test_status.py +428 -0
  45. oc_box-0.1.23/tests/test_terminal.py +390 -0
  46. oc_box-0.1.23/tests/test_updater.py +526 -0
  47. oc_box-0.1.23/tests/test_version.py +137 -0
  48. oc_box-0.1.23/tests/test_workspace_identity.py +431 -0
  49. oc_box-0.1.23/tests/test_workspace_repair.py +312 -0
  50. oc_box-0.1.23/tools/build_docs.py +231 -0
  51. oc_box-0.1.23/tools/check_package.py +242 -0
  52. oc_box-0.1.23/tools/diagnose_import.py +126 -0
  53. oc_box-0.1.23/updater.py +255 -0
  54. oc_box-0.1.23/version_info.py +71 -0
  55. 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
@@ -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.