ai-push-hooks 0.2.0 → 0.2.1

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.
package/CHANGELOG.md CHANGED
@@ -4,7 +4,28 @@ All notable changes to this project are documented here. The format is based on
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
- No changes yet.
7
+ ## [0.2.1] - 2026-09-08
8
+
9
+ This is a beta patch release. Python and npm both use `0.2.1`, the canonical
10
+ Git tag is `v0.2.1`, npm uses the `beta` dist-tag, and GitHub marks the release
11
+ as a prerelease.
12
+
13
+ ### Fixed
14
+
15
+ - Restored OpenCode's built-in plugins, including built-in authentication such as
16
+ Codex OAuth, during isolated runs. `--pure` still excludes external plugins,
17
+ and project/global configuration and plugins remain isolated.
18
+ - Restored forwarding of recognized provider environment variables, including
19
+ `OPENAI_API_KEY`, so OpenCode itself selects the authentication path.
20
+ - Prevented hook-launched Beads alignment updates from inheriting schema and
21
+ remote-migration safety overrides.
22
+ - Made post-publication PyPI verification tolerate bounded 404/partial metadata
23
+ propagation while retaining fail-closed artifact hash and authentication checks.
24
+
25
+ ### Documentation
26
+
27
+ - Documented the native `bd` maintenance, backup, rehearsal, and remote
28
+ publication boundaries; Beads-Rust (`br`) is not supported.
8
29
 
9
30
  ## [0.2.0] - 2026-09-06
10
31
 
@@ -58,6 +79,7 @@ the exact `0.2.0` version rather than a PyPI beta channel.
58
79
  - Preserved Git porcelain paths and protected pre-existing dirty allowlisted files during apply steps.
59
80
  - Clarified module-local artifact references and standardized the repository hook integration.
60
81
 
61
- [Unreleased]: https://github.com/shanebishop1/ai-push-hooks/compare/v0.2.0...HEAD
82
+ [Unreleased]: https://github.com/shanebishop1/ai-push-hooks/compare/v0.2.1...HEAD
83
+ [0.2.1]: https://github.com/shanebishop1/ai-push-hooks/compare/v0.2.0...v0.2.1
62
84
  [0.2.0]: https://github.com/shanebishop1/ai-push-hooks/compare/v0.1.19...v0.2.0
63
85
  [0.1.19]: https://github.com/shanebishop1/ai-push-hooks/compare/v0.1.18...v0.1.19
package/README.md CHANGED
@@ -12,7 +12,7 @@ Use it to keep docs aligned with code, check branch/task consistency, or prepare
12
12
  - [Python 3.10–3.13](https://www.python.org/downloads/). Python is required even when installing the npm wrapper. The wrapper probes Python 3.14, 3.13, 3.12, 3.11, 3.10, then `python`; the 3.14 probe is not a beta support claim. Python 3.10 additionally needs the `tomli` package available to that interpreter.
13
13
  - [OpenCode](https://opencode.ai/docs/#install) is optional for workflows that use only deterministic steps, but the `minimal-docs` starter uses `llm` and `apply`. Those steps also need a provider/model and authentication; check with `opencode auth list`.
14
14
  - [GitHub CLI (`gh`)](https://cli.github.com/manual/installation) is optional and needed only for `gh_pr_create`.
15
- - [Beads (`bd`)](https://github.com/steveyegge/beads) is optional and needed only for Beads alignment steps.
15
+ - [Beads (`bd`)](https://github.com/steveyegge/beads) is optional and needed only for Beads alignment steps. The integration requires the native `bd` CLI; Beads-Rust (`br`) is not a supported substitute.
16
16
  - [Lefthook](https://lefthook.dev/installation/) and [Mise](https://mise.jdx.dev/getting-started.html) are optional hook-manager/tool-version alternatives described below.
17
17
 
18
18
  ### Install ai-push-hooks
@@ -21,7 +21,7 @@ This is the shortest path. It installs the package, writes the exact starter
21
21
  configuration filename, and installs a repository-local `pre-push` delegate:
22
22
 
23
23
  ```bash
24
- python -m pip install ai-push-hooks==0.2.0
24
+ python -m pip install ai-push-hooks==0.2.1
25
25
  ai-push-hooks init --template minimal-docs
26
26
  ai-push-hooks install
27
27
  ```
@@ -33,9 +33,9 @@ the bare remote. The first command above can instead be `uv tool install
33
33
  ai-push-hooks` or `pipx install ai-push-hooks` when using an isolated
34
34
  application environment.
35
35
 
36
- These instructions describe the `0.2.0` beta release. npm exposes it through
36
+ These instructions describe the `0.2.1` beta release. npm exposes it through
37
37
  the `beta` dist-tag; PyPI has no separate beta channel, so Python installation
38
- must select the exact `0.2.0` version. Published `0.1.19` artifacts retain
38
+ must select the exact `0.2.1` version. Published `0.1.19` artifacts retain
39
39
  historical provenance and must not be assumed to contain this release's
40
40
  `install` command.
41
41
 
@@ -55,7 +55,7 @@ npx --no-install ai-push-hooks install
55
55
  # or: pnpm add -D ai-push-hooks && pnpm exec ai-push-hooks install
56
56
  ```
57
57
 
58
- Use `ai-push-hooks@0.2.0` instead of `@beta` when an exact npm version pin is
58
+ Use `ai-push-hooks@0.2.1` instead of `@beta` when an exact npm version pin is
59
59
  required.
60
60
 
61
61
  The npm package does not contain a Python runtime. Ensure the Python
@@ -85,14 +85,14 @@ resolved. The fallback delegate fails clearly with status 127 if
85
85
  Pin an approved published release in the consuming repository:
86
86
 
87
87
  ```bash
88
- mise use npm:ai-push-hooks@0.2.0
88
+ mise use npm:ai-push-hooks@0.2.1
89
89
  ```
90
90
 
91
91
  This adds the following project-level tool entry to `mise.toml` and installs it:
92
92
 
93
93
  ```toml
94
94
  [tools]
95
- "npm:ai-push-hooks" = "0.2.0"
95
+ "npm:ai-push-hooks" = "0.2.1"
96
96
  ```
97
97
 
98
98
  After checking in `mise.toml`, other contributors can install the pinned tool with `mise install`.
@@ -101,12 +101,30 @@ After checking in `mise.toml`, other contributors can install the pinned tool wi
101
101
 
102
102
  OpenCode runs in `--pure` mode with project configuration disabled, isolated home/config/cache/state directories, sharing disabled, and an ai-push-hooks-owned custom agent configuration. Read-only steps run in an empty scratch directory, receive only hook-owned artifacts through `--file`, and have every tool denied. Apply steps run against a private temporary workspace containing only unignored regular files matching `allow_paths`; their agent permits only reads and allowlisted edits in that workspace. Casefolded, Unicode-normalized `.git` and `AGENTS.md` paths are always protected.
103
103
 
104
- Global and repository OpenCode instructions, custom agents, MCP servers, formatters, LSP configuration, sharing, and plugins are not inherited. The existing XDG data directory is retained for OpenCode authentication/session state, and recognized provider environment variables are forwarded. Custom providers defined only in global OpenCode configuration are therefore unsupported; use a built-in provider with OpenCode auth state or environment credentials.
104
+ Built-in OpenCode plugins remain enabled, including built-in authentication plugins such as Codex OAuth. Normal `--pure` execution disables external plugins, while the hook's empty plugin configuration and project-config disablement prevent project and global plugins and configuration from being inherited. The existing XDG data directory is retained for OpenCode authentication/session state, and recognized provider environment variables, including `OPENAI_API_KEY`, are forwarded; OpenCode itself chooses the authentication path using its normal precedence. Custom providers defined only in global OpenCode configuration are therefore unsupported; use a built-in provider with OpenCode auth state or environment credentials.
105
105
 
106
106
  After OpenCode session finalization, apply verifies that the Git-visible checkout, index, current-worktree control state, and critical shared `HEAD`/config/packed-refs/refs/hooks state still match their baselines. Pre-existing symlinks in monitored Git metadata fail closed before OpenCode runs, and symlinks introduced during execution fail before propagation. Apply then preflights every destination against its exact baseline type, content digest, and mode before propagating anything, performs atomic file replacement, and verifies the resulting checkout and protected Git state again. Safe existing ordinary `rwx` modes are preserved, existing special bits are stripped, new or group/world-writable modes become owner-only, and staged files carrying setuid/setgid/sticky bits are rejected before any propagation. Hook-owned runtime files default to `0600` and runtime directories to `0700`.
107
107
 
108
108
  These controls are OpenCode permission and workspace isolation, not an operating-system sandbox. Compare-and-swap preflight minimizes lost updates but cannot make the interval between preflight and filesystem replacement atomic against an independent local process. Ignored worktree trees, Git object/LFS stores, shared reflogs, and metadata belonging only to other linked worktrees are intentionally excluded from bounded snapshots; direct changes there may not be detected. Critical shared refs/config/hooks remain monitored. Automatic rollback is avoided so pre-existing user changes are not overwritten.
109
109
 
110
+ ### Beads maintenance boundary
111
+
112
+ The `beads_alignment` executor is for ordinary native `bd update` and `bd close`
113
+ operations only. It does not run migrations, synchronize embedded Dolt, or
114
+ publish Dolt refs. Hook-launched Beads commands also discard
115
+ `BD_ALLOW_REMOTE_MIGRATE`, `BD_IGNORE_SCHEMA_SKEW`, and `BD_SMART_GATE` from
116
+ their inherited environment so an operator maintenance override cannot leak
117
+ into a push hook.
118
+
119
+ Treat a Beads schema migration as separate operator maintenance. Pin and
120
+ verify the native `bd` version, stop Beads writers and hooks, take a cold full
121
+ backup of `.beads`, and rehearse against a disposable copy before opening the
122
+ live embedded-Dolt store. Verify the schema, semantic issue/dependency data,
123
+ memories, and a clean Dolt working set before and after the live cutover.
124
+ Remote publication, including `bd dolt push`, is a separate explicit action;
125
+ a successful local migration does not authorize it. Do not replace this flow
126
+ with Beads-Rust (`br`).
127
+
110
128
  ## Full-featured alternative: Lefthook
111
129
 
112
130
  Use Lefthook when the repository needs several hook commands, shared hook
@@ -160,7 +178,7 @@ Configure modules and steps in the [configuration reference](#configuration-refe
160
178
  ## Troubleshooting
161
179
 
162
180
  - **`opencode is required but not installed`:** install OpenCode and ensure `opencode` (or `opencode-cli`) is on `PATH` for the Git hook process.
163
- - **Provider/model authentication fails:** run `opencode auth list`, authenticate a built-in provider, and verify `[llm].model`. Project/global custom-provider configuration is intentionally not loaded; see [OpenCode isolation limits](#opencode-isolation-limits).
181
+ - **Provider/model authentication fails:** run `opencode auth list`, authenticate a built-in provider, and verify `[llm].model`. Built-in auth plugins remain available, while project/global custom-provider configuration is intentionally not loaded. Recognized provider environment variables, including `OPENAI_API_KEY`, are forwarded and OpenCode chooses authentication. See [OpenCode isolation limits](#opencode-isolation-limits).
164
182
  - **The hook does not run:** rerun `lefthook install`, check `git config --get core.hooksPath`, and verify the pre-push path with the command above.
165
183
  - **The push is blocked after docs changed:** this is the expected edit-review-commit flow. Review `git diff`, validate and commit the changes, then push again.
166
184
  - **Find logs or transcripts:** inspect `.git/ai-push-hooks/logs`, `.git/ai-push-hooks/summaries`, and (when enabled) `.git/ai-push-hooks/transcripts`.
package/SECURITY.md CHANGED
@@ -8,7 +8,7 @@ Please do not open a public issue for a suspected vulnerability. Report it priva
8
8
 
9
9
  ai-push-hooks treats repository content, Git paths and metadata, configuration, model output, and concurrent local filesystem changes as potentially unsafe. Its controls constrain model-visible inputs and apply destinations, protect Git metadata and instruction files, validate filesystem state before propagation, and fail closed by default. They are designed to prevent accidental or model-directed changes outside configured boundaries, not to protect against a malicious user or process with the same operating-system permissions.
10
10
 
11
- OpenCode is a separate local process and communicates with the model provider selected in `[llm].model`. Diffs, changed-file context, prompts, and step artifacts can therefore leave the machine under that provider's terms. ai-push-hooks forwards recognized provider credential environment variables and retains OpenCode's existing authentication data directory, but disables sharing and does not inherit project/global plugins, MCP servers, instructions, or custom-provider configuration. Do not commit secrets, and review provider retention and privacy policies before use on sensitive repositories.
11
+ OpenCode is a separate local process and communicates with the model provider selected in `[llm].model`. Diffs, changed-file context, prompts, and step artifacts can therefore leave the machine under that provider's terms. ai-push-hooks retains OpenCode's existing authentication data directory and forwards recognized provider credential environment variables, including `OPENAI_API_KEY`; OpenCode itself chooses authentication using its normal precedence. Built-in authentication plugins remain available, while `--pure` excludes external plugins and the isolated project/config setup excludes project/global plugins, MCP servers, instructions, and custom-provider configuration. Do not commit secrets, and review provider retention and privacy policies before use on sensitive repositories.
12
12
 
13
13
  Hook logs, summaries, run artifacts, and transcripts are stored locally under `.git/ai-push-hooks/` with private runtime permissions. Transcript capture defaults to **on** at `.git/ai-push-hooks/transcripts`; set `logging.capture_llm_transcript = false` to disable it. OpenCode session deletion defaults to on, but provider-side retention is controlled by the provider.
14
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-push-hooks",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Run structured AI-assisted checks and allowlisted maintenance before git push",
5
5
  "license": "MIT",
6
6
  "author": {
package/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ai-push-hooks"
7
- version = "0.2.0"
7
+ version = "0.2.1"
8
8
  description = "Run structured AI-assisted checks and allowlisted maintenance before git push"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -78,6 +78,13 @@ BEADS_ENV_NAMES = frozenset(
78
78
  }
79
79
  )
80
80
  BEADS_ENV_PREFIXES = ("AWS_", "BD_", "BEADS_", "DOLT_")
81
+ BEADS_MIGRATION_OVERRIDE_ENV_NAMES = frozenset(
82
+ {
83
+ "BD_ALLOW_REMOTE_MIGRATE",
84
+ "BD_IGNORE_SCHEMA_SKEW",
85
+ "BD_SMART_GATE",
86
+ }
87
+ )
81
88
  GITHUB_REPOSITORY_COMPONENT = re.compile(r"[A-Za-z0-9_.-]+\Z")
82
89
  GIT_DIFF_CHUNK_BYTES = 64 * 1024
83
90
  GIT_ERROR_BYTES = 64 * 1024
@@ -950,7 +957,8 @@ def beads_alignment_env() -> dict[str, str]:
950
957
  return {
951
958
  name: value
952
959
  for name, value in os.environ.items()
953
- if name in BEADS_ENV_NAMES or name.startswith(BEADS_ENV_PREFIXES)
960
+ if name not in BEADS_MIGRATION_OVERRIDE_ENV_NAMES
961
+ and (name in BEADS_ENV_NAMES or name.startswith(BEADS_ENV_PREFIXES))
954
962
  }
955
963
 
956
964
 
@@ -100,7 +100,6 @@ def opencode_isolation_env(
100
100
  "OPENCODE_DISABLE_CLAUDE_CODE": "true",
101
101
  "OPENCODE_DISABLE_CLAUDE_CODE_PROMPT": "true",
102
102
  "OPENCODE_DISABLE_CLAUDE_CODE_SKILLS": "true",
103
- "OPENCODE_DISABLE_DEFAULT_PLUGINS": "true",
104
103
  "OPENCODE_DISABLE_LSP_DOWNLOAD": "true",
105
104
  "OPENCODE_DISABLE_SHARE": "true",
106
105
  "OPENCODE_DISABLE_AUTOUPDATE": "true",