brindle 0.3.5__tar.gz → 0.3.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.
- {brindle-0.3.5 → brindle-0.3.6}/PKG-INFO +2 -2
- {brindle-0.3.5 → brindle-0.3.6}/README.md +1 -1
- {brindle-0.3.5 → brindle-0.3.6}/pyproject.toml +6 -2
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/usage.py +3 -3
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/watch.py +20 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/watch_costs.py +2 -1
- {brindle-0.3.5 → brindle-0.3.6}/.gitignore +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/LICENSE +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/SCHEDULE-A +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/__init__.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/__main__.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/account.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/agents.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/airgap.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/antigravity.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/autopilot.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/budget.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_agents/__init__.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_agents/backend-auditor.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_agents/developer-codex.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_agents/developer-fable.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_agents/developer-gemini.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_agents/developer-heavy.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_agents/developer-light.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_agents/developer-local.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_agents/developer.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_agents/qa.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_agents/reviewer-codex.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_agents/reviewer-gemini.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_agents/reviewer-local.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_agents/reviewer.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_agents/subagent.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_agents/supervisor.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_rules/__init__.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_rules/security/backend.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_rules/style/minimal-diff.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/builtin_rules/tests/only.md +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/ci_adapters.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/ci_client.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/ci_federation.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/ci_hosts.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/cli.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/codemap.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/codex_hook.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/company_identity.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/company_login.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/config.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/conflicts.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/cost.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/cost_estimate.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/cull.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/db.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/demo.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/detect.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/doctor.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/escapes.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/events.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/gates.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/git.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/guardrails.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/history.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/identity_lock.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/inbox.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/keys_cmds.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/keystore.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/launch_health.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/learned_rules.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/learning.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/legacy.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/mcp_server.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/model_access.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/model_availability.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/native/__init__.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/native/client.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/native/loop.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/native/permissions.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/native/runner.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/native/serve.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/native/tools.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pane_auth.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/permissions.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pipeline.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/plugins.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/policy.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pool.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pricing.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/__init__.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/_files.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/account.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/audit_chain.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/audit_export.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/auth.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/brief_learning.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/cost_centers.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/credentials.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/features.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/keys.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/learning.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/license.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/loopback.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/managed_models.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/org_profiles.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/orgkey.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/rollout.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/settings_sync.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/status.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/team_events.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/pro/team_policy.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/procs.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/profiles.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/providers.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/quota.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/repo_cmds.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/repos.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/rewind.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/rule_checks.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/savings.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/scratch.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/secrets.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/self_serve.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/services.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/sessions.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/sidebar_follow.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/signin_pause.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/status_cache.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/tasks.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/tmux.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/view.py +0 -0
- {brindle-0.3.5 → brindle-0.3.6}/src/brindle/workspaces.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: brindle
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.6
|
|
4
4
|
Summary: Run coding agents in parallel, each on its own git branch, with a supervisor that delegates, reviews, and merges
|
|
5
5
|
Project-URL: Homepage, https://pawdelta.com/brindle/
|
|
6
6
|
Project-URL: Documentation, https://pawdelta.com/brindle/docs/recommended-use
|
|
@@ -89,7 +89,7 @@ uv tool install --editable ~/Projects/brindle # or from a local checkout
|
|
|
89
89
|
brindle drives Claude Code, so you need that too (`npm install -g @anthropic-ai/claude-code`).
|
|
90
90
|
|
|
91
91
|
`brindle --version` prints the installed version; the tmux status bar of every brindle
|
|
92
|
-
session shows it too (`brindle 0.3.
|
|
92
|
+
session shows it too (`brindle 0.3.6`). A session started before an upgrade keeps
|
|
93
93
|
running the old code, and shows the old number, until you restart it.
|
|
94
94
|
|
|
95
95
|
## Quick start
|
|
@@ -59,7 +59,7 @@ uv tool install --editable ~/Projects/brindle # or from a local checkout
|
|
|
59
59
|
brindle drives Claude Code, so you need that too (`npm install -g @anthropic-ai/claude-code`).
|
|
60
60
|
|
|
61
61
|
`brindle --version` prints the installed version; the tmux status bar of every brindle
|
|
62
|
-
session shows it too (`brindle 0.3.
|
|
62
|
+
session shows it too (`brindle 0.3.6`). A session started before an upgrade keeps
|
|
63
63
|
running the old code, and shows the old number, until you restart it.
|
|
64
64
|
|
|
65
65
|
## Quick start
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "brindle"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.6"
|
|
4
4
|
description = "Run coding agents in parallel, each on its own git branch, with a supervisor that delegates, reviews, and merges"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -51,6 +51,7 @@ audit_export = "brindle.pro.audit_export:make"
|
|
|
51
51
|
[dependency-groups]
|
|
52
52
|
dev = [
|
|
53
53
|
"pytest>=8",
|
|
54
|
+
"pytest-cov>=7.0",
|
|
54
55
|
"pytest-xdist>=3.8.0",
|
|
55
56
|
"python-hcl2>=8.1.4",
|
|
56
57
|
"pyyaml>=6.0.3",
|
|
@@ -74,4 +75,7 @@ only-include = ["src", "README.md", "LICENSE", "SCHEDULE-A", "pyproject.toml"]
|
|
|
74
75
|
[tool.pytest.ini_options]
|
|
75
76
|
testpaths = ["tests"]
|
|
76
77
|
pythonpath = ["tests"]
|
|
77
|
-
markers = [
|
|
78
|
+
markers = [
|
|
79
|
+
"serial: run outside xdist (`pytest -m serial`); the parallel pass skips these",
|
|
80
|
+
"variant(reason): an input variant that covers no new code on purpose (see scripts/check_new_tests.py)",
|
|
81
|
+
]
|
|
@@ -376,12 +376,12 @@ def antigravity_agent_usage(db: DB, agent) -> Usage | None:
|
|
|
376
376
|
offset = 0
|
|
377
377
|
inp, out, read, write = 0, 0, 0, 0
|
|
378
378
|
model = "gemini-2.5-pro"
|
|
379
|
-
if cached and
|
|
379
|
+
if cached and cached["inode"] == st.st_ino and cached["size"] <= st.st_size:
|
|
380
380
|
offset = cached["size"]
|
|
381
381
|
inp = cached["input_tokens"]
|
|
382
382
|
out = cached["output_tokens"]
|
|
383
383
|
read = cached["cache_read_tokens"]
|
|
384
|
-
write = cached["
|
|
384
|
+
write = cached["cache_creation_tokens"]
|
|
385
385
|
if cached["model"]:
|
|
386
386
|
model = cached["model"]
|
|
387
387
|
|
|
@@ -402,7 +402,7 @@ def antigravity_agent_usage(db: DB, agent) -> Usage | None:
|
|
|
402
402
|
read += ev.get("cache_read_tokens", 0)
|
|
403
403
|
if ev.get("model"):
|
|
404
404
|
model = ev["model"]
|
|
405
|
-
db.set_usage_cache(str(path), st.st_size, inp, out, read, write, model,
|
|
405
|
+
db.set_usage_cache(str(path), st.st_size, inp, out, read, write, model, None, st.st_ino)
|
|
406
406
|
|
|
407
407
|
if inp == 0 and out == 0:
|
|
408
408
|
return None
|
|
@@ -1006,4 +1006,24 @@ def run(repo_root: str | None, sidebar: bool = False) -> None:
|
|
|
1006
1006
|
# Esc clears the filter; don't make it wait curses' default second to
|
|
1007
1007
|
# tell a lone Esc from the start of an arrow key's escape sequence.
|
|
1008
1008
|
os.environ.setdefault("ESCDELAY", "25")
|
|
1009
|
+
_log_to_file()
|
|
1009
1010
|
curses.wrapper(_loop, repo_root, sidebar)
|
|
1011
|
+
|
|
1012
|
+
|
|
1013
|
+
def _log_to_file() -> None:
|
|
1014
|
+
"""Send warnings and errors to ``watch.log``: without a handler, logging
|
|
1015
|
+
falls back to stderr, which prints tracebacks over the curses screen."""
|
|
1016
|
+
import logging
|
|
1017
|
+
|
|
1018
|
+
from brindle.config import brindle_home
|
|
1019
|
+
|
|
1020
|
+
try:
|
|
1021
|
+
brindle_home().mkdir(parents=True, exist_ok=True)
|
|
1022
|
+
handler: logging.Handler = logging.FileHandler(brindle_home() / "watch.log", encoding="utf-8")
|
|
1023
|
+
handler.setFormatter(logging.Formatter("%(asctime)s %(name)s %(levelname)s %(message)s"))
|
|
1024
|
+
except OSError:
|
|
1025
|
+
handler = logging.NullHandler()
|
|
1026
|
+
root = logging.getLogger()
|
|
1027
|
+
root.addHandler(handler)
|
|
1028
|
+
if root.level == logging.NOTSET or root.level > logging.WARNING:
|
|
1029
|
+
root.setLevel(logging.WARNING)
|
|
@@ -343,7 +343,8 @@ def provider_rows(providers: list[tuple[str, int]], width: int) -> list[str]:
|
|
|
343
343
|
|
|
344
344
|
def title(collapsed: bool, width: int, local_: Local | None) -> str:
|
|
345
345
|
arrow = "▸ " if collapsed else "▾ "
|
|
346
|
-
|
|
346
|
+
# The provider with the least headroom left: the one that holds work up.
|
|
347
|
+
top = ([min(local_.providers, key=lambda p: (p[1], p[0]))] if (local_ and local_.providers)
|
|
347
348
|
else (shares(local_.models)[:1] if local_ else []))
|
|
348
349
|
tail = f" ({short(top[0][0])} {top[0][1]}%)" if top else ""
|
|
349
350
|
if len(arrow) + len("Costs") + len(tail) > width:
|
|
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
|
|
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
|