@team-agent/installer 0.2.11 → 0.3.1
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 +1204 -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 +1207 -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 +557 -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 +1084 -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 +526 -0
- package/crates/team-agent/src/leader/rediscover.rs +1101 -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 +237 -0
- package/crates/team-agent/src/leader/tests/identity.rs +206 -0
- package/crates/team-agent/src/leader/tests/idle.rs +272 -0
- package/crates/team-agent/src/leader/tests/lease_api.rs +225 -0
- package/crates/team-agent/src/leader/tests/lease_claim.rs +410 -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 +489 -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 +2109 -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 +985 -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 +710 -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 +187 -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 +468 -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 +743 -0
- package/crates/team-agent/src/messaging/helpers.rs +209 -0
- package/crates/team-agent/src/messaging/leader_receiver.rs +329 -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 +553 -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 +578 -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 +659 -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 +765 -0
- package/crates/team-agent/src/tmux_backend.rs +810 -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 +118 -112
- 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
|
@@ -0,0 +1,710 @@
|
|
|
1
|
+
//! lifecycle 数据类型:newtype / enum / data struct / error / outcome-report 集中定义。
|
|
2
|
+
|
|
3
|
+
use std::collections::BTreeMap;
|
|
4
|
+
use std::path::PathBuf;
|
|
5
|
+
|
|
6
|
+
use serde::{Deserialize, Serialize};
|
|
7
|
+
use thiserror::Error;
|
|
8
|
+
|
|
9
|
+
use crate::model::ids::AgentId;
|
|
10
|
+
use crate::provider::{RolloutPath, SessionId};
|
|
11
|
+
use crate::transport::{PaneId, SessionName, WindowName};
|
|
12
|
+
|
|
13
|
+
use super::DisplayBackend;
|
|
14
|
+
|
|
15
|
+
// ===========================================================================
|
|
16
|
+
// CROSS-LANE PLACEHOLDERS(13/14/15 兄弟 lane 尚未交付;leader 集成时 reconcile)
|
|
17
|
+
// ===========================================================================
|
|
18
|
+
|
|
19
|
+
/// step8 provider 还未暴露的 launch/resume/fork 命令构造门面。lifecycle 经它构造
|
|
20
|
+
/// provider 命令字符串(`shell_command_for_agent`/`shell_resume_command_for_agent`/
|
|
21
|
+
/// `shell_fork_command_for_agent`,`runtime` 自由函数)—— provider lane 落地后替换为
|
|
22
|
+
/// 真实 `provider::shell_*` API。**PLACEHOLDER**:仅占位 argv,字段映射由 provider lane 定。
|
|
23
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
24
|
+
pub struct ShellCommand {
|
|
25
|
+
pub argv: Vec<String>,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/// `EventLog` 已在 step4 落地,但 lifecycle 发射的 typed `EventKind` 名集(`lifecycle.*`/
|
|
29
|
+
/// `restart.*`/`display.*`)是 step4 owned 的稳定事件名(JSON 名与 Python 一致)。
|
|
30
|
+
/// **PLACEHOLDER**:此处仅命名 lifecycle 关心的事件名常量集,leader 集成时映射到
|
|
31
|
+
/// step4 `event_log::EventLog::write(name, fields)`。
|
|
32
|
+
pub mod event_names {
|
|
33
|
+
// lifecycle 步进事件(Gap 15/16:发射顺序被测试锁死)。
|
|
34
|
+
pub const ADD_STEP_COMPLETED: &str = "lifecycle.add_step_completed";
|
|
35
|
+
pub const ADD_STEP_ROLLED_BACK: &str = "lifecycle.add_step_rolled_back";
|
|
36
|
+
pub const ADD_FAILED: &str = "lifecycle.add_failed";
|
|
37
|
+
pub const REMOVE_STEP_COMPLETED: &str = "lifecycle.remove_step_completed";
|
|
38
|
+
pub const REMOVE_ROLLED_BACK: &str = "lifecycle.remove_rolled_back";
|
|
39
|
+
// restart 决策事件(Route B audit 契约必发)。
|
|
40
|
+
pub const RESTART_RESUME_DECISION: &str = "restart.resume_decision";
|
|
41
|
+
pub const RESTART_ATOMIC_REFUSAL: &str = "restart.atomic_refusal";
|
|
42
|
+
pub const RESTART_FIRST_SEND_AT_INVALID: &str = "restart.first_send_at_invalid";
|
|
43
|
+
pub const RESTART_FRESH_SPAWN: &str = "restart.fresh_spawn";
|
|
44
|
+
pub const RESTART_ROLLBACK_SESSION: &str = "restart.rollback_session";
|
|
45
|
+
// display 事件(C15/C16:每次降级非静默)。
|
|
46
|
+
pub const DISPLAY_BACKEND_RESOLVED: &str = "display.backend_resolved";
|
|
47
|
+
pub const DISPLAY_ADAPTIVE_OPENED: &str = "display.adaptive_opened";
|
|
48
|
+
pub const DISPLAY_ADAPTIVE_BLOCKED: &str = "display.adaptive_blocked";
|
|
49
|
+
pub const DISPLAY_ADAPTIVE_REBUILT: &str = "display.adaptive_rebuilt";
|
|
50
|
+
pub const DISPLAY_ADAPTIVE_CLOSED: &str = "display.adaptive_closed";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ===========================================================================
|
|
54
|
+
// NEWTYPES(card §3:散 str → newtype。`AgentId`/`SessionName` 复用既有;
|
|
55
|
+
// 此处新增 plan id / 派生 session 名)
|
|
56
|
+
// ===========================================================================
|
|
57
|
+
|
|
58
|
+
/// `PlanId`(`_PLAN_ID_RE = ^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$`,`orchestrator/state.py:11`)。
|
|
59
|
+
/// **必须 newtype**:防路径穿越(无 `/`、空格);`sanitize_plan_id` 拒绝则 `InvalidPlanId`。
|
|
60
|
+
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
|
|
61
|
+
#[serde(transparent)]
|
|
62
|
+
pub struct PlanId(String);
|
|
63
|
+
|
|
64
|
+
impl PlanId {
|
|
65
|
+
/// `sanitize_plan_id`(`orchestrator/state.py:18`):正则校验,失败 → `Err`。
|
|
66
|
+
pub fn parse(raw: &str) -> Result<Self, LifecycleError> {
|
|
67
|
+
let mut chars = raw.chars();
|
|
68
|
+
let first_ok = chars
|
|
69
|
+
.next()
|
|
70
|
+
.map(|c| c.is_ascii_alphanumeric())
|
|
71
|
+
.unwrap_or(false);
|
|
72
|
+
let rest_ok = chars.all(|c| c.is_ascii_alphanumeric() || matches!(c, '_' | '.' | '-'));
|
|
73
|
+
if first_ok && rest_ok && raw.len() <= 64 {
|
|
74
|
+
Ok(Self(raw.to_string()))
|
|
75
|
+
} else {
|
|
76
|
+
Err(LifecycleError::InvalidPlanId(format!(
|
|
77
|
+
"{raw:?} does not match ^[A-Za-z0-9][A-Za-z0-9_.-]{{0,63}}$; no slashes, spaces, or path-traversal segments are allowed"
|
|
78
|
+
)))
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
pub fn as_str(&self) -> &str {
|
|
82
|
+
&self.0
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
impl std::fmt::Display for PlanId {
|
|
87
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
88
|
+
f.write_str(&self.0)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/// ghostty 派生的唯一 linked-session 名(`ghostty_display_session_name`,sha1 派生,
|
|
93
|
+
/// `display/ghostty.py`)。与 worker 的 `SessionName` 类型上区分,防混传(card §57)。
|
|
94
|
+
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
|
95
|
+
#[serde(transparent)]
|
|
96
|
+
pub struct DisplaySessionName(pub String);
|
|
97
|
+
|
|
98
|
+
impl DisplaySessionName {
|
|
99
|
+
pub fn as_str(&self) -> &str {
|
|
100
|
+
&self.0
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ===========================================================================
|
|
105
|
+
// ENUM(card §3/§11:散字符串 → 穷尽 enum)
|
|
106
|
+
// ===========================================================================
|
|
107
|
+
|
|
108
|
+
/// `start_mode` / `restart_mode`(`start.py:179`,`orchestration.py:208`)。
|
|
109
|
+
/// **必须 enum**:start/restart 全程穷尽分支;`noop`(窗口已存在且非 force)只在
|
|
110
|
+
/// `start_agent` 出现。
|
|
111
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
|
112
|
+
#[serde(rename_all = "snake_case")]
|
|
113
|
+
pub enum StartMode {
|
|
114
|
+
Resumed,
|
|
115
|
+
Fresh,
|
|
116
|
+
FreshAfterMissingRollout,
|
|
117
|
+
Noop,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/// Route B resume 决策(`orchestration.py:498-505`)。每非 paused worker 发一条
|
|
121
|
+
/// `restart.resume_decision`;`Refuse` 是 atomic refusal 的唯一触发。
|
|
122
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
|
123
|
+
#[serde(rename_all = "snake_case")]
|
|
124
|
+
pub enum ResumeDecision {
|
|
125
|
+
Resume,
|
|
126
|
+
FreshStart,
|
|
127
|
+
Refuse,
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/// `first_send_at` 严格分类(`_classify_first_send_at`,`orchestration.py:399-426`)。
|
|
131
|
+
/// **必须 enum + 严格解析**:显式拒空串 / `0` / `False` / `"null"` / 非 ISO;
|
|
132
|
+
/// garbage **hard refuse**,绝不靠 truthiness 把 `""` 当 absent 漏过去(陷阱)。
|
|
133
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
|
134
|
+
#[serde(rename_all = "snake_case")]
|
|
135
|
+
pub enum FirstSendAtState {
|
|
136
|
+
/// `null` / 缺失 —— worker 从未交互,可丢弃 fresh。
|
|
137
|
+
Absent,
|
|
138
|
+
/// 合法 ISO-8601 UTC 串。
|
|
139
|
+
Valid,
|
|
140
|
+
/// `""` / `0` / `False` / `"null"` / 非 ISO —— state.json 损坏,决策前 hard refuse。
|
|
141
|
+
Corrupt,
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/// adaptive 阻塞 reason(`ADAPTIVE_BLOCK_REASONS`,6 个封闭值,`display/adaptive.py:21`)。
|
|
145
|
+
/// **必须 enum**(契约 C16 封闭集);`adaptive_blocked` 对越界 reason 兜底成
|
|
146
|
+
/// `AggregatorRebuildFailed`。
|
|
147
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
|
148
|
+
#[serde(rename_all = "snake_case")]
|
|
149
|
+
pub enum AdaptiveBlockReason {
|
|
150
|
+
LeaderNotInTmux,
|
|
151
|
+
SplitFailed,
|
|
152
|
+
WindowCreateFailed,
|
|
153
|
+
WorkerSessionMissing,
|
|
154
|
+
NotImplementedThisPlatform,
|
|
155
|
+
AggregatorRebuildFailed,
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/// display `status`(`agent_state["display"]["status"]`,`start.py:123`)。
|
|
159
|
+
/// **应 enum**:决定 `start_agent` 是否重开显示。
|
|
160
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
|
161
|
+
#[serde(rename_all = "snake_case")]
|
|
162
|
+
pub enum DisplayStatus {
|
|
163
|
+
Opened,
|
|
164
|
+
Blocked,
|
|
165
|
+
Stopped,
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/// plan `status`(`orchestrator/__init__.py`)。**应 enum**:`start_plan` 对已
|
|
169
|
+
/// running/halted/completed 幂等返回。
|
|
170
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
|
171
|
+
#[serde(rename_all = "snake_case")]
|
|
172
|
+
pub enum PlanStatus {
|
|
173
|
+
Running,
|
|
174
|
+
Halted,
|
|
175
|
+
Completed,
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/// 危险审批继承来源(`config.py:16` `dangerous_auto_approve_source`)。**应 enum**:
|
|
179
|
+
/// launch 在 `inherited=false` 且无 `--yes` 时 raise(`core.py:120`)。
|
|
180
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
|
181
|
+
#[serde(rename_all = "snake_case")]
|
|
182
|
+
pub enum DangerousApprovalSource {
|
|
183
|
+
RuntimeConfig,
|
|
184
|
+
LeaderProcess,
|
|
185
|
+
Disabled,
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ===========================================================================
|
|
189
|
+
// DATA STRUCT(每 worker display / restart 候选 / plan state / 危险审批)
|
|
190
|
+
// ===========================================================================
|
|
191
|
+
|
|
192
|
+
/// adaptive 能力探测结果(`probe_display_capabilities`,`display/adaptive.py:31`)。
|
|
193
|
+
/// **C13 一等公民**:分支只看 probe,不看 `cfg!(target_os)`;Windows/WSL →
|
|
194
|
+
/// `NotImplementedThisPlatform`。
|
|
195
|
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
196
|
+
pub struct DisplayProbe {
|
|
197
|
+
pub in_tmux: bool,
|
|
198
|
+
pub platform: String,
|
|
199
|
+
pub leader_session: Option<SessionName>,
|
|
200
|
+
pub leader_pane: Option<PaneId>,
|
|
201
|
+
pub caps: CapsFlags,
|
|
202
|
+
/// 探测后的 adaptive 状态(可开 / 已封闭+reason)。
|
|
203
|
+
pub adaptive_status: DisplayStatus,
|
|
204
|
+
/// 封闭时填 reason(C16 封闭集)。
|
|
205
|
+
pub reason: Option<AdaptiveBlockReason>,
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/// 平台能力位(`caps{tmux_append_windows, adaptive_display}`)。
|
|
209
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
|
210
|
+
pub struct CapsFlags {
|
|
211
|
+
pub tmux_append_windows: bool,
|
|
212
|
+
pub adaptive_display: bool,
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/// 每 worker display state(写进 `state.agents.<id>.display`)。adaptive vs ghostty_window
|
|
216
|
+
/// vs ghostty_workspace 字段不同 → enum 区分(card §50)。
|
|
217
|
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
218
|
+
#[serde(tag = "backend", rename_all = "snake_case")]
|
|
219
|
+
pub enum WorkerDisplay {
|
|
220
|
+
Adaptive {
|
|
221
|
+
status: DisplayStatus,
|
|
222
|
+
window: Option<WindowName>,
|
|
223
|
+
pane_id: Option<PaneId>,
|
|
224
|
+
target: Option<String>,
|
|
225
|
+
leader_session: Option<SessionName>,
|
|
226
|
+
},
|
|
227
|
+
GhosttyWindow {
|
|
228
|
+
status: DisplayStatus,
|
|
229
|
+
linked_session: DisplaySessionName,
|
|
230
|
+
display_session: DisplaySessionName,
|
|
231
|
+
},
|
|
232
|
+
GhosttyWorkspace {
|
|
233
|
+
status: DisplayStatus,
|
|
234
|
+
display_session: DisplaySessionName,
|
|
235
|
+
},
|
|
236
|
+
Blocked {
|
|
237
|
+
reason: AdaptiveBlockReason,
|
|
238
|
+
},
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/// `RestartCandidate`(`restart/selection.py:27`)。`select_restart_state` 多 team 选择;
|
|
242
|
+
/// `has_context` 是 resume 可行性粗判。
|
|
243
|
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
244
|
+
pub struct RestartCandidate {
|
|
245
|
+
pub session_name: SessionName,
|
|
246
|
+
pub team_name: String,
|
|
247
|
+
pub state_path: PathBuf,
|
|
248
|
+
pub spec_path: PathBuf,
|
|
249
|
+
pub agents: Vec<AgentId>,
|
|
250
|
+
pub has_context: bool,
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/// 危险审批继承态(`config.py:16` `dangerous_auto_approve{_source,_inherited,_provider,_flag}`)。
|
|
254
|
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
255
|
+
pub struct DangerousApproval {
|
|
256
|
+
pub enabled: bool,
|
|
257
|
+
pub source: DangerousApprovalSource,
|
|
258
|
+
pub inherited: bool,
|
|
259
|
+
pub provider: Option<String>,
|
|
260
|
+
pub flag: Option<String>,
|
|
261
|
+
pub worker_capability_above_leader: bool,
|
|
262
|
+
pub ancestry_binary_name: Option<String>,
|
|
263
|
+
pub unexpected_binary: bool,
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/// `PlanState`(`orchestrator/__init__.py:51`)。plan 多 stage 状态机持久态。
|
|
267
|
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
268
|
+
pub struct PlanState {
|
|
269
|
+
pub plan_id: PlanId,
|
|
270
|
+
pub plan_path: PathBuf,
|
|
271
|
+
pub team: Option<String>,
|
|
272
|
+
pub current_stage: i64,
|
|
273
|
+
pub started_at: String,
|
|
274
|
+
pub completed_stages: Vec<String>,
|
|
275
|
+
pub status: PlanStatus,
|
|
276
|
+
pub halt_reason: Option<String>,
|
|
277
|
+
pub halt_artifact: Option<PathBuf>,
|
|
278
|
+
pub stages: Vec<PlanStage>,
|
|
279
|
+
pub current_dispatch: Option<String>,
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/// 单 stage(`orchestrator/plan.py` stage mapping)。
|
|
283
|
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
284
|
+
pub struct PlanStage {
|
|
285
|
+
pub id: String,
|
|
286
|
+
pub assignee: Option<AgentId>,
|
|
287
|
+
pub prompt: Option<String>,
|
|
288
|
+
pub on_result: Option<PlanCondition>,
|
|
289
|
+
pub status: Option<String>,
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/// plan 推进条件(封闭文法 `_CONDITION_RE`,`orchestrator/plan.py:9`)。
|
|
293
|
+
/// **必须 typed**:`any` | `report_result.<field> == '<value>'`;越界 → `InvalidPlan`。
|
|
294
|
+
/// 不做成自由表达式。
|
|
295
|
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
296
|
+
pub enum PlanCondition {
|
|
297
|
+
/// 无条件推进。
|
|
298
|
+
Any,
|
|
299
|
+
/// `report_result.<field> == '<value>'`。
|
|
300
|
+
FieldEq { field: String, value: String },
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
impl PlanCondition {
|
|
304
|
+
/// 解析封闭条件文法。越界 raise `InvalidPlan`(`orchestrator/plan.py:_is_supported_condition`)。
|
|
305
|
+
pub fn parse(expr: &str) -> Result<Self, LifecycleError> {
|
|
306
|
+
let trimmed = expr.trim();
|
|
307
|
+
if trimmed.eq_ignore_ascii_case("any") {
|
|
308
|
+
return Ok(Self::Any);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
let Some(rest) = trimmed.strip_prefix("report_result.") else {
|
|
312
|
+
return Err(LifecycleError::InvalidPlan(format!(
|
|
313
|
+
"unsupported condition: {expr}"
|
|
314
|
+
)));
|
|
315
|
+
};
|
|
316
|
+
let Some((field, value_expr)) = rest.split_once("==") else {
|
|
317
|
+
return Err(LifecycleError::InvalidPlan(format!(
|
|
318
|
+
"unsupported condition: {expr}"
|
|
319
|
+
)));
|
|
320
|
+
};
|
|
321
|
+
let field = field.trim();
|
|
322
|
+
if field.is_empty() || !field.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') {
|
|
323
|
+
return Err(LifecycleError::InvalidPlan(format!(
|
|
324
|
+
"unsupported condition: {expr}"
|
|
325
|
+
)));
|
|
326
|
+
}
|
|
327
|
+
let value_expr = value_expr.trim();
|
|
328
|
+
let value = if let Some(inner) = value_expr
|
|
329
|
+
.strip_prefix('\'')
|
|
330
|
+
.and_then(|v| v.strip_suffix('\''))
|
|
331
|
+
{
|
|
332
|
+
inner
|
|
333
|
+
} else if let Some(inner) = value_expr
|
|
334
|
+
.strip_prefix('"')
|
|
335
|
+
.and_then(|v| v.strip_suffix('"'))
|
|
336
|
+
{
|
|
337
|
+
inner
|
|
338
|
+
} else {
|
|
339
|
+
return Err(LifecycleError::InvalidPlan(format!(
|
|
340
|
+
"unsupported condition: {expr}"
|
|
341
|
+
)));
|
|
342
|
+
};
|
|
343
|
+
Ok(Self::FieldEq {
|
|
344
|
+
field: field.to_string(),
|
|
345
|
+
value: value.to_string(),
|
|
346
|
+
})
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// ===========================================================================
|
|
351
|
+
// ERROR(card §10:fallible 边界;daemon/CLI 入口返 rich Result<Report, Error>)
|
|
352
|
+
// ===========================================================================
|
|
353
|
+
|
|
354
|
+
/// lifecycle 子系统错误。能力性降级(adaptive blocked)**不**走这里 —— 那是 typed
|
|
355
|
+
/// outcome(`DisplayStatus::Blocked` / `AdaptiveBlockReason`)。这里只装真失败:
|
|
356
|
+
/// owner-gate 拒绝、session 冲突、state 写崩(bug-084)、provider/transport I/O、回滚失败。
|
|
357
|
+
#[derive(Debug, Error)]
|
|
358
|
+
pub enum LifecycleError {
|
|
359
|
+
/// owner-gate 拒绝(foreign owner;`check_team_owner` 失败 —— lifecycle 第一道门)。
|
|
360
|
+
#[error("owner gate refused: {0}")]
|
|
361
|
+
OwnerRefused(String),
|
|
362
|
+
/// 同名 tmux session 已存在 —— **拒绝而非 kill**(`core.py:127`,`orchestration.py:79`)。
|
|
363
|
+
#[error("tmux session conflict: {0}")]
|
|
364
|
+
SessionConflict(String),
|
|
365
|
+
/// 危险自动审批未显式确认(`core.py:120`:inherited=false 且无 --yes)。
|
|
366
|
+
#[error("dangerous auto-approve requires explicit --yes: {0}")]
|
|
367
|
+
DangerousApprovalRequired(String),
|
|
368
|
+
/// 启动前门失败(`ensure_agent_start_requirements`:provider/profile/model check)。
|
|
369
|
+
#[error("agent start requirement unmet: {0}")]
|
|
370
|
+
RequirementUnmet(String),
|
|
371
|
+
/// state 持久化失败(bug-084:`os.replace` EACCES/EPERM/EBUSY 退避后仍败)。
|
|
372
|
+
#[error("state persistence failed: {0}")]
|
|
373
|
+
StatePersist(String),
|
|
374
|
+
/// 编译 spec / role doc 失败(`compile_team`/`compile_role_doc_agent`)。
|
|
375
|
+
#[error("spec compile failed: {0}")]
|
|
376
|
+
Compile(String),
|
|
377
|
+
/// provider 命令构造 / resume 不可用(`ResumeUnavailable`)。
|
|
378
|
+
#[error("provider error: {0}")]
|
|
379
|
+
Provider(String),
|
|
380
|
+
/// transport I/O(tmux new-session / new-window / kill 等子进程失败)。
|
|
381
|
+
#[error("transport error: {0}")]
|
|
382
|
+
Transport(String),
|
|
383
|
+
/// 原子动作中途失败且**回滚也失败**(字节级回滚写回失败 —— Gap 15/16 最坏臂)。
|
|
384
|
+
#[error("rollback failed after {step}: {detail}")]
|
|
385
|
+
RollbackFailed { step: String, detail: String },
|
|
386
|
+
/// plan id 非法(`sanitize_plan_id` 拒绝;防路径穿越)。
|
|
387
|
+
#[error("invalid plan id: {0}")]
|
|
388
|
+
InvalidPlanId(String),
|
|
389
|
+
/// plan YAML 校验失败(`InvalidPlanError`)。
|
|
390
|
+
#[error("invalid plan: {0}")]
|
|
391
|
+
InvalidPlan(String),
|
|
392
|
+
/// 多 team 选择歧义 / 未找到(`select_restart_state`)。
|
|
393
|
+
#[error("team select: {0}")]
|
|
394
|
+
TeamSelect(String),
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// ===========================================================================
|
|
398
|
+
// OUTCOME / REPORT(rich return — 契约断言这些 carry 的值)
|
|
399
|
+
// ===========================================================================
|
|
400
|
+
|
|
401
|
+
/// `launch(...)` 报告(`launch/core.py:294` 的 typed dict)。dry-run 时 `agents` 空、
|
|
402
|
+
/// `safety` 填充。
|
|
403
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
404
|
+
pub struct LaunchReport {
|
|
405
|
+
pub session_name: SessionName,
|
|
406
|
+
/// 实际起的 worker(冷启;dry-run 时空)。
|
|
407
|
+
pub started: Vec<StartedAgent>,
|
|
408
|
+
/// 是否 dry-run(只解析路由/权限,不起进程)。
|
|
409
|
+
pub dry_run: bool,
|
|
410
|
+
/// 路由决策(每 task 一条;`routing.decision` 事件)。
|
|
411
|
+
pub routes: Vec<RoutingDecision>,
|
|
412
|
+
/// 权限摘要(每 agent 一条)。
|
|
413
|
+
pub permissions: Vec<PermissionSummary>,
|
|
414
|
+
/// 危险审批安全态(dry-run 报告里的 `safety`)。
|
|
415
|
+
pub safety: DangerousApproval,
|
|
416
|
+
/// leader receiver(attach 成功时;经 step10 leader::attach_leader_to_state)。
|
|
417
|
+
pub leader_receiver_attached: bool,
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/// 单个已起 worker(`launch` 的 `agents[]` / `started`)。
|
|
421
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
422
|
+
pub struct StartedAgent {
|
|
423
|
+
pub agent_id: AgentId,
|
|
424
|
+
pub start_mode: StartMode,
|
|
425
|
+
pub target: String,
|
|
426
|
+
pub session_id: Option<SessionId>,
|
|
427
|
+
pub rollout_path: Option<RolloutPath>,
|
|
428
|
+
pub display: WorkerDisplay,
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/// 路由决策(`routing.decision` 事件 / launch `routes[]`)。
|
|
432
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
433
|
+
pub struct RoutingDecision {
|
|
434
|
+
pub task_id: Option<String>,
|
|
435
|
+
pub selected_agent: AgentId,
|
|
436
|
+
pub reason: String,
|
|
437
|
+
pub manual_override: bool,
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/// 权限摘要(`resolve_permissions(agent)` 的 typed 版)。**PLACEHOLDER 字段**:
|
|
441
|
+
/// 实际形状由 step6 compiler 的 `resolve_permissions` 决定,集成时映射。
|
|
442
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
443
|
+
pub struct PermissionSummary {
|
|
444
|
+
pub agent_id: AgentId,
|
|
445
|
+
pub raw: serde_json::Value,
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/// BUG-7 (0.3.1): quick-start cannot honestly report "ready" before the workers'
|
|
449
|
+
/// MCP tool sets have actually loaded — provider-side schema rejections (codex
|
|
450
|
+
/// invalid_function_parameters etc.) happen AFTER spawn and silently disable the
|
|
451
|
+
/// worker. The report must therefore carry a readiness verdict so the CLI surface
|
|
452
|
+
/// never emits bare "ready" while worker capability is unverified or already known
|
|
453
|
+
/// to be degraded.
|
|
454
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
455
|
+
pub enum QuickStartReadiness {
|
|
456
|
+
/// At least one agent already failed to materialize a live tmux window (BUG-2
|
|
457
|
+
/// observable). The team is *not* ready; user must inspect / restart.
|
|
458
|
+
Degraded { unhealthy_agents: Vec<String> },
|
|
459
|
+
/// All spawned agents have live windows but their MCP tool set load has NOT
|
|
460
|
+
/// been verified yet — provider-side schema/auth failures could still leave
|
|
461
|
+
/// the worker unable to call team_orchestrator tools. CLI must label this
|
|
462
|
+
/// `pending` / `unverified`, NOT bare `ready`.
|
|
463
|
+
PendingToolLoad,
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/// `quick_start(...)` 报告(`diagnose/quick_start.py:103` typed 版)。`Refused` 区分
|
|
467
|
+
/// existing-context(需 restart 或 --fresh)与 preflight 失败。
|
|
468
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
469
|
+
pub enum QuickStartReport {
|
|
470
|
+
/// 起队成功 + wait_ready 就绪。
|
|
471
|
+
Ready {
|
|
472
|
+
session_name: SessionName,
|
|
473
|
+
launch: Box<LaunchReport>,
|
|
474
|
+
next_actions: Vec<String>,
|
|
475
|
+
/// BUG-7: real readiness verdict. `Ready` ⇒ the wrapper completed AND the
|
|
476
|
+
/// caller already verified tool-set availability; the framework itself
|
|
477
|
+
/// never emits this without an external observable confirming worker
|
|
478
|
+
/// tool calls succeeded. quick_start_with_transport always defaults to
|
|
479
|
+
/// [`QuickStartReadiness::PendingToolLoad`] (or `Degraded` if any agent
|
|
480
|
+
/// failed to spawn) so the CLI surface cannot lie about availability.
|
|
481
|
+
worker_readiness: QuickStartReadiness,
|
|
482
|
+
},
|
|
483
|
+
/// 已有 runtime state,非 --fresh → 引导用 restart(`quick_start.py:42`)。
|
|
484
|
+
ExistingRuntime {
|
|
485
|
+
team: Option<String>,
|
|
486
|
+
session_name: Option<SessionName>,
|
|
487
|
+
state_path: Option<PathBuf>,
|
|
488
|
+
next_actions: Vec<String>,
|
|
489
|
+
},
|
|
490
|
+
/// preflight 阻塞(`quick_start.py:59`)。
|
|
491
|
+
PreflightBlocked {
|
|
492
|
+
summary: String,
|
|
493
|
+
blockers: Vec<String>,
|
|
494
|
+
next_actions: Vec<String>,
|
|
495
|
+
},
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/// 单 worker 动作通用 envelope(`{ok, agent_id, status, ...}`,`operations.py`/`agents.py`/
|
|
499
|
+
/// `start.py`)。status 的语义随动作不同,故各动作有专属 outcome enum 收口;此 struct
|
|
500
|
+
/// 是它们共享的字段载体。
|
|
501
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
502
|
+
pub struct AgentActionEnvelope {
|
|
503
|
+
pub agent_id: AgentId,
|
|
504
|
+
pub state_file: PathBuf,
|
|
505
|
+
/// coordinator 起后的报告(launch/start/fork/restart 末尾起 coordinator)。
|
|
506
|
+
pub coordinator_started: bool,
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/// `start_agent(...)` 结果(`start.py:101/134/353`)。穷尽 start 路径。
|
|
510
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
511
|
+
pub enum StartAgentOutcome {
|
|
512
|
+
/// 起/复活成功,carry start_mode(resumed/fresh/fresh_after_missing_rollout)。
|
|
513
|
+
Running {
|
|
514
|
+
env: AgentActionEnvelope,
|
|
515
|
+
start_mode: StartMode,
|
|
516
|
+
target: String,
|
|
517
|
+
session_id: Option<SessionId>,
|
|
518
|
+
rollout_path: Option<RolloutPath>,
|
|
519
|
+
},
|
|
520
|
+
/// 窗口已存在且非 force → noop(`start.py:134`)。
|
|
521
|
+
Noop {
|
|
522
|
+
env: AgentActionEnvelope,
|
|
523
|
+
target: String,
|
|
524
|
+
},
|
|
525
|
+
/// agent paused → 不起(`start.py:101`,reason=agent_paused)。
|
|
526
|
+
Paused { agent_id: AgentId },
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/// `stop_agent(...)` 结果(`operations.py:99`)。同时关显示(`test_stop_agent_display`)。
|
|
530
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
531
|
+
pub struct StopAgentReport {
|
|
532
|
+
pub agent_id: AgentId,
|
|
533
|
+
pub target: String,
|
|
534
|
+
/// 实际 kill 了的 window(已停则 false)。
|
|
535
|
+
pub stopped: bool,
|
|
536
|
+
pub display_closed: bool,
|
|
537
|
+
pub state_file: PathBuf,
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/// `reset_agent(...)` 结果(`operations.py:104/133`)。**必须 `discard_session=true`**,
|
|
541
|
+
/// 否则 `Refused{ DiscardSessionRequired }`(`test_reset_agent_discard`)。
|
|
542
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
543
|
+
pub enum ResetAgentOutcome {
|
|
544
|
+
/// discard + 重起成功。
|
|
545
|
+
Reset {
|
|
546
|
+
env: AgentActionEnvelope,
|
|
547
|
+
start_mode: StartMode,
|
|
548
|
+
},
|
|
549
|
+
/// 未传 discard_session → 拒绝(不丢上下文的误用保护)。
|
|
550
|
+
Refused { reason: ResetRefusal },
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
|
554
|
+
#[serde(rename_all = "snake_case")]
|
|
555
|
+
pub enum ResetRefusal {
|
|
556
|
+
DiscardSessionRequired,
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/// `add_agent(...)` 结果(`operations.py:272`)。动态 role doc 编译进 spec + 起 worker;
|
|
560
|
+
/// 失败字节级回滚 spec_yaml / workspace_state / **team_state.md** / role_file(Gap 15.11)。
|
|
561
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
562
|
+
pub struct AddAgentReport {
|
|
563
|
+
pub env: AgentActionEnvelope,
|
|
564
|
+
pub start_mode: StartMode,
|
|
565
|
+
/// 写入的动态 role file 路径。
|
|
566
|
+
pub role_file: PathBuf,
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/// `fork_agent(...)` 结果(`operations.py:402`)。native session fork(provider 须
|
|
570
|
+
/// supports_session_fork ∧ auth_mode!=compatible_api)。
|
|
571
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
572
|
+
pub struct ForkAgentReport {
|
|
573
|
+
pub source_agent_id: AgentId,
|
|
574
|
+
pub new_agent_id: AgentId,
|
|
575
|
+
pub env: AgentActionEnvelope,
|
|
576
|
+
pub session_id: Option<SessionId>,
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/// `remove_agent(...)` 结果(`agents.py:54/56/150`)。`_RemoveRollback` 快照
|
|
580
|
+
/// spec/state/team_state/role_file/agent_health 字节级回滚(Gap 16)。
|
|
581
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
582
|
+
pub enum RemoveAgentOutcome {
|
|
583
|
+
/// 原子摘除成功(spec/state/team_state/role-file/agent_health 全删)。
|
|
584
|
+
Removed {
|
|
585
|
+
agent_id: AgentId,
|
|
586
|
+
state_file: PathBuf,
|
|
587
|
+
/// GC 掉的 agent_health 行(`test_remove_agent_health_gc`)。
|
|
588
|
+
agent_health_deleted: bool,
|
|
589
|
+
},
|
|
590
|
+
/// 未传 from_spec 确认(`agents.py:54`)。
|
|
591
|
+
RefusedFromSpecConfirm { agent_id: AgentId },
|
|
592
|
+
/// 运行中未传 force(`agents.py:56`)。
|
|
593
|
+
RefusedForceRequired { agent_id: AgentId },
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/// `restart(...)` 结果(`orchestration.py:114/142/387`)。Route B:**先全量验证**
|
|
597
|
+
/// (resume 决策 + first_send_at 校验)**再**破坏性 teardown。refuse 时 nothing created。
|
|
598
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
599
|
+
pub enum RestartReport {
|
|
600
|
+
/// 整队重建成功。每 worker 已发 `restart.resume_decision`。
|
|
601
|
+
Restarted {
|
|
602
|
+
session_name: SessionName,
|
|
603
|
+
agents: Vec<RestartedAgent>,
|
|
604
|
+
coordinator_started: bool,
|
|
605
|
+
},
|
|
606
|
+
/// atomic refusal(`reason=resume_atomicity`):某 interacted worker 不可 resume
|
|
607
|
+
/// 且非 allow_fresh。**nothing created yet**,无需回滚。
|
|
608
|
+
RefusedResumeAtomicity {
|
|
609
|
+
unresumable: Vec<UnresumableWorker>,
|
|
610
|
+
allow_fresh: bool,
|
|
611
|
+
error: String,
|
|
612
|
+
},
|
|
613
|
+
/// first_send_at 损坏(`reason=invalid_first_send_at`):决策前 hard refuse。
|
|
614
|
+
RefusedInvalidFirstSendAt {
|
|
615
|
+
invalid: Vec<CorruptFirstSendAt>,
|
|
616
|
+
allow_fresh: bool,
|
|
617
|
+
error: String,
|
|
618
|
+
},
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/// 单个重建后的 worker(carry restart_mode)。
|
|
622
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
623
|
+
pub struct RestartedAgent {
|
|
624
|
+
pub agent_id: AgentId,
|
|
625
|
+
pub restart_mode: StartMode,
|
|
626
|
+
pub decision: ResumeDecision,
|
|
627
|
+
pub session_id: Option<SessionId>,
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/// atomic refusal 里的不可重建 worker(`orchestration.py:517`)。
|
|
631
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
632
|
+
pub struct UnresumableWorker {
|
|
633
|
+
pub agent_id: AgentId,
|
|
634
|
+
/// `no_persisted_session_id` | `session_unresumable`。
|
|
635
|
+
pub reason: String,
|
|
636
|
+
pub session_id: Option<SessionId>,
|
|
637
|
+
pub first_send_at: Option<String>,
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/// first_send_at 损坏条目(`restart.first_send_at_invalid` 事件 payload)。
|
|
641
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
642
|
+
pub struct CorruptFirstSendAt {
|
|
643
|
+
pub worker_id: AgentId,
|
|
644
|
+
pub raw_first_send_at: serde_json::Value,
|
|
645
|
+
pub raw_first_send_at_type: String,
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/// Route B 全量验证产物(`_emit_resume_decisions` + `_collect_corrupt_first_send_at`,
|
|
649
|
+
/// `orchestration.py:430/467`)。restart() **先**算它(纯计算,无副作用),corrupt 非空则
|
|
650
|
+
/// hard-refuse;否则按 decisions/unresumable 决定 teardown。把"每非 paused worker 发一条
|
|
651
|
+
/// `restart.resume_decision`" 与 "python type().__name__ 映射" 从 start_agent 的整条
|
|
652
|
+
/// lock+spawn 路径里**分离出来**,使 Route B audit 契约可在 fixture state 上单元级断言
|
|
653
|
+
/// (gate gap:restart() 只返回终态 RestartReport,缺隔离测试面)。
|
|
654
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
655
|
+
pub struct RestartPlan {
|
|
656
|
+
/// 每非 paused worker 一条决策(顺序 = restart_agents 顺序);Route B audit 契约必发。
|
|
657
|
+
pub decisions: Vec<RestartedAgent>,
|
|
658
|
+
/// first_send_at 损坏条目(决策前 hard-refuse 的依据;carry python type-name)。
|
|
659
|
+
pub corrupt_entries: Vec<CorruptFirstSendAt>,
|
|
660
|
+
/// allow_fresh=false 且 interacted-but-unresumable 的 worker(atomic_refusal 触发集)。
|
|
661
|
+
pub unresumable: Vec<UnresumableWorker>,
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/// display 解析结果(`resolve_display_backend`,`display/backend.py`)。非默认时非静默
|
|
665
|
+
/// 发 `display.backend_resolved`。
|
|
666
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
667
|
+
pub struct ResolvedBackend {
|
|
668
|
+
pub backend: DisplayBackend,
|
|
669
|
+
/// 是否非默认(默认 adaptive;非默认非静默发事件)。
|
|
670
|
+
pub non_default: bool,
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/// `open_worker_displays` 结果(`display/worker_window.py`)。每 worker 一个
|
|
674
|
+
/// `WorkerDisplay`,失败不阻塞 team readiness(C14)。
|
|
675
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
676
|
+
pub struct OpenDisplaysReport {
|
|
677
|
+
pub backend: DisplayBackend,
|
|
678
|
+
pub displays: BTreeMap<String, WorkerDisplay>,
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/// `close_team_display_backends` 结果(`display/close.py`,C9 close-by-recorded-backend)。
|
|
682
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
683
|
+
pub struct CloseDisplaysReport {
|
|
684
|
+
/// 按 state 记录的后端关掉的窗口/会话标识。
|
|
685
|
+
pub closed: Vec<String>,
|
|
686
|
+
/// orphan 清理(adaptive 只删带 team tag 的窗口,C2 leader pane 安全)。
|
|
687
|
+
pub orphans_cleaned: Vec<String>,
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/// plan 状态机推进结果(`orchestrator/__init__.py` start_plan / handle_report_result /
|
|
691
|
+
/// halt_plan 的 typed 版)。
|
|
692
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
693
|
+
pub enum PlanProgress {
|
|
694
|
+
/// 仍运行,当前 stage。
|
|
695
|
+
Running {
|
|
696
|
+
plan_id: PlanId,
|
|
697
|
+
current_stage: i64,
|
|
698
|
+
state_path: PathBuf,
|
|
699
|
+
},
|
|
700
|
+
/// 全 stage 完成。
|
|
701
|
+
Completed { plan_id: PlanId },
|
|
702
|
+
/// halted(carry reason + artifact)。
|
|
703
|
+
Halted {
|
|
704
|
+
plan_id: PlanId,
|
|
705
|
+
reason: String,
|
|
706
|
+
artifact: Option<PathBuf>,
|
|
707
|
+
},
|
|
708
|
+
/// report_result 不匹配任何 stage 条件 → no-op(`__init__.py:96`)。
|
|
709
|
+
NoMatch,
|
|
710
|
+
}
|