agentgov-cli 0.1.18__tar.gz → 0.1.19__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 (28) hide show
  1. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/PKG-INFO +1 -1
  2. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/client_assets/hooks/userpromptsubmit_workitem.py +112 -3
  3. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/pyproject.toml +1 -1
  4. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/.gitignore +0 -0
  5. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/README.md +0 -0
  6. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/__init__.py +0 -0
  7. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/asset_manifest.py +0 -0
  8. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/claude_env.py +0 -0
  9. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/client_assets/commands/workitem.md +0 -0
  10. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/client_assets/hooks/pretooluse_pathguard.py +0 -0
  11. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/client_assets/hooks/sessionstart_register.py +0 -0
  12. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/client_assets/managed-settings.json.tmpl +0 -0
  13. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/client_assets/statusline/agentgov_statusline.sh +0 -0
  14. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/__init__.py +0 -0
  15. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/doctor.py +0 -0
  16. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/gateway.py +0 -0
  17. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/install.py +0 -0
  18. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/login.py +0 -0
  19. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/register_device.py +0 -0
  20. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/status.py +0 -0
  21. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/uninstall.py +0 -0
  22. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/workitem.py +0 -0
  23. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/wrap.py +0 -0
  24. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/gateway_process.py +0 -0
  25. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/loopback.py +0 -0
  26. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/main.py +0 -0
  27. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/port_resolver.py +0 -0
  28. {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/hatch_build.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agentgov-cli
3
- Version: 0.1.18
3
+ Version: 0.1.19
4
4
  Summary: AgentGov CLI — wrap Claude Code, bind work items, check gateway health.
5
5
  Author: AgentGov Contributors
6
6
  License: Apache-2.0
@@ -817,6 +817,100 @@ def _gateway_in_request_path(session_id: str, *, gateway_url_answered: bool) ->
817
817
  return _gateway_answers_at(base, session_id)
818
818
 
819
819
 
820
+ def _is_git_repo(path: str) -> bool:
821
+ """True when `path` sits inside a git work tree.
822
+
823
+ Returns True on any failure to decide. A hook that cannot run `git` must not
824
+ invent a permanent-failure verdict: being wrong in that direction blocks a
825
+ developer whose setup is fine, which is worse than the generic retry advice.
826
+ """
827
+ if not path:
828
+ return False
829
+ try:
830
+ r = subprocess.run(
831
+ ["git", "-C", path, "rev-parse", "--is-inside-work-tree"],
832
+ capture_output=True,
833
+ text=True,
834
+ timeout=5,
835
+ check=False,
836
+ )
837
+ except (OSError, subprocess.SubprocessError):
838
+ return True
839
+ return r.stdout.strip() == "true"
840
+
841
+
842
+ def _nearest_repo_below(path: str, max_depth: int = 2) -> str:
843
+ """A git checkout nested just inside `path`, if there is exactly one.
844
+
845
+ The case this exists for: a wrapper folder containing the real project, e.g.
846
+ `ManifestAlignmentApp/ManifestExpo`. Opening the editor at the wrapper leaves
847
+ the session with no repository at all, and the developer sees a message about
848
+ the gateway rather than about where they opened their editor.
849
+
850
+ Naming the actual directory turns a hunt into a click. Only an unambiguous
851
+ answer is offered — with two or more candidates the guess could send someone
852
+ to the wrong project, and a confidently wrong suggestion is worse than none.
853
+ """
854
+ try:
855
+ entries = sorted(
856
+ e for e in os.listdir(path) if not e.startswith(".") and os.path.isdir(os.path.join(path, e))
857
+ )
858
+ except OSError:
859
+ return ""
860
+ found = [e for e in entries if os.path.isdir(os.path.join(path, e, ".git"))]
861
+ if len(found) == 1:
862
+ return os.path.join(path, found[0])
863
+ if max_depth > 1:
864
+ # One level deeper, for `repos/<name>/<project>` layouts. Still only
865
+ # accepted when a single candidate exists anywhere at that level.
866
+ deeper = [
867
+ d
868
+ for e in entries
869
+ for d in [_nearest_repo_below(os.path.join(path, e), max_depth - 1)]
870
+ if d
871
+ ]
872
+ if len(deeper) == 1:
873
+ return deeper[0]
874
+ return ""
875
+
876
+
877
+ def _not_a_repository_message(cwd: str) -> str:
878
+ """Say what is actually wrong, and where the repository probably is.
879
+
880
+ Replaces the transient-sounding "the gateway does not recognise this session
881
+ … send your prompt again" for the one case where retrying can never work.
882
+ """
883
+ nested = _nearest_repo_below(cwd)
884
+ lines = [
885
+ "\U0001f4cc AgentGov: this folder is not a git repository, so there is "
886
+ "nothing to authorize.",
887
+ "",
888
+ f" Claude Code was opened at: {cwd or 'an unknown directory'}",
889
+ " A session is registered against a repository, so a folder without one",
890
+ " cannot be governed — and retrying will not change that.",
891
+ ]
892
+ if nested:
893
+ lines += [
894
+ "",
895
+ f" The repository appears to be one level in: {nested}",
896
+ " Open that folder in your editor instead, then send your prompt again.",
897
+ ]
898
+ else:
899
+ lines += [
900
+ "",
901
+ " Open your editor at the folder that contains `.git`, or run",
902
+ " `git init` here if this really is a new project.",
903
+ ]
904
+ lines += [
905
+ "",
906
+ " Then check the repository is granted to you:",
907
+ " git remote get-url origin # this exact text must appear on the Grants page",
908
+ "",
909
+ " Nothing was sent upstream and no tokens were used.",
910
+ ]
911
+ return "\n".join(lines)
912
+
913
+
820
914
  def _gateway_unreachable_message() -> str:
821
915
  """Why a blocked prompt was blocked, when the cause is not the work item.
822
916
 
@@ -1614,9 +1708,24 @@ def main() -> None:
1614
1708
  _allow_reporting(root_label, repo_display, child_label)
1615
1709
 
1616
1710
  if _needs_registration(data):
1617
- # The gateway does not recognise this session. This is almost always
1618
- # TRANSIENT, not an attack: the gateway keeps sessions in memory, so a
1619
- # restart or reinstall forgets every editor window that is already open.
1711
+ # BEFORE assuming this is transient, rule out the one cause that never is.
1712
+ #
1713
+ # A session can only be registered against a repository, so if the editor
1714
+ # was opened in a directory that is not a git checkout there is nothing to
1715
+ # register and re-registering cannot succeed. The developer was
1716
+ # nonetheless told "this is usually temporary — send your prompt again",
1717
+ # and retried, and retried. It cost a real user ten rounds of debugging on
1718
+ # a folder that merely had the project nested one level inside it.
1719
+ #
1720
+ # This is the same defect as reporting a database timeout as 401 or a
1721
+ # Stripe misconfiguration as "try again shortly": a permanent condition
1722
+ # dressed as a transient one, which turns a five-second fix into an hour.
1723
+ # The check is cheap and runs only on the failure path.
1724
+ if not _is_git_repo(cwd):
1725
+ _block(_not_a_repository_message(cwd))
1726
+
1727
+ # Genuinely transient: the gateway keeps sessions in memory, so a restart
1728
+ # forgets every editor window that is already open.
1620
1729
  #
1621
1730
  # Blocking here was a serious mistake. It bricked every open Claude Code
1622
1731
  # window after a gateway restart, with a message telling the developer to
@@ -2,7 +2,7 @@
2
2
  # PyPI: `agentgov` was rejected as too similar to existing `agent-gov`.
3
3
  # Package name is agentgov-cli; the console command it installs is still `agentgov`.
4
4
  name = "agentgov-cli"
5
- version = "0.1.18"
5
+ version = "0.1.19"
6
6
  description = "AgentGov CLI — wrap Claude Code, bind work items, check gateway health."
7
7
  readme = "README.md"
8
8
  license = { text = "Apache-2.0" }
File without changes
File without changes