@team-agent/installer 0.2.11 → 0.3.0
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.
- package/Cargo.lock +744 -0
- package/Cargo.toml +34 -0
- package/crates/team-agent/Cargo.toml +33 -0
- package/crates/team-agent/src/cli/adapters.rs +1343 -0
- package/crates/team-agent/src/cli/diagnose.rs +554 -0
- package/crates/team-agent/src/cli/emit.rs +1077 -0
- package/crates/team-agent/src/cli/helpers.rs +88 -0
- package/crates/team-agent/src/cli/leader.rs +216 -0
- package/crates/team-agent/src/cli/mod.rs +1141 -0
- package/crates/team-agent/src/cli/profile.rs +306 -0
- package/crates/team-agent/src/cli/send.rs +215 -0
- package/crates/team-agent/src/cli/status.rs +179 -0
- package/crates/team-agent/src/cli/status_port.rs +502 -0
- package/crates/team-agent/src/cli/tests/base.rs +616 -0
- package/crates/team-agent/src/cli/tests/compile.rs +96 -0
- package/crates/team-agent/src/cli/tests/divergence.rs +509 -0
- package/crates/team-agent/src/cli/tests/lane_c.rs +333 -0
- package/crates/team-agent/src/cli/tests/leader_watch.rs +395 -0
- package/crates/team-agent/src/cli/tests/main_preserved.rs +675 -0
- package/crates/team-agent/src/cli/tests/missing_subcommands.rs +390 -0
- package/crates/team-agent/src/cli/tests/mod.rs +97 -0
- package/crates/team-agent/src/cli/tests/peer_allow.rs +137 -0
- package/crates/team-agent/src/cli/tests/repair_state_byte_lock.rs +302 -0
- package/crates/team-agent/src/cli/tests/run_delegation.rs +305 -0
- package/crates/team-agent/src/cli/tests/status_send.rs +385 -0
- package/crates/team-agent/src/cli/tests/verb_profile.rs +182 -0
- package/crates/team-agent/src/cli/tests/verb_settle.rs +236 -0
- package/crates/team-agent/src/cli/tests/verb_validate.rs +184 -0
- package/crates/team-agent/src/cli/types.rs +605 -0
- package/crates/team-agent/src/compiler/tests.rs +701 -0
- package/crates/team-agent/src/compiler.rs +489 -0
- package/crates/team-agent/src/coordinator/backoff.rs +153 -0
- package/crates/team-agent/src/coordinator/health.rs +436 -0
- package/crates/team-agent/src/coordinator/mod.rs +80 -0
- package/crates/team-agent/src/coordinator/orphan.rs +179 -0
- package/crates/team-agent/src/coordinator/tests/abnormal.rs +255 -0
- package/crates/team-agent/src/coordinator/tests/basics.rs +262 -0
- package/crates/team-agent/src/coordinator/tests/daemon.rs +323 -0
- package/crates/team-agent/src/coordinator/tests/health_sync.rs +263 -0
- package/crates/team-agent/src/coordinator/tests/main_preserved.rs +136 -0
- package/crates/team-agent/src/coordinator/tests/mod.rs +310 -0
- package/crates/team-agent/src/coordinator/tests/spine.rs +261 -0
- package/crates/team-agent/src/coordinator/tests/takeover.rs +227 -0
- package/crates/team-agent/src/coordinator/tests/tick_core.rs +256 -0
- package/crates/team-agent/src/coordinator/tests/watch.rs +167 -0
- package/crates/team-agent/src/coordinator/tick.rs +2032 -0
- package/crates/team-agent/src/coordinator/types.rs +584 -0
- package/crates/team-agent/src/db/migration.rs +716 -0
- package/crates/team-agent/src/db/mod.rs +23 -0
- package/crates/team-agent/src/db/schema.rs +378 -0
- package/crates/team-agent/src/event_log.rs +375 -0
- package/crates/team-agent/src/fake_worker.rs +253 -0
- package/crates/team-agent/src/leader/helpers.rs +190 -0
- package/crates/team-agent/src/leader/inject.rs +33 -0
- package/crates/team-agent/src/leader/lease.rs +1063 -0
- package/crates/team-agent/src/leader/mod.rs +99 -0
- package/crates/team-agent/src/leader/owner_bind.rs +292 -0
- package/crates/team-agent/src/leader/rediscover/tests.rs +525 -0
- package/crates/team-agent/src/leader/rediscover.rs +1099 -0
- package/crates/team-agent/src/leader/start.rs +273 -0
- package/crates/team-agent/src/leader/takeover.rs +235 -0
- package/crates/team-agent/src/leader/tests/basics.rs +183 -0
- package/crates/team-agent/src/leader/tests/byte_findings.rs +234 -0
- package/crates/team-agent/src/leader/tests/identity.rs +206 -0
- package/crates/team-agent/src/leader/tests/idle.rs +271 -0
- package/crates/team-agent/src/leader/tests/lease_api.rs +225 -0
- package/crates/team-agent/src/leader/tests/lease_claim.rs +253 -0
- package/crates/team-agent/src/leader/tests/mod.rs +125 -0
- package/crates/team-agent/src/leader/tests/rediscover.rs +351 -0
- package/crates/team-agent/src/leader/tests/wake_start_owner.rs +204 -0
- package/crates/team-agent/src/leader/types.rs +487 -0
- package/crates/team-agent/src/lib.rs +85 -0
- package/crates/team-agent/src/lifecycle/display.rs +228 -0
- package/crates/team-agent/src/lifecycle/helpers.rs +112 -0
- package/crates/team-agent/src/lifecycle/launch/plan.rs +227 -0
- package/crates/team-agent/src/lifecycle/launch.rs +1833 -0
- package/crates/team-agent/src/lifecycle/mod.rs +62 -0
- package/crates/team-agent/src/lifecycle/restart/agent.rs +533 -0
- package/crates/team-agent/src/lifecycle/restart/common.rs +517 -0
- package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +41 -0
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +268 -0
- package/crates/team-agent/src/lifecycle/restart/remove.rs +780 -0
- package/crates/team-agent/src/lifecycle/restart/selection.rs +208 -0
- package/crates/team-agent/src/lifecycle/restart/team_state.rs +242 -0
- package/crates/team-agent/src/lifecycle/restart.rs +76 -0
- package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +455 -0
- package/crates/team-agent/src/lifecycle/tests/core.rs +989 -0
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +583 -0
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +933 -0
- package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +265 -0
- package/crates/team-agent/src/lifecycle/tests.rs +27 -0
- package/crates/team-agent/src/lifecycle/types.rs +685 -0
- package/crates/team-agent/src/main.rs +41 -0
- package/crates/team-agent/src/mcp_server/helpers.rs +228 -0
- package/crates/team-agent/src/mcp_server/mod.rs +183 -0
- package/crates/team-agent/src/mcp_server/normalize.rs +312 -0
- package/crates/team-agent/src/mcp_server/tests/golden.rs +283 -0
- package/crates/team-agent/src/mcp_server/tests/normalize.rs +244 -0
- package/crates/team-agent/src/mcp_server/tests/scoped.rs +189 -0
- package/crates/team-agent/src/mcp_server/tests/send.rs +222 -0
- package/crates/team-agent/src/mcp_server/tests/tools.rs +158 -0
- package/crates/team-agent/src/mcp_server/tests/wire.rs +159 -0
- package/crates/team-agent/src/mcp_server/tests.rs +38 -0
- package/crates/team-agent/src/mcp_server/tools.rs +603 -0
- package/crates/team-agent/src/mcp_server/types.rs +421 -0
- package/crates/team-agent/src/mcp_server/wire.rs +388 -0
- package/crates/team-agent/src/message_store.rs +767 -0
- package/crates/team-agent/src/messaging/activity.rs +433 -0
- package/crates/team-agent/src/messaging/delivery.rs +542 -0
- package/crates/team-agent/src/messaging/helpers.rs +209 -0
- package/crates/team-agent/src/messaging/leader_receiver.rs +340 -0
- package/crates/team-agent/src/messaging/mod.rs +147 -0
- package/crates/team-agent/src/messaging/peers.rs +32 -0
- package/crates/team-agent/src/messaging/results.rs +537 -0
- package/crates/team-agent/src/messaging/scheduler.rs +344 -0
- package/crates/team-agent/src/messaging/selftest.rs +100 -0
- package/crates/team-agent/src/messaging/send.rs +582 -0
- package/crates/team-agent/src/messaging/tests/basic.rs +357 -0
- package/crates/team-agent/src/messaging/tests/main_preserved.rs +122 -0
- package/crates/team-agent/src/messaging/tests/mod.rs +293 -0
- package/crates/team-agent/src/messaging/tests/runtime.rs +1422 -0
- package/crates/team-agent/src/messaging/tests/spine.rs +437 -0
- package/crates/team-agent/src/messaging/trust.rs +192 -0
- package/crates/team-agent/src/messaging/types.rs +355 -0
- package/crates/team-agent/src/messaging/watchers.rs +591 -0
- package/crates/team-agent/src/model/enums.rs +311 -0
- package/crates/team-agent/src/model/errors.rs +17 -0
- package/crates/team-agent/src/model/ids.rs +155 -0
- package/crates/team-agent/src/model/mod.rs +22 -0
- package/crates/team-agent/src/model/paths.rs +228 -0
- package/crates/team-agent/src/model/permissions.rs +567 -0
- package/crates/team-agent/src/model/routing.rs +340 -0
- package/crates/team-agent/src/model/spec.rs +680 -0
- package/crates/team-agent/src/model/task_graph.rs +380 -0
- package/crates/team-agent/src/model/testdata/fuzz.golden.yaml +43 -0
- package/crates/team-agent/src/model/testdata/fuzz.yaml +43 -0
- package/crates/team-agent/src/model/testdata/spec_invalid_a.yaml +207 -0
- package/crates/team-agent/src/model/testdata/team.spec.golden.yaml +206 -0
- package/crates/team-agent/src/model/testdata/team.spec.yaml +206 -0
- package/crates/team-agent/src/model/yaml/tests.rs +288 -0
- package/crates/team-agent/src/model/yaml.rs +800 -0
- package/crates/team-agent/src/packaging/install.rs +305 -0
- package/crates/team-agent/src/packaging/migrate.rs +30 -0
- package/crates/team-agent/src/packaging/mod.rs +82 -0
- package/crates/team-agent/src/packaging/repair.rs +24 -0
- package/crates/team-agent/src/packaging/tests.rs +829 -0
- package/crates/team-agent/src/packaging/types.rs +369 -0
- package/crates/team-agent/src/provider/adapter.rs +801 -0
- package/crates/team-agent/src/provider/approvals/mod.rs +2 -0
- package/crates/team-agent/src/provider/approvals/parsing.rs +452 -0
- package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +163 -0
- package/crates/team-agent/src/provider/classify.rs +456 -0
- package/crates/team-agent/src/provider/faults.rs +136 -0
- package/crates/team-agent/src/provider/helpers.rs +41 -0
- package/crates/team-agent/src/provider/mod.rs +53 -0
- package/crates/team-agent/src/provider/startup_prompt.rs +423 -0
- package/crates/team-agent/src/provider/tests/adapter.rs +239 -0
- package/crates/team-agent/src/provider/tests/classify.rs +240 -0
- package/crates/team-agent/src/provider/tests/faults.rs +120 -0
- package/crates/team-agent/src/provider/tests/idle.rs +208 -0
- package/crates/team-agent/src/provider/tests/wire.rs +213 -0
- package/crates/team-agent/src/provider/tests.rs +31 -0
- package/crates/team-agent/src/provider/types.rs +424 -0
- package/crates/team-agent/src/state/identity.rs +656 -0
- package/crates/team-agent/src/state/mod.rs +58 -0
- package/crates/team-agent/src/state/owner_gate.rs +423 -0
- package/crates/team-agent/src/state/persist.rs +712 -0
- package/crates/team-agent/src/state/projection.rs +657 -0
- package/crates/team-agent/src/state/selector.rs +105 -0
- package/crates/team-agent/src/state/testdata/state-rich.canonical.json +133 -0
- package/crates/team-agent/src/tmux_backend/tests.rs +586 -0
- package/crates/team-agent/src/tmux_backend.rs +758 -0
- package/crates/team-agent/src/transport/test_support.rs +252 -0
- package/crates/team-agent/src/transport/tests/behavior.rs +327 -0
- package/crates/team-agent/src/transport/tests/mod.rs +199 -0
- package/crates/team-agent/src/transport/tests/wire.rs +527 -0
- package/crates/team-agent/src/transport.rs +774 -0
- package/npm/install.mjs +90 -106
- package/package.json +15 -13
- package/crates/team-agent-core/Cargo.toml +0 -12
- package/crates/team-agent-core/src/lib.rs +0 -332
- package/crates/team-agent-core/src/main.rs +0 -152
- package/pyproject.toml +0 -18
- package/scripts/install.py +0 -88
- package/scripts/run_regression_tests.py +0 -83
- package/src/team_agent/__init__.py +0 -3
- package/src/team_agent/__main__.py +0 -5
- package/src/team_agent/_legacy_pane_discovery.py +0 -186
- package/src/team_agent/abnormal_track.py +0 -253
- package/src/team_agent/approvals/__init__.py +0 -65
- package/src/team_agent/approvals/constants.py +0 -6
- package/src/team_agent/approvals/parsing.py +0 -176
- package/src/team_agent/approvals/runtime_prompts.py +0 -171
- package/src/team_agent/approvals/status.py +0 -176
- package/src/team_agent/cli/__init__.py +0 -137
- package/src/team_agent/cli/commands.py +0 -481
- package/src/team_agent/cli/e2e.py +0 -202
- package/src/team_agent/cli/helpers.py +0 -226
- package/src/team_agent/cli/parser.py +0 -540
- package/src/team_agent/compiler.py +0 -334
- package/src/team_agent/coordinator/__init__.py +0 -53
- package/src/team_agent/coordinator/__main__.py +0 -119
- package/src/team_agent/coordinator/lifecycle.py +0 -411
- package/src/team_agent/coordinator/metadata.py +0 -61
- package/src/team_agent/coordinator/paths.py +0 -17
- package/src/team_agent/diagnose/__init__.py +0 -48
- package/src/team_agent/diagnose/checks.py +0 -101
- package/src/team_agent/diagnose/comms.py +0 -213
- package/src/team_agent/diagnose/health.py +0 -241
- package/src/team_agent/diagnose/orphan_cleanup.py +0 -364
- package/src/team_agent/diagnose/preflight.py +0 -194
- package/src/team_agent/diagnose/quick_start.py +0 -324
- package/src/team_agent/display/__init__.py +0 -92
- package/src/team_agent/display/adaptive.py +0 -511
- package/src/team_agent/display/backend.py +0 -46
- package/src/team_agent/display/close.py +0 -154
- package/src/team_agent/display/ghostty.py +0 -77
- package/src/team_agent/display/rebuild.py +0 -102
- package/src/team_agent/display/tiling.py +0 -156
- package/src/team_agent/display/worker_window.py +0 -114
- package/src/team_agent/display/workspace.py +0 -382
- package/src/team_agent/errors.py +0 -10
- package/src/team_agent/events.py +0 -84
- package/src/team_agent/fake_worker.py +0 -80
- package/src/team_agent/idle_predicate.py +0 -218
- package/src/team_agent/idle_takeover.py +0 -59
- package/src/team_agent/idle_takeover_wiring.py +0 -114
- package/src/team_agent/launch/__init__.py +0 -41
- package/src/team_agent/launch/bootstrap.py +0 -85
- package/src/team_agent/launch/config.py +0 -106
- package/src/team_agent/launch/core.py +0 -301
- package/src/team_agent/launch/requirements.py +0 -57
- package/src/team_agent/leader/__init__.py +0 -926
- package/src/team_agent/leader_binding.py +0 -183
- package/src/team_agent/lifecycle/__init__.py +0 -5
- package/src/team_agent/lifecycle/agents.py +0 -278
- package/src/team_agent/lifecycle/operations.py +0 -411
- package/src/team_agent/lifecycle/paste_buffer_hygiene.py +0 -39
- package/src/team_agent/lifecycle/start.py +0 -363
- package/src/team_agent/mcp_server/__init__.py +0 -42
- package/src/team_agent/mcp_server/__main__.py +0 -7
- package/src/team_agent/mcp_server/contracts.py +0 -148
- package/src/team_agent/mcp_server/normalize.py +0 -257
- package/src/team_agent/mcp_server/server.py +0 -150
- package/src/team_agent/mcp_server/tools.py +0 -352
- package/src/team_agent/message_store/__init__.py +0 -23
- package/src/team_agent/message_store/agent_health.py +0 -113
- package/src/team_agent/message_store/core.py +0 -497
- package/src/team_agent/message_store/leader_notification_log.py +0 -198
- package/src/team_agent/message_store/result_watchers.py +0 -251
- package/src/team_agent/message_store/schema.py +0 -308
- package/src/team_agent/message_store/schema_migration.py +0 -448
- package/src/team_agent/messaging/__init__.py +0 -1
- package/src/team_agent/messaging/activity_detector.py +0 -262
- package/src/team_agent/messaging/delivery.py +0 -504
- package/src/team_agent/messaging/deps.py +0 -247
- package/src/team_agent/messaging/idle_alerts.py +0 -423
- package/src/team_agent/messaging/internal_delivery.py +0 -46
- package/src/team_agent/messaging/leader.py +0 -497
- package/src/team_agent/messaging/leader_api_errors.py +0 -216
- package/src/team_agent/messaging/leader_panes.py +0 -673
- package/src/team_agent/messaging/owner_bypass.py +0 -29
- package/src/team_agent/messaging/result_delivery.py +0 -539
- package/src/team_agent/messaging/results.py +0 -447
- package/src/team_agent/messaging/scheduler.py +0 -450
- package/src/team_agent/messaging/send.py +0 -532
- package/src/team_agent/messaging/session_drift.py +0 -94
- package/src/team_agent/messaging/tmux_io.py +0 -506
- package/src/team_agent/messaging/tmux_prompt.py +0 -338
- package/src/team_agent/messaging/trust_auto_answer.py +0 -52
- package/src/team_agent/orchestrator/__init__.py +0 -376
- package/src/team_agent/orchestrator/plan.py +0 -122
- package/src/team_agent/orchestrator/state.py +0 -128
- package/src/team_agent/paths.py +0 -45
- package/src/team_agent/permissions.py +0 -123
- package/src/team_agent/profiles/__init__.py +0 -82
- package/src/team_agent/profiles/constants.py +0 -19
- package/src/team_agent/profiles/core.py +0 -407
- package/src/team_agent/profiles/helpers.py +0 -69
- package/src/team_agent/profiles/provider_env.py +0 -188
- package/src/team_agent/profiles/smoke.py +0 -201
- package/src/team_agent/provider_cli/__init__.py +0 -43
- package/src/team_agent/provider_cli/adapter.py +0 -172
- package/src/team_agent/provider_cli/base.py +0 -48
- package/src/team_agent/provider_cli/claude.py +0 -503
- package/src/team_agent/provider_cli/codex.py +0 -336
- package/src/team_agent/provider_cli/copilot.py +0 -8
- package/src/team_agent/provider_cli/fake.py +0 -39
- package/src/team_agent/provider_cli/gemini.py +0 -95
- package/src/team_agent/provider_cli/opencode.py +0 -8
- package/src/team_agent/provider_cli/prompt.py +0 -62
- package/src/team_agent/provider_cli/registry.py +0 -18
- package/src/team_agent/provider_cli/unsupported.py +0 -32
- package/src/team_agent/provider_state/README.md +0 -78
- package/src/team_agent/provider_state/__init__.py +0 -91
- package/src/team_agent/provider_state/claude.py +0 -86
- package/src/team_agent/provider_state/codex.py +0 -84
- package/src/team_agent/provider_state/common.py +0 -207
- package/src/team_agent/provider_state/registry.py +0 -118
- package/src/team_agent/providers.py +0 -163
- package/src/team_agent/quality_gates.py +0 -104
- package/src/team_agent/restart/__init__.py +0 -34
- package/src/team_agent/restart/orchestration.py +0 -554
- package/src/team_agent/restart/selection.py +0 -89
- package/src/team_agent/restart/snapshot.py +0 -70
- package/src/team_agent/routing.py +0 -84
- package/src/team_agent/runtime.py +0 -1243
- package/src/team_agent/rust_core.py +0 -327
- package/src/team_agent/sessions/__init__.py +0 -25
- package/src/team_agent/sessions/capture.py +0 -144
- package/src/team_agent/sessions/inventory.py +0 -44
- package/src/team_agent/sessions/resume.py +0 -135
- package/src/team_agent/simple_yaml.py +0 -236
- package/src/team_agent/spec.py +0 -370
- package/src/team_agent/state.py +0 -693
- package/src/team_agent/status/__init__.py +0 -63
- package/src/team_agent/status/approvals.py +0 -52
- package/src/team_agent/status/compact.py +0 -158
- package/src/team_agent/status/constants.py +0 -18
- package/src/team_agent/status/inbox.py +0 -58
- package/src/team_agent/status/peek.py +0 -117
- package/src/team_agent/status/queries.py +0 -199
- package/src/team_agent/task_graph.py +0 -80
- package/src/team_agent/terminal.py +0 -57
- package/src/team_agent/wake.py +0 -58
- package/src/team_agent/watch/__init__.py +0 -145
|
@@ -1,1243 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import json
|
|
4
|
-
import hashlib
|
|
5
|
-
import os
|
|
6
|
-
import re
|
|
7
|
-
import signal
|
|
8
|
-
import shlex
|
|
9
|
-
import shutil
|
|
10
|
-
import subprocess
|
|
11
|
-
import sys
|
|
12
|
-
import time
|
|
13
|
-
import copy
|
|
14
|
-
import fcntl
|
|
15
|
-
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
16
|
-
from contextlib import contextmanager
|
|
17
|
-
from datetime import datetime, timedelta, timezone
|
|
18
|
-
from pathlib import Path
|
|
19
|
-
from typing import Any
|
|
20
|
-
|
|
21
|
-
from team_agent.errors import RuntimeError, ValidationError
|
|
22
|
-
from team_agent.events import EventLog
|
|
23
|
-
from team_agent.message_store import MessageStore
|
|
24
|
-
from team_agent.paths import artifacts_dir, logs_dir, messages_dir, runtime_dir, team_workspace
|
|
25
|
-
from team_agent.permissions import missing_tools, resolve_permissions
|
|
26
|
-
from team_agent.profiles import (
|
|
27
|
-
compact_profile_check,
|
|
28
|
-
effective_model,
|
|
29
|
-
prepare_agent_profile_launch,
|
|
30
|
-
smoke_check_agent_profile,
|
|
31
|
-
validate_agent_profile,
|
|
32
|
-
)
|
|
33
|
-
from team_agent.rust_core import core_binary, list_targets as core_list_targets, redact_text, render_message as core_render_message
|
|
34
|
-
from team_agent.providers import (
|
|
35
|
-
ResumeUnavailable,
|
|
36
|
-
get_adapter,
|
|
37
|
-
shell_command_for_agent,
|
|
38
|
-
shell_fork_command_for_agent,
|
|
39
|
-
shell_resume_command_for_agent,
|
|
40
|
-
)
|
|
41
|
-
from team_agent.display import (
|
|
42
|
-
GHOSTTY_DISPLAY_BACKENDS,
|
|
43
|
-
GHOSTTY_WORKSPACE_PANES_PER_WINDOW,
|
|
44
|
-
close_ghostty_display as _close_ghostty_display,
|
|
45
|
-
close_ghostty_workspace as _close_ghostty_workspace,
|
|
46
|
-
close_ghostty_workspace_slot as _close_ghostty_workspace_slot,
|
|
47
|
-
close_team_display_backends as _close_team_display_backends,
|
|
48
|
-
ghostty_app_exists as _ghostty_app_exists,
|
|
49
|
-
ghostty_attach_args as _ghostty_attach_args,
|
|
50
|
-
ghostty_command as _ghostty_command,
|
|
51
|
-
ghostty_display_session_name as _ghostty_display_session_name,
|
|
52
|
-
ghostty_pids_by_title as _ghostty_pids_by_title,
|
|
53
|
-
ghostty_workspace_aggregator_name as _ghostty_workspace_aggregator_name,
|
|
54
|
-
ghostty_workspace_blocked as _ghostty_workspace_blocked,
|
|
55
|
-
ghostty_workspace_pane_command as _ghostty_workspace_pane_command,
|
|
56
|
-
ghostty_workspace_pane_title as _ghostty_workspace_pane_title,
|
|
57
|
-
ghostty_workspace_partial_update_display as _ghostty_workspace_partial_update_display,
|
|
58
|
-
ghostty_workspace_window_name as _ghostty_workspace_window_name,
|
|
59
|
-
kill_ghostty_workspace_linked_sessions as _kill_ghostty_workspace_linked_sessions,
|
|
60
|
-
open_ghostty_worker_window as _open_ghostty_worker_window,
|
|
61
|
-
open_ghostty_workspace as _open_ghostty_workspace,
|
|
62
|
-
open_ghostty_workspace_agent_display as _open_ghostty_workspace_agent_display,
|
|
63
|
-
open_worker_displays as _open_worker_displays,
|
|
64
|
-
prepare_ghostty_display_session as _prepare_ghostty_display_session,
|
|
65
|
-
prepare_ghostty_workspace_aggregator as _prepare_ghostty_workspace_aggregator,
|
|
66
|
-
prepare_ghostty_workspace_linked_sessions as _prepare_ghostty_workspace_linked_sessions,
|
|
67
|
-
set_ghostty_workspace_pane_title as _set_ghostty_workspace_pane_title,
|
|
68
|
-
)
|
|
69
|
-
from team_agent.leader import (
|
|
70
|
-
LEADER_OWNERSHIP_LOCK,
|
|
71
|
-
attach_leader,
|
|
72
|
-
attach_leader_to_state as _attach_leader_to_state,
|
|
73
|
-
claim_leader as _legacy_claim_leader,
|
|
74
|
-
leader_identity,
|
|
75
|
-
leader_session_name as _leader_session_name,
|
|
76
|
-
leader_start_plan,
|
|
77
|
-
start_leader,
|
|
78
|
-
)
|
|
79
|
-
from team_agent.launch import (
|
|
80
|
-
DANGEROUS_LEADER_FLAGS,
|
|
81
|
-
attach_team_profile_dirs as _attach_team_profile_dirs,
|
|
82
|
-
command_has_flag as _command_has_flag,
|
|
83
|
-
compile_team_dir_spec as _compile_team_dir_spec,
|
|
84
|
-
detect_inherited_dangerous_permissions as _detect_inherited_dangerous_permissions,
|
|
85
|
-
effective_runtime_config as _effective_runtime_config,
|
|
86
|
-
ensure_agent_start_requirements as _ensure_agent_start_requirements,
|
|
87
|
-
init_workspace,
|
|
88
|
-
is_team_doc_dir as _is_team_doc_dir,
|
|
89
|
-
launch,
|
|
90
|
-
process_ancestry as _process_ancestry,
|
|
91
|
-
process_info as _process_info,
|
|
92
|
-
requires_direct_leader_receiver as _requires_direct_leader_receiver,
|
|
93
|
-
spec_team_dir as _spec_team_dir,
|
|
94
|
-
tmux_session_conflict_error as _tmux_session_conflict_error,
|
|
95
|
-
validate_file,
|
|
96
|
-
)
|
|
97
|
-
from team_agent.approvals import (
|
|
98
|
-
APPROVAL_CHOICE_RE as _APPROVAL_CHOICE_RE,
|
|
99
|
-
INTERNAL_MCP_APPROVAL_CHOICE,
|
|
100
|
-
INTERNAL_MCP_AUTO_APPROVE_TOOLS,
|
|
101
|
-
STARTUP_PROMPT_RUNTIME_CHECK_LIMIT,
|
|
102
|
-
active_approval_choice_index as _active_approval_choice_index,
|
|
103
|
-
active_approval_control_index as _active_approval_control_index,
|
|
104
|
-
age_text as _age_text,
|
|
105
|
-
agent_health_status as _agent_health_status,
|
|
106
|
-
approval_choice_keys as _approval_choice_keys,
|
|
107
|
-
approval_prompt_fingerprint as _approval_prompt_fingerprint,
|
|
108
|
-
capture_has_approval_prompt as _capture_has_approval_prompt,
|
|
109
|
-
capture_has_team_orchestrator_mcp_prompt as _capture_has_team_orchestrator_mcp_prompt,
|
|
110
|
-
choose_internal_mcp_approval_choice as _choose_internal_mcp_approval_choice,
|
|
111
|
-
current_task_for_agent as _current_task_for_agent,
|
|
112
|
-
detect_provider_status as _detect_provider_status,
|
|
113
|
-
extract_approval_choices as _extract_approval_choices,
|
|
114
|
-
extract_approval_prompt as _extract_approval_prompt,
|
|
115
|
-
extract_command_approval_subject as _extract_command_approval_subject,
|
|
116
|
-
handle_internal_mcp_approval_prompt as _handle_internal_mcp_approval_prompt,
|
|
117
|
-
handle_provider_runtime_prompts as _handle_provider_runtime_prompts,
|
|
118
|
-
handle_provider_startup_prompts as _handle_provider_startup_prompts,
|
|
119
|
-
is_approval_control_line as _is_approval_control_line,
|
|
120
|
-
line_is_approval_choice as _line_is_approval_choice,
|
|
121
|
-
refresh_agent_runtime_statuses as _refresh_agent_runtime_statuses,
|
|
122
|
-
submit_internal_mcp_approval as _submit_internal_mcp_approval,
|
|
123
|
-
sync_agent_health as _sync_agent_health,
|
|
124
|
-
)
|
|
125
|
-
from team_agent.diagnose import (
|
|
126
|
-
compact_model_checks as _compact_model_checks,
|
|
127
|
-
diagnose,
|
|
128
|
-
doctor,
|
|
129
|
-
ensure_profiles_for_roles as _ensure_profiles_for_roles,
|
|
130
|
-
format_model_check_failures as _format_model_check_failures,
|
|
131
|
-
format_profile_check_failures as _format_profile_check_failures,
|
|
132
|
-
format_profile_smoke_failures as _format_profile_smoke_failures,
|
|
133
|
-
model_checks_for_agents as _model_checks_for_agents,
|
|
134
|
-
prepare_quick_start_team as _prepare_quick_start_team,
|
|
135
|
-
preflight,
|
|
136
|
-
preflight_blockers as _preflight_blockers,
|
|
137
|
-
preflight_next_actions as _preflight_next_actions,
|
|
138
|
-
profile_checks_for_agents as _profile_checks_for_agents,
|
|
139
|
-
profile_smoke_checks_for_agents as _profile_smoke_checks_for_agents,
|
|
140
|
-
quick_start as _legacy_quick_start,
|
|
141
|
-
repair_state,
|
|
142
|
-
settle,
|
|
143
|
-
start,
|
|
144
|
-
wait_ready,
|
|
145
|
-
)
|
|
146
|
-
from team_agent.coordinator import (
|
|
147
|
-
COORDINATOR_PROTOCOL_VERSION,
|
|
148
|
-
coordinator_health,
|
|
149
|
-
coordinator_log_path,
|
|
150
|
-
coordinator_meta_path,
|
|
151
|
-
coordinator_metadata_ok as _coordinator_metadata_ok,
|
|
152
|
-
coordinator_pid_path,
|
|
153
|
-
coordinator_tick,
|
|
154
|
-
message_store_schema_health as _message_store_schema_health,
|
|
155
|
-
pid_is_running as _pid_is_running,
|
|
156
|
-
read_coordinator_metadata as _read_coordinator_metadata,
|
|
157
|
-
start_coordinator,
|
|
158
|
-
stop_coordinator,
|
|
159
|
-
write_coordinator_metadata,
|
|
160
|
-
)
|
|
161
|
-
from team_agent.restart import (
|
|
162
|
-
format_restart_candidates as _format_restart_candidates,
|
|
163
|
-
quick_start_existing_context as _quick_start_existing_context,
|
|
164
|
-
restart,
|
|
165
|
-
restart_candidate_from_state as _restart_candidate_from_state,
|
|
166
|
-
restart_candidates as _restart_candidates,
|
|
167
|
-
rollback_restart_session as _rollback_restart_session,
|
|
168
|
-
safe_snapshot_name as _safe_snapshot_name,
|
|
169
|
-
save_team_runtime_snapshot as _save_team_runtime_snapshot,
|
|
170
|
-
select_restart_state as _select_restart_state,
|
|
171
|
-
state_has_restart_context as _state_has_restart_context,
|
|
172
|
-
state_team_name as _state_team_name,
|
|
173
|
-
team_runtime_snapshot_dir as _team_runtime_snapshot_dir,
|
|
174
|
-
load_snapshot_state as _load_snapshot_state,
|
|
175
|
-
)
|
|
176
|
-
from team_agent.routing import route_task
|
|
177
|
-
from team_agent.sessions import (
|
|
178
|
-
attach_profile_resume_root as _attach_profile_resume_root,
|
|
179
|
-
capture_agent_session as _capture_agent_session,
|
|
180
|
-
capture_missing_sessions as _capture_missing_sessions,
|
|
181
|
-
clear_session_capture_fields as _clear_session_capture_fields,
|
|
182
|
-
copy_session_metadata as _copy_session_metadata,
|
|
183
|
-
prepare_resume_state as _prepare_resume_state,
|
|
184
|
-
recover_resume_session_from_events as _recover_resume_session_from_events,
|
|
185
|
-
sessions_overview as sessions,
|
|
186
|
-
)
|
|
187
|
-
from team_agent.status import (
|
|
188
|
-
APPROVAL_SCAN_LINES,
|
|
189
|
-
PEEK_MAX_LINES,
|
|
190
|
-
PEEK_MAX_MATCHES,
|
|
191
|
-
PEEK_SEARCH_SCAN_LINES,
|
|
192
|
-
PENDING_DELIVERY_STATUSES,
|
|
193
|
-
STATUS_EVENT_LIMIT,
|
|
194
|
-
STATUS_TEXT_LIMIT,
|
|
195
|
-
approvals,
|
|
196
|
-
compact_agent_state as _compact_agent_state,
|
|
197
|
-
compact_event as _compact_event,
|
|
198
|
-
compact_mapping as _compact_mapping,
|
|
199
|
-
compact_status as _compact_status,
|
|
200
|
-
compact_task as _compact_task,
|
|
201
|
-
compact_value as _compact_value,
|
|
202
|
-
format_approvals,
|
|
203
|
-
format_inbox,
|
|
204
|
-
format_search_matches as _format_search_matches,
|
|
205
|
-
format_status,
|
|
206
|
-
inbox,
|
|
207
|
-
latest_result_summaries as _latest_result_summaries,
|
|
208
|
-
peek,
|
|
209
|
-
queued_message_statuses as _queued_message_statuses,
|
|
210
|
-
result_summary_from_row as _result_summary_from_row,
|
|
211
|
-
search_lines as _search_lines,
|
|
212
|
-
status,
|
|
213
|
-
validate_line_count as _validate_line_count,
|
|
214
|
-
)
|
|
215
|
-
from team_agent.simple_yaml import dumps
|
|
216
|
-
from team_agent.spec import load_spec, validate_result_envelope, validate_spec, workspace_from_spec
|
|
217
|
-
from team_agent.state import (
|
|
218
|
-
SESSION_CAPTURE_FIELDS,
|
|
219
|
-
SESSION_STATE_FIELDS,
|
|
220
|
-
check_team_owner,
|
|
221
|
-
load_runtime_state,
|
|
222
|
-
normalize_agent_session_state,
|
|
223
|
-
populate_team_owner_from_env,
|
|
224
|
-
runtime_state_path,
|
|
225
|
-
save_runtime_state,
|
|
226
|
-
save_team_scoped_state,
|
|
227
|
-
select_runtime_state,
|
|
228
|
-
team_state_key,
|
|
229
|
-
write_spec,
|
|
230
|
-
write_team_state,
|
|
231
|
-
)
|
|
232
|
-
|
|
233
|
-
# Import-time assertions: lifecycle/start.py + messaging/deps.py keep an
|
|
234
|
-
# existence check on these runtime symbols. The aliases above pin them so
|
|
235
|
-
# accidental rename in team_agent.sessions trips a loud ImportError here.
|
|
236
|
-
assert callable(_attach_profile_resume_root)
|
|
237
|
-
assert callable(_capture_agent_session)
|
|
238
|
-
assert callable(_capture_missing_sessions)
|
|
239
|
-
assert callable(_clear_session_capture_fields)
|
|
240
|
-
assert callable(_copy_session_metadata)
|
|
241
|
-
assert callable(_prepare_resume_state)
|
|
242
|
-
assert callable(_recover_resume_session_from_events)
|
|
243
|
-
assert callable(sessions)
|
|
244
|
-
|
|
245
|
-
# Display lane re-exports: lifecycle/start.py + lifecycle/operations.py +
|
|
246
|
-
# existing tests assume team_agent.runtime exposes these names. Each alias
|
|
247
|
-
# fails at import if team_agent.display drops the symbol, preventing the
|
|
248
|
-
# 0a36ad9-style "imports in HEAD, body missing on disk" hazard.
|
|
249
|
-
assert callable(_close_ghostty_display)
|
|
250
|
-
assert callable(_close_ghostty_workspace)
|
|
251
|
-
assert callable(_close_ghostty_workspace_slot)
|
|
252
|
-
assert callable(_ghostty_app_exists)
|
|
253
|
-
assert callable(_ghostty_attach_args)
|
|
254
|
-
assert callable(_ghostty_command)
|
|
255
|
-
assert callable(_ghostty_display_session_name)
|
|
256
|
-
assert callable(_ghostty_pids_by_title)
|
|
257
|
-
assert callable(_ghostty_workspace_aggregator_name)
|
|
258
|
-
assert callable(_ghostty_workspace_blocked)
|
|
259
|
-
assert callable(_ghostty_workspace_pane_command)
|
|
260
|
-
assert callable(_ghostty_workspace_pane_title)
|
|
261
|
-
assert callable(_ghostty_workspace_partial_update_display)
|
|
262
|
-
assert callable(_ghostty_workspace_window_name)
|
|
263
|
-
assert callable(_kill_ghostty_workspace_linked_sessions)
|
|
264
|
-
assert callable(_open_ghostty_worker_window)
|
|
265
|
-
assert callable(_open_ghostty_workspace)
|
|
266
|
-
assert callable(_open_ghostty_workspace_agent_display)
|
|
267
|
-
assert callable(_open_worker_displays)
|
|
268
|
-
assert callable(_prepare_ghostty_display_session)
|
|
269
|
-
assert callable(_prepare_ghostty_workspace_aggregator)
|
|
270
|
-
assert callable(_prepare_ghostty_workspace_linked_sessions)
|
|
271
|
-
assert callable(_set_ghostty_workspace_pane_title)
|
|
272
|
-
assert isinstance(GHOSTTY_WORKSPACE_PANES_PER_WINDOW, int)
|
|
273
|
-
|
|
274
|
-
# Status lane re-exports: the runtime.* alias for each status helper keeps
|
|
275
|
-
# CLI handlers and existing tests stable; constants travel through runtime
|
|
276
|
-
# so callers that read runtime.APPROVAL_SCAN_LINES (or the others) still
|
|
277
|
-
# resolve. Drift in team_agent.status fails loudly here.
|
|
278
|
-
assert callable(approvals)
|
|
279
|
-
assert callable(format_approvals)
|
|
280
|
-
assert callable(format_inbox)
|
|
281
|
-
assert callable(format_status)
|
|
282
|
-
assert callable(inbox)
|
|
283
|
-
assert callable(peek)
|
|
284
|
-
assert callable(status)
|
|
285
|
-
assert callable(_compact_agent_state)
|
|
286
|
-
assert callable(_compact_event)
|
|
287
|
-
assert callable(_compact_mapping)
|
|
288
|
-
assert callable(_compact_status)
|
|
289
|
-
assert callable(_compact_task)
|
|
290
|
-
assert callable(_compact_value)
|
|
291
|
-
assert callable(_format_search_matches)
|
|
292
|
-
assert callable(_latest_result_summaries)
|
|
293
|
-
assert callable(_queued_message_statuses)
|
|
294
|
-
assert callable(_result_summary_from_row)
|
|
295
|
-
assert callable(_search_lines)
|
|
296
|
-
assert callable(_validate_line_count)
|
|
297
|
-
assert isinstance(APPROVAL_SCAN_LINES, int)
|
|
298
|
-
assert isinstance(PEEK_MAX_LINES, int)
|
|
299
|
-
assert isinstance(PEEK_MAX_MATCHES, int)
|
|
300
|
-
assert isinstance(PEEK_SEARCH_SCAN_LINES, int)
|
|
301
|
-
assert isinstance(STATUS_EVENT_LIMIT, int)
|
|
302
|
-
assert isinstance(STATUS_TEXT_LIMIT, int)
|
|
303
|
-
assert isinstance(PENDING_DELIVERY_STATUSES, set)
|
|
304
|
-
|
|
305
|
-
# Restart lane re-exports: lifecycle/agents.py + lifecycle/operations.py
|
|
306
|
-
# call runtime._save_team_runtime_snapshot, existing tests target
|
|
307
|
-
# runtime.restart, runtime._select_restart_state, runtime._rollback_restart_session,
|
|
308
|
-
# runtime._safe_snapshot_name, etc. The aliases above plus these assertions
|
|
309
|
-
# catch any rename or removal in team_agent.restart at import time.
|
|
310
|
-
assert callable(restart)
|
|
311
|
-
assert callable(_rollback_restart_session)
|
|
312
|
-
assert callable(_save_team_runtime_snapshot)
|
|
313
|
-
assert callable(_restart_candidates)
|
|
314
|
-
assert callable(_restart_candidate_from_state)
|
|
315
|
-
assert callable(_state_has_restart_context)
|
|
316
|
-
assert callable(_select_restart_state)
|
|
317
|
-
assert callable(_format_restart_candidates)
|
|
318
|
-
assert callable(_quick_start_existing_context)
|
|
319
|
-
assert callable(_safe_snapshot_name)
|
|
320
|
-
assert callable(_state_team_name)
|
|
321
|
-
assert callable(_team_runtime_snapshot_dir)
|
|
322
|
-
assert callable(_load_snapshot_state)
|
|
323
|
-
|
|
324
|
-
# Coordinator lane re-exports keep runtime.coordinator_health,
|
|
325
|
-
# runtime.start_coordinator, runtime.coordinator_pid_path, etc. resolving
|
|
326
|
-
# for the daemon entry (team_agent.coordinator.__main__) and the existing
|
|
327
|
-
# tests. One representative identity smoke + one lightweight loop catch
|
|
328
|
-
# any rename or drop in team_agent.coordinator at import time without the
|
|
329
|
-
# over-coupled per-symbol assertIs sweep. Per-helper behavior is verified
|
|
330
|
-
# by tests/test_coordinator_boundary.py and the broader suite.
|
|
331
|
-
import team_agent.coordinator as _coordinator_pkg
|
|
332
|
-
assert start_coordinator is _coordinator_pkg.start_coordinator
|
|
333
|
-
for _name in (
|
|
334
|
-
"COORDINATOR_PROTOCOL_VERSION",
|
|
335
|
-
"coordinator_health",
|
|
336
|
-
"coordinator_log_path",
|
|
337
|
-
"coordinator_meta_path",
|
|
338
|
-
"coordinator_metadata_ok",
|
|
339
|
-
"coordinator_pid_path",
|
|
340
|
-
"coordinator_tick",
|
|
341
|
-
"message_store_schema_health",
|
|
342
|
-
"pid_is_running",
|
|
343
|
-
"read_coordinator_metadata",
|
|
344
|
-
"start_coordinator",
|
|
345
|
-
"stop_coordinator",
|
|
346
|
-
"write_coordinator_metadata",
|
|
347
|
-
):
|
|
348
|
-
assert hasattr(_coordinator_pkg, _name), f"team_agent.coordinator missing {_name}"
|
|
349
|
-
del _coordinator_pkg, _name
|
|
350
|
-
|
|
351
|
-
# Diagnose lane re-exports keep runtime.diagnose, runtime.doctor,
|
|
352
|
-
# runtime.preflight, runtime.start, runtime.quick_start, runtime.wait_ready,
|
|
353
|
-
# runtime.settle, runtime.repair_state plus the private helper aliases
|
|
354
|
-
# resolving for CLI handlers and existing tests. Same identity-smoke +
|
|
355
|
-
# lightweight-loop convention as coordinator.
|
|
356
|
-
import team_agent.diagnose as _diagnose_pkg
|
|
357
|
-
assert diagnose is _diagnose_pkg.diagnose
|
|
358
|
-
for _name in (
|
|
359
|
-
"compact_model_checks",
|
|
360
|
-
"diagnose",
|
|
361
|
-
"doctor",
|
|
362
|
-
"ensure_profiles_for_roles",
|
|
363
|
-
"format_model_check_failures",
|
|
364
|
-
"format_profile_check_failures",
|
|
365
|
-
"format_profile_smoke_failures",
|
|
366
|
-
"model_checks_for_agents",
|
|
367
|
-
"prepare_quick_start_team",
|
|
368
|
-
"preflight",
|
|
369
|
-
"preflight_blockers",
|
|
370
|
-
"preflight_next_actions",
|
|
371
|
-
"profile_checks_for_agents",
|
|
372
|
-
"profile_smoke_checks_for_agents",
|
|
373
|
-
"quick_start",
|
|
374
|
-
"repair_state",
|
|
375
|
-
"settle",
|
|
376
|
-
"start",
|
|
377
|
-
"wait_ready",
|
|
378
|
-
):
|
|
379
|
-
assert hasattr(_diagnose_pkg, _name), f"team_agent.diagnose missing {_name}"
|
|
380
|
-
del _diagnose_pkg, _name
|
|
381
|
-
|
|
382
|
-
# Approvals lane re-exports keep runtime.<symbol> resolving for the
|
|
383
|
-
# coordinator-tick + status-refresh + prompt-detection helpers that
|
|
384
|
-
# messaging/lifecycle/tests look up via the runtime alias surface. Same
|
|
385
|
-
# calibrated convention as coordinator and diagnose: one identity smoke
|
|
386
|
-
# + one lightweight loop over the full public name set.
|
|
387
|
-
import team_agent.approvals as _approvals_pkg
|
|
388
|
-
assert _refresh_agent_runtime_statuses is _approvals_pkg.refresh_agent_runtime_statuses
|
|
389
|
-
for _name in (
|
|
390
|
-
"APPROVAL_CHOICE_RE",
|
|
391
|
-
"INTERNAL_MCP_APPROVAL_CHOICE",
|
|
392
|
-
"INTERNAL_MCP_AUTO_APPROVE_TOOLS",
|
|
393
|
-
"STARTUP_PROMPT_RUNTIME_CHECK_LIMIT",
|
|
394
|
-
"active_approval_choice_index",
|
|
395
|
-
"active_approval_control_index",
|
|
396
|
-
"age_text",
|
|
397
|
-
"agent_health_status",
|
|
398
|
-
"approval_choice_keys",
|
|
399
|
-
"approval_prompt_fingerprint",
|
|
400
|
-
"capture_has_approval_prompt",
|
|
401
|
-
"capture_has_team_orchestrator_mcp_prompt",
|
|
402
|
-
"choose_internal_mcp_approval_choice",
|
|
403
|
-
"current_task_for_agent",
|
|
404
|
-
"detect_provider_status",
|
|
405
|
-
"extract_approval_choices",
|
|
406
|
-
"extract_approval_prompt",
|
|
407
|
-
"extract_command_approval_subject",
|
|
408
|
-
"handle_internal_mcp_approval_prompt",
|
|
409
|
-
"handle_provider_runtime_prompts",
|
|
410
|
-
"handle_provider_startup_prompts",
|
|
411
|
-
"is_approval_control_line",
|
|
412
|
-
"line_is_approval_choice",
|
|
413
|
-
"refresh_agent_runtime_statuses",
|
|
414
|
-
"submit_internal_mcp_approval",
|
|
415
|
-
"sync_agent_health",
|
|
416
|
-
):
|
|
417
|
-
assert hasattr(_approvals_pkg, _name), f"team_agent.approvals missing {_name}"
|
|
418
|
-
del _approvals_pkg, _name
|
|
419
|
-
|
|
420
|
-
# Launch lane re-exports keep runtime.launch, runtime.init_workspace,
|
|
421
|
-
# runtime.validate_file plus the private bootstrap/config helpers
|
|
422
|
-
# resolving for CLI handlers and tests. Same calibrated convention.
|
|
423
|
-
import team_agent.launch as _launch_pkg
|
|
424
|
-
assert launch is _launch_pkg.launch
|
|
425
|
-
for _name in (
|
|
426
|
-
"DANGEROUS_LEADER_FLAGS",
|
|
427
|
-
"attach_team_profile_dirs",
|
|
428
|
-
"command_has_flag",
|
|
429
|
-
"compile_team_dir_spec",
|
|
430
|
-
"detect_inherited_dangerous_permissions",
|
|
431
|
-
"effective_runtime_config",
|
|
432
|
-
"ensure_agent_start_requirements",
|
|
433
|
-
"init_workspace",
|
|
434
|
-
"is_team_doc_dir",
|
|
435
|
-
"launch",
|
|
436
|
-
"process_ancestry",
|
|
437
|
-
"process_info",
|
|
438
|
-
"requires_direct_leader_receiver",
|
|
439
|
-
"spec_team_dir",
|
|
440
|
-
"tmux_session_conflict_error",
|
|
441
|
-
"validate_file",
|
|
442
|
-
):
|
|
443
|
-
assert hasattr(_launch_pkg, _name), f"team_agent.launch missing {_name}"
|
|
444
|
-
del _launch_pkg, _name
|
|
445
|
-
|
|
446
|
-
# Leader lane re-exports keep runtime leader helpers resolving for CLI handlers and tests.
|
|
447
|
-
import team_agent.leader as _leader_pkg
|
|
448
|
-
assert attach_leader is _leader_pkg.attach_leader
|
|
449
|
-
for _name in ("attach_leader", "attach_leader_to_state", "claim_leader", "leader_identity", "leader_session_name", "leader_start_plan", "start_leader"):
|
|
450
|
-
assert hasattr(_leader_pkg, _name), f"team_agent.leader missing {_name}"
|
|
451
|
-
del _leader_pkg, _name
|
|
452
|
-
from team_agent.task_graph import ready_tasks, update_task_status
|
|
453
|
-
from team_agent.task_graph import TASK_STATUSES
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
TMUX_PANE_FORMAT = (
|
|
457
|
-
"#{pane_id}\t#{session_name}\t#{window_index}\t#{window_name}\t"
|
|
458
|
-
"#{pane_index}\t#{pane_tty}\t#{pane_current_command}\t#{pane_active}\t"
|
|
459
|
-
"#{pane_current_path}\t#{session_attached}\t#{pane_in_mode}"
|
|
460
|
-
)
|
|
461
|
-
HEALTH_STATUSES = {"RUNNING", "IDLE", "AWAITING_APPROVAL", "BLOCKED", "ERROR", "DONE"}
|
|
462
|
-
DELIVERY_CAPTURE_LINES = 40
|
|
463
|
-
SUBMITTED_DELIVERY_STATUSES = {"injected", "visible", "submitted", "submitted_unverified", "delivered", "acknowledged"}
|
|
464
|
-
TMUX_STDIN_BUFFER_THRESHOLD = 16 * 1024
|
|
465
|
-
TMUX_PASTE_MIN_READY_TIMEOUT = 1.5
|
|
466
|
-
TMUX_PASTE_MAX_READY_TIMEOUT = 30.0
|
|
467
|
-
TMUX_PASTE_BYTES_PER_SECOND = 25_000
|
|
468
|
-
TMUX_SUBMIT_MIN_SETTLE_TIMEOUT = 0.35
|
|
469
|
-
TMUX_SUBMIT_MAX_SETTLE_TIMEOUT = 15.0
|
|
470
|
-
TMUX_SUBMIT_BYTES_PER_SECOND = 50_000
|
|
471
|
-
PASTED_CONTENT_PROMPT_RE = re.compile(
|
|
472
|
-
r"\[\s*Pasted\s+(?:Content\s+\d+\s+chars?|text\s+#\d+\s+\+\s*\d+\s+lines?)\s*\]",
|
|
473
|
-
re.IGNORECASE,
|
|
474
|
-
)
|
|
475
|
-
|
|
476
|
-
def run_cmd(args: list[str], timeout: int = 20) -> subprocess.CompletedProcess[str]:
|
|
477
|
-
return subprocess.run(args, text=True, capture_output=True, timeout=timeout, check=False)
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
def ensure_workspace_dirs(workspace: Path) -> None:
|
|
481
|
-
for path in [runtime_dir(workspace), logs_dir(workspace), artifacts_dir(workspace), messages_dir(workspace)]:
|
|
482
|
-
path.mkdir(parents=True, exist_ok=True)
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
def shutdown(workspace: Path, keep_logs: bool = True, team: str | None = None) -> dict[str, Any]:
|
|
486
|
-
from team_agent.state import resolve_team_scoped_state
|
|
487
|
-
state, refusal = resolve_team_scoped_state(workspace, team)
|
|
488
|
-
if refusal:
|
|
489
|
-
return refusal
|
|
490
|
-
gate = check_team_owner(state)
|
|
491
|
-
if gate:
|
|
492
|
-
return gate
|
|
493
|
-
session_name = state.get("session_name")
|
|
494
|
-
resolved_team_id = (
|
|
495
|
-
team
|
|
496
|
-
or state.get("active_team_key")
|
|
497
|
-
or (team_state_key(state) if state.get("session_name") else None)
|
|
498
|
-
)
|
|
499
|
-
event_log = EventLog(workspace)
|
|
500
|
-
captured: list[str] = []
|
|
501
|
-
closed_displays: set[str] = set()
|
|
502
|
-
missing_before = [agent_id for agent_id, agent_state in state.get("agents", {}).items() if not agent_state.get("session_id")]
|
|
503
|
-
fallback_captured = _capture_missing_sessions(workspace, state, event_log, timeout_s=2.0, log_miss=False)
|
|
504
|
-
event_log.write("shutdown.session_capture_checked", missing_before=missing_before, captured=fallback_captured)
|
|
505
|
-
for agent_id, agent_state in state.get("agents", {}).items():
|
|
506
|
-
if not agent_state.get("session_id"):
|
|
507
|
-
event_log.write(
|
|
508
|
-
"shutdown.session_capture_missed",
|
|
509
|
-
agent_id=agent_id,
|
|
510
|
-
provider=agent_state.get("provider"),
|
|
511
|
-
spawn_cwd=agent_state.get("spawn_cwd"),
|
|
512
|
-
)
|
|
513
|
-
coordinator = stop_coordinator(workspace)
|
|
514
|
-
if session_name and _tmux_session_exists(session_name):
|
|
515
|
-
leader_receiver = state.get("leader_receiver", {})
|
|
516
|
-
leader_window = leader_receiver.get("window") if leader_receiver.get("mode") != "direct_tmux" else None
|
|
517
|
-
if leader_window and _tmux_window_exists(session_name, leader_window):
|
|
518
|
-
log_path = logs_dir(workspace) / f"{leader_window}.scrollback"
|
|
519
|
-
proc = run_cmd(["tmux", "capture-pane", "-p", "-S", "-", "-t", f"{session_name}:{leader_window}"], timeout=10)
|
|
520
|
-
if proc.returncode == 0:
|
|
521
|
-
log_path.write_text(proc.stdout, encoding="utf-8")
|
|
522
|
-
captured.append(str(log_path))
|
|
523
|
-
for agent_id, agent_state in state.get("agents", {}).items():
|
|
524
|
-
window = agent_state.get("window", agent_id)
|
|
525
|
-
log_path = logs_dir(workspace) / f"{agent_id}.scrollback"
|
|
526
|
-
proc = run_cmd(["tmux", "capture-pane", "-p", "-S", "-", "-t", f"{session_name}:{window}"], timeout=10)
|
|
527
|
-
if proc.returncode == 0:
|
|
528
|
-
log_path.write_text(proc.stdout, encoding="utf-8")
|
|
529
|
-
captured.append(str(log_path))
|
|
530
|
-
display_cleanup = _close_team_display_backends(state, event_log)
|
|
531
|
-
for agent_id, agent_state in state.get("agents", {}).items():
|
|
532
|
-
_close_ghostty_display(agent_id, agent_state, event_log)
|
|
533
|
-
closed_displays.add(agent_id)
|
|
534
|
-
proc = run_cmd(["tmux", "kill-session", "-t", session_name], timeout=10)
|
|
535
|
-
if proc.returncode != 0:
|
|
536
|
-
if "can't find session" in proc.stderr:
|
|
537
|
-
event_log.write("shutdown.idempotent", session=session_name, reason="session disappeared before kill")
|
|
538
|
-
else:
|
|
539
|
-
raise RuntimeError(f"tmux kill-session failed: {proc.stderr.strip()}")
|
|
540
|
-
else:
|
|
541
|
-
event_log.write("shutdown.kill_session", session=session_name, keep_logs=keep_logs, captured=captured)
|
|
542
|
-
else:
|
|
543
|
-
event_log.write("shutdown.idempotent", session=session_name, reason="session missing")
|
|
544
|
-
display_cleanup = _close_team_display_backends(state, event_log)
|
|
545
|
-
for agent_id, agent_state in state.get("agents", {}).items():
|
|
546
|
-
if agent_id not in closed_displays:
|
|
547
|
-
_close_ghostty_display(agent_id, agent_state, event_log)
|
|
548
|
-
mcp_path = Path(agent_state["mcp_config"]) if agent_state.get("mcp_config") else None
|
|
549
|
-
try:
|
|
550
|
-
get_adapter(agent_state["provider"]).cleanup_mcp(workspace, agent_id, mcp_path)
|
|
551
|
-
event_log.write(
|
|
552
|
-
"shutdown.mcp_cleanup",
|
|
553
|
-
agent_id=agent_id,
|
|
554
|
-
provider=agent_state.get("provider"),
|
|
555
|
-
mcp_config=str(mcp_path) if mcp_path else None,
|
|
556
|
-
)
|
|
557
|
-
except Exception as exc:
|
|
558
|
-
event_log.write(
|
|
559
|
-
"shutdown.mcp_cleanup_failed",
|
|
560
|
-
agent_id=agent_id,
|
|
561
|
-
provider=agent_state.get("provider"),
|
|
562
|
-
mcp_config=str(mcp_path) if mcp_path else None,
|
|
563
|
-
error=str(exc),
|
|
564
|
-
)
|
|
565
|
-
if agent_state.get("status") != "paused":
|
|
566
|
-
agent_state["status"] = "stopped"
|
|
567
|
-
save_team_scoped_state(workspace, state)
|
|
568
|
-
_save_team_runtime_snapshot(workspace, state)
|
|
569
|
-
# 0.2.6 Family B (C10/C11/C12): atomically unregister the team and
|
|
570
|
-
# archive its runtime snapshot directory. Both branches of --keep-logs
|
|
571
|
-
# still drop the team from state.teams; logs survive inside the
|
|
572
|
-
# archived directory.
|
|
573
|
-
archive_path, teams_remaining, new_active = _commit_shutdown_cleanup(
|
|
574
|
-
workspace, str(resolved_team_id or ""), session_name, event_log
|
|
575
|
-
)
|
|
576
|
-
result = {
|
|
577
|
-
"ok": True,
|
|
578
|
-
"session_name": session_name,
|
|
579
|
-
"team": resolved_team_id,
|
|
580
|
-
"logs": captured,
|
|
581
|
-
"coordinator": coordinator,
|
|
582
|
-
"archive_path": archive_path,
|
|
583
|
-
"teams_remaining": teams_remaining,
|
|
584
|
-
"new_active_team_key": new_active,
|
|
585
|
-
"cleanup_mode": "synchronous_committed",
|
|
586
|
-
}
|
|
587
|
-
removed_orphans = (display_cleanup or {}).get("orphans_removed") or {}
|
|
588
|
-
remaining_orphans = (display_cleanup or {}).get("orphans_detected") or {}
|
|
589
|
-
if removed_orphans:
|
|
590
|
-
result["orphans_detected"] = removed_orphans
|
|
591
|
-
result["warnings"] = ["Adaptive display tmux objects were found and removed during shutdown cleanup."]
|
|
592
|
-
if remaining_orphans:
|
|
593
|
-
result["cleanup_mode"] = "synchronous_with_orphans"
|
|
594
|
-
result["orphans_detected"] = remaining_orphans
|
|
595
|
-
result["warning"] = "Adaptive display tmux objects remain after shutdown cleanup."
|
|
596
|
-
event_log.write(
|
|
597
|
-
"shutdown.orphans_detected",
|
|
598
|
-
warning=result["warning"],
|
|
599
|
-
message=result["warning"],
|
|
600
|
-
orphans_detected=remaining_orphans,
|
|
601
|
-
adaptive_display_sessions=remaining_orphans.get("adaptive_display_sessions", []),
|
|
602
|
-
adaptive_overview_windows=remaining_orphans.get("adaptive_overview_windows", []),
|
|
603
|
-
)
|
|
604
|
-
return result
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
def _commit_shutdown_cleanup(
|
|
608
|
-
workspace: Path,
|
|
609
|
-
team_key: str,
|
|
610
|
-
session_name: str | None,
|
|
611
|
-
event_log: EventLog,
|
|
612
|
-
) -> tuple[str | None, list[str], str | None]:
|
|
613
|
-
import shutil as _shutil
|
|
614
|
-
from datetime import datetime as _dt, timezone as _tz
|
|
615
|
-
workspace_state = load_runtime_state(workspace)
|
|
616
|
-
teams = workspace_state.get("teams") if isinstance(workspace_state.get("teams"), dict) else {}
|
|
617
|
-
if team_key and team_key in teams:
|
|
618
|
-
teams.pop(team_key, None)
|
|
619
|
-
if workspace_state.get("active_team_key") == team_key:
|
|
620
|
-
workspace_state["active_team_key"] = None
|
|
621
|
-
workspace_state["teams"] = teams
|
|
622
|
-
archive_dest: Path | None = None
|
|
623
|
-
if session_name:
|
|
624
|
-
runtime_teams_dir = runtime_dir(workspace) / "teams"
|
|
625
|
-
from team_agent.restart.snapshot import safe_snapshot_name as _safe
|
|
626
|
-
snapshot_name = _safe(str(session_name))
|
|
627
|
-
snapshot_dir = runtime_teams_dir / snapshot_name
|
|
628
|
-
if snapshot_dir.exists():
|
|
629
|
-
ts = _dt.now(_tz.utc).strftime("%Y%m%dT%H%M%SZ")
|
|
630
|
-
archive_dest = runtime_teams_dir / f".archived-{snapshot_name}-{ts}"
|
|
631
|
-
try:
|
|
632
|
-
_shutil.move(str(snapshot_dir), str(archive_dest))
|
|
633
|
-
except OSError as exc:
|
|
634
|
-
event_log.write(
|
|
635
|
-
"team.shutdown_blocked",
|
|
636
|
-
reason="archive_move_failed",
|
|
637
|
-
team_key=team_key,
|
|
638
|
-
error=str(exc),
|
|
639
|
-
hint="check filesystem permissions on .team/runtime/teams and rerun shutdown",
|
|
640
|
-
)
|
|
641
|
-
return None, sorted(teams.keys()), workspace_state.get("active_team_key")
|
|
642
|
-
save_runtime_state(workspace, workspace_state)
|
|
643
|
-
archive_path_str = str(archive_dest) if archive_dest is not None else None
|
|
644
|
-
new_active = workspace_state.get("active_team_key")
|
|
645
|
-
event_log.write(
|
|
646
|
-
"team.shutdown_completed",
|
|
647
|
-
team_key=team_key,
|
|
648
|
-
archive_path=archive_path_str,
|
|
649
|
-
teams_remaining=sorted(teams.keys()),
|
|
650
|
-
new_active_team_key=new_active,
|
|
651
|
-
)
|
|
652
|
-
return archive_path_str, sorted(teams.keys()), new_active
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
def remove_agent(
|
|
657
|
-
workspace: Path,
|
|
658
|
-
agent_id: str,
|
|
659
|
-
*,
|
|
660
|
-
from_spec: bool = False,
|
|
661
|
-
confirm: bool = False,
|
|
662
|
-
force: bool = False,
|
|
663
|
-
team: str | None = None,
|
|
664
|
-
) -> dict[str, Any]:
|
|
665
|
-
from team_agent.lifecycle.agents import remove_agent as lifecycle_remove_agent
|
|
666
|
-
|
|
667
|
-
with _runtime_lock(workspace, "remove-agent"):
|
|
668
|
-
return lifecycle_remove_agent(workspace, agent_id, from_spec=from_spec, confirm=confirm, force=force, team=team)
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
def acknowledge_idle(workspace: Path, agent_id: str | None = None, *, team: str | None = None) -> dict[str, Any]:
|
|
672
|
-
with _runtime_lock(workspace, "acknowledge-idle"):
|
|
673
|
-
try:
|
|
674
|
-
state = select_runtime_state(workspace, team)
|
|
675
|
-
except Exception as exc:
|
|
676
|
-
return {"ok": False, "status": "refused", "reason": "team_target_unresolved", "team": team, "error": str(exc)}
|
|
677
|
-
gate = check_team_owner(state)
|
|
678
|
-
if gate:
|
|
679
|
-
return gate
|
|
680
|
-
now_dt = datetime.now(timezone.utc); now = now_dt.isoformat()
|
|
681
|
-
ttl_seconds = 1800
|
|
682
|
-
expires_at = (now_dt + timedelta(seconds=ttl_seconds)).isoformat()
|
|
683
|
-
owner_team_id = team_state_key(state); coordinator = state.setdefault("coordinator", {})
|
|
684
|
-
coordinator.setdefault("idle_acknowledged", {})[owner_team_id] = {"acknowledged_at": now, "expires_at": expires_at, "ttl_seconds": ttl_seconds}
|
|
685
|
-
team_suppressions = coordinator.setdefault("suppressed_idle_alerts", {}).setdefault(owner_team_id, {})
|
|
686
|
-
entry = {"suppressed_at": now, "suppressed_by": "manual_acknowledge", "manual_acknowledge": True, "expires_at": expires_at, "ttl_seconds": ttl_seconds}
|
|
687
|
-
for worker_id in state.get("agents", {}):
|
|
688
|
-
team_suppressions.setdefault(worker_id, {})["idle_fallback"] = dict(entry)
|
|
689
|
-
save_team_scoped_state(workspace, state)
|
|
690
|
-
EventLog(workspace).write("coordinator.idle_acknowledged", agent_id=agent_id, team=owner_team_id, acknowledged_at=now, expires_at=expires_at, ttl_seconds=ttl_seconds)
|
|
691
|
-
return {"ok": True, "team": owner_team_id, "agent_id": agent_id, "acknowledged_at": now, "expires_at": expires_at, "ttl_seconds": ttl_seconds}
|
|
692
|
-
|
|
693
|
-
_OWNER_IDENTITY_FIELDS = (
|
|
694
|
-
"pane_id",
|
|
695
|
-
"leader_session_uuid",
|
|
696
|
-
"machine_fingerprint",
|
|
697
|
-
"provider",
|
|
698
|
-
"os_user",
|
|
699
|
-
)
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
def _owner_identity_matches(existing: dict[str, Any], candidate: dict[str, Any]) -> bool:
|
|
703
|
-
for field in _OWNER_IDENTITY_FIELDS:
|
|
704
|
-
if str(existing.get(field) or "") != str(candidate.get(field) or ""):
|
|
705
|
-
return False
|
|
706
|
-
return True
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
def _resolve_owner_team_id(state: dict[str, Any], team: str | None) -> str | None:
|
|
710
|
-
if team:
|
|
711
|
-
return str(team)
|
|
712
|
-
active = state.get("active_team_key")
|
|
713
|
-
if active:
|
|
714
|
-
return str(active)
|
|
715
|
-
teams = state.get("teams") or {}
|
|
716
|
-
if isinstance(teams, dict) and len(teams) == 1:
|
|
717
|
-
return next(iter(teams))
|
|
718
|
-
return None
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
def takeover(workspace: Path, team: str | None = None, confirm: bool = False) -> dict[str, Any]:
|
|
722
|
-
"""0.2.6 Family A: positive-source ownership rebind.
|
|
723
|
-
|
|
724
|
-
Identity is sourced exclusively from ``bind_owner_from_caller_pane``
|
|
725
|
-
(``$TMUX_PANE`` + one targeted ``tmux display-message``). The new
|
|
726
|
-
owner record force-writes every identity field into
|
|
727
|
-
``state.teams[<team_id>].team_owner``; old fields are not merged,
|
|
728
|
-
migrated, or setdefaulted. Idempotent: re-running with the same
|
|
729
|
-
caller identity returns success without mutating state.
|
|
730
|
-
"""
|
|
731
|
-
if not confirm:
|
|
732
|
-
return {
|
|
733
|
-
"ok": False,
|
|
734
|
-
"status": "refused",
|
|
735
|
-
"reason": "confirm_required",
|
|
736
|
-
"action": "rerun with --confirm to claim ownership of this team",
|
|
737
|
-
}
|
|
738
|
-
from team_agent.leader_binding import (
|
|
739
|
-
bind_owner_from_caller_pane,
|
|
740
|
-
emit_owner_bound_event,
|
|
741
|
-
)
|
|
742
|
-
with _runtime_lock(workspace, LEADER_OWNERSHIP_LOCK):
|
|
743
|
-
state = load_runtime_state(workspace)
|
|
744
|
-
team_id = _resolve_owner_team_id(state, team)
|
|
745
|
-
if not team_id:
|
|
746
|
-
return {
|
|
747
|
-
"ok": False,
|
|
748
|
-
"status": "refused",
|
|
749
|
-
"reason": "team_target_unresolved",
|
|
750
|
-
"team": team,
|
|
751
|
-
"hint": "pass --team <name> or run quick-start first to register an active team.",
|
|
752
|
-
}
|
|
753
|
-
bind = bind_owner_from_caller_pane(workspace, team_id)
|
|
754
|
-
if not bind.get("ok"):
|
|
755
|
-
return {"ok": False, "status": "refused", **bind}
|
|
756
|
-
new_owner = bind["owner"]
|
|
757
|
-
teams = state.setdefault("teams", {})
|
|
758
|
-
team_entry = teams.get(team_id) or {}
|
|
759
|
-
existing_owner = team_entry.get("team_owner") if isinstance(team_entry.get("team_owner"), dict) else {}
|
|
760
|
-
if existing_owner and _owner_identity_matches(existing_owner, new_owner):
|
|
761
|
-
return {
|
|
762
|
-
"ok": True,
|
|
763
|
-
"status": "claimed",
|
|
764
|
-
"team": team_id,
|
|
765
|
-
"team_owner": existing_owner,
|
|
766
|
-
"idempotent": True,
|
|
767
|
-
}
|
|
768
|
-
team_entry["team_owner"] = new_owner
|
|
769
|
-
teams[team_id] = team_entry
|
|
770
|
-
if team_state_key(state) == team_id:
|
|
771
|
-
state["team_owner"] = new_owner
|
|
772
|
-
from team_agent.leader import _write_lease_dual_state
|
|
773
|
-
_write_lease_dual_state(workspace, state)
|
|
774
|
-
emit_owner_bound_event(
|
|
775
|
-
workspace,
|
|
776
|
-
caller_pane_id=bind.get("caller_pane_id", ""),
|
|
777
|
-
caller_current_command=bind.get("caller_current_command", ""),
|
|
778
|
-
derived_leader_session_uuid=new_owner["leader_session_uuid"],
|
|
779
|
-
team_id=team_id,
|
|
780
|
-
old_leader_session_uuid=str(existing_owner.get("leader_session_uuid") or ""),
|
|
781
|
-
)
|
|
782
|
-
return {
|
|
783
|
-
"ok": True,
|
|
784
|
-
"status": "claimed",
|
|
785
|
-
"team": team_id,
|
|
786
|
-
"team_owner": new_owner,
|
|
787
|
-
"previous_owner": existing_owner or None,
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
def claim_leader(workspace: Path, team: str | None = None, confirm: bool = False) -> dict[str, Any]:
|
|
792
|
-
"""0.2.6 Family A: positive-source claim-leader.
|
|
793
|
-
|
|
794
|
-
Calls :func:`bind_owner_from_caller_pane` to confirm the caller is in
|
|
795
|
-
a leader-shaped tmux pane, then delegates to the legacy multi-
|
|
796
|
-
candidate lease arbiter for residual handling. The bind step is the
|
|
797
|
-
only source of caller identity; the legacy lease path no longer
|
|
798
|
-
re-derives it.
|
|
799
|
-
"""
|
|
800
|
-
from team_agent.leader_binding import bind_owner_from_caller_pane
|
|
801
|
-
state = load_runtime_state(workspace)
|
|
802
|
-
team_id = _resolve_owner_team_id(state, team) or team_state_key(state)
|
|
803
|
-
bind = bind_owner_from_caller_pane(workspace, team_id)
|
|
804
|
-
if not bind.get("ok"):
|
|
805
|
-
return {"ok": False, "status": "refused", **bind}
|
|
806
|
-
return _legacy_claim_leader(workspace, team=team, confirm=confirm)
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
def quick_start(
|
|
810
|
-
agents_dir: Path,
|
|
811
|
-
name: str | None = None,
|
|
812
|
-
yes: bool = False,
|
|
813
|
-
fresh: bool = False,
|
|
814
|
-
team_id: str | None = None,
|
|
815
|
-
) -> dict[str, Any]:
|
|
816
|
-
"""0.2.6 Family A: positive-source quick-start.
|
|
817
|
-
|
|
818
|
-
The caller-pane shape gate is owned by
|
|
819
|
-
:func:`bind_owner_from_caller_pane`. Quick-start binds the caller
|
|
820
|
-
pane BEFORE any team setup runs; ``$TMUX_PANE`` missing or the
|
|
821
|
-
caller pane not running a leader host short-circuits to a refusal
|
|
822
|
-
(no fallback to legacy reverse-scan). On success, the legacy
|
|
823
|
-
bootstrap brings up the workspace and the bind-derived
|
|
824
|
-
``team_owner`` is force-written into
|
|
825
|
-
``state.teams[team_id].team_owner`` so the runtime owner identity
|
|
826
|
-
matches the caller pane verbatim.
|
|
827
|
-
"""
|
|
828
|
-
from team_agent.leader_binding import (
|
|
829
|
-
bind_owner_from_caller_pane,
|
|
830
|
-
emit_owner_bound_event,
|
|
831
|
-
)
|
|
832
|
-
from team_agent.diagnose.quick_start import prepare_quick_start_team
|
|
833
|
-
|
|
834
|
-
# Pre-resolve team_dir + workspace so the caller-pane bind can write
|
|
835
|
-
# its audit event before any worker is spawned. ``prepare_quick_start_team``
|
|
836
|
-
# is idempotent (mkdir + shutil.copy2 of role docs) and used inside
|
|
837
|
-
# ``_legacy_quick_start`` as the very first step anyway.
|
|
838
|
-
team_dir = prepare_quick_start_team(
|
|
839
|
-
Path(agents_dir).resolve(), Path.cwd().resolve(), name, team_id=team_id
|
|
840
|
-
)
|
|
841
|
-
workspace = team_workspace(team_dir)
|
|
842
|
-
ensure_workspace_dirs(workspace)
|
|
843
|
-
# Spark MED 1 (b1b17b1 review): the on-disk team_dir already passed
|
|
844
|
-
# through ``_safe_snapshot_name``; reusing ``team_dir.name`` here
|
|
845
|
-
# keeps the on-disk path and the state.teams key aligned. Using the
|
|
846
|
-
# raw ``team_id`` would have split the two writes whenever the
|
|
847
|
-
# caller-supplied id contained spaces or shell-unsafe characters.
|
|
848
|
-
resolved_team_id = team_dir.name or "current"
|
|
849
|
-
bind = bind_owner_from_caller_pane(workspace, resolved_team_id)
|
|
850
|
-
if not bind.get("ok"):
|
|
851
|
-
return {"ok": False, "status": "refused", **bind}
|
|
852
|
-
new_owner = bind["owner"]
|
|
853
|
-
result = _legacy_quick_start(
|
|
854
|
-
Path(agents_dir).resolve(), name=name, yes=yes, fresh=fresh, team_id=team_id
|
|
855
|
-
)
|
|
856
|
-
# Spark MED 2 (b1b17b1 review): only commit the owner force-write
|
|
857
|
-
# and emit ``owner.bound_from_caller_pane`` when the legacy bootstrap
|
|
858
|
-
# actually succeeded. Otherwise pass the refusal envelope back
|
|
859
|
-
# verbatim — ``existing_runtime_state`` / ``preflight`` failures
|
|
860
|
-
# must not leave a "team owner claimed" side effect behind.
|
|
861
|
-
if not result.get("ok"):
|
|
862
|
-
return result
|
|
863
|
-
state = load_runtime_state(workspace)
|
|
864
|
-
teams = state.setdefault("teams", {})
|
|
865
|
-
team_entry = teams.get(resolved_team_id) or {}
|
|
866
|
-
existing_owner = (
|
|
867
|
-
team_entry.get("team_owner")
|
|
868
|
-
if isinstance(team_entry.get("team_owner"), dict)
|
|
869
|
-
else {}
|
|
870
|
-
)
|
|
871
|
-
if not (existing_owner and _owner_identity_matches(existing_owner, new_owner)):
|
|
872
|
-
team_entry["team_owner"] = new_owner
|
|
873
|
-
teams[resolved_team_id] = team_entry
|
|
874
|
-
if not state.get("active_team_key"):
|
|
875
|
-
state["active_team_key"] = resolved_team_id
|
|
876
|
-
from team_agent.leader import _write_lease_dual_state
|
|
877
|
-
_write_lease_dual_state(workspace, state)
|
|
878
|
-
emit_owner_bound_event(
|
|
879
|
-
workspace,
|
|
880
|
-
caller_pane_id=bind.get("caller_pane_id", ""),
|
|
881
|
-
caller_current_command=bind.get("caller_current_command", ""),
|
|
882
|
-
derived_leader_session_uuid=new_owner["leader_session_uuid"],
|
|
883
|
-
team_id=resolved_team_id,
|
|
884
|
-
old_leader_session_uuid=str(existing_owner.get("leader_session_uuid") or ""),
|
|
885
|
-
)
|
|
886
|
-
return result
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
def _running_agent_state(workspace: Path, agent: dict[str, Any], previous: dict[str, Any]) -> dict[str, Any]:
|
|
890
|
-
agent_state = dict(previous)
|
|
891
|
-
agent_state.update(
|
|
892
|
-
{
|
|
893
|
-
"status": "running",
|
|
894
|
-
"provider": agent["provider"],
|
|
895
|
-
"agent_id": agent["id"],
|
|
896
|
-
"model": agent.get("model"),
|
|
897
|
-
"auth_mode": agent.get("auth_mode"),
|
|
898
|
-
"profile": agent.get("profile"),
|
|
899
|
-
"window": agent["id"],
|
|
900
|
-
"permissions": resolve_permissions(agent),
|
|
901
|
-
"spawn_cwd": str(workspace),
|
|
902
|
-
}
|
|
903
|
-
)
|
|
904
|
-
return agent_state
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
def _handle_startup_prompts_and_verify_window(
|
|
908
|
-
adapter: Any,
|
|
909
|
-
event_log: EventLog,
|
|
910
|
-
event_prefix: str,
|
|
911
|
-
agent_id: str,
|
|
912
|
-
provider: str,
|
|
913
|
-
session_name: str,
|
|
914
|
-
start_mode: str,
|
|
915
|
-
) -> bool:
|
|
916
|
-
handled_prompts = adapter.handle_startup_prompts(session_name, agent_id, checks=20, sleep_s=0.5)
|
|
917
|
-
for prompt_event in handled_prompts:
|
|
918
|
-
event_log.write(f"{event_prefix}.startup_prompt_handled", agent_id=agent_id, provider=provider, **prompt_event)
|
|
919
|
-
deadline = time.monotonic() + 1.0
|
|
920
|
-
saw_window = False
|
|
921
|
-
while True:
|
|
922
|
-
if _tmux_window_exists(session_name, agent_id):
|
|
923
|
-
saw_window = True
|
|
924
|
-
if time.monotonic() >= deadline:
|
|
925
|
-
return True
|
|
926
|
-
elif saw_window or time.monotonic() >= deadline:
|
|
927
|
-
break
|
|
928
|
-
time.sleep(0.2)
|
|
929
|
-
event_log.write(
|
|
930
|
-
f"{event_prefix}.window_missing_after_start",
|
|
931
|
-
agent_id=agent_id,
|
|
932
|
-
provider=provider,
|
|
933
|
-
start_mode=start_mode,
|
|
934
|
-
target=f"{session_name}:{agent_id}",
|
|
935
|
-
saw_window=saw_window,
|
|
936
|
-
)
|
|
937
|
-
return False
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
def shutil_which(command: str) -> str | None:
|
|
943
|
-
from shutil import which
|
|
944
|
-
|
|
945
|
-
return which(command)
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
@contextmanager
|
|
949
|
-
def _runtime_lock(workspace: Path, name: str, timeout: float = 5.0):
|
|
950
|
-
lock_path = runtime_dir(workspace) / f"{name}.lock"
|
|
951
|
-
lock_path.parent.mkdir(parents=True, exist_ok=True)
|
|
952
|
-
event_log = EventLog(workspace)
|
|
953
|
-
log_lock_events = name != "state-save"
|
|
954
|
-
start = time.monotonic()
|
|
955
|
-
with lock_path.open("w", encoding="utf-8") as lock_file:
|
|
956
|
-
while True:
|
|
957
|
-
try:
|
|
958
|
-
fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
959
|
-
waited = time.monotonic() - start
|
|
960
|
-
if log_lock_events:
|
|
961
|
-
event_log.write("runtime.lock_acquired", lock=name, waited_sec=round(waited, 3))
|
|
962
|
-
break
|
|
963
|
-
except BlockingIOError:
|
|
964
|
-
if time.monotonic() - start >= timeout:
|
|
965
|
-
if log_lock_events:
|
|
966
|
-
event_log.write("runtime.lock_busy", lock=name, timeout_sec=timeout)
|
|
967
|
-
raise RuntimeError(
|
|
968
|
-
f"{name} is locked by another team-agent process; serialize team-agent {name} calls and retry"
|
|
969
|
-
)
|
|
970
|
-
time.sleep(0.05)
|
|
971
|
-
try:
|
|
972
|
-
yield
|
|
973
|
-
finally:
|
|
974
|
-
fcntl.flock(lock_file.fileno(), fcntl.LOCK_UN)
|
|
975
|
-
if log_lock_events:
|
|
976
|
-
event_log.write("runtime.lock_released", lock=name)
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
def _leader_id(state: dict[str, Any], spec: dict[str, Any]) -> str:
|
|
980
|
-
return state.get("leader", {}).get("id") or spec.get("leader", {}).get("id") or "leader"
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
def _is_leader_sender(sender: str, leader_id: str) -> bool:
|
|
984
|
-
return sender in {leader_id, "leader", "Leader"}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
def _is_leader_target(target: str | None, leader_id: str) -> bool:
|
|
988
|
-
return target in {leader_id, "leader", "Leader"}
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
def _spec_agent_ids(spec: dict[str, Any]) -> list[str]:
|
|
992
|
-
return [str(agent["id"]) for agent in spec.get("agents", [])]
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
def _runtime_team_agent_ids(state: dict[str, Any], spec: dict[str, Any]) -> list[str]:
|
|
996
|
-
runtime_agents = state.get("agents", {})
|
|
997
|
-
return [agent_id for agent_id in _spec_agent_ids(spec) if agent_id in runtime_agents]
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
def _is_runtime_team_agent(agent_id: str, state: dict[str, Any], spec: dict[str, Any]) -> bool:
|
|
1001
|
-
return agent_id in set(_runtime_team_agent_ids(state, spec))
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
def get_adapter_or_raise(name: str) -> str:
|
|
1005
|
-
if name == "tmux" and not shutil_which("tmux"):
|
|
1006
|
-
raise RuntimeError("tmux is not installed; install tmux 3.3+ before launch")
|
|
1007
|
-
return name
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
def _tmux_session_exists(session_name: str | None) -> bool:
|
|
1011
|
-
if not session_name:
|
|
1012
|
-
return False
|
|
1013
|
-
proc = run_cmd(["tmux", "has-session", "-t", session_name], timeout=5)
|
|
1014
|
-
return proc.returncode == 0
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
def _tmux_start_command_for_agent_window(session_name: str, window_name: str, command: str) -> tuple[list[str], str]:
|
|
1018
|
-
if _tmux_session_exists(session_name):
|
|
1019
|
-
return ["tmux", "new-window", "-t", session_name, "-n", window_name, "sh", "-lc", command], "new-window"
|
|
1020
|
-
return ["tmux", "new-session", "-d", "-s", session_name, "-n", window_name, "sh", "-lc", command], "new-session"
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
def _tmux_window_exists(session_name: str | None, window: str | None) -> bool:
|
|
1024
|
-
if not session_name or not window:
|
|
1025
|
-
return False
|
|
1026
|
-
proc = run_cmd(["tmux", "list-windows", "-t", session_name, "-F", "#{window_name}"], timeout=5)
|
|
1027
|
-
if proc.returncode != 0:
|
|
1028
|
-
return False
|
|
1029
|
-
return window in proc.stdout.splitlines()
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
def _find_task(tasks: list[dict[str, Any]], task_id: str) -> dict[str, Any]:
|
|
1033
|
-
for task in tasks:
|
|
1034
|
-
if task.get("id") == task_id:
|
|
1035
|
-
return task
|
|
1036
|
-
raise RuntimeError(f"unknown task id: {task_id}")
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
def _find_task_or_none(tasks: list[dict[str, Any]], task_id: str) -> dict[str, Any] | None:
|
|
1040
|
-
for task in tasks:
|
|
1041
|
-
if task.get("id") == task_id:
|
|
1042
|
-
return task
|
|
1043
|
-
return None
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
def _is_message_scoped_result(store: MessageStore, envelope: dict[str, Any]) -> bool:
|
|
1047
|
-
task_id = str(envelope.get("task_id") or "")
|
|
1048
|
-
agent_id = str(envelope.get("agent_id") or "")
|
|
1049
|
-
if not task_id.startswith("msg_"):
|
|
1050
|
-
return False
|
|
1051
|
-
message = _message_by_id(store, task_id)
|
|
1052
|
-
return bool(message and message.get("recipient") == agent_id)
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
def _find_agent(spec: dict[str, Any], agent_id: str | None) -> dict[str, Any] | None:
|
|
1056
|
-
if not agent_id:
|
|
1057
|
-
return None
|
|
1058
|
-
for agent in spec.get("agents", []):
|
|
1059
|
-
if agent.get("id") == agent_id:
|
|
1060
|
-
return agent
|
|
1061
|
-
if spec.get("leader", {}).get("id") == agent_id:
|
|
1062
|
-
return spec["leader"]
|
|
1063
|
-
return None
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
def _result_status_to_task_status(task: dict[str, Any], result_status: str) -> str:
|
|
1067
|
-
if result_status == "success":
|
|
1068
|
-
return "done"
|
|
1069
|
-
if result_status == "blocked":
|
|
1070
|
-
return "blocked"
|
|
1071
|
-
if result_status in {"partial", "failed"}:
|
|
1072
|
-
return _retry_or_failed(task)
|
|
1073
|
-
raise KeyError(result_status)
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
def _retry_or_failed(task: dict[str, Any]) -> str:
|
|
1077
|
-
retry_count = int(task.get("retry_count") or 0)
|
|
1078
|
-
retry_limit = int(task.get("retry_limit") or 0)
|
|
1079
|
-
if retry_count < retry_limit:
|
|
1080
|
-
task["retry_count"] = retry_count + 1
|
|
1081
|
-
return "needs_retry"
|
|
1082
|
-
task["retry_count"] = retry_count
|
|
1083
|
-
return "failed"
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
def _deliver_pending_message(workspace: Path, state: dict[str, Any], message_id: str, wait_visible: bool = True, timeout: float = 30.0, *, _trust_retry_attempt: int = 1) -> dict[str, Any]:
|
|
1087
|
-
from team_agent.messaging.delivery import _deliver_pending_message as impl
|
|
1088
|
-
|
|
1089
|
-
return impl(workspace, state, message_id, wait_visible, timeout, _trust_retry_attempt=_trust_retry_attempt)
|
|
1090
|
-
|
|
1091
|
-
def _enable_codex_fast_mode(session_name: str, window_name: str) -> dict[str, Any]:
|
|
1092
|
-
from team_agent.messaging.tmux_prompt import _enable_codex_fast_mode as impl
|
|
1093
|
-
|
|
1094
|
-
return impl(session_name, window_name)
|
|
1095
|
-
|
|
1096
|
-
def _leader_command_provider(command: str) -> str | None:
|
|
1097
|
-
from team_agent.messaging.leader_panes import _leader_command_provider as impl
|
|
1098
|
-
|
|
1099
|
-
return impl(command)
|
|
1100
|
-
|
|
1101
|
-
def _message_by_id(store: MessageStore, message_id: str) -> dict[str, Any] | None:
|
|
1102
|
-
from team_agent.messaging.leader import _message_by_id as impl
|
|
1103
|
-
|
|
1104
|
-
return impl(store, message_id)
|
|
1105
|
-
|
|
1106
|
-
def _resolve_leader_pane(pane: str | None, provider: str, workspace: Path | None = None, require_current: bool = False) -> tuple[dict[str, str], str]:
|
|
1107
|
-
from team_agent.messaging.leader_panes import _resolve_leader_pane as impl
|
|
1108
|
-
|
|
1109
|
-
return impl(pane, provider, workspace, require_current)
|
|
1110
|
-
|
|
1111
|
-
def _target_fingerprint(pane_info: dict[str, Any]) -> str:
|
|
1112
|
-
from team_agent.messaging.leader_panes import _target_fingerprint as impl
|
|
1113
|
-
|
|
1114
|
-
return impl(pane_info)
|
|
1115
|
-
|
|
1116
|
-
def _validate_leader_receiver(receiver: dict[str, Any]) -> dict[str, Any]:
|
|
1117
|
-
from team_agent.messaging.leader_panes import _validate_leader_receiver as impl
|
|
1118
|
-
|
|
1119
|
-
return impl(receiver)
|
|
1120
|
-
|
|
1121
|
-
def collect(workspace: Path, result_file: Path | None = None, *, ensure_coordinator: bool = True) -> dict[str, Any]:
|
|
1122
|
-
from team_agent.messaging.results import collect as impl
|
|
1123
|
-
|
|
1124
|
-
return impl(workspace, result_file, ensure_coordinator=ensure_coordinator)
|
|
1125
|
-
|
|
1126
|
-
def send_message(workspace: Path, target: str | list[str] | None, content: str, task_id: str | None = None, sender: str = "leader", requires_ack: bool = True, confirm_human: bool = False, wait_visible: bool = True, timeout: float = 30.0, lock_timeout: float = 5.0, watch_result: bool = False, block_until_delivered: bool = True, team: str | None = None) -> dict[str, Any]:
|
|
1127
|
-
from team_agent.messaging.send import send_message as impl
|
|
1128
|
-
|
|
1129
|
-
return impl(workspace, target, content, task_id, sender, requires_ack, confirm_human, wait_visible, timeout, lock_timeout, watch_result, block_until_delivered, team)
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
# Lazy-resolved delegation surface. 77 wrappers that used to live inline in
|
|
1133
|
-
# runtime.py collapse into this single map plus a PEP 562 __getattr__. Tests
|
|
1134
|
-
# that patch team_agent.runtime.<name> still work because mock.patch's
|
|
1135
|
-
# setattr shadows the attribute via runtime.__dict__ until the patch exits;
|
|
1136
|
-
# attribute access outside a patch resolves via __getattr__ which imports
|
|
1137
|
-
# the target module lazily (no top-level cycle into messaging/lifecycle/etc.).
|
|
1138
|
-
_DELEGATE_MAP: dict[str, str] = {
|
|
1139
|
-
'_broadcast_message_unlocked': 'team_agent.messaging.send._broadcast_message_unlocked',
|
|
1140
|
-
'_broadcast_targets': 'team_agent.messaging.send._broadcast_targets',
|
|
1141
|
-
'_capture_contains_message_fragment': 'team_agent.messaging.tmux_prompt._capture_contains_message_fragment',
|
|
1142
|
-
'_capture_has_pasted_content_prompt': 'team_agent.messaging.tmux_prompt._capture_has_pasted_content_prompt',
|
|
1143
|
-
'_capture_tmux_pane_text': 'team_agent.messaging.tmux_prompt._capture_tmux_pane_text',
|
|
1144
|
-
'_choose_leader_submit_key': 'team_agent.messaging.leader_panes._choose_leader_submit_key',
|
|
1145
|
-
'_collect_results_and_notify_watchers': 'team_agent.messaging.results._collect_results_and_notify_watchers',
|
|
1146
|
-
'_compact_broadcast_delivery': 'team_agent.messaging.send._compact_broadcast_delivery',
|
|
1147
|
-
'_compact_visible_text': 'team_agent.messaging.tmux_prompt._compact_visible_text',
|
|
1148
|
-
'_coordinator_should_run': 'team_agent.messaging.results._coordinator_should_run',
|
|
1149
|
-
'_deliver_pending_messages': 'team_agent.messaging.delivery._deliver_pending_messages',
|
|
1150
|
-
'_detect_stuck_agents': 'team_agent.messaging.scheduler._detect_stuck_agents',
|
|
1151
|
-
'_ensure_coordinator_after_collect': 'team_agent.messaging.results._ensure_coordinator_after_collect',
|
|
1152
|
-
'_fail_leader_delivery': 'team_agent.messaging.leader._fail_leader_delivery',
|
|
1153
|
-
'_fire_due_scheduled_events': 'team_agent.messaging.scheduler._fire_due_scheduled_events',
|
|
1154
|
-
'_format_leader_pane_candidates': 'team_agent.messaging.leader_panes._format_leader_pane_candidates',
|
|
1155
|
-
'_format_report_result_notification': 'team_agent.messaging.results._format_report_result_notification',
|
|
1156
|
-
'_format_result_watcher_notification': 'team_agent.messaging.results._format_result_watcher_notification',
|
|
1157
|
-
'_format_team_agent_message': 'team_agent.messaging.leader._format_team_agent_message',
|
|
1158
|
-
'_infer_active_tmux_pane': 'team_agent.messaging.leader_panes._infer_active_tmux_pane',
|
|
1159
|
-
'_infer_workspace_tmux_pane': 'team_agent.messaging.leader_panes._infer_workspace_tmux_pane',
|
|
1160
|
-
'_is_strong_message_fragment': 'team_agent.messaging.tmux_prompt._is_strong_message_fragment',
|
|
1161
|
-
'_leader_command_is_exact': 'team_agent.messaging.leader_panes._leader_command_is_exact',
|
|
1162
|
-
'_leader_command_looks_usable': 'team_agent.messaging.leader_panes._leader_command_looks_usable',
|
|
1163
|
-
'_leader_inbox_path': 'team_agent.messaging.leader._leader_inbox_path',
|
|
1164
|
-
'_leader_pane_rank': 'team_agent.messaging.leader_panes._leader_pane_rank',
|
|
1165
|
-
'_leader_receiver_is_direct': 'team_agent.messaging.leader._leader_receiver_is_direct',
|
|
1166
|
-
'_leader_submit_verification': 'team_agent.messaging.tmux_io._leader_submit_verification',
|
|
1167
|
-
'_message_content_lines': 'team_agent.messaging.tmux_prompt._message_content_lines',
|
|
1168
|
-
'_message_fragment_candidates': 'team_agent.messaging.tmux_prompt._message_fragment_candidates',
|
|
1169
|
-
'_message_payload': 'team_agent.messaging.leader._message_payload',
|
|
1170
|
-
'_mirror_peer_message_to_leader': 'team_agent.messaging.leader._mirror_peer_message_to_leader',
|
|
1171
|
-
'_notify_leader_of_report_result': 'team_agent.messaging.results._notify_leader_of_report_result',
|
|
1172
|
-
'_notify_result_watchers': 'team_agent.messaging.results._notify_result_watchers',
|
|
1173
|
-
'_pane_is_usable_leader': 'team_agent.messaging.leader_panes._pane_is_usable_leader',
|
|
1174
|
-
'_pane_path_matches_workspace': 'team_agent.messaging.leader_panes._pane_path_matches_workspace',
|
|
1175
|
-
'_parse_tmux_pane_info': 'team_agent.messaging.leader_panes._parse_tmux_pane_info',
|
|
1176
|
-
'_prepare_tmux_pane_for_input': 'team_agent.messaging.tmux_io._prepare_tmux_pane_for_input',
|
|
1177
|
-
'_record_invalid_result': 'team_agent.messaging.results._record_invalid_result',
|
|
1178
|
-
'_rediscover_leader_receiver': 'team_agent.messaging.leader_panes._rediscover_leader_receiver',
|
|
1179
|
-
'_schedule_send_retry': 'team_agent.messaging.scheduler._schedule_send_retry',
|
|
1180
|
-
'_send_message_unlocked': 'team_agent.messaging.send._send_message_unlocked',
|
|
1181
|
-
'_send_single_message_unlocked': 'team_agent.messaging.send._send_single_message_unlocked',
|
|
1182
|
-
'_send_to_leader_receiver': 'team_agent.messaging.leader._send_to_leader_receiver',
|
|
1183
|
-
'_start_agent_unlocked': 'team_agent.lifecycle.start._start_agent_unlocked',
|
|
1184
|
-
'_submit_worker_prompt': 'team_agent.messaging.tmux_prompt._submit_worker_prompt',
|
|
1185
|
-
'_team_state_result_entries': 'team_agent.messaging.results._team_state_result_entries',
|
|
1186
|
-
'_tmux_current_client_pane_info': 'team_agent.messaging.leader_panes._tmux_current_client_pane_info',
|
|
1187
|
-
'_tmux_inject_text': 'team_agent.messaging.tmux_io._tmux_inject_text',
|
|
1188
|
-
'_tmux_list_panes': 'team_agent.messaging.leader_panes._tmux_list_panes',
|
|
1189
|
-
'_tmux_load_buffer_stdin': 'team_agent.messaging.tmux_io._tmux_load_buffer_stdin',
|
|
1190
|
-
'_tmux_pane_info': 'team_agent.messaging.leader_panes._tmux_pane_info',
|
|
1191
|
-
'_tmux_paste_ready_timeout': 'team_agent.messaging.tmux_io._tmux_paste_ready_timeout',
|
|
1192
|
-
'_tmux_set_buffer_text': 'team_agent.messaging.tmux_io._tmux_set_buffer_text',
|
|
1193
|
-
'_tmux_submit_settle_timeout': 'team_agent.messaging.tmux_io._tmux_submit_settle_timeout',
|
|
1194
|
-
'_tmux_text_size': 'team_agent.messaging.tmux_io._tmux_text_size',
|
|
1195
|
-
'_tmux_truthy': 'team_agent.messaging.leader_panes._tmux_truthy',
|
|
1196
|
-
'_wait_for_message_ready': 'team_agent.messaging.tmux_prompt._wait_for_message_ready',
|
|
1197
|
-
'_wait_for_pasted_prompt_cleared': 'team_agent.messaging.tmux_prompt._wait_for_pasted_prompt_cleared',
|
|
1198
|
-
'_wait_for_visible_token': 'team_agent.messaging.tmux_prompt._wait_for_visible_token',
|
|
1199
|
-
'_wait_for_worker_message_ready': 'team_agent.messaging.tmux_prompt._wait_for_worker_message_ready',
|
|
1200
|
-
'_watcher_matches_result': 'team_agent.messaging.results._watcher_matches_result',
|
|
1201
|
-
'_write_leader_fallback_audit': 'team_agent.messaging.leader._write_leader_fallback_audit',
|
|
1202
|
-
'add_agent': 'team_agent.lifecycle.operations.add_agent',
|
|
1203
|
-
'allow_peer_talk': 'team_agent.messaging.leader.allow_peer_talk',
|
|
1204
|
-
'fork_agent': 'team_agent.lifecycle.operations.fork_agent',
|
|
1205
|
-
'report_result': 'team_agent.messaging.results.report_result',
|
|
1206
|
-
'reset_agent': 'team_agent.lifecycle.operations.reset_agent',
|
|
1207
|
-
'start_agent': 'team_agent.lifecycle.start.start_agent',
|
|
1208
|
-
'stop_agent': 'team_agent.lifecycle.operations.stop_agent',
|
|
1209
|
-
'stuck_cancel': 'team_agent.messaging.scheduler.stuck_cancel',
|
|
1210
|
-
'stuck_list': 'team_agent.messaging.scheduler.stuck_list',
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
def __getattr__(name: str) -> Any:
|
|
1215
|
-
target = _DELEGATE_MAP.get(name)
|
|
1216
|
-
if target is None:
|
|
1217
|
-
raise AttributeError(f"module 'team_agent.runtime' has no attribute {name!r}")
|
|
1218
|
-
module_path, _, attr = target.rpartition('.')
|
|
1219
|
-
import importlib
|
|
1220
|
-
try:
|
|
1221
|
-
# Eager import + cache so subsequent runtime.<name> lookups return
|
|
1222
|
-
# the same object (stable identity), preserve the real callable's
|
|
1223
|
-
# signature/docstring/qualname for inspect.signature and
|
|
1224
|
-
# functools.wraps, and skip __getattr__ entirely on the hot path.
|
|
1225
|
-
real = getattr(importlib.import_module(module_path), attr)
|
|
1226
|
-
except Exception:
|
|
1227
|
-
# Partial-load fallback: messaging/deps.py runs a top-level
|
|
1228
|
-
# hasattr(_runtime, _name) sweep while the messaging package is
|
|
1229
|
-
# still loading, so eager import of a messaging.* target would
|
|
1230
|
-
# cycle. Return a deferred proxy that retries at call time and
|
|
1231
|
-
# self-installs the real callable on first successful call so
|
|
1232
|
-
# subsequent calls hit the cache.
|
|
1233
|
-
def _proxy(*args: Any, **kwargs: Any) -> Any:
|
|
1234
|
-
real_callable = getattr(importlib.import_module(module_path), attr)
|
|
1235
|
-
globals()[name] = real_callable
|
|
1236
|
-
return real_callable(*args, **kwargs)
|
|
1237
|
-
|
|
1238
|
-
_proxy.__name__ = name
|
|
1239
|
-
_proxy.__qualname__ = name
|
|
1240
|
-
_proxy.__module__ = "team_agent.runtime"
|
|
1241
|
-
return _proxy
|
|
1242
|
-
globals()[name] = real
|
|
1243
|
-
return real
|