@team-agent/installer 0.2.10 → 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 -83
- package/src/team_agent/coordinator/lifecycle.py +0 -363
- 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 -200
- package/src/team_agent/idle_takeover.py +0 -59
- package/src/team_agent/idle_takeover_wiring.py +0 -111
- 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 -254
- package/src/team_agent/messaging/delivery.py +0 -473
- 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 -457
- 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 -86
- 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 -1239
- 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 -143
- 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 -602
- 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,481 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import argparse
|
|
4
|
-
import json
|
|
5
|
-
import shutil
|
|
6
|
-
import sys
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
from typing import Any
|
|
9
|
-
|
|
10
|
-
from team_agent import compiler, profiles, runtime
|
|
11
|
-
from team_agent.errors import TeamAgentError
|
|
12
|
-
from team_agent.paths import repo_root, team_workspace
|
|
13
|
-
from team_agent.spec import validate_result_envelope
|
|
14
|
-
|
|
15
|
-
from team_agent.cli.helpers import _provider_args
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def cmd_quick_start(args: argparse.Namespace) -> dict[str, Any]:
|
|
19
|
-
result = runtime.quick_start(Path(args.agents_dir), name=args.name, yes=args.yes, fresh=args.fresh, team_id=args.team_id)
|
|
20
|
-
if args.json or not result.get("ok"):
|
|
21
|
-
return result
|
|
22
|
-
return result["summary"]
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def cmd_codex(args: argparse.Namespace) -> None:
|
|
26
|
-
runtime.start_leader("codex", _provider_args(args.provider_args), Path.cwd().resolve())
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def cmd_claude(args: argparse.Namespace) -> None:
|
|
30
|
-
runtime.start_leader("claude_code", _provider_args(args.provider_args), Path.cwd().resolve())
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def cmd_init(args: argparse.Namespace) -> dict[str, Any]:
|
|
34
|
-
paths = runtime.init_workspace(Path(args.workspace).resolve(), force=args.force)
|
|
35
|
-
return {"ok": True, "spec": str(paths["spec"]), "state": str(paths["state"])}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def cmd_validate(args: argparse.Namespace) -> dict[str, Any]:
|
|
39
|
-
return runtime.validate_file(Path(args.spec).resolve())
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def cmd_compile(args: argparse.Namespace) -> dict[str, Any]:
|
|
43
|
-
result = compiler.compile_team(Path(args.team).resolve(), Path(args.out).resolve())
|
|
44
|
-
return {"ok": True, "team_dir": result["team_dir"], "out": result["out"], "agents": [a["id"] for a in result["spec"]["agents"]]}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def _profile_scope(args: argparse.Namespace) -> tuple[Path, Path | None]:
|
|
48
|
-
team = getattr(args, "team", None)
|
|
49
|
-
if team:
|
|
50
|
-
team_dir = Path(team).resolve()
|
|
51
|
-
return team_workspace(team_dir), team_dir / "profiles"
|
|
52
|
-
return Path(args.workspace).resolve(), None
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def cmd_profile_init(args: argparse.Namespace) -> dict[str, Any]:
|
|
56
|
-
workspace, profiles_dir = _profile_scope(args)
|
|
57
|
-
return profiles.init_profile(workspace, args.name, args.auth_mode, profiles_dir=profiles_dir)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def cmd_profile_doctor(args: argparse.Namespace) -> dict[str, Any]:
|
|
61
|
-
workspace, profiles_dir = _profile_scope(args)
|
|
62
|
-
return profiles.doctor_profile(workspace, args.name, profiles_dir=profiles_dir)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def cmd_profile_show(args: argparse.Namespace) -> dict[str, Any]:
|
|
66
|
-
workspace, profiles_dir = _profile_scope(args)
|
|
67
|
-
return profiles.show_profile(workspace, args.name, profiles_dir=profiles_dir)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def cmd_launch(args: argparse.Namespace) -> dict[str, Any]:
|
|
71
|
-
return runtime.launch(Path(args.spec).resolve(), dry_run=args.dry_run, auto_approve=args.yes)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def cmd_preflight(args: argparse.Namespace) -> dict[str, Any]:
|
|
75
|
-
return runtime.preflight(Path(args.team).resolve())
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def cmd_start(args: argparse.Namespace) -> dict[str, Any]:
|
|
79
|
-
return runtime.start(Path(args.team).resolve(), yes=args.yes)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def cmd_wait_ready(args: argparse.Namespace) -> dict[str, Any]:
|
|
83
|
-
return runtime.wait_ready(Path(args.workspace).resolve(), timeout=args.timeout)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def cmd_settle(args: argparse.Namespace) -> dict[str, Any]:
|
|
87
|
-
return runtime.settle(Path(args.workspace).resolve())
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def cmd_status(args: argparse.Namespace) -> dict[str, Any]:
|
|
91
|
-
if getattr(args, "summary", False) is True:
|
|
92
|
-
if getattr(args, "json", False) is True:
|
|
93
|
-
raise TeamAgentError("--summary and --json are mutually exclusive")
|
|
94
|
-
if getattr(args, "agent", None):
|
|
95
|
-
raise TeamAgentError("status --summary does not accept an agent argument")
|
|
96
|
-
data = runtime.status(Path(args.workspace).resolve(), as_json=True, compact=False)
|
|
97
|
-
return _format_status_summary(data)
|
|
98
|
-
if getattr(args, "json", False) is True:
|
|
99
|
-
return runtime.status(Path(args.workspace).resolve(), as_json=True, compact=not (getattr(args, "detail", False) is True))
|
|
100
|
-
return runtime.format_status(Path(args.workspace).resolve(), getattr(args, "agent", None))
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def cmd_watch(args: argparse.Namespace) -> None:
|
|
104
|
-
from team_agent.watch import run_watch
|
|
105
|
-
try:
|
|
106
|
-
run_watch(Path(args.workspace).resolve(), team=getattr(args, "team", None))
|
|
107
|
-
except KeyboardInterrupt:
|
|
108
|
-
raise SystemExit(0)
|
|
109
|
-
raise SystemExit(0)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def cmd_approvals(args: argparse.Namespace) -> dict[str, Any]:
|
|
113
|
-
if args.json:
|
|
114
|
-
return runtime.approvals(Path(args.workspace).resolve(), agent_id=args.agent)
|
|
115
|
-
return runtime.format_approvals(Path(args.workspace).resolve(), agent_id=args.agent)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def cmd_peek(args: argparse.Namespace) -> dict[str, Any]:
|
|
119
|
-
if not args.allow_raw_screen:
|
|
120
|
-
raise TeamAgentError(
|
|
121
|
-
"raw worker terminal inspection requires explicit user authorization and --allow-raw-screen; "
|
|
122
|
-
"normal operation must use status, approvals, inbox, collect, or event logs"
|
|
123
|
-
)
|
|
124
|
-
result = runtime.peek(
|
|
125
|
-
Path(args.workspace).resolve(),
|
|
126
|
-
args.agent,
|
|
127
|
-
head=args.head,
|
|
128
|
-
tail=args.tail,
|
|
129
|
-
search=args.search,
|
|
130
|
-
context=args.context,
|
|
131
|
-
)
|
|
132
|
-
if args.json:
|
|
133
|
-
return result
|
|
134
|
-
return result["text"]
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
def cmd_inbox(args: argparse.Namespace) -> dict[str, Any]:
|
|
138
|
-
since = getattr(args, "since", None)
|
|
139
|
-
if args.json:
|
|
140
|
-
return runtime.inbox(Path(args.workspace).resolve(), args.agent, limit=args.limit, since=since)
|
|
141
|
-
return runtime.format_inbox(Path(args.workspace).resolve(), args.agent, limit=args.limit, since=since)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
def cmd_sessions(args: argparse.Namespace) -> dict[str, Any]:
|
|
145
|
-
return runtime.sessions(Path(args.workspace).resolve())
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
def cmd_attach_leader(args: argparse.Namespace) -> dict[str, Any]:
|
|
149
|
-
return runtime.attach_leader(Path(args.workspace).resolve(), pane=args.pane, provider=args.provider)
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
def cmd_takeover(args: argparse.Namespace) -> dict[str, Any]:
|
|
153
|
-
return runtime.takeover(Path(args.workspace).resolve(), team=args.team, confirm=args.confirm)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
def cmd_claim_leader(args: argparse.Namespace) -> dict[str, Any]:
|
|
157
|
-
return runtime.claim_leader(Path(args.workspace).resolve(), team=args.team, confirm=args.confirm)
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
def cmd_identity(args: argparse.Namespace) -> dict[str, Any]:
|
|
161
|
-
return runtime.leader_identity(Path(args.workspace).resolve(), team=args.team)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
def cmd_send(args: argparse.Namespace) -> dict[str, Any]:
|
|
165
|
-
target = _send_target(args)
|
|
166
|
-
return runtime.send_message(
|
|
167
|
-
Path(args.workspace).resolve(),
|
|
168
|
-
target,
|
|
169
|
-
" ".join(args.message),
|
|
170
|
-
task_id=args.task,
|
|
171
|
-
sender=args.sender,
|
|
172
|
-
requires_ack=not args.no_ack,
|
|
173
|
-
confirm_human=args.confirm_human,
|
|
174
|
-
wait_visible=not args.no_wait,
|
|
175
|
-
timeout=args.timeout,
|
|
176
|
-
watch_result=args.watch_result,
|
|
177
|
-
team=args.team,
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
def _send_target(args: argparse.Namespace) -> str | list[str] | None:
|
|
182
|
-
if getattr(args, "targets", None):
|
|
183
|
-
return [item.strip() for item in args.targets.split(",") if item.strip()]
|
|
184
|
-
return args.target
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
def cmd_collect(args: argparse.Namespace) -> dict[str, Any]:
|
|
188
|
-
result_file = Path(args.result_file).resolve() if args.result_file else None
|
|
189
|
-
return runtime.collect(Path(args.workspace).resolve(), result_file=result_file)
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
def cmd_diagnose(args: argparse.Namespace) -> dict[str, Any]:
|
|
193
|
-
return runtime.diagnose(Path(args.workspace).resolve())
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
def cmd_repair_state(args: argparse.Namespace) -> dict[str, Any]:
|
|
197
|
-
return runtime.repair_state(
|
|
198
|
-
Path(args.workspace).resolve(),
|
|
199
|
-
task_id=args.task,
|
|
200
|
-
assignee=args.assignee,
|
|
201
|
-
status_value=args.status,
|
|
202
|
-
summary=args.summary,
|
|
203
|
-
)
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
def cmd_validate_result(args: argparse.Namespace) -> dict[str, Any]:
|
|
207
|
-
if args.file:
|
|
208
|
-
raw = Path(args.file).read_text(encoding="utf-8")
|
|
209
|
-
elif args.result:
|
|
210
|
-
raw = args.result
|
|
211
|
-
else:
|
|
212
|
-
raw = sys.stdin.read()
|
|
213
|
-
envelope = json.loads(raw)
|
|
214
|
-
validate_result_envelope(envelope)
|
|
215
|
-
return {"ok": True, "task_id": envelope["task_id"], "agent_id": envelope["agent_id"], "status": envelope["status"]}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
def cmd_doctor(args: argparse.Namespace) -> dict[str, Any] | str:
|
|
219
|
-
gate = getattr(args, "gate", None)
|
|
220
|
-
if getattr(args, "fix", False) is True and not gate:
|
|
221
|
-
raise TeamAgentError("--fix requires --gate")
|
|
222
|
-
if getattr(args, "comms", False) is True or gate == "comms":
|
|
223
|
-
from team_agent.diagnose.comms import COMMS_BOUNDARY_TEXT, run_comms_selftest
|
|
224
|
-
result = run_comms_selftest(
|
|
225
|
-
Path(args.workspace).resolve(),
|
|
226
|
-
team=getattr(args, "team", None),
|
|
227
|
-
gate=gate,
|
|
228
|
-
)
|
|
229
|
-
if args.json:
|
|
230
|
-
return result
|
|
231
|
-
return f"{COMMS_BOUNDARY_TEXT}\n{json.dumps(result, indent=2, ensure_ascii=False, sort_keys=True)}"
|
|
232
|
-
if isinstance(gate, str) and gate:
|
|
233
|
-
from team_agent.diagnose.orphan_cleanup import orphan_gate
|
|
234
|
-
if gate != "orphans":
|
|
235
|
-
raise TeamAgentError(f"unknown doctor gate: {gate}")
|
|
236
|
-
return orphan_gate(fix=bool(getattr(args, "fix", False)), confirm=bool(getattr(args, "confirm", False)))
|
|
237
|
-
from team_agent.message_store.schema import SCHEMA_VERSION
|
|
238
|
-
from team_agent.message_store.schema_migration import fix_schema_layout, schema_diagnosis
|
|
239
|
-
if getattr(args, "fix_schema", False) is True:
|
|
240
|
-
return fix_schema_layout(Path(args.workspace).resolve(), schema_version=SCHEMA_VERSION)
|
|
241
|
-
schema = schema_diagnosis(Path(args.workspace).resolve(), schema_version=SCHEMA_VERSION)
|
|
242
|
-
if schema.get("layout_diffs"):
|
|
243
|
-
return {
|
|
244
|
-
"ok": True,
|
|
245
|
-
"schema": schema,
|
|
246
|
-
"coordinator": {
|
|
247
|
-
"schema_ok": False,
|
|
248
|
-
"schema_error": "team.db physical layout drift detected",
|
|
249
|
-
},
|
|
250
|
-
}
|
|
251
|
-
if getattr(args, "cleanup_orphans", False):
|
|
252
|
-
from team_agent.diagnose.orphan_cleanup import cleanup_orphan_coordinators, format_cleanup_orphans
|
|
253
|
-
result = cleanup_orphan_coordinators(confirm=bool(getattr(args, "confirm", False)))
|
|
254
|
-
if args.json:
|
|
255
|
-
return result
|
|
256
|
-
return format_cleanup_orphans(result)
|
|
257
|
-
spec = Path(args.spec).resolve() if args.spec else None
|
|
258
|
-
result = runtime.doctor(spec)
|
|
259
|
-
result["schema"] = schema
|
|
260
|
-
return result
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
def _format_status_summary(data: dict[str, Any]) -> str:
|
|
264
|
-
coordinator = data.get("coordinator") or {}
|
|
265
|
-
receiver = data.get("leader_receiver") or {}
|
|
266
|
-
agents = data.get("agents") or {}
|
|
267
|
-
health = data.get("agent_health") or {}
|
|
268
|
-
latest = (data.get("latest_results") or [{}])[0] if data.get("latest_results") else None
|
|
269
|
-
counts = _agent_summary_counts(agents, health)
|
|
270
|
-
agents_line = (
|
|
271
|
-
f"agents: {len(agents)} — running={counts['running']} busy={counts['busy']} "
|
|
272
|
-
f"idle={counts['idle']} stopped={counts['stopped']} failed={counts['failed']} "
|
|
273
|
-
f"unknown={counts['unknown']}"
|
|
274
|
-
)
|
|
275
|
-
# C3 (cr verdict, 2026-05-27): append a (N interacted, M never) marker
|
|
276
|
-
# only when at least one worker has a valid first_send_at stamp. When N
|
|
277
|
-
# is zero, the agents line stays byte-identical to the pre-Route-B
|
|
278
|
-
# output so the Gap 18a triage contract (strict five-line shape with
|
|
279
|
-
# exact line[2] string) remains unchanged.
|
|
280
|
-
interacted_count, never_count = _interaction_counts(agents)
|
|
281
|
-
if interacted_count > 0:
|
|
282
|
-
agents_line = f"{agents_line} ({interacted_count} interacted, {never_count} never)"
|
|
283
|
-
return "\n".join([
|
|
284
|
-
f"coordinator: {coordinator.get('status') or 'stopped'} schema_ok={bool(coordinator.get('schema_ok'))} tmux={bool(data.get('tmux_session_present'))}",
|
|
285
|
-
f"receiver: {receiver.get('pane_id') or '-'} cmd={receiver.get('pane_current_command') or receiver.get('current_command') or '-'}",
|
|
286
|
-
agents_line,
|
|
287
|
-
f"queued: {len(data.get('queued_messages') or [])} mailbox messages awaiting delivery",
|
|
288
|
-
_latest_result_line(latest),
|
|
289
|
-
])
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
def _interaction_counts(agents: dict[str, Any]) -> tuple[int, int]:
|
|
293
|
-
"""Return (interacted, never_interacted) over the agents dict. An agent is
|
|
294
|
-
interacted when its `interacted` field (added by status.queries.status) is
|
|
295
|
-
a non-empty string other than the literal "never". This intentionally
|
|
296
|
-
sources from the enriched per-status interacted field rather than re-
|
|
297
|
-
parsing first_send_at so the summary stays a derived view."""
|
|
298
|
-
interacted = 0
|
|
299
|
-
never = 0
|
|
300
|
-
for entry in agents.values():
|
|
301
|
-
marker = (entry or {}).get("interacted") if isinstance(entry, dict) else None
|
|
302
|
-
if isinstance(marker, str) and marker and marker != "never":
|
|
303
|
-
interacted += 1
|
|
304
|
-
else:
|
|
305
|
-
never += 1
|
|
306
|
-
return interacted, never
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
def _agent_summary_counts(agents: dict[str, Any], health: dict[str, Any]) -> dict[str, int]:
|
|
310
|
-
counts = dict.fromkeys(("running", "busy", "idle", "stopped", "failed", "unknown"), 0)
|
|
311
|
-
for agent_id, agent in agents.items():
|
|
312
|
-
raw = str((agent or {}).get("status") or "").lower()
|
|
313
|
-
hstatus = str((health.get(agent_id) or {}).get("status") or "").lower()
|
|
314
|
-
if raw in {"failed", "error"} or hstatus in {"failed", "error"}:
|
|
315
|
-
counts["failed"] += 1
|
|
316
|
-
elif raw in {"stopped", "done"} or hstatus == "done":
|
|
317
|
-
counts["stopped"] += 1
|
|
318
|
-
elif raw == "busy" or hstatus in {"running", "working"}:
|
|
319
|
-
counts["busy"] += 1
|
|
320
|
-
elif hstatus == "idle":
|
|
321
|
-
counts["idle"] += 1
|
|
322
|
-
elif raw in {"blocked", "awaiting_approval", "interrupted", "missing", "stuck", "uncertain"} or hstatus in {
|
|
323
|
-
"blocked", "awaiting_approval", "interrupted", "missing", "stuck", "uncertain"
|
|
324
|
-
}:
|
|
325
|
-
counts["unknown"] += 1
|
|
326
|
-
elif raw == "running":
|
|
327
|
-
counts["running"] += 1
|
|
328
|
-
else:
|
|
329
|
-
counts["unknown"] += 1
|
|
330
|
-
return counts
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
def _latest_result_line(result: dict[str, Any] | None) -> str:
|
|
334
|
-
if not result:
|
|
335
|
-
return "latest result: none"
|
|
336
|
-
summary = str(result.get("summary") or "").replace("\n", " ")[:80]
|
|
337
|
-
return f"latest result: {result.get('agent_id') or '-'} -> {summary or '-'} @ {runtime._age_text(result.get('created_at'))}"
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
def cmd_shutdown(args: argparse.Namespace) -> dict[str, Any]:
|
|
341
|
-
return runtime.shutdown(Path(args.workspace).resolve(), keep_logs=args.keep_logs, team=args.team)
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
def cmd_restart(args: argparse.Namespace) -> dict[str, Any]:
|
|
345
|
-
return runtime.restart(Path(args.workspace).resolve(), allow_fresh=args.allow_fresh, team=args.team)
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
def cmd_start_agent(args: argparse.Namespace) -> dict[str, Any]:
|
|
349
|
-
return runtime.start_agent(
|
|
350
|
-
Path(args.workspace).resolve(),
|
|
351
|
-
args.agent,
|
|
352
|
-
force=args.force,
|
|
353
|
-
open_display=not args.no_display,
|
|
354
|
-
allow_fresh=args.allow_fresh,
|
|
355
|
-
team=args.team,
|
|
356
|
-
)
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
def cmd_stop_agent(args: argparse.Namespace) -> dict[str, Any]:
|
|
360
|
-
return runtime.stop_agent(Path(args.workspace).resolve(), args.agent, team=args.team)
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
def cmd_reset_agent(args: argparse.Namespace) -> dict[str, Any]:
|
|
364
|
-
return runtime.reset_agent(
|
|
365
|
-
Path(args.workspace).resolve(),
|
|
366
|
-
args.agent,
|
|
367
|
-
discard_session=args.discard_session,
|
|
368
|
-
open_display=not args.no_display,
|
|
369
|
-
team=args.team,
|
|
370
|
-
)
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
def cmd_add_agent(args: argparse.Namespace) -> dict[str, Any]:
|
|
374
|
-
return runtime.add_agent(
|
|
375
|
-
Path(args.workspace).resolve(),
|
|
376
|
-
args.agent,
|
|
377
|
-
role_file_path=args.role_file,
|
|
378
|
-
open_display=not args.no_display,
|
|
379
|
-
team=args.team,
|
|
380
|
-
)
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
def cmd_fork_agent(args: argparse.Namespace) -> dict[str, Any]:
|
|
384
|
-
return runtime.fork_agent(
|
|
385
|
-
Path(args.workspace).resolve(),
|
|
386
|
-
args.source_agent,
|
|
387
|
-
as_agent_id=args.as_agent,
|
|
388
|
-
label=args.label,
|
|
389
|
-
open_display=not args.no_display,
|
|
390
|
-
team=args.team,
|
|
391
|
-
)
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
def cmd_remove_agent(args: argparse.Namespace) -> dict[str, Any]:
|
|
395
|
-
return runtime.remove_agent(
|
|
396
|
-
Path(args.workspace).resolve(),
|
|
397
|
-
args.agent,
|
|
398
|
-
from_spec=args.from_spec,
|
|
399
|
-
confirm=args.confirm,
|
|
400
|
-
force=args.force,
|
|
401
|
-
team=args.team,
|
|
402
|
-
)
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
def cmd_stuck_list(args: argparse.Namespace) -> dict[str, Any]:
|
|
406
|
-
return runtime.stuck_list(Path(args.workspace).resolve())
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
def cmd_stuck_cancel(args: argparse.Namespace) -> dict[str, Any]:
|
|
410
|
-
return runtime.stuck_cancel(
|
|
411
|
-
Path(args.workspace).resolve(),
|
|
412
|
-
args.agent,
|
|
413
|
-
alert_type=args.alert_type,
|
|
414
|
-
suppressed_by="leader",
|
|
415
|
-
)
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
def cmd_acknowledge_idle(args: argparse.Namespace) -> dict[str, Any]:
|
|
419
|
-
return runtime.acknowledge_idle(Path(args.workspace).resolve(), team=args.team)
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
def cmd_allow_peer_talk(args: argparse.Namespace) -> dict[str, Any]:
|
|
423
|
-
return runtime.allow_peer_talk(Path(args.workspace).resolve(), args.agent_a, args.agent_b)
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
def cmd_run_overnight(args: argparse.Namespace) -> dict[str, Any]:
|
|
427
|
-
from team_agent import orchestrator
|
|
428
|
-
workspace = Path(args.workspace).resolve()
|
|
429
|
-
if args.status:
|
|
430
|
-
return orchestrator.plan_status(workspace, plan_id=args.plan_id)
|
|
431
|
-
if args.halt:
|
|
432
|
-
if not args.plan_id:
|
|
433
|
-
raise TeamAgentError("--halt requires --plan-id")
|
|
434
|
-
return orchestrator.halt_plan(workspace, args.plan_id, reason=args.reason)
|
|
435
|
-
if not args.plan:
|
|
436
|
-
raise TeamAgentError("--plan PATH is required unless --status or --halt is used")
|
|
437
|
-
return orchestrator.start_plan(workspace, Path(args.plan).resolve(), start=not args.no_start)
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
def cmd_advanced(args: argparse.Namespace) -> str:
|
|
441
|
-
return "\n".join(
|
|
442
|
-
[
|
|
443
|
-
"Low-level commands:",
|
|
444
|
-
" init validate compile profile launch preflight start wait-ready settle",
|
|
445
|
-
" sessions attach-leader collect diagnose repair-state validate-result",
|
|
446
|
-
" install-skill e2e",
|
|
447
|
-
]
|
|
448
|
-
)
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
def cmd_install_skill(args: argparse.Namespace) -> dict[str, Any]:
|
|
452
|
-
source = repo_root() / "skills" / "team-agent"
|
|
453
|
-
if args.dest and args.target == "all":
|
|
454
|
-
raise TeamAgentError("--dest cannot be combined with --target all")
|
|
455
|
-
if args.dest:
|
|
456
|
-
dest_dir = Path(args.dest).expanduser().resolve()
|
|
457
|
-
return _install_skill_to(source, dest_dir, args.dry_run)
|
|
458
|
-
if args.target == "all":
|
|
459
|
-
results = [
|
|
460
|
-
_install_skill_to(source, _skill_dest_dir("codex"), args.dry_run),
|
|
461
|
-
_install_skill_to(source, _skill_dest_dir("claude"), args.dry_run),
|
|
462
|
-
]
|
|
463
|
-
return {"ok": all(item["ok"] for item in results), "targets": results}
|
|
464
|
-
return _install_skill_to(source, _skill_dest_dir(args.target), args.dry_run)
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
def _skill_dest_dir(target: str) -> Path:
|
|
468
|
-
if target == "claude":
|
|
469
|
-
dest_dir = Path.home() / ".claude" / "skills" / "team-agent"
|
|
470
|
-
else:
|
|
471
|
-
dest_dir = Path.home() / ".codex" / "skills" / "team-agent"
|
|
472
|
-
return dest_dir
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
def _install_skill_to(source: Path, dest_dir: Path, dry_run: bool) -> dict[str, Any]:
|
|
476
|
-
dest = dest_dir / "SKILL.md"
|
|
477
|
-
if dry_run:
|
|
478
|
-
return {"ok": True, "source": str(source / "SKILL.md"), "dest": str(dest), "dry_run": True}
|
|
479
|
-
dest_dir.mkdir(parents=True, exist_ok=True)
|
|
480
|
-
shutil.copytree(source, dest_dir, dirs_exist_ok=True)
|
|
481
|
-
return {"ok": True, "source": str(source / "SKILL.md"), "dest": str(dest)}
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import argparse
|
|
4
|
-
import tempfile
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from typing import Any
|
|
7
|
-
|
|
8
|
-
from team_agent import runtime
|
|
9
|
-
from team_agent.simple_yaml import dumps
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def cmd_e2e(args: argparse.Namespace) -> dict[str, Any]:
|
|
13
|
-
providers = [item.strip() for item in args.providers.split(",") if item.strip()]
|
|
14
|
-
workspace = Path(args.workspace).resolve() if args.workspace else Path(tempfile.mkdtemp(prefix="team-agent-e2e-"))
|
|
15
|
-
workspace.mkdir(parents=True, exist_ok=True)
|
|
16
|
-
results: dict[str, Any] = {"workspace": str(workspace), "providers": {}, "ok": True}
|
|
17
|
-
if "fake" in providers:
|
|
18
|
-
spec_path = workspace / "team.spec.yaml"
|
|
19
|
-
spec_path.write_text(dumps(_fake_spec(workspace)), encoding="utf-8")
|
|
20
|
-
results["providers"]["fake"] = _run_fake_e2e(spec_path, workspace)
|
|
21
|
-
results["ok"] = results["ok"] and results["providers"]["fake"]["ok"]
|
|
22
|
-
for provider in [p for p in providers if p != "fake"]:
|
|
23
|
-
from team_agent.providers import get_adapter
|
|
24
|
-
|
|
25
|
-
adapter = get_adapter(provider)
|
|
26
|
-
installed = adapter.is_installed()
|
|
27
|
-
if not installed:
|
|
28
|
-
provider_result = {
|
|
29
|
-
"ok": False,
|
|
30
|
-
"skipped": True,
|
|
31
|
-
"reason": f"{adapter.command_name} not installed",
|
|
32
|
-
"version": None,
|
|
33
|
-
}
|
|
34
|
-
elif not args.real:
|
|
35
|
-
provider_result = {
|
|
36
|
-
"ok": False,
|
|
37
|
-
"skipped": True,
|
|
38
|
-
"reason": "real provider launch disabled; rerun with --real on an authenticated machine",
|
|
39
|
-
"version": adapter.version(),
|
|
40
|
-
}
|
|
41
|
-
else:
|
|
42
|
-
provider_result = _run_real_launch_smoke(provider, workspace)
|
|
43
|
-
results["providers"][provider] = provider_result
|
|
44
|
-
results["ok"] = results["ok"] and provider_result["ok"]
|
|
45
|
-
return results
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def _run_fake_e2e(spec_path: Path, workspace: Path) -> dict[str, Any]:
|
|
49
|
-
launched = runtime.launch(spec_path, auto_approve=True)
|
|
50
|
-
sent = runtime.send_message(workspace, None, "implement fake task", task_id="task_impl", requires_ack=True)
|
|
51
|
-
import time
|
|
52
|
-
|
|
53
|
-
time.sleep(1.0)
|
|
54
|
-
collected = runtime.collect(workspace)
|
|
55
|
-
stopped = runtime.shutdown(workspace)
|
|
56
|
-
return {"ok": bool(launched["ok"] and sent["ok"] and collected["collected"] and stopped["ok"]), "launch": launched, "send": sent, "collect": collected, "shutdown": stopped}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def _run_real_launch_smoke(provider: str, workspace: Path) -> dict[str, Any]:
|
|
60
|
-
spec_path = workspace / f"team.{provider}.spec.yaml"
|
|
61
|
-
spec = _fake_spec(workspace)
|
|
62
|
-
spec["team"]["name"] = f"real-{provider}-smoke"
|
|
63
|
-
spec["leader"]["provider"] = provider
|
|
64
|
-
spec["agents"][0]["provider"] = provider
|
|
65
|
-
spec["agents"][0]["id"] = f"{provider}_smoke"
|
|
66
|
-
spec["agents"][0]["tools"] = ["fs_read", "fs_list", "git_diff", "mcp_team", "provider_builtin"]
|
|
67
|
-
spec["agents"][0]["role"] = "reviewer"
|
|
68
|
-
spec["agents"][0]["system_prompt"]["inline"] = (
|
|
69
|
-
"Real provider smoke. Do not edit files or run shell. "
|
|
70
|
-
"Do not call team-agent launch and do not create a nested Team Agent team. "
|
|
71
|
-
"When asked, call team_orchestrator.report_result exactly once with result_envelope_v1."
|
|
72
|
-
)
|
|
73
|
-
spec["routing"]["rules"][0]["assign_to"] = spec["agents"][0]["id"]
|
|
74
|
-
spec["runtime"]["session_name"] = f"team-agent-real-{provider}"
|
|
75
|
-
spec["runtime"]["startup_order"] = [spec["agents"][0]["id"]]
|
|
76
|
-
spec["tasks"][0]["id"] = f"task_real_{provider}_callback"
|
|
77
|
-
spec["tasks"][0]["title"] = f"Real {provider} callback smoke"
|
|
78
|
-
spec["tasks"][0]["assignee"] = spec["agents"][0]["id"]
|
|
79
|
-
spec["tasks"][0]["requires_tools"] = ["fs_read", "git_diff"]
|
|
80
|
-
spec["tasks"][0]["type"] = "review"
|
|
81
|
-
spec_path.write_text(dumps(spec), encoding="utf-8")
|
|
82
|
-
launched = runtime.launch(spec_path, auto_approve=True)
|
|
83
|
-
import time
|
|
84
|
-
|
|
85
|
-
time.sleep(10.0 if provider == "codex" else 3.0)
|
|
86
|
-
collected = None
|
|
87
|
-
sent = None
|
|
88
|
-
if provider == "codex":
|
|
89
|
-
task_id = spec["tasks"][0]["id"]
|
|
90
|
-
agent_id = spec["agents"][0]["id"]
|
|
91
|
-
message = (
|
|
92
|
-
"Do not call team-agent launch and do not create a nested Team Agent team. "
|
|
93
|
-
"Do not edit files or run shell. "
|
|
94
|
-
"Call team_orchestrator.report_result with envelope "
|
|
95
|
-
f'{{"schema_version":"result_envelope_v1","task_id":"{task_id}",'
|
|
96
|
-
f'"agent_id":"{agent_id}","status":"success","summary":"ok",'
|
|
97
|
-
'"changes":[],"tests":[{"command":"real-codex-callback-smoke","status":"passed"}],'
|
|
98
|
-
'"risks":[],"artifacts":[],"next_actions":[]}. Do not edit files or run shell.'
|
|
99
|
-
)
|
|
100
|
-
sent = runtime.send_message(workspace, agent_id, message, task_id=task_id, requires_ack=True)
|
|
101
|
-
for _ in range(24):
|
|
102
|
-
time.sleep(5.0)
|
|
103
|
-
result = runtime.collect(workspace)
|
|
104
|
-
if result["collected"]:
|
|
105
|
-
collected = result
|
|
106
|
-
break
|
|
107
|
-
status = runtime.status(workspace, as_json=True)
|
|
108
|
-
stopped = runtime.shutdown(workspace)
|
|
109
|
-
agent_id = spec["agents"][0]["id"]
|
|
110
|
-
agent_status = status["agents"].get(agent_id, {})
|
|
111
|
-
callback_ok = provider != "codex" or bool(collected and collected["collected"])
|
|
112
|
-
return {
|
|
113
|
-
"ok": bool(launched["ok"] and stopped["ok"] and agent_status.get("tmux_window_present") and callback_ok),
|
|
114
|
-
"launch": launched,
|
|
115
|
-
"send": sent,
|
|
116
|
-
"collect": collected,
|
|
117
|
-
"status": status,
|
|
118
|
-
"shutdown": stopped,
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def _fake_spec(workspace: Path) -> dict[str, Any]:
|
|
123
|
-
return {
|
|
124
|
-
"version": 1,
|
|
125
|
-
"team": {
|
|
126
|
-
"name": "fake-e2e",
|
|
127
|
-
"mode": "supervisor_worker",
|
|
128
|
-
"objective": "Exercise fake provider orchestration.",
|
|
129
|
-
"workspace": str(workspace),
|
|
130
|
-
},
|
|
131
|
-
"leader": {
|
|
132
|
-
"id": "leader",
|
|
133
|
-
"role": "leader",
|
|
134
|
-
"provider": "fake",
|
|
135
|
-
"model": None,
|
|
136
|
-
"tools": ["fs_read", "fs_list", "mcp_team"],
|
|
137
|
-
"context_policy": {
|
|
138
|
-
"keep_user_thread": True,
|
|
139
|
-
"receive_worker_outputs": "structured_only",
|
|
140
|
-
"max_worker_result_tokens": 2000,
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
"agents": [
|
|
144
|
-
{
|
|
145
|
-
"id": "fake_impl",
|
|
146
|
-
"role": "implementation_engineer",
|
|
147
|
-
"provider": "fake",
|
|
148
|
-
"model": None,
|
|
149
|
-
"working_directory": str(workspace),
|
|
150
|
-
"system_prompt": {"inline": "Handle fake implementation tasks.", "file": None},
|
|
151
|
-
"tools": ["fs_read", "fs_write", "fs_list", "execute_bash", "git_diff", "mcp_team", "provider_builtin"],
|
|
152
|
-
"permission_mode": "restricted",
|
|
153
|
-
"preferred_for": ["implementation"],
|
|
154
|
-
"avoid_for": [],
|
|
155
|
-
"output_contract": {"format": "result_envelope_v1", "required_fields": ["task_id", "status", "summary", "artifacts"]},
|
|
156
|
-
}
|
|
157
|
-
],
|
|
158
|
-
"routing": {
|
|
159
|
-
"default_assignee": "leader",
|
|
160
|
-
"rules": [{"id": "implementation-to-fake", "match": {"type": ["implementation"]}, "assign_to": "fake_impl", "priority": 10}],
|
|
161
|
-
},
|
|
162
|
-
"communication": {
|
|
163
|
-
"protocol": "mcp_inbox",
|
|
164
|
-
"topology": "leader_centered",
|
|
165
|
-
"worker_to_worker": True,
|
|
166
|
-
"ack_timeout_sec": 2,
|
|
167
|
-
"result_format": "result_envelope_v1",
|
|
168
|
-
"message_store": {"sqlite": ".team/runtime/team.db", "mirror_files": ".team/messages"},
|
|
169
|
-
},
|
|
170
|
-
"runtime": {
|
|
171
|
-
"backend": "tmux",
|
|
172
|
-
"display_backend": "none",
|
|
173
|
-
"session_name": "team-agent-fake-e2e",
|
|
174
|
-
"auto_launch": True,
|
|
175
|
-
"require_user_approval_before_launch": False,
|
|
176
|
-
"max_active_agents": 1,
|
|
177
|
-
"startup_order": ["fake_impl"],
|
|
178
|
-
},
|
|
179
|
-
"context": {
|
|
180
|
-
"state_file": "team_state.md",
|
|
181
|
-
"artifact_dir": ".team/artifacts",
|
|
182
|
-
"log_dir": ".team/logs",
|
|
183
|
-
"summarization": {
|
|
184
|
-
"worker_full_logs": "retain_outside_leader_context",
|
|
185
|
-
"state_update": "after_each_result",
|
|
186
|
-
},
|
|
187
|
-
},
|
|
188
|
-
"tasks": [
|
|
189
|
-
{
|
|
190
|
-
"id": "task_impl",
|
|
191
|
-
"title": "Fake implementation",
|
|
192
|
-
"type": "implementation",
|
|
193
|
-
"assignee": None,
|
|
194
|
-
"deps": [],
|
|
195
|
-
"acceptance": ["fake result collected"],
|
|
196
|
-
"status": "pending",
|
|
197
|
-
"requires_tools": ["fs_write", "execute_bash"],
|
|
198
|
-
"files": ["src/example.py"],
|
|
199
|
-
"risk": "low",
|
|
200
|
-
}
|
|
201
|
-
],
|
|
202
|
-
}
|