agentpool-cli 0.1.4__tar.gz → 0.1.6__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.
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/CHANGELOG.md +11 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/PKG-INFO +2 -1
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/pyproject.toml +2 -1
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/server.json +2 -2
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/__init__.py +1 -1
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/usage/_common.py +43 -1
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/usage/ccusage.py +3 -8
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/usage/codexbar.py +3 -2
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/usage/copilot.py +2 -1
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/usage/devin.py +2 -1
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/unit/test_usage_probes.py +56 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/uv.lock +3 -1
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/.cursor/mcp.json.example +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/.github/CODEOWNERS +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/.github/ISSUE_TEMPLATE/provider_probe.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/.github/dependabot.yml +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/.github/workflows/ci.yml +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/.github/workflows/release.yml +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/.gitignore +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/.mcp.json.example +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/AGENTS.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/CONTRIBUTING.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/LICENSE +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/README.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/SECURITY.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/agent-cli-and-mcp.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/agentpool-skill.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/architecture.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/examples/README.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/examples.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/install.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/mcp-clients.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/mcp-tools.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/model-catalog.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/onboarding.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/provider-adapters.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/provider-lifecycle-matrix.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/quickstart.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/release.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/security.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/setup-claude-code.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/setup-codex.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/setup-copilot.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/setup-cursor-cli.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/setup-cursor.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/setup-devin.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/setup-droid.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/stats.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/usage-detection.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/docs/usage-probe-matrix.md +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/scripts/install.sh +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/agent_io.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/artifacts.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/cli.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/config.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/event_detection.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/fixtures/__init__.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/fixtures/fake_agents/__init__.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/fixtures/fake_agents/fake_approval_agent.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/fixtures/fake_agents/fake_common.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/fixtures/fake_agents/fake_completed_agent.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/fixtures/fake_agents/fake_idle_agent.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/fixtures/fake_agents/fake_limit_agent.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/fixtures/fake_agents/fake_patch_agent.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/fixtures/fake_agents/fake_question_agent.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/git_worktree.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/mcp/__init__.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/mcp/resources.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/mcp/tools.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/mcp_server.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/models.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/onboarding.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/policy.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/preferences.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/provider_model_catalog.json +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/providers/__init__.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/providers/base.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/providers/registry.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/redaction.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/runtimes/__init__.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/runtimes/base.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/runtimes/tmux.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/session_manager.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/stats/__init__.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/stats/card.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/stats/compute.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/stats/queries.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/stats/render.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/stats/window.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/store.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/usage/__init__.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/usage/claude.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/usage/codex.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/usage/combine.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/usage/parsers.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/usage/probes.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/usage/provider_parsers.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/usage/summary.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/utils.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/fixtures/provider_model_catalog_golden.json +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/fixtures/stats_seed.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/fixtures/usage/claude_usage.txt +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/fixtures/usage/codex_rate_limits.json +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/fixtures/usage/copilot_user.json +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/fixtures/usage/devin_plan_status.json +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/integration/test_fake_tmux_flow.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/unit/test_agent_io.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/unit/test_cli.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/unit/test_event_policy.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/unit/test_mcp_surface.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/unit/test_mcp_tools.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/unit/test_models_config_store.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/unit/test_onboarding.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/unit/test_redaction.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/unit/test_stats_cli.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/unit/test_stats_mcp.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/unit/test_stats_window.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/unit/test_usage_provider_parsers.py +0 -0
- {agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/unit/test_usage_summary_enrichment.py +0 -0
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.1.6 - 2026-06-01
|
|
6
|
+
|
|
7
|
+
- Run external usage helper commands in isolated, non-interactive subprocess
|
|
8
|
+
sessions so CodexBar/ccusage/GitHub CLI probes cannot inherit or disturb the
|
|
9
|
+
MCP host terminal.
|
|
10
|
+
|
|
11
|
+
## 0.1.5 - 2026-05-31
|
|
12
|
+
|
|
13
|
+
- Use a certifi-backed TLS context for native usage HTTP probes so uv-tool
|
|
14
|
+
installs on macOS can reach GitHub Copilot and Devin APIs reliably.
|
|
15
|
+
|
|
5
16
|
## 0.1.4 - 2026-05-31
|
|
6
17
|
|
|
7
18
|
- Add Markdown delegation preferences at `~/.agentpool/preferences.md`, surfaced
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentpool-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
4
4
|
Summary: Make full use of every coding-agent subscription you pay for: a local CLI + MCP server that surfaces live usage limits and offloads work to providers with headroom.
|
|
5
5
|
Author: AgentPool contributors
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
License-File: LICENSE
|
|
8
8
|
Requires-Python: >=3.11
|
|
9
|
+
Requires-Dist: certifi>=2024
|
|
9
10
|
Requires-Dist: mcp<2,>=1.27
|
|
10
11
|
Requires-Dist: pydantic>=2
|
|
11
12
|
Requires-Dist: pyyaml>=6
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "agentpool-cli"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.6"
|
|
8
8
|
description = "Make full use of every coding-agent subscription you pay for: a local CLI + MCP server that surfaces live usage limits and offloads work to providers with headroom."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -14,6 +14,7 @@ authors = [
|
|
|
14
14
|
]
|
|
15
15
|
dependencies = [
|
|
16
16
|
"mcp>=1.27,<2",
|
|
17
|
+
"certifi>=2024",
|
|
17
18
|
"pydantic>=2",
|
|
18
19
|
"pyyaml>=6",
|
|
19
20
|
"rich>=13",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "io.github.sidduHERE/agentpool",
|
|
4
4
|
"title": "AgentPool",
|
|
5
5
|
"description": "See each coding-agent subscription's live limits and offload work to one with headroom.",
|
|
6
|
-
"version": "0.1.
|
|
6
|
+
"version": "0.1.6",
|
|
7
7
|
"repository": {
|
|
8
8
|
"url": "https://github.com/sidduHERE/agentpool",
|
|
9
9
|
"source": "github"
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
{
|
|
14
14
|
"registryType": "pypi",
|
|
15
15
|
"identifier": "agentpool-cli",
|
|
16
|
-
"version": "0.1.
|
|
16
|
+
"version": "0.1.6",
|
|
17
17
|
"transport": {
|
|
18
18
|
"type": "stdio"
|
|
19
19
|
},
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
5
|
+
import ssl
|
|
5
6
|
import subprocess
|
|
6
7
|
import tempfile
|
|
7
8
|
import time
|
|
@@ -12,6 +13,8 @@ from datetime import UTC, datetime
|
|
|
12
13
|
from pathlib import Path
|
|
13
14
|
from typing import Any
|
|
14
15
|
|
|
16
|
+
import certifi
|
|
17
|
+
|
|
15
18
|
from agentpool.models import CapacitySnapshot, Confidence, TmuxSessionRef, UsageStatus, UsageWindow, UsageWindowKind
|
|
16
19
|
from agentpool.runtimes.tmux import TmuxRuntime
|
|
17
20
|
|
|
@@ -53,9 +56,48 @@ def _extract_json_payload(text: str) -> Any:
|
|
|
53
56
|
raise ProbeError("No JSON payload found." if not errors else f"No parseable JSON payload found: {errors[-1]}")
|
|
54
57
|
|
|
55
58
|
|
|
59
|
+
def _urlopen(
|
|
60
|
+
request: urllib.request.Request,
|
|
61
|
+
*,
|
|
62
|
+
timeout: float = 10,
|
|
63
|
+
) -> Any:
|
|
64
|
+
context = ssl.create_default_context(cafile=certifi.where())
|
|
65
|
+
return urllib.request.urlopen(request, timeout=timeout, context=context)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _probe_env() -> dict[str, str]:
|
|
69
|
+
env = os.environ.copy()
|
|
70
|
+
env.update(
|
|
71
|
+
{
|
|
72
|
+
"TERM": "dumb",
|
|
73
|
+
"NO_COLOR": "1",
|
|
74
|
+
"CLICOLOR": "0",
|
|
75
|
+
"FORCE_COLOR": "0",
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
return env
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _run_probe_command(
|
|
82
|
+
command: list[str],
|
|
83
|
+
*,
|
|
84
|
+
timeout: float,
|
|
85
|
+
) -> subprocess.CompletedProcess[str]:
|
|
86
|
+
return subprocess.run(
|
|
87
|
+
command,
|
|
88
|
+
stdin=subprocess.DEVNULL,
|
|
89
|
+
capture_output=True,
|
|
90
|
+
text=True,
|
|
91
|
+
timeout=timeout,
|
|
92
|
+
check=False,
|
|
93
|
+
start_new_session=True,
|
|
94
|
+
env=_probe_env(),
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
56
98
|
def _request_json(request: urllib.request.Request) -> dict[str, Any]:
|
|
57
99
|
try:
|
|
58
|
-
with
|
|
100
|
+
with _urlopen(request, timeout=10) as response:
|
|
59
101
|
data = response.read()
|
|
60
102
|
except urllib.error.HTTPError as exc:
|
|
61
103
|
body = exc.read().decode("utf-8", errors="replace")[:500]
|
|
@@ -13,6 +13,7 @@ from agentpool.usage._common import (
|
|
|
13
13
|
_extract_json_payload,
|
|
14
14
|
_number,
|
|
15
15
|
_parse_datetime,
|
|
16
|
+
_run_probe_command,
|
|
16
17
|
unavailable,
|
|
17
18
|
unknown,
|
|
18
19
|
)
|
|
@@ -24,7 +25,7 @@ def detect_ccusage(binary: str | None = None) -> dict[str, Any]:
|
|
|
24
25
|
return {"installed": False, "path": None, "version": None, "safe_source": "local_claude_code_logs"}
|
|
25
26
|
version = None
|
|
26
27
|
try:
|
|
27
|
-
proc =
|
|
28
|
+
proc = _run_probe_command([*command, "--version"], timeout=5)
|
|
28
29
|
if proc.returncode == 0:
|
|
29
30
|
version = (proc.stdout or proc.stderr).strip().splitlines()[0][:200]
|
|
30
31
|
except (OSError, subprocess.TimeoutExpired):
|
|
@@ -48,13 +49,7 @@ def ccusage_usage_snapshot(provider_id: str, binary: str | None = None) -> Capac
|
|
|
48
49
|
"ccusage CLI is not installed. Set AGENTPOOL_CCUSAGE_COMMAND to an explicit command if desired.",
|
|
49
50
|
)
|
|
50
51
|
try:
|
|
51
|
-
proc =
|
|
52
|
-
[*command, "blocks", "--json", "--offline", "--active", "--no-color"],
|
|
53
|
-
capture_output=True,
|
|
54
|
-
text=True,
|
|
55
|
-
timeout=45,
|
|
56
|
-
check=False,
|
|
57
|
-
)
|
|
52
|
+
proc = _run_probe_command([*command, "blocks", "--json", "--offline", "--active", "--no-color"], timeout=45)
|
|
58
53
|
except (OSError, subprocess.TimeoutExpired) as exc:
|
|
59
54
|
return unknown(provider_id, f"ccusage probe failed: {exc}", source="ccusage")
|
|
60
55
|
text = "\n".join(part for part in [proc.stdout, proc.stderr] if part)
|
|
@@ -13,6 +13,7 @@ from agentpool.usage._common import (
|
|
|
13
13
|
_int_number,
|
|
14
14
|
_number,
|
|
15
15
|
_parse_datetime,
|
|
16
|
+
_run_probe_command,
|
|
16
17
|
_status_from_windows,
|
|
17
18
|
_clean_optional_string,
|
|
18
19
|
unavailable,
|
|
@@ -48,7 +49,7 @@ def detect_codexbar(binary: str | None = None) -> dict[str, Any]:
|
|
|
48
49
|
}
|
|
49
50
|
version = None
|
|
50
51
|
try:
|
|
51
|
-
proc =
|
|
52
|
+
proc = _run_probe_command([executable, "--version"], timeout=3)
|
|
52
53
|
if proc.returncode == 0:
|
|
53
54
|
version = (proc.stdout or proc.stderr).strip().splitlines()[0][:200]
|
|
54
55
|
except (OSError, subprocess.TimeoutExpired):
|
|
@@ -93,7 +94,7 @@ def codexbar_usage_snapshot(
|
|
|
93
94
|
"--no-color",
|
|
94
95
|
]
|
|
95
96
|
try:
|
|
96
|
-
proc =
|
|
97
|
+
proc = _run_probe_command(command, timeout=45)
|
|
97
98
|
except (OSError, subprocess.TimeoutExpired) as exc:
|
|
98
99
|
return unknown(provider_id, f"CodexBar usage probe failed: {exc}", source="codexbar")
|
|
99
100
|
text = "\n".join(part for part in [proc.stdout, proc.stderr] if part)
|
|
@@ -14,6 +14,7 @@ from agentpool.usage._common import (
|
|
|
14
14
|
_number,
|
|
15
15
|
_parse_datetime,
|
|
16
16
|
_request_json,
|
|
17
|
+
_run_probe_command,
|
|
17
18
|
_status_from_windows,
|
|
18
19
|
unknown,
|
|
19
20
|
)
|
|
@@ -94,7 +95,7 @@ def _copilot_token() -> tuple[str, str] | None:
|
|
|
94
95
|
gh = shutil.which("gh")
|
|
95
96
|
if not gh:
|
|
96
97
|
return None
|
|
97
|
-
proc =
|
|
98
|
+
proc = _run_probe_command([gh, "auth", "token"], timeout=5)
|
|
98
99
|
token = proc.stdout.strip()
|
|
99
100
|
if proc.returncode == 0 and token:
|
|
100
101
|
return token, "gh auth token"
|
|
@@ -14,6 +14,7 @@ from agentpool.usage._common import (
|
|
|
14
14
|
_epoch_seconds,
|
|
15
15
|
_number,
|
|
16
16
|
_tmux_slash_usage_probe,
|
|
17
|
+
_urlopen,
|
|
17
18
|
_clean_optional_string,
|
|
18
19
|
_status_from_windows,
|
|
19
20
|
unavailable,
|
|
@@ -79,7 +80,7 @@ def _devin_plan_status_usage_snapshot(provider_id: str) -> CapacitySnapshot:
|
|
|
79
80
|
method="POST",
|
|
80
81
|
)
|
|
81
82
|
try:
|
|
82
|
-
with
|
|
83
|
+
with _urlopen(request, timeout=10) as response:
|
|
83
84
|
data = response.read()
|
|
84
85
|
except urllib.error.HTTPError as exc:
|
|
85
86
|
body = exc.read().decode("utf-8", errors="replace")[:500].replace(token, "<redacted>")
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
+
import ssl
|
|
5
|
+
import subprocess
|
|
6
|
+
import urllib.request
|
|
4
7
|
from datetime import UTC, datetime
|
|
5
8
|
from pathlib import Path
|
|
6
9
|
|
|
7
10
|
import pytest
|
|
8
11
|
|
|
9
12
|
from agentpool.models import UsageStatus, UsageWindowKind
|
|
13
|
+
from agentpool.usage import _common as usage_common
|
|
10
14
|
from agentpool.usage import devin as devin_usage
|
|
11
15
|
from agentpool.usage.probes import (
|
|
12
16
|
CODEXBAR_PROVIDER_MAP,
|
|
@@ -278,6 +282,58 @@ def test_parse_copilot_legacy_monthly_limited_counts() -> None:
|
|
|
278
282
|
assert snapshot.windows[0].remaining_percent == 10
|
|
279
283
|
|
|
280
284
|
|
|
285
|
+
def test_usage_http_requests_use_certifi_context(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
286
|
+
seen: dict[str, object] = {}
|
|
287
|
+
|
|
288
|
+
class Response:
|
|
289
|
+
def __enter__(self) -> "Response":
|
|
290
|
+
return self
|
|
291
|
+
|
|
292
|
+
def __exit__(self, *args: object) -> None:
|
|
293
|
+
return None
|
|
294
|
+
|
|
295
|
+
def read(self) -> bytes:
|
|
296
|
+
return b"{\"ok\": true}"
|
|
297
|
+
|
|
298
|
+
def fake_urlopen(request: urllib.request.Request, **kwargs: object) -> Response:
|
|
299
|
+
seen.update(kwargs)
|
|
300
|
+
return Response()
|
|
301
|
+
|
|
302
|
+
monkeypatch.setattr(usage_common.urllib.request, "urlopen", fake_urlopen)
|
|
303
|
+
|
|
304
|
+
payload = usage_common._request_json(urllib.request.Request("https://example.test/usage"))
|
|
305
|
+
|
|
306
|
+
assert payload == {"ok": True}
|
|
307
|
+
assert seen["timeout"] == 10
|
|
308
|
+
assert isinstance(seen["context"], ssl.SSLContext)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def test_usage_probe_subprocesses_are_tty_isolated(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
312
|
+
seen: dict[str, object] = {}
|
|
313
|
+
|
|
314
|
+
def fake_run(command: list[str], **kwargs: object) -> subprocess.CompletedProcess[str]:
|
|
315
|
+
seen.update(kwargs)
|
|
316
|
+
return subprocess.CompletedProcess(command, 0, "{}", "")
|
|
317
|
+
|
|
318
|
+
monkeypatch.setattr(usage_common.subprocess, "run", fake_run)
|
|
319
|
+
|
|
320
|
+
result = usage_common._run_probe_command(["codexbar", "usage"], timeout=7)
|
|
321
|
+
|
|
322
|
+
assert result.returncode == 0
|
|
323
|
+
assert seen["stdin"] is subprocess.DEVNULL
|
|
324
|
+
assert seen["capture_output"] is True
|
|
325
|
+
assert seen["text"] is True
|
|
326
|
+
assert seen["timeout"] == 7
|
|
327
|
+
assert seen["check"] is False
|
|
328
|
+
assert seen["start_new_session"] is True
|
|
329
|
+
env = seen["env"]
|
|
330
|
+
assert isinstance(env, dict)
|
|
331
|
+
assert env["TERM"] == "dumb"
|
|
332
|
+
assert env["NO_COLOR"] == "1"
|
|
333
|
+
assert env["CLICOLOR"] == "0"
|
|
334
|
+
assert env["FORCE_COLOR"] == "0"
|
|
335
|
+
|
|
336
|
+
|
|
281
337
|
def test_devin_plan_status_request_contains_auth_and_top_up_flag() -> None:
|
|
282
338
|
data = _encode_devin_plan_status_request("devin-session-token$abc")
|
|
283
339
|
assert b"devin-session-token$abc" in data
|
|
@@ -3,9 +3,10 @@ requires-python = ">=3.11"
|
|
|
3
3
|
|
|
4
4
|
[[package]]
|
|
5
5
|
name = "agentpool-cli"
|
|
6
|
-
version = "0.1.
|
|
6
|
+
version = "0.1.6"
|
|
7
7
|
source = { editable = "." }
|
|
8
8
|
dependencies = [
|
|
9
|
+
{ name = "certifi" },
|
|
9
10
|
{ name = "mcp" },
|
|
10
11
|
{ name = "pydantic" },
|
|
11
12
|
{ name = "pyyaml" },
|
|
@@ -24,6 +25,7 @@ dev = [
|
|
|
24
25
|
|
|
25
26
|
[package.metadata]
|
|
26
27
|
requires-dist = [
|
|
28
|
+
{ name = "certifi", specifier = ">=2024" },
|
|
27
29
|
{ name = "mcp", specifier = ">=1.27,<2" },
|
|
28
30
|
{ name = "pillow", marker = "extra == 'card'", specifier = ">=10" },
|
|
29
31
|
{ name = "pydantic", specifier = ">=2" },
|
|
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
|
{agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/fixtures/fake_agents/fake_common.py
RENAMED
|
File without changes
|
|
File without changes
|
{agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/fixtures/fake_agents/fake_idle_agent.py
RENAMED
|
File without changes
|
{agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/fixtures/fake_agents/fake_limit_agent.py
RENAMED
|
File without changes
|
{agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/src/agentpool/fixtures/fake_agents/fake_patch_agent.py
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
|
|
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
|
{agentpool_cli-0.1.4 → agentpool_cli-0.1.6}/tests/fixtures/provider_model_catalog_golden.json
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|