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.
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/PKG-INFO +1 -1
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/client_assets/hooks/userpromptsubmit_workitem.py +112 -3
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/pyproject.toml +1 -1
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/.gitignore +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/README.md +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/__init__.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/asset_manifest.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/claude_env.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/client_assets/commands/workitem.md +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/client_assets/hooks/pretooluse_pathguard.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/client_assets/hooks/sessionstart_register.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/client_assets/managed-settings.json.tmpl +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/client_assets/statusline/agentgov_statusline.sh +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/__init__.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/doctor.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/gateway.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/install.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/login.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/register_device.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/status.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/uninstall.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/workitem.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/commands/wrap.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/gateway_process.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/loopback.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/main.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/port_resolver.py +0 -0
- {agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/hatch_build.py +0 -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
|
-
#
|
|
1618
|
-
#
|
|
1619
|
-
#
|
|
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.
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/client_assets/hooks/pretooluse_pathguard.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentgov_cli-0.1.18 → agentgov_cli-0.1.19}/agentgov_cli/client_assets/managed-settings.json.tmpl
RENAMED
|
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
|