brindle 0.4.4__tar.gz → 0.4.5__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.4.4 → brindle-0.4.5}/PKG-INFO +1 -1
- {brindle-0.4.4 → brindle-0.4.5}/pyproject.toml +1 -1
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/agents.py +11 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/sessions.py +16 -1
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/sidebar_follow.py +55 -4
- {brindle-0.4.4 → brindle-0.4.5}/.gitignore +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/LICENSE +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/README.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/SCHEDULE-A +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/__init__.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/__main__.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/account.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/airgap.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/antigravity.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/assembler.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/assets/braid_dark.png +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/assets/braid_light.png +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/autopilot.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/budget.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/__init__.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/backend-auditor.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/coordinator.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/developer-codex.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/developer-fable.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/developer-gemini.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/developer-heavy.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/developer-light.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/developer-local.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/developer-opencode.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/developer-sonnet.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/developer.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/qa.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/reviewer-codex.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/reviewer-gemini.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/reviewer-local.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/reviewer-opencode.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/reviewer.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/subagent.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_agents/supervisor.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_rules/__init__.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_rules/security/backend.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_rules/style/minimal-diff.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/builtin_rules/tests/only.md +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/ci_adapters.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/ci_client.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/ci_federation.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/ci_hosts.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/cli.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/cloud_credential.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/cloud_login.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/codemap.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/codemap_docs.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/codex_hook.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/company_identity.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/company_login.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/config.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/conflicts.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/coordinator.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/cost.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/cost_estimate.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/cull.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/db.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/demo.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/detect.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/doctor.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/escapes.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/events.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/gates.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/git.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/guardrails.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/history.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/identity_lock.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/inbox.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/kb.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/key_check.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/keys_cmds.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/keystore.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/knowledge.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/launch_health.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/learned_rules.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/learning.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/legacy.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/local_setup.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/login_pause.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/mcp_server.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/model_access.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/model_availability.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/native/__init__.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/native/catalog.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/native/client.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/native/loop.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/native/lsp.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/native/permissions.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/native/runner.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/native/serve.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/native/tools.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/opencode.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pane_auth.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/permissions.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/picker.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pipeline.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/plugins.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/policy.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pool.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pricing.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/__init__.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/_files.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/account.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/audit_chain.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/audit_export.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/auth.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/brief_learning.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/cost_centers.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/credentials.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/features.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/keys.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/learning.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/license.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/loopback.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/managed_models.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/org_profiles.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/orgkey.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/rollout.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/route_health.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/settings_sync.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/status.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/team_events.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/pro/team_policy.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/procs.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/profiles.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/prompt_answer.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/providers.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/quota.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/repo_cmds.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/repos.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/rewind.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/rule_checks.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/savings.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/scratch.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/secrets.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/self_serve.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/services.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/sidebar_logo.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/signin_pause.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/status_cache.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/tasks.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/tmux.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/updates.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/upgrade.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/usage.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/view.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/wake.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/watch.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/watch_costs.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/web/__init__.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/web/chat.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/web/dashboard.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/web/diff.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/web/server.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/web/static/app.js +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/web/static/index.html +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/worker_models.py +0 -0
- {brindle-0.4.4 → brindle-0.4.5}/src/brindle/workspaces.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: brindle
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.5
|
|
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
|
|
@@ -2184,12 +2184,17 @@ def close_removed(db: DB, agent_id: str) -> None:
|
|
|
2184
2184
|
note.unlink()
|
|
2185
2185
|
except OSError:
|
|
2186
2186
|
session = ""
|
|
2187
|
+
root_id = root_of(db, agent_id) # before kill drops the record that links it
|
|
2187
2188
|
try:
|
|
2188
2189
|
kill(db, agent_id)
|
|
2189
2190
|
except AgentError:
|
|
2190
2191
|
pass
|
|
2191
2192
|
if session and db.workspace_by_tmux_session(session) is None \
|
|
2192
2193
|
and not tmux.session_attached(session):
|
|
2194
|
+
# A sidebar left in this session would go down with it.
|
|
2195
|
+
sidebar = db.get_sidebar_pane(root_id)
|
|
2196
|
+
if sidebar and sidebar != SIDEBAR_DISMISSED and tmux.pane_session(sidebar) == session:
|
|
2197
|
+
sidebar_come_home(db, root_id, sidebar)
|
|
2193
2198
|
tmux.kill_session(session)
|
|
2194
2199
|
|
|
2195
2200
|
|
|
@@ -2213,6 +2218,12 @@ def _stop(db: DB, agent: Agent) -> None:
|
|
|
2213
2218
|
# Only a window on the server brindle is using: another server's pane
|
|
2214
2219
|
# ids mean other panes here (see same_server).
|
|
2215
2220
|
window = agent.tmux_window if same_server(agent) and owns_pane(db, agent) else ""
|
|
2221
|
+
if window:
|
|
2222
|
+
from brindle.sidebar_follow import rescue_sidebar_from_window
|
|
2223
|
+
|
|
2224
|
+
# Before the pids are read: a moved pane keeps its process, and the
|
|
2225
|
+
# sidebar's would otherwise be stopped with the agent's.
|
|
2226
|
+
rescue_sidebar_from_window(db, agent)
|
|
2216
2227
|
pane_pids = tmux.window_pids(window) if window else []
|
|
2217
2228
|
if window:
|
|
2218
2229
|
tmux.kill_window(window)
|
|
@@ -40,10 +40,22 @@ class Session:
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
def paused(db: DB, repo_root: str) -> list[Session]:
|
|
43
|
-
"""Paused sessions whose chat ran in ``repo_root``, newest first.
|
|
43
|
+
"""Paused sessions whose chat ran in ``repo_root``, newest first. A
|
|
44
|
+
"failed" chat whose pane is still running isn't one: that status also
|
|
45
|
+
marks a live chat (a brief whose delivery wasn't confirmed, an auth error
|
|
46
|
+
on one turn), and dropping it (see enforce) would close it mid-session."""
|
|
44
47
|
out = []
|
|
48
|
+
panes = owners = None
|
|
45
49
|
for ws in db.find_workspaces(repo_root):
|
|
46
50
|
for a in db.list_agents(ws.id):
|
|
51
|
+
if a.mode == "interactive" and a.status == "failed":
|
|
52
|
+
if panes is None:
|
|
53
|
+
panes = tmux.list_panes()
|
|
54
|
+
owners = agents.pane_owners(db, panes)
|
|
55
|
+
# On another server, its own server's panes say whose its pane is.
|
|
56
|
+
mine = owners if agents.same_server(a, panes) else None
|
|
57
|
+
if agents.is_alive(a, panes) and agents.owns_pane(db, a, mine):
|
|
58
|
+
continue
|
|
47
59
|
if a.mode == "interactive" and a.status in ("paused", "failed"):
|
|
48
60
|
members = agents.tree(db, a.id)
|
|
49
61
|
branches = []
|
|
@@ -212,6 +224,9 @@ def _forget(db: DB, s: Session) -> None:
|
|
|
212
224
|
# some other pane here (see agents.same_server).
|
|
213
225
|
if (a.tmux_window and agents.same_server(a, panes) and agents.is_alive(a, panes)
|
|
214
226
|
and agents.owns_pane(db, a, owners)):
|
|
227
|
+
from brindle.sidebar_follow import rescue_sidebar_from_window
|
|
228
|
+
|
|
229
|
+
rescue_sidebar_from_window(db, a)
|
|
215
230
|
tmux.kill_window(a.tmux_window)
|
|
216
231
|
ws = db.get_workspace(a.workspace_id)
|
|
217
232
|
if ws and ws.kind == "worktree":
|
|
@@ -196,6 +196,54 @@ def rescue_sidebar(db: DB, ws: Workspace) -> None:
|
|
|
196
196
|
pass
|
|
197
197
|
|
|
198
198
|
|
|
199
|
+
def _home_session(db: DB, root_id: str, sidebar: str) -> str | None:
|
|
200
|
+
"""The brindle session whose agent window ``sidebar`` sits in. Not
|
|
201
|
+
``tmux.pane_session``: a window the app linked into its own
|
|
202
|
+
``brindle-view-*`` session reports that one, and that session being
|
|
203
|
+
attached says nothing about the person's terminal on the brindle session."""
|
|
204
|
+
window = tmux.pane_window(sidebar)
|
|
205
|
+
for agent in db.list_agents():
|
|
206
|
+
if (window and agent.tmux_window and root_of(db, agent.id) == root_id
|
|
207
|
+
and tmux.pane_window(agent.tmux_window) == window):
|
|
208
|
+
ws = db.get_workspace(agent.workspace_id)
|
|
209
|
+
if ws is not None:
|
|
210
|
+
return ws.tmux_session
|
|
211
|
+
return tmux.pane_session(sidebar)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def rescue_sidebar_from_window(db: DB, agent: Agent) -> None:
|
|
215
|
+
"""Call before ``agent``'s tmux window is killed: if its root's sidebar is
|
|
216
|
+
a pane in that window, move it to a window of the root's session that
|
|
217
|
+
survives (the root's active one, else any other agent's there: a worker
|
|
218
|
+
sharing the root's workspace has its window in the same session). Never
|
|
219
|
+
raises."""
|
|
220
|
+
try:
|
|
221
|
+
if not agent.tmux_window:
|
|
222
|
+
return
|
|
223
|
+
root_id = root_of(db, agent.id)
|
|
224
|
+
root = db.get_agent(root_id)
|
|
225
|
+
root_ws = db.get_workspace(root.workspace_id) if root else None
|
|
226
|
+
if root is None or root_ws is None or agent.id == root_id:
|
|
227
|
+
return
|
|
228
|
+
with _sidebar_lock(root_id):
|
|
229
|
+
sidebar = db.get_sidebar_pane(root_id)
|
|
230
|
+
doomed = tmux.pane_window(agent.tmux_window)
|
|
231
|
+
if not (_valid_sidebar(sidebar, root_id) and doomed
|
|
232
|
+
and tmux.pane_window(sidebar) == doomed):
|
|
233
|
+
return
|
|
234
|
+
candidates = [tmux.active_window(root_ws.tmux_session)]
|
|
235
|
+
candidates += [tmux.pane_window(a.tmux_window) for a in db.list_agents(root_ws.id)
|
|
236
|
+
if a.tmux_window and a.status not in ("paused", "done")]
|
|
237
|
+
for window in candidates:
|
|
238
|
+
target_pane = window and window != doomed and tmux.agent_pane_in_window(window, sidebar)
|
|
239
|
+
if target_pane:
|
|
240
|
+
_note_sidebar_move(f"rescue to {root_ws.tmux_session}", sidebar, target_pane)
|
|
241
|
+
tmux.move_pane(sidebar, target_pane, SIDEBAR_COLUMNS, _sidebar_position(root_ws))
|
|
242
|
+
return
|
|
243
|
+
except Exception: # noqa: BLE001 - cleanup must not fail because of the sidebar
|
|
244
|
+
pass
|
|
245
|
+
|
|
246
|
+
|
|
199
247
|
def sidebar_follow(db: DB, session: str) -> None:
|
|
200
248
|
ws = db.workspace_by_tmux_session(session)
|
|
201
249
|
if ws is None:
|
|
@@ -240,10 +288,13 @@ def sidebar_follow(db: DB, session: str) -> None:
|
|
|
240
288
|
if tmux.pane_window(sidebar) == window:
|
|
241
289
|
_repaint(sidebar)
|
|
242
290
|
return
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
291
|
+
# Never take it out of another session someone still looks at: the
|
|
292
|
+
# person's own switch-client leaves that session first, so it reads
|
|
293
|
+
# unattached by now. A second client (the app's, attached to a
|
|
294
|
+
# worker's session) changing windows must not pull it from their terminal.
|
|
295
|
+
home = _home_session(db, root_id, sidebar)
|
|
296
|
+
if home and home != session and tmux.session_attached(home):
|
|
297
|
+
return
|
|
247
298
|
target_pane = tmux.agent_pane_in_window(window, sidebar)
|
|
248
299
|
if not target_pane:
|
|
249
300
|
return
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|