gitvow 0.34.1__tar.gz → 0.34.2__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 (94) hide show
  1. {gitvow-0.34.1/src/gitvow.egg-info → gitvow-0.34.2}/PKG-INFO +1 -1
  2. {gitvow-0.34.1 → gitvow-0.34.2}/pyproject.toml +1 -1
  3. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/hooks/__init__.py +15 -8
  4. {gitvow-0.34.1 → gitvow-0.34.2/src/gitvow.egg-info}/PKG-INFO +1 -1
  5. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_hooks_disabled.py +20 -0
  6. {gitvow-0.34.1 → gitvow-0.34.2}/LICENSE +0 -0
  7. {gitvow-0.34.1 → gitvow-0.34.2}/README.md +0 -0
  8. {gitvow-0.34.1 → gitvow-0.34.2}/setup.cfg +0 -0
  9. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/__init__.py +0 -0
  10. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/__main__.py +0 -0
  11. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/adapters.py +0 -0
  12. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/carry.py +0 -0
  13. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/claims.py +0 -0
  14. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/cli.py +0 -0
  15. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/collect.py +0 -0
  16. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/decisions.py +0 -0
  17. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/default_policy.json +0 -0
  18. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/digest.py +0 -0
  19. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/export.py +0 -0
  20. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/install.py +0 -0
  21. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/intent.py +0 -0
  22. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/notes.py +0 -0
  23. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/outcomes.py +0 -0
  24. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/pack.py +0 -0
  25. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/paths.py +0 -0
  26. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/policy.py +0 -0
  27. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/pricing.py +0 -0
  28. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/proposals.py +0 -0
  29. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/providers.py +0 -0
  30. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/reach.py +0 -0
  31. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/recall.py +0 -0
  32. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/redact.py +0 -0
  33. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/report.py +0 -0
  34. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/rules.py +0 -0
  35. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/safewrite.py +0 -0
  36. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/scan.py +0 -0
  37. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/selftest.py +0 -0
  38. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/serve.py +0 -0
  39. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/snapshots.py +0 -0
  40. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/state.py +0 -0
  41. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/status.py +0 -0
  42. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/sync.py +0 -0
  43. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/targets.py +0 -0
  44. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow/transcript.py +0 -0
  45. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow.egg-info/SOURCES.txt +0 -0
  46. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow.egg-info/dependency_links.txt +0 -0
  47. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow.egg-info/entry_points.txt +0 -0
  48. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow.egg-info/requires.txt +0 -0
  49. {gitvow-0.34.1 → gitvow-0.34.2}/src/gitvow.egg-info/top_level.txt +0 -0
  50. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_adapters.py +0 -0
  51. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_answered_confirm_commit.py +0 -0
  52. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_carry.py +0 -0
  53. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_claims.py +0 -0
  54. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_collect.py +0 -0
  55. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_command_position.py +0 -0
  56. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_commit_window.py +0 -0
  57. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_cost.py +0 -0
  58. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_decisions.py +0 -0
  59. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_defects_0_32_1.py +0 -0
  60. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_digest.py +0 -0
  61. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_duplicate_hooks.py +0 -0
  62. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_e2e_globalopt.py +0 -0
  63. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_export.py +0 -0
  64. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_external_adapter.py +0 -0
  65. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_git_rules.py +0 -0
  66. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_hardening.py +0 -0
  67. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_hooks.py +0 -0
  68. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_install_cli.py +0 -0
  69. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_intent.py +0 -0
  70. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_native_question.py +0 -0
  71. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_opencode.py +0 -0
  72. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_outcomes.py +0 -0
  73. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_pack.py +0 -0
  74. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_packaging.py +0 -0
  75. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_policy.py +0 -0
  76. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_policy_refresh.py +0 -0
  77. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_proposals.py +0 -0
  78. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_providers.py +0 -0
  79. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_reach.py +0 -0
  80. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_recall.py +0 -0
  81. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_redact.py +0 -0
  82. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_report.py +0 -0
  83. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_rules.py +0 -0
  84. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_scan.py +0 -0
  85. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_serve.py +0 -0
  86. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_snapshots.py +0 -0
  87. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_status.py +0 -0
  88. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_status_environment.py +0 -0
  89. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_symlinked_paths.py +0 -0
  90. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_sync.py +0 -0
  91. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_sync_http.py +0 -0
  92. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_targets.py +0 -0
  93. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_tiers.py +0 -0
  94. {gitvow-0.34.1 → gitvow-0.34.2}/tests/test_transcript_formats.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitvow
3
- Version: 0.34.1
3
+ Version: 0.34.2
4
4
  Summary: Provenance and policy gate for AI-agent coding sessions: session trailers on commits, redacted session notes in git, a tool-call gate, and a local ledger. No runtime dependencies.
5
5
  Author-email: Nikhil Bora <nikhil@wirevow.com>
6
6
  License: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gitvow"
7
- version = "0.34.1"
7
+ version = "0.34.2"
8
8
  description = "Provenance and policy gate for AI-agent coding sessions: session trailers on commits, redacted session notes in git, a tool-call gate, and a local ledger. No runtime dependencies."
9
9
  readme = "README.md"
10
10
  license = {text = "Apache-2.0"}
@@ -469,6 +469,21 @@ def post_tool_use(h: dict[str, Any], home: str | None = None) -> tuple[int, str]
469
469
  cwd = target_cwd(tool, inp, session_cwd)
470
470
  if _duplicate(h, cwd, "post"):
471
471
  return 0, ""
472
+ code, msg = _post_tool_use(h, home, tool, inp, cwd)
473
+ if tool == "Bash" and PUSH_RE.search(inp.get("command", "")) and not os.environ.get("GITVOW_PUSHING_NOTES"):
474
+ # The notes travel after the branch, never alongside it: the pre-push hook stepped aside for this push
475
+ # (or never ran, as under Gemini). Done last, after any note for a `commit && push` chain was attached,
476
+ # so the note travels with the push it belongs to.
477
+ st = load_state(cwd)
478
+ if "pending_push" in st:
479
+ st.pop("pending_push", None)
480
+ save_state(cwd, st)
481
+ _push_notes_after(cwd, inp.get("command", ""))
482
+ return code, msg
483
+
484
+
485
+ def _post_tool_use(h: dict[str, Any], home: str | None, tool: str, inp: dict[str, Any], cwd: str) -> tuple[int, str]:
486
+ session_cwd = h.get("cwd") or os.getcwd()
472
487
  if tool in EDIT_TOOLS:
473
488
  fp = str(inp.get("file_path") or inp.get("notebook_path") or "")
474
489
  if fp:
@@ -489,14 +504,6 @@ def post_tool_use(h: dict[str, Any], home: str | None = None) -> tuple[int, str]
489
504
  return 0, ""
490
505
  if tool == "Bash" and not COMMIT_RE.search(inp.get("command", "")):
491
506
  _record_prompt_approval(cwd, inp, home)
492
- if PUSH_RE.search(inp.get("command", "")) and not os.environ.get("GITVOW_PUSHING_NOTES"):
493
- # The notes travel after the branch, never alongside it: the pre-push hook stepped aside for this
494
- # push (or never ran, as under Gemini), so carry them now, sequentially.
495
- st = load_state(cwd)
496
- if "pending_push" in st:
497
- st.pop("pending_push", None)
498
- save_state(cwd, st)
499
- _push_notes_after(cwd, inp.get("command", ""))
500
507
  return 0, ""
501
508
  if tool != "Bash":
502
509
  return 0, ""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitvow
3
- Version: 0.34.1
3
+ Version: 0.34.2
4
4
  Summary: Provenance and policy gate for AI-agent coding sessions: session trailers on commits, redacted session notes in git, a tool-call gate, and a local ledger. No runtime dependencies.
5
5
  Author-email: Nikhil Bora <nikhil@wirevow.com>
6
6
  License: Apache-2.0
@@ -157,3 +157,23 @@ def test_the_pre_push_hook_steps_aside_for_an_agents_push(repo, home, payload, t
157
157
  git(repo, "notes", "--ref=gitvow/s1", "add", "-f", "-m", 'gitvow-session\n{"y": 2}', "HEAD")
158
158
  subprocess.run(["git", "push", "-q", "origin", "HEAD:refs/heads/feature2"], cwd=repo, check=True)
159
159
  assert git(bare, "rev-parse", "refs/notes/gitvow/s1") == git(repo, "rev-parse", "refs/notes/gitvow/s1")
160
+
161
+
162
+ def test_a_commit_and_push_chain_sends_the_note_with_the_push(repo, home, payload, transcript, tmp_path):
163
+ """`git commit … && git push` takes the commit path; the notes must still follow, after the note is attached."""
164
+ bare = tmp_path / "remote.git"
165
+ subprocess.run(["git", "init", "-q", "--bare", str(bare)], check=True)
166
+ git(repo, "remote", "add", "origin", str(bare))
167
+ _write_git_hook(str(repo / ".gitvow" / "git-hooks"))
168
+ git(repo, "config", "core.hooksPath", ".gitvow/git-hooks")
169
+ session_start(payload("SessionStart"), str(home))
170
+ cmd = "git commit -am x && git push origin HEAD:refs/heads/feature" # not protected: no question
171
+ assert pre_tool_use(payload("PreToolUse", "Bash", {"command": cmd}, transcript), str(home))[0] == 0
172
+ (repo / "a.txt").write_text("chain\n")
173
+ git(repo, "commit", "-qam", "chain")
174
+ subprocess.run(["git", "push", "-q", "origin", "HEAD:refs/heads/feature"], cwd=repo, check=True)
175
+ assert git(bare, "for-each-ref", "refs/notes/") == "" # the hook stepped aside for the agent's push
176
+ code, msg = post_tool_use(payload("PostToolUse", "Bash", {"command": cmd}, transcript), str(home))
177
+ assert code == 0 and "session note attached" in msg
178
+ local = git(repo, "rev-parse", "refs/notes/gitvow/sess-1")
179
+ assert git(bare, "rev-parse", "refs/notes/gitvow/sess-1") == local # the note just written is on the remote
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes