@team-agent/installer 0.5.65 → 0.5.68
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 +8 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/Cargo.toml +6 -0
- package/crates/team-agent/src/cli/adapters.rs +6 -1
- package/crates/team-agent/src/cli/diagnose.rs +82 -0
- package/crates/team-agent/src/cli/emit.rs +3 -3
- package/crates/team-agent/src/cli/grok_slot.rs +299 -0
- package/crates/team-agent/src/cli/leader.rs +21 -7
- package/crates/team-agent/src/cli/leaders.rs +125 -1
- package/crates/team-agent/src/cli/mod.rs +20 -0
- package/crates/team-agent/src/cli/send/presentation.rs +7 -1
- package/crates/team-agent/src/cli/spec.rs +2 -0
- package/crates/team-agent/src/cli/status_port/compact.rs +28 -0
- package/crates/team-agent/src/cli/status_port/snapshot.rs +25 -1
- package/crates/team-agent/src/cli/tests/base.rs +26 -3
- package/crates/team-agent/src/cli/tests/compile.rs +1 -1
- package/crates/team-agent/src/cli/tests/missing_subcommands.rs +129 -19
- package/crates/team-agent/src/cli/tests/mod.rs +2 -2
- package/crates/team-agent/src/cli/tests/run_delegation.rs +1 -1
- package/crates/team-agent/src/cli/tests/shutdown_kill_plan.rs +387 -6
- package/crates/team-agent/src/cli/tests/status_send.rs +79 -10
- package/crates/team-agent/src/cli/tests/verb_validate.rs +1 -1
- package/crates/team-agent/src/communication_mode/mod.rs +6 -4
- package/crates/team-agent/src/compiler/tests.rs +23 -20
- package/crates/team-agent/src/compiler.rs +84 -5
- package/crates/team-agent/src/conpty/backend.rs +16 -0
- package/crates/team-agent/src/coordinator/backoff.rs +55 -0
- package/crates/team-agent/src/coordinator/conpty_shim.rs +82 -0
- package/crates/team-agent/src/coordinator/health.rs +173 -0
- package/crates/team-agent/src/coordinator/mod.rs +31 -0
- package/crates/team-agent/src/coordinator/orphan.rs +31 -0
- package/crates/team-agent/src/coordinator/runtime_detectors.rs +30 -0
- package/crates/team-agent/src/coordinator/runtime_observation.rs +25 -0
- package/crates/team-agent/src/coordinator/steps/abnormal.rs +59 -0
- package/crates/team-agent/src/coordinator/steps/delivery.rs +10 -0
- package/crates/team-agent/src/coordinator/steps/health_sync.rs +10 -0
- package/crates/team-agent/src/coordinator/steps/mod.rs +22 -0
- package/crates/team-agent/src/coordinator/steps/persist.rs +10 -0
- package/crates/team-agent/src/coordinator/steps/runtime_prompts.rs +10 -0
- package/crates/team-agent/src/coordinator/steps/session_gate.rs +10 -0
- package/crates/team-agent/src/coordinator/tick.rs +133 -22
- package/crates/team-agent/src/coordinator/types.rs +49 -0
- package/crates/team-agent/src/db/message_store.rs +39 -5
- package/crates/team-agent/src/layout/worker_env.rs +20 -3
- package/crates/team-agent/src/layout/worker_window_helpers.rs +2 -0
- package/crates/team-agent/src/leader/provider_attribution.rs +53 -0
- package/crates/team-agent/src/leader/registry.rs +65 -0
- package/crates/team-agent/src/leader/start.rs +1080 -58
- package/crates/team-agent/src/leader/tests/team_in_team_state_scope_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/display.rs +56 -0
- package/crates/team-agent/src/lifecycle/helpers.rs +57 -0
- package/crates/team-agent/src/lifecycle/launch/add_agent.rs +332 -14
- package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +69 -2
- package/crates/team-agent/src/lifecycle/launch/agent_state.rs +196 -2
- package/crates/team-agent/src/lifecycle/launch/clone_agent.rs +101 -11
- package/crates/team-agent/src/lifecycle/launch/cursor_create_chat.rs +229 -0
- package/crates/team-agent/src/lifecycle/launch/cursor_mcp.rs +332 -0
- package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +204 -457
- package/crates/team-agent/src/lifecycle/launch/fork_entry.rs +24 -0
- package/crates/team-agent/src/lifecycle/launch/grok_per_seat.rs +260 -0
- package/crates/team-agent/src/lifecycle/launch/identity.rs +146 -0
- package/crates/team-agent/src/lifecycle/launch/layout.rs +60 -0
- package/crates/team-agent/src/lifecycle/launch/leader_context.rs +112 -0
- package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +530 -0
- package/crates/team-agent/src/lifecycle/launch/ownership.rs +40 -0
- package/crates/team-agent/src/lifecycle/launch/plan.rs +31 -0
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +66 -0
- package/crates/team-agent/src/lifecycle/launch/quick_start_transport.rs +78 -0
- package/crates/team-agent/src/lifecycle/launch/readiness.rs +85 -38
- package/crates/team-agent/src/lifecycle/launch/role_source.rs +44 -44
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +101 -4
- package/crates/team-agent/src/lifecycle/launch/spec_state.rs +244 -48
- package/crates/team-agent/src/lifecycle/launch/state_projection.rs +109 -2
- package/crates/team-agent/src/lifecycle/launch/worker_env.rs +214 -1
- package/crates/team-agent/src/lifecycle/launch.rs +209 -43
- package/crates/team-agent/src/lifecycle/lock.rs +42 -1
- package/crates/team-agent/src/lifecycle/mod.rs +11 -0
- package/crates/team-agent/src/lifecycle/pane_input_lock.rs +161 -0
- package/crates/team-agent/src/lifecycle/profile_launch.rs +98 -0
- package/crates/team-agent/src/lifecycle/profile_smoke.rs +51 -1
- package/crates/team-agent/src/lifecycle/restart/agent.rs +213 -3
- package/crates/team-agent/src/lifecycle/restart/common.rs +373 -18
- package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +27 -0
- package/crates/team-agent/src/lifecycle/restart/preflight.rs +25 -0
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +165 -15
- package/crates/team-agent/src/lifecycle/restart/remove.rs +196 -5
- package/crates/team-agent/src/lifecycle/restart/selection.rs +72 -0
- package/crates/team-agent/src/lifecycle/restart/team_state.rs +22 -0
- package/crates/team-agent/src/lifecycle/restart.rs +29 -0
- package/crates/team-agent/src/lifecycle/tests/acceptance_b_batch_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +3 -4
- package/crates/team-agent/src/lifecycle/tests/behavioral_diff_264_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +4 -4
- package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +309 -0
- package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +159 -174
- package/crates/team-agent/src/lifecycle/tests/communication_mode_runtime_contract_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +15 -13
- package/crates/team-agent/src/lifecycle/tests/core.rs +4 -18
- package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/cursor_mcp_overlay.rs +287 -0
- package/crates/team-agent/src/lifecycle/tests/cursor_require_explicit_model_red.rs +229 -0
- package/crates/team-agent/src/lifecycle/tests/cursor_restart_resume_red.rs +353 -0
- package/crates/team-agent/src/lifecycle/tests/display_adaptive_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/f032_startup_prompt_best_effort_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +784 -0
- package/crates/team-agent/src/lifecycle/tests/gate_fixtures.rs +562 -0
- package/crates/team-agent/src/lifecycle/tests/grok_effort_argv_red.rs +239 -0
- package/crates/team-agent/src/lifecycle/tests/grok_mcp_overlay_red.rs +498 -0
- package/crates/team-agent/src/lifecycle/tests/grok_require_explicit_model_red.rs +250 -0
- package/crates/team-agent/src/lifecycle/tests/grok_restart_resume_red.rs +293 -0
- package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +3 -0
- package/crates/team-agent/src/lifecycle/tests/host_cotenant_death_p0_contract.rs +3 -3
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +65 -40
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +20 -32
- package/crates/team-agent/src/lifecycle/tests/lifecycle_rollback_red.rs +17 -9
- package/crates/team-agent/src/lifecycle/tests/mcp_tool_name_format_red.rs +69 -0
- package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +24 -23
- package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +98 -62
- package/crates/team-agent/src/lifecycle/tests/quick_start_worker_readiness_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/restart_build_before_destroy_0540_contract.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/restart_liveness_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +3 -1
- package/crates/team-agent/src/lifecycle/tests/restart_session_capture_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/resume_recover_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +41 -8
- package/crates/team-agent/src/lifecycle/tests/status_credential_redaction_contract.rs +3 -3
- package/crates/team-agent/src/lifecycle/tests/subprep_codex_trust_roundtrip_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/swallow_batch4_semantics_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/team_in_team_sibling_quick_start_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/team_in_team_state_scope_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/team_key_retirement_txn_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +60 -2
- package/crates/team-agent/src/lifecycle/tests/upgrade_compat_0211_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/verify_rs031_window_consistency_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +69 -26
- package/crates/team-agent/src/lifecycle/tests.rs +23 -15
- package/crates/team-agent/src/lifecycle/types.rs +61 -2
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +200 -33
- package/crates/team-agent/src/mcp_server/tests/scoped.rs +100 -1
- package/crates/team-agent/src/mcp_server/tests.rs +196 -2
- package/crates/team-agent/src/messaging/delivery.rs +405 -40
- package/crates/team-agent/src/messaging/helpers.rs +2 -0
- package/crates/team-agent/src/messaging/leader_receiver.rs +53 -1
- package/crates/team-agent/src/messaging/results.rs +4 -0
- package/crates/team-agent/src/messaging/send.rs +34 -0
- package/crates/team-agent/src/messaging/tests/dup_inject.rs +406 -0
- package/crates/team-agent/src/messaging/tests/e23.rs +9 -0
- package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +66 -0
- package/crates/team-agent/src/messaging/tests/main_preserved.rs +1 -1
- package/crates/team-agent/src/messaging/tests/mod.rs +1 -0
- package/crates/team-agent/src/messaging/types.rs +4 -1
- package/crates/team-agent/src/model/enums.rs +14 -5
- package/crates/team-agent/src/model/permissions.rs +3 -0
- package/crates/team-agent/src/model/spec.rs +129 -6
- package/crates/team-agent/src/model/testdata/spec_invalid_a.yaml +3 -1
- package/crates/team-agent/src/model/testdata/team.spec.golden.yaml +3 -1
- package/crates/team-agent/src/model/testdata/team.spec.yaml +3 -1
- package/crates/team-agent/src/os_probe.rs +73 -2
- package/crates/team-agent/src/provider/adapter.rs +231 -4
- package/crates/team-agent/src/provider/adapters/claude.rs +5 -2
- package/crates/team-agent/src/provider/adapters/codex.rs +5 -2
- package/crates/team-agent/src/provider/adapters/copilot.rs +5 -2
- package/crates/team-agent/src/provider/adapters/cursor_agent.rs +86 -0
- package/crates/team-agent/src/provider/adapters/grok.rs +157 -0
- package/crates/team-agent/src/provider/adapters/mod.rs +2 -0
- package/crates/team-agent/src/provider/bypass_flags.rs +124 -0
- package/crates/team-agent/src/provider/classify.rs +4 -2
- package/crates/team-agent/src/provider/faults.rs +2 -1
- package/crates/team-agent/src/provider/mod.rs +13 -0
- package/crates/team-agent/src/provider/session/capture.rs +158 -20
- package/crates/team-agent/src/provider/session/context_fork/claude.rs +38 -1
- package/crates/team-agent/src/provider/session/context_fork/codex.rs +72 -1
- package/crates/team-agent/src/provider/session/context_fork/outcome.rs +57 -1
- package/crates/team-agent/src/provider/session/context_fork.rs +77 -3
- package/crates/team-agent/src/provider/session/mod.rs +18 -0
- package/crates/team-agent/src/provider/session/resume.rs +57 -0
- package/crates/team-agent/src/provider/session_scan/claude.rs +125 -1
- package/crates/team-agent/src/provider/session_scan/codex.rs +94 -1
- package/crates/team-agent/src/provider/session_scan/common.rs +204 -2
- package/crates/team-agent/src/provider/session_scan/copilot.rs +33 -1
- package/crates/team-agent/src/provider/session_scan/cursor.rs +538 -0
- package/crates/team-agent/src/provider/session_scan/grok.rs +288 -0
- package/crates/team-agent/src/provider/session_scan.rs +8 -0
- package/crates/team-agent/src/provider/submit_now.rs +94 -0
- package/crates/team-agent/src/provider/tests/adapter.rs +304 -0
- package/crates/team-agent/src/provider/types.rs +4 -2
- package/crates/team-agent/src/provider/wire.rs +23 -1
- package/crates/team-agent/src/state/persist.rs +301 -8
- package/crates/team-agent/src/state/repository.rs +5 -0
- package/crates/team-agent/src/tmux_backend/tests.rs +1737 -42
- package/crates/team-agent/src/tmux_backend.rs +1083 -75
- package/crates/team-agent/src/transport/test_support.rs +20 -0
- package/crates/team-agent/src/transport/tests/wire.rs +28 -2
- package/crates/team-agent/src/transport.rs +265 -1
- package/npm/install.mjs +129 -73
- package/package.json +4 -4
- package/skills/team-agent/SKILL.md +33 -238
- package/skills/team-agent/command-coverage.json +31 -0
- package/crates/team-agent/src/lifecycle/launch/approval.rs +0 -134
- package/crates/team-agent/src/lifecycle/launch/fork_agent/completion.rs +0 -59
- package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +0 -483
- package/crates/team-agent/src/lifecycle/launch/fork_pending.rs +0 -109
- package/crates/team-agent/src/lifecycle/launch/fork_state.rs +0 -447
- package/crates/team-agent/src/lifecycle/tests/codex_mcp_approval_inheritance_red.rs +0 -1187
- package/crates/team-agent/src/lifecycle/tests/worker_dangerous_bypass_argv_red.rs +0 -327
|
@@ -1,3 +1,43 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: coordinator daemon 的健康判定、幂等启停与只读观测面——pid/metadata/schema 三合一健康、spawn 与终止、runtime 路径、以及 team-agent watch 的事件渲染
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: coordinator_health
|
|
6
|
+
//! what: 由 pid 文件、coordinator.json 与 message store schema 合成 HealthReport,ok 与 service_available 分开表达
|
|
7
|
+
//! - name: start_coordinator
|
|
8
|
+
//! what: 幂等启动:已健康则 no-op,metadata 不兼容先停再起,schema 不兼容拒启并给修复 hint
|
|
9
|
+
//! - name: start_coordinator_with_team
|
|
10
|
+
//! what: 同上,并把 team_key 以 --team 传给子进程,免得 daemon 自己从 state 推
|
|
11
|
+
//! - name: stop_coordinator
|
|
12
|
+
//! what: 终止 daemon 并清 pid/meta;pid 文件缺失时用 ps 扫描发现流浪 coordinator
|
|
13
|
+
//! - name: collect_watch_lines
|
|
14
|
+
//! what: 从 events.jsonl 与结果表增量取出可渲染行,并推进 WatchCursor
|
|
15
|
+
//! - name: render_event_line
|
|
16
|
+
//! what: 把一条结构化事件渲染成人类可读行,不认识的事件返回 None
|
|
17
|
+
//! - name: run_watch
|
|
18
|
+
//! what: team-agent watch 主循环:反复 collect 后输出并 sleep
|
|
19
|
+
//! - name: coordinator_pid_path
|
|
20
|
+
//! what: coordinator.pid 的位置
|
|
21
|
+
//! - name: coordinator_meta_path
|
|
22
|
+
//! what: coordinator.json 的位置
|
|
23
|
+
//! - name: coordinator_log_path
|
|
24
|
+
//! what: coordinator.log 的位置
|
|
25
|
+
//! depends:
|
|
26
|
+
//! - super::types
|
|
27
|
+
//! - crate::message_store
|
|
28
|
+
//! - crate::db::schema
|
|
29
|
+
//! - crate::event_log
|
|
30
|
+
//! - crate::model::paths
|
|
31
|
+
//! - crate::packaging
|
|
32
|
+
//! - crate::platform::process
|
|
33
|
+
//! - crate::os_probe
|
|
34
|
+
//! boundary:
|
|
35
|
+
//! - 不做 tick 编排,也不投递任何消息
|
|
36
|
+
//! - 不读 provider 凭据、不碰 .env;身份只取自当前可执行文件与已落盘 metadata
|
|
37
|
+
//! - 终止进程限定本 workspace:优先按本次判定拿到的精确 pid;pid 文件缺失时的流浪回收会按 ps 命令行匹配「coordinator --workspace <本 ws>」发现目标,仍不做跨 workspace 的 pkill/killall 泛清
|
|
38
|
+
//! - watch 侧只读:不重放已归档段,rotation 只插一条 marker 并重置 offset
|
|
39
|
+
//! maturity: wired
|
|
40
|
+
//! ---
|
|
1
41
|
//!
|
|
2
42
|
//! coordinator 健康/身份 & 只读可观测面:metadata 身份原语 + coordinator 路径 + watch 实时流。
|
|
3
43
|
|
|
@@ -27,6 +67,12 @@ use super::types::{
|
|
|
27
67
|
// ===========================================================================
|
|
28
68
|
|
|
29
69
|
/// `coordinator_health`(`lifecycle.py:38-46`):`running ∧ metadata_ok ∧ schema_ok` → typed report.
|
|
70
|
+
/// ---
|
|
71
|
+
/// purpose: 一次性判定本 workspace 的 coordinator daemon 是否健康
|
|
72
|
+
/// params:
|
|
73
|
+
/// workspace: workspace 根;pid/metadata 路径与 message store 都由它派生
|
|
74
|
+
/// returns: HealthReport。ok = 进程在跑 ∧ metadata 三元全等 ∧ 二进制身份一致 ∧ schema 兼容;service_available 刻意排除二进制身份,表示「这个 daemon 还能处理本队队列」;status 区分 Missing / InvalidPid / Running / Stale
|
|
75
|
+
/// ---
|
|
30
76
|
pub fn coordinator_health(workspace: &WorkspacePath) -> HealthReport {
|
|
31
77
|
let schema = message_store_schema_health(workspace);
|
|
32
78
|
let current_binary_identity = current_coordinator_binary_identity();
|
|
@@ -73,6 +119,13 @@ pub fn coordinator_health(workspace: &WorkspacePath) -> HealthReport {
|
|
|
73
119
|
|
|
74
120
|
/// `start_coordinator`(`lifecycle.py:49-121`):幂等 — 已健康 no-op(AlreadyRunning);metadata 不兼容
|
|
75
121
|
/// 先 stop 再起;schema 不兼容拒启 + hint;否则 spawn `team-agent coordinator --workspace <ws>`。
|
|
122
|
+
/// ---
|
|
123
|
+
/// purpose: 不带 team_key 的幂等启动入口
|
|
124
|
+
/// params:
|
|
125
|
+
/// workspace: workspace 根
|
|
126
|
+
/// returns: 与 start_coordinator_with_team(workspace, None) 完全一致
|
|
127
|
+
/// errors: 同 start_coordinator_with_team
|
|
128
|
+
/// ---
|
|
76
129
|
pub fn start_coordinator(workspace: &WorkspacePath) -> Result<StartReport, StartError> {
|
|
77
130
|
start_coordinator_with_team(workspace, None)
|
|
78
131
|
}
|
|
@@ -85,6 +138,14 @@ pub fn start_coordinator(workspace: &WorkspacePath) -> Result<StartReport, Start
|
|
|
85
138
|
///
|
|
86
139
|
/// Callers that CAN pass team_key (Batch 9 quick-start Windows path)
|
|
87
140
|
/// SHOULD — that avoids Batch 8's F8 seed-state trap.
|
|
141
|
+
/// ---
|
|
142
|
+
/// purpose: 幂等启动 coordinator daemon 子进程,并把不兼容/需轮换的情形分成互不折叠的结局
|
|
143
|
+
/// params:
|
|
144
|
+
/// workspace: workspace 根
|
|
145
|
+
/// team_key: 传给子进程的 --team;None 或空串时子进程回落到 state.active_team_key
|
|
146
|
+
/// returns: StartReport。已健康 → AlreadyRunning(含「daemon 比调用方新,保留不动」这一支,rotation_reason=daemon_newer_than_caller);schema 不兼容 → SchemaIncompatible 且 ok=false 并带修复 hint;在跑但 wire metadata 不兼容、或 metadata 指向调用方自身、或先停失败 → RestartIncompatibleStopFailed;成功 spawn → Started,因身份轮换而重起则为 StartedAfterRotation
|
|
147
|
+
/// errors: 建目录、开日志、spawn、写 pid/metadata 或写事件失败时返回 StartError;「拒启」不是 Err,而是 ok=false 的报告
|
|
148
|
+
/// ---
|
|
88
149
|
pub fn start_coordinator_with_team(
|
|
89
150
|
workspace: &WorkspacePath,
|
|
90
151
|
team_key: Option<&str>,
|
|
@@ -322,6 +383,13 @@ fn detach_daemon_child(command: &mut Command) {
|
|
|
322
383
|
fn detach_daemon_child(_command: &mut Command) {}
|
|
323
384
|
|
|
324
385
|
/// `stop_coordinator`(`lifecycle.py:228-247`):SIGTERM pid + 清 pid/meta → typed report。
|
|
386
|
+
/// ---
|
|
387
|
+
/// purpose: 停掉本 workspace 的 coordinator daemon 并清掉 pid/meta 文件
|
|
388
|
+
/// params:
|
|
389
|
+
/// workspace: workspace 根
|
|
390
|
+
/// returns: StopReport。pid 文件不存在时先尝试按 ps 发现流浪 coordinator,仍没有则 Missing;pid 文件内容非法 → 清文件并报 InvalidPidRemoved;终止成功 → Stopped;信号发不出去 → KillFailed
|
|
391
|
+
/// errors: 删 pid/meta 文件失败时返回 StopError;本函数不写事件(EventLog 变体在此路径无产生点)
|
|
392
|
+
/// ---
|
|
325
393
|
pub fn stop_coordinator(workspace: &WorkspacePath) -> Result<StopReport, StopError> {
|
|
326
394
|
let pid_path = coordinator_pid_path(workspace);
|
|
327
395
|
if !pid_path.exists() {
|
|
@@ -498,6 +566,12 @@ fn terminate_pid(pid: Pid) -> bool {
|
|
|
498
566
|
|
|
499
567
|
/// Public wrapper for diagnostic cleanup paths that must reuse coordinator
|
|
500
568
|
/// shutdown's SIGTERM-then-SIGKILL semantics.
|
|
569
|
+
/// ---
|
|
570
|
+
/// purpose: 把 coordinator 停机用的「先温和后强制」终止语义暴露给诊断清理路径复用
|
|
571
|
+
/// params:
|
|
572
|
+
/// pid: 要终止的进程;只终止这棵进程树,不做名字匹配的批量清理
|
|
573
|
+
/// returns: 超时窗口内整棵树都不再存活为 true
|
|
574
|
+
/// ---
|
|
501
575
|
pub fn terminate_pid_tree(pid: Pid) -> bool {
|
|
502
576
|
terminate_pid(pid)
|
|
503
577
|
}
|
|
@@ -607,6 +681,14 @@ fn wait_until_not_running(pid: Pid, timeout: Duration) -> bool {
|
|
|
607
681
|
/// `ps stat=` step has no analogue). This preserves the coordinator's
|
|
608
682
|
/// "am I the owner" check without silently reporting stale pids as
|
|
609
683
|
/// alive.
|
|
684
|
+
/// ---
|
|
685
|
+
/// purpose: 判断某 pid 是不是本 coordinator 还能拥有的活进程(Unix 实现)
|
|
686
|
+
/// params:
|
|
687
|
+
/// pid: 待判定进程号
|
|
688
|
+
/// returns: 存活且非僵尸为 true。语义与通用存活探针不同:signal 返回 EPERM 一律判 false,因为 coordinator 只认自己能发信号的进程;另用 ps 的 stat 排掉僵尸
|
|
689
|
+
/// errors: 除 EPERM/ESRCH 外的 signal 错误、以及 ps 探测失败时返回 io::Error
|
|
690
|
+
/// cfg: unix
|
|
691
|
+
/// ---
|
|
610
692
|
#[cfg(unix)]
|
|
611
693
|
pub fn pid_is_running(pid: Pid) -> Result<bool, std::io::Error> {
|
|
612
694
|
let Ok(pid_t) = libc::pid_t::try_from(pid.get()) else {
|
|
@@ -640,6 +722,14 @@ pub fn pid_is_running(pid: Pid) -> Result<bool, std::io::Error> {
|
|
|
640
722
|
/// treats as `Live`; so on Windows the coordinator sees a process
|
|
641
723
|
/// it can't query as still-running (safer than pretending it's gone
|
|
642
724
|
/// and losing the ownership handle).
|
|
725
|
+
/// ---
|
|
726
|
+
/// purpose: 判断某 pid 是不是本 coordinator 还能拥有的活进程(非 Unix 实现)
|
|
727
|
+
/// params:
|
|
728
|
+
/// pid: 待判定进程号
|
|
729
|
+
/// returns: 平台层报 Live 为 true,Dead 或 Unknown 均为 false。Windows 没有僵尸态,故不做 ps stat 那一步;平台层把拒绝访问算作 Live,于是查不动的进程仍被视为在跑
|
|
730
|
+
/// errors: 平台层存活查询失败时返回 io::Error
|
|
731
|
+
/// cfg: not(unix)
|
|
732
|
+
/// ---
|
|
643
733
|
#[cfg(not(unix))]
|
|
644
734
|
pub fn pid_is_running(pid: Pid) -> Result<bool, std::io::Error> {
|
|
645
735
|
match crate::platform::process::pid_liveness(pid.get())? {
|
|
@@ -650,11 +740,21 @@ pub fn pid_is_running(pid: Pid) -> Result<bool, std::io::Error> {
|
|
|
650
740
|
}
|
|
651
741
|
|
|
652
742
|
/// `read_coordinator_metadata`(`metadata.py:28-34`)。读 `coordinator.json`;损坏/缺失/非 dict → `None`。
|
|
743
|
+
/// ---
|
|
744
|
+
/// purpose: 读出已落盘的 coordinator.json
|
|
745
|
+
/// params:
|
|
746
|
+
/// workspace: workspace 根
|
|
747
|
+
/// returns: 解析成功才有值;文件缺失、读不动或 JSON 形状不符一律为 None,绝不返回半份 metadata
|
|
748
|
+
/// ---
|
|
653
749
|
pub fn read_coordinator_metadata(workspace: &WorkspacePath) -> Option<CoordinatorMetadata> {
|
|
654
750
|
let text = std::fs::read_to_string(coordinator_meta_path(workspace)).ok()?;
|
|
655
751
|
serde_json::from_str(&text).ok()
|
|
656
752
|
}
|
|
657
753
|
|
|
754
|
+
/// ---
|
|
755
|
+
/// purpose: 给出「当前这个 CLI 二进制」的身份,用于和 daemon 已记录的身份比对
|
|
756
|
+
/// returns: 路径取自当前可执行文件(尽量 canonicalize)而非 PATH 查找,版本取自编译进来的包版本;路径取不到时退化成 <unknown>。测试可用 TEAM_AGENT_TEST_CALLER_BINARY_IDENTITY 覆盖,且只有两字段都非空才采信
|
|
757
|
+
/// ---
|
|
658
758
|
pub fn current_coordinator_binary_identity() -> CoordinatorBinaryIdentity {
|
|
659
759
|
if let Ok(raw) = std::env::var("TEAM_AGENT_TEST_CALLER_BINARY_IDENTITY") {
|
|
660
760
|
if let Ok(identity) = serde_json::from_str::<CoordinatorBinaryIdentity>(&raw) {
|
|
@@ -675,10 +775,24 @@ pub fn current_coordinator_binary_identity() -> CoordinatorBinaryIdentity {
|
|
|
675
775
|
|
|
676
776
|
/// `coordinator_metadata_ok` now includes daemon binary identity in addition
|
|
677
777
|
/// to the original pid/protocol/schema tuple.
|
|
778
|
+
/// ---
|
|
779
|
+
/// purpose: 判断已落盘 metadata 是否与当前事实完全一致
|
|
780
|
+
/// params:
|
|
781
|
+
/// metadata: 已读出的 coordinator.json;None 视为不一致
|
|
782
|
+
/// pid: 实际观测到的 daemon pid
|
|
783
|
+
/// returns: pid、协议版本、message store schema 版本、以及 daemon 二进制身份四者全对才为 true
|
|
784
|
+
/// ---
|
|
678
785
|
pub fn coordinator_metadata_ok(metadata: Option<&CoordinatorMetadata>, pid: Pid) -> bool {
|
|
679
786
|
coordinator_metadata_mismatch_reason(metadata, pid).is_none()
|
|
680
787
|
}
|
|
681
788
|
|
|
789
|
+
/// ---
|
|
790
|
+
/// purpose: 给出 metadata 不一致的机器可读原因,而不是只给一个布尔
|
|
791
|
+
/// params:
|
|
792
|
+
/// metadata: 已读出的 coordinator.json;None 时原因为 MetadataMissing
|
|
793
|
+
/// pid: 实际观测到的 daemon pid
|
|
794
|
+
/// returns: 第一个不匹配项对应的原因;全部一致时为 None。先判 pid/协议/schema 这组线协议字段,再判二进制身份
|
|
795
|
+
/// ---
|
|
682
796
|
pub fn coordinator_metadata_mismatch_reason(
|
|
683
797
|
metadata: Option<&CoordinatorMetadata>,
|
|
684
798
|
pid: Pid,
|
|
@@ -833,6 +947,15 @@ fn path_matches(metadata_path: &str, path: &Path) -> bool {
|
|
|
833
947
|
|
|
834
948
|
/// `write_coordinator_metadata`(`metadata.py:46-61`)。写 `coordinator.json`(pretty indent=2),
|
|
835
949
|
/// `updated_at = now(utc).isoformat()`。
|
|
950
|
+
/// ---
|
|
951
|
+
/// purpose: 落盘 coordinator.json,把当前 daemon 的身份三元与二进制身份记下来
|
|
952
|
+
/// params:
|
|
953
|
+
/// workspace: workspace 根
|
|
954
|
+
/// pid: 本次要记录的 daemon pid
|
|
955
|
+
/// source: 这份 metadata 是 daemon 自举时写的还是 CLI start 时写的
|
|
956
|
+
/// returns: 写成功返回 ()。协议版本与 schema 版本取自当前构建常量,updated_at 是写入时刻的 UTC
|
|
957
|
+
/// errors: 建目录、序列化或写文件失败时返回 io::Error
|
|
958
|
+
/// ---
|
|
836
959
|
pub fn write_coordinator_metadata(
|
|
837
960
|
workspace: &WorkspacePath,
|
|
838
961
|
pid: Pid,
|
|
@@ -856,6 +979,12 @@ pub fn write_coordinator_metadata(
|
|
|
856
979
|
std::fs::write(path, text)
|
|
857
980
|
}
|
|
858
981
|
|
|
982
|
+
/// ---
|
|
983
|
+
/// purpose: 用「能不能真的打开本队 message store」来判 schema 兼容门
|
|
984
|
+
/// params:
|
|
985
|
+
/// workspace: workspace 根
|
|
986
|
+
/// returns: 打开成功则 ok=true 且 error/action 为空;失败则 ok=false,带 InitFailed 原文与修复 hint。schema_version 恒为当前构建的版本号
|
|
987
|
+
/// ---
|
|
859
988
|
pub(crate) fn message_store_schema_health(workspace: &WorkspacePath) -> SchemaHealth {
|
|
860
989
|
match MessageStore::open(workspace.as_path()) {
|
|
861
990
|
Ok(_) => SchemaHealth {
|
|
@@ -894,16 +1023,34 @@ fn remove_file_if_exists(path: &Path) -> Result<(), std::io::Error> {
|
|
|
894
1023
|
// ===========================================================================
|
|
895
1024
|
|
|
896
1025
|
/// `coordinator.pid` 路径(`paths.py:8`)= `runtime_dir(workspace)/coordinator.pid`。
|
|
1026
|
+
/// ---
|
|
1027
|
+
/// purpose: 给出 coordinator.pid 的位置
|
|
1028
|
+
/// params:
|
|
1029
|
+
/// workspace: workspace 根
|
|
1030
|
+
/// returns: runtime 目录下的 coordinator.pid;只算路径,不保证文件存在
|
|
1031
|
+
/// ---
|
|
897
1032
|
pub fn coordinator_pid_path(workspace: &WorkspacePath) -> PathBuf {
|
|
898
1033
|
crate::model::paths::runtime_dir(workspace.as_path()).join("coordinator.pid")
|
|
899
1034
|
}
|
|
900
1035
|
|
|
901
1036
|
/// `coordinator.json` 路径(`paths.py:12`)。
|
|
1037
|
+
/// ---
|
|
1038
|
+
/// purpose: 给出 coordinator.json 的位置
|
|
1039
|
+
/// params:
|
|
1040
|
+
/// workspace: workspace 根
|
|
1041
|
+
/// returns: runtime 目录下的 coordinator.json;只算路径,不保证文件存在
|
|
1042
|
+
/// ---
|
|
902
1043
|
pub fn coordinator_meta_path(workspace: &WorkspacePath) -> PathBuf {
|
|
903
1044
|
crate::model::paths::runtime_dir(workspace.as_path()).join("coordinator.json")
|
|
904
1045
|
}
|
|
905
1046
|
|
|
906
1047
|
/// `coordinator.log` 路径(`paths.py:16`)。
|
|
1048
|
+
/// ---
|
|
1049
|
+
/// purpose: 给出 coordinator.log 的位置
|
|
1050
|
+
/// params:
|
|
1051
|
+
/// workspace: workspace 根
|
|
1052
|
+
/// returns: runtime 目录下的 coordinator.log;daemon 子进程的 stdout/stderr 都追加到这里
|
|
1053
|
+
/// ---
|
|
907
1054
|
pub fn coordinator_log_path(workspace: &WorkspacePath) -> PathBuf {
|
|
908
1055
|
crate::model::paths::runtime_dir(workspace.as_path()).join("coordinator.log")
|
|
909
1056
|
}
|
|
@@ -915,6 +1062,16 @@ pub fn coordinator_log_path(workspace: &WorkspacePath) -> PathBuf {
|
|
|
915
1062
|
/// `collect_watch_lines`(`watch.py:40`)。tail events.jsonl(过滤 team)+ latest_results,
|
|
916
1063
|
/// 渲染人类可读行;处理 log rotation(ROTATION_MARKER + offset 重置,不重放历史段)。
|
|
917
1064
|
/// 推进 `cursor`。
|
|
1065
|
+
/// ---
|
|
1066
|
+
/// purpose: 增量取出自上次游标以来的可渲染 watch 行(事件 + 结果两路)
|
|
1067
|
+
/// params:
|
|
1068
|
+
/// workspace: workspace 根
|
|
1069
|
+
/// cursor: 可变游标,函数会推进 offset、已见结果 id 集合与归档签名
|
|
1070
|
+
/// store: 已打开的 message store,用于取结果行
|
|
1071
|
+
/// team: 只看这个 team 的事件;None 表示不过滤
|
|
1072
|
+
/// returns: 本次新增的渲染行,事件行在前、结果行在后;无新内容时为空 Vec
|
|
1073
|
+
/// errors: 读事件文件或查库失败时返回 WatchError
|
|
1074
|
+
/// ---
|
|
918
1075
|
pub fn collect_watch_lines(
|
|
919
1076
|
workspace: &WorkspacePath,
|
|
920
1077
|
cursor: &mut WatchCursor,
|
|
@@ -1031,6 +1188,12 @@ fn collect_result_lines(
|
|
|
1031
1188
|
/// `render_event_line`(`watch.py:46-63`)。把一条 step 4 事件渲染成人类可读行;非可渲染事件 → `None`。
|
|
1032
1189
|
/// 消费的事件类型:`result_received` / `leader_receiver.{injected,submitted}` / `send.failed` /
|
|
1033
1190
|
/// `leader_receiver.rebind_required` / `leader.api_error`(card 表)。
|
|
1191
|
+
/// ---
|
|
1192
|
+
/// purpose: 把一条结构化事件渲染成一行人类可读文本
|
|
1193
|
+
/// params:
|
|
1194
|
+
/// event: 事件 JSON 对象;靠其中的 event 字段分派
|
|
1195
|
+
/// returns: 已知事件类型返回渲染行,其余一律 None(不猜、不打印原始 JSON)。摘要字段做长度截断
|
|
1196
|
+
/// ---
|
|
1034
1197
|
pub fn render_event_line(event: &Value) -> Option<String> {
|
|
1035
1198
|
let event_name = event.get("event").and_then(Value::as_str)?;
|
|
1036
1199
|
match event_name {
|
|
@@ -1087,6 +1250,16 @@ pub fn render_event_line(event: &Value) -> Option<String> {
|
|
|
1087
1250
|
|
|
1088
1251
|
/// `run_watch`(`watch.py:25`)。`team-agent watch` 主循环:反复 `collect_watch_lines` + 输出 + sleep。
|
|
1089
1252
|
/// `output`/`sleep` 注入便于测试。§10 返 Result。
|
|
1253
|
+
/// ---
|
|
1254
|
+
/// purpose: team-agent watch 的主循环:反复增量收集、输出、休眠
|
|
1255
|
+
/// params:
|
|
1256
|
+
/// workspace: workspace 根
|
|
1257
|
+
/// team: 只看这个 team;None 表示不过滤
|
|
1258
|
+
/// interval_sec: 轮询间隔;非有限值或非正数时回落到内置默认
|
|
1259
|
+
/// output: 输出回调,注入以便测试;本函数自己不写 stdout
|
|
1260
|
+
/// returns: 循环结束时为 Ok。这是个长跑循环,正常运行期间不返回
|
|
1261
|
+
/// errors: 打开 message store 或某轮收集失败时返回 WatchError
|
|
1262
|
+
/// ---
|
|
1090
1263
|
pub fn run_watch(
|
|
1091
1264
|
workspace: &WorkspacePath,
|
|
1092
1265
|
team: Option<&str>,
|
|
@@ -1,3 +1,34 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: coordinator 子系统装配面——声明各子模块并把它们的公开面重导出到 crate::coordinator
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: run_daemon
|
|
6
|
+
//! what: per-workspace daemon 进程入口(主循环 + 退避)
|
|
7
|
+
//! - name: coordinator_health
|
|
8
|
+
//! what: pid/metadata/schema 三合一健康判定
|
|
9
|
+
//! - name: start_coordinator
|
|
10
|
+
//! what: 幂等启动 daemon 子进程
|
|
11
|
+
//! - name: stop_coordinator
|
|
12
|
+
//! what: 停 daemon 并清 pid/meta
|
|
13
|
+
//! - name: run_watch
|
|
14
|
+
//! what: team-agent watch 的只读事件流主循环
|
|
15
|
+
//! - name: detect_whole_team_gone
|
|
16
|
+
//! what: 不依赖 coordinator 存活的整队消失判定
|
|
17
|
+
//! depends:
|
|
18
|
+
//! - crate::state
|
|
19
|
+
//! - crate::message_store
|
|
20
|
+
//! - crate::messaging
|
|
21
|
+
//! - crate::transport
|
|
22
|
+
//! - crate::provider
|
|
23
|
+
//! - crate::leader
|
|
24
|
+
//! - crate::event_log
|
|
25
|
+
//! boundary:
|
|
26
|
+
//! - 不实现消息投递与结果回收本体(在 crate::messaging,本模块只按固定顺序调用)
|
|
27
|
+
//! - 不直接依赖任何 provider client crate,provider 一律经 ProviderAdapter trait
|
|
28
|
+
//! - 不做物理注入/键盘写入,注入归 crate::transport
|
|
29
|
+
//! - 无 pending obligation 时不注入任何探索性 prompt
|
|
30
|
+
//! maturity: wired
|
|
31
|
+
//! ---
|
|
1
32
|
//!
|
|
2
33
|
//! step 12 · coordinator — daemon lifecycle / single-tick orchestration SKELETON (ROUND-0).
|
|
3
34
|
//!
|
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: 两个纯判定——daemon 自己是不是该自杀的孤儿,以及整个队是不是已经全没了
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: should_orphan_self_terminate
|
|
6
|
+
//! what: ppid 变更 + 被 init 收养 + workspace 已消失,三者同时成立才判孤儿
|
|
7
|
+
//! - name: detect_whole_team_gone
|
|
8
|
+
//! what: 由存活快照判整队消失,并区分 clean/restart(静默)与 unexpected(写 marker + 延迟升报)
|
|
9
|
+
//! depends:
|
|
10
|
+
//! - super::types
|
|
11
|
+
//! boundary:
|
|
12
|
+
//! - 不杀任何进程,也不发信号;只给判定结果,动作归调用方
|
|
13
|
+
//! - 不读屏、不命名 provider;只消费结构化存活快照
|
|
14
|
+
//! - 不直接升报用户,unexpected 只落 durable marker,等下一条 leader 命令再升
|
|
15
|
+
//! maturity: wired
|
|
16
|
+
//! ---
|
|
1
17
|
//!
|
|
2
18
|
//! 孤儿自终止判定(Gap 37b)+ provider-neutral 整队消失检测。
|
|
3
19
|
|
|
@@ -9,6 +25,14 @@ use super::types::{
|
|
|
9
25
|
/// 孤儿自终止判定(`__main__.py:51-59`,Gap 37b)。仅当
|
|
10
26
|
/// `current_ppid != initial_ppid ∧ current_ppid == 1 ∧ !workspace.exists()` 三者**同时**成立 → true。
|
|
11
27
|
/// 少一个条件都不能误杀正常 daemon(card §91)。
|
|
28
|
+
/// ---
|
|
29
|
+
/// purpose: 判断本 daemon 是否已成为应当自我终止的孤儿
|
|
30
|
+
/// params:
|
|
31
|
+
/// initial_ppid: 进程启动那一刻记下的父 pid
|
|
32
|
+
/// current_ppid: 当前父 pid;被 init/launchd 收养后为 1
|
|
33
|
+
/// workspace: 本 daemon 服务的 workspace 根,用其存在性作第三个条件
|
|
34
|
+
/// returns: 三个条件同时成立才为 true;少一个都返回 false,宁可不自杀
|
|
35
|
+
/// ---
|
|
12
36
|
pub fn should_orphan_self_terminate(
|
|
13
37
|
initial_ppid: u32,
|
|
14
38
|
current_ppid: u32,
|
|
@@ -25,6 +49,13 @@ pub fn should_orphan_self_terminate(
|
|
|
25
49
|
/// `detect_whole_team_gone`(`abnormal_track.py:91`,C10/C13)。coordinator-independent 整队消失检测:
|
|
26
50
|
/// 全死(coordinator + leader + 所有 worker + 所有 session)且非 clean_shutdown/restart →
|
|
27
51
|
/// 写 durable marker + 延迟到下条 leader 命令再 escalate。clean/restart 静默。
|
|
52
|
+
/// ---
|
|
53
|
+
/// purpose: 由整队存活快照判定「整队消失」并给出分类与后续处置标志
|
|
54
|
+
/// params:
|
|
55
|
+
/// snapshot: coordinator/leader/各 worker 进程/transport 会话的存活位,以及 clean_shutdown、restart_in_progress 两个意图位
|
|
56
|
+
/// marker_store: durable marker 写入口;仅 unexpected_exit 分支会被调用
|
|
57
|
+
/// returns: 任一成员存活则 Alive 且全部标志为 false;全死时按 clean_shutdown、restart_in_progress、unexpected_exit 依次分类,只有 unexpected 才置 notify/escalate 并写 marker
|
|
58
|
+
/// ---
|
|
28
59
|
pub fn detect_whole_team_gone(
|
|
29
60
|
snapshot: &TeamPresenceSnapshot,
|
|
30
61
|
marker_store: &mut dyn MarkerStore,
|
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: 三个只读运行时探测——上下文压缩、Codex session 漂移、leader 端 API 错误——全部值变才发事件
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: observe_runtime
|
|
6
|
+
//! what: 对本 tick 的每条捕获事实跑三个探测,收集结果并写变化驱动的事件
|
|
7
|
+
//! depends:
|
|
8
|
+
//! - super::runtime_observation
|
|
9
|
+
//! - super::types
|
|
10
|
+
//! - crate::event_log
|
|
11
|
+
//! - crate::state::projection
|
|
12
|
+
//! - crate::state::ownership
|
|
13
|
+
//! - crate::model::enums
|
|
14
|
+
//! boundary:
|
|
15
|
+
//! - 只分类不动作:不重启 agent、不清 session、不投递任何消息,只给 recommendation 文案
|
|
16
|
+
//! - 事件是 change-driven:计数/指纹不变的那一 tick 不重发,去重键存在 state 里
|
|
17
|
+
//! - 只读 scrollback 尾与已存 session id,不与 provider 进程交互
|
|
18
|
+
//! maturity: wired
|
|
19
|
+
//! ---
|
|
1
20
|
//!
|
|
2
21
|
use std::collections::BTreeMap;
|
|
3
22
|
use std::path::Path;
|
|
@@ -15,6 +34,15 @@ use super::types::{CompactionResult, LeaderApiError, SessionDriftResult};
|
|
|
15
34
|
|
|
16
35
|
const COMPACTION_RESET_THRESHOLD_DEFAULT: i64 = 3;
|
|
17
36
|
|
|
37
|
+
/// ---
|
|
38
|
+
/// purpose: 对本 tick 的全部捕获事实依次跑 compaction / session-drift / leader-api-error 三个探测
|
|
39
|
+
/// params:
|
|
40
|
+
/// workspace: workspace 根,用于打开事件日志
|
|
41
|
+
/// state: 可变运行时状态;探测在其中读写压缩计数、漂移标记与 api-error 指纹这些跨 tick 去重键
|
|
42
|
+
/// captures_by_agent: 本 tick 的 per-agent 捕获事实,按 agent_id 有序
|
|
43
|
+
/// leader_capture: leader 侧捕获;为 None 时 api-error 结果为空,且不清除既有指纹
|
|
44
|
+
/// returns: 捕获事实原样带回,附三组探测结果;未命中的探测对应空 Vec
|
|
45
|
+
/// ---
|
|
18
46
|
pub fn observe_runtime(
|
|
19
47
|
workspace: &Path,
|
|
20
48
|
state: &mut Value,
|
|
@@ -554,6 +582,8 @@ fn runtime_event_provider_name(provider: Provider) -> &'static str {
|
|
|
554
582
|
Provider::Codex => "codex",
|
|
555
583
|
Provider::Copilot => "copilot",
|
|
556
584
|
Provider::GeminiCli => "gemini_cli",
|
|
585
|
+
Provider::Grok => "grok",
|
|
586
|
+
Provider::CursorAgent => "cursor_agent",
|
|
557
587
|
Provider::Fake => "fake",
|
|
558
588
|
}
|
|
559
589
|
}
|
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: 运行时观测的类型缝——定义「一次 tick 捕到的事实」与「探测结果集合」两个形状,并把探测转交 runtime_detectors
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: observe
|
|
6
|
+
//! what: 把本 tick 的 per-agent 捕获事实与 leader 捕获事实交给探测器,返回结果集合
|
|
7
|
+
//! depends:
|
|
8
|
+
//! - super::runtime_detectors
|
|
9
|
+
//! - super::types
|
|
10
|
+
//! - crate::provider
|
|
11
|
+
//! - crate::transport
|
|
12
|
+
//! boundary:
|
|
13
|
+
//! - 不做捕获本身(scrollback/pane 快照由 tick 侧采集后传入)
|
|
14
|
+
//! - 不做任何判定,判定全在 runtime_detectors
|
|
15
|
+
//! maturity: wired
|
|
16
|
+
//! ---
|
|
1
17
|
//!
|
|
2
18
|
//! Shared coordinator runtime observation seam.
|
|
3
19
|
//!
|
|
@@ -49,6 +65,15 @@ pub struct RuntimeObservationResults {
|
|
|
49
65
|
pub api_errors: Vec<LeaderApiError>,
|
|
50
66
|
}
|
|
51
67
|
|
|
68
|
+
/// ---
|
|
69
|
+
/// purpose: 本 tick 观测的统一入口,把捕获事实转交 runtime_detectors 并原样带回结果
|
|
70
|
+
/// params:
|
|
71
|
+
/// workspace: workspace 根,探测器据此写事件日志
|
|
72
|
+
/// state: 可变运行时状态;探测器在其中保存跨 tick 的去重/计数键
|
|
73
|
+
/// captures_by_agent: 本 tick 每个 agent 的捕获事实(scrollback 尾、pane 信息、已存 session id 等)
|
|
74
|
+
/// leader_capture: leader 侧捕获事实;缺失表示本 tick 没拿到 leader 屏幕,api-error 探测随之为空
|
|
75
|
+
/// returns: 捕获事实原样回传,外加 compaction / session_drift / leader api-error 三组探测结果
|
|
76
|
+
/// ---
|
|
52
77
|
pub fn observe(
|
|
53
78
|
workspace: &Path,
|
|
54
79
|
state: &mut Value,
|
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: tick 的异常退出检测步骤——按 agent 读有界 rollout 尾,判「最新一条显式 provider 错误是否属于当前 worker 世代」,据此决定通知还是只留审计
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: detect_abnormal_exits
|
|
6
|
+
//! what: 遍历受监视 agent,产出 worker.abnormal_exit 通知或 dead_only 审计事件,并把本轮观测写回 state 的 abnormal_exit_watch
|
|
7
|
+
//! - name: explicit_process_liveness
|
|
8
|
+
//! what: 从 agent JSON 的显式存活字段解析进程存活态,不做任何探测
|
|
9
|
+
//! - name: read_tail_text
|
|
10
|
+
//! what: 有界读文件尾部文本,超长时从尾部 max_bytes 处起读
|
|
11
|
+
//! - name: metadata_mtime_ns
|
|
12
|
+
//! what: 把文件 metadata 的 mtime 归一成纳秒整数,供跨 tick 变化比较
|
|
13
|
+
//! depends:
|
|
14
|
+
//! - super::super::health
|
|
15
|
+
//! - super::super::tick
|
|
16
|
+
//! - super::super::types
|
|
17
|
+
//! - crate::event_log
|
|
18
|
+
//! - crate::messaging
|
|
19
|
+
//! - crate::provider
|
|
20
|
+
//! - crate::transport
|
|
21
|
+
//! - crate::state::projection
|
|
22
|
+
//! boundary:
|
|
23
|
+
//! - 不重启、不清理、不做物理注入:写事件与 state 观测记录之外,异常通知会经 crate::messaging 的 leader funnel 入库为 accepted 消息(物理注入由后续 deliver_pending 完成)
|
|
24
|
+
//! - 进程已死但没有显式错误时不通知,只落 dead_only 审计
|
|
25
|
+
//! - 通知事件里的 queued 只表示消息入库,不表示已送达
|
|
26
|
+
//! - rollout 尾读是有界的(首行可能被截断,消费方只解析最后一条完整 JSONL 记录)
|
|
27
|
+
//! maturity: wired
|
|
28
|
+
//! ---
|
|
1
29
|
//!
|
|
2
30
|
//! unit-11 (Stage 4) — coordinator tick `abnormal` step group.
|
|
3
31
|
//!
|
|
@@ -23,6 +51,17 @@ use super::super::types::Pid;
|
|
|
23
51
|
/// provider error that is fresh for the current worker cohort. A dead process
|
|
24
52
|
/// without an explicit error remains a suppressed `dead_only` audit event; process
|
|
25
53
|
/// liveness is otherwise diagnostic data for this path.
|
|
54
|
+
/// ---
|
|
55
|
+
/// purpose: 跑一轮异常退出检测,把结论落成事件与 state 里的 abnormal_exit_watch 记录
|
|
56
|
+
/// params:
|
|
57
|
+
/// workspace: workspace 根,用于解析 rollout 相对路径
|
|
58
|
+
/// transport: pane 存活探测通道;只读探测,不注入
|
|
59
|
+
/// state: 可变运行时状态;本轮观测(size/mtime/世代/去重键)写回 coordinator.abnormal_exit_watch
|
|
60
|
+
/// event_log: 事件出口
|
|
61
|
+
/// targets: 本 tick 已采到的 pane 快照,避免每 agent 重新列一遍
|
|
62
|
+
/// returns: 检测跑完即 Ok;「有没有异常」不由返回值表达,只体现在事件与 state 里
|
|
63
|
+
/// errors: 事件写入等不可恢复失败时返回 TickError;单个 agent 的 rollout metadata 读不到不算错误,记为 unverifiable 继续
|
|
64
|
+
/// ---
|
|
26
65
|
pub(crate) fn detect_abnormal_exits(
|
|
27
66
|
workspace: &Path,
|
|
28
67
|
transport: &dyn crate::transport::Transport,
|
|
@@ -476,6 +515,12 @@ fn agent_pid(agent: &Value) -> Option<Pid> {
|
|
|
476
515
|
.find_map(|key| json_u32(agent.get(key)).map(Pid::new))
|
|
477
516
|
}
|
|
478
517
|
|
|
518
|
+
/// ---
|
|
519
|
+
/// purpose: 只从 agent JSON 里已写明的存活字段读出进程存活态,不做任何主动探测
|
|
520
|
+
/// params:
|
|
521
|
+
/// agent: agent 状态对象;先下钻 provider_process / process 子对象,再看本层的 *_liveness 串字段
|
|
522
|
+
/// returns: 命中显式字段时给出 Alive/Dead/Unverifiable;没有任何显式字段时为 None,交调用方走探测路径
|
|
523
|
+
/// ---
|
|
479
524
|
pub(crate) fn explicit_process_liveness(agent: &Value) -> Option<ProcessLiveness> {
|
|
480
525
|
if let Some(process) = agent
|
|
481
526
|
.get("provider_process")
|
|
@@ -836,6 +881,12 @@ fn process_liveness_wire(state: ProcessLiveness) -> &'static str {
|
|
|
836
881
|
}
|
|
837
882
|
}
|
|
838
883
|
|
|
884
|
+
/// ---
|
|
885
|
+
/// purpose: 把文件修改时间归一成自 UNIX 纪元起的纳秒整数,供跨 tick 比较「rollout 有没有变过」
|
|
886
|
+
/// params:
|
|
887
|
+
/// metadata: 目标文件的 metadata
|
|
888
|
+
/// returns: 纳秒时间戳;取不到 mtime 或早于纪元时为 None。乘加均为 saturating,不会回绕
|
|
889
|
+
/// ---
|
|
839
890
|
pub(crate) fn metadata_mtime_ns(metadata: &std::fs::Metadata) -> Option<u64> {
|
|
840
891
|
let duration = metadata
|
|
841
892
|
.modified()
|
|
@@ -977,6 +1028,14 @@ const ABNORMAL_TAIL_BYTES: u64 = 131_072;
|
|
|
977
1028
|
///
|
|
978
1029
|
/// P1: bounded tail read; a partial first line is harmless (the consumer only parses
|
|
979
1030
|
/// the latest complete JSONL record) and lossy UTF-8 keeps a mid-codepoint seek safe.
|
|
1031
|
+
/// ---
|
|
1032
|
+
/// purpose: 有界读取文件尾部文本,避免整份 rollout 进内存
|
|
1033
|
+
/// params:
|
|
1034
|
+
/// path: 目标文件
|
|
1035
|
+
/// max_bytes: 最多回读的字节数;文件更短时整份读出
|
|
1036
|
+
/// returns: 尾部文本。按字节 seek,首行可能被截断,且用有损 UTF-8 解码,切在码点中间也安全
|
|
1037
|
+
/// errors: 打开、取长度或读取失败时返回底层 io::Error
|
|
1038
|
+
/// ---
|
|
980
1039
|
pub(crate) fn read_tail_text(path: &Path, max_bytes: u64) -> std::io::Result<String> {
|
|
981
1040
|
use std::io::{Read, Seek, SeekFrom};
|
|
982
1041
|
let mut file = std::fs::File::open(path)?;
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: coordinator tick delivery 步骤组的占位命名空间——实现仍在 tick.rs
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides: []
|
|
5
|
+
//! depends: []
|
|
6
|
+
//! boundary:
|
|
7
|
+
//! - 本文件当前不含任何 item:消息投递 FSM 的 tick 步骤未来迁入处
|
|
8
|
+
//! - 迁移落地前不要在此新增逻辑,否则步骤顺序会分裂成两处
|
|
9
|
+
//! maturity: signature_only
|
|
10
|
+
//! ---
|
|
1
11
|
//!
|
|
2
12
|
//! unit-11 (Stage 4) — coordinator tick `delivery` step group.
|
|
3
13
|
//!
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: coordinator tick health_sync 步骤组的占位命名空间——实现仍在 tick.rs
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides: []
|
|
5
|
+
//! depends: []
|
|
6
|
+
//! boundary:
|
|
7
|
+
//! - 本文件当前不含任何 item:worker 存活对账步骤未来迁入处
|
|
8
|
+
//! - 迁移落地前不要在此新增逻辑,否则步骤顺序会分裂成两处
|
|
9
|
+
//! maturity: signature_only
|
|
10
|
+
//! ---
|
|
1
11
|
//!
|
|
2
12
|
//! unit-11 (Stage 4) — coordinator tick `health_sync` step group.
|
|
3
13
|
//!
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: tick 步骤组的命名空间与规范顺序——给每个步骤组一个稳定标签与固定次序,供编排器与事件日志共用
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: ordered
|
|
6
|
+
//! what: 步骤组的规范顺序(穷尽枚举),编排器必须按此序调用
|
|
7
|
+
//! - name: as_str
|
|
8
|
+
//! what: 步骤组的稳定标签(tick.<group>),进事件与指标字段
|
|
9
|
+
//! depends: []
|
|
10
|
+
//! boundary:
|
|
11
|
+
//! - 不含任何步骤的实现,只定义分组身份与顺序
|
|
12
|
+
//! - persist 必须排最后、session_gate 必须排最前,这是顺序本身承载的约束
|
|
13
|
+
//! maturity: wired
|
|
14
|
+
//! ---
|
|
1
15
|
//!
|
|
2
16
|
//! unit-11 (Stage 4) — coordinator tick steps namespace.
|
|
3
17
|
//!
|
|
@@ -37,6 +51,10 @@ pub enum TickStepGroup {
|
|
|
37
51
|
|
|
38
52
|
impl TickStepGroup {
|
|
39
53
|
/// Stable label used in event-log and metric fields.
|
|
54
|
+
/// ---
|
|
55
|
+
/// purpose: 给步骤组一个稳定标签,供事件日志与指标字段使用
|
|
56
|
+
/// returns: 形如 tick.<group> 的稳定串;已发布的取值不可改写,只可新增
|
|
57
|
+
/// ---
|
|
40
58
|
pub fn as_str(self) -> &'static str {
|
|
41
59
|
match self {
|
|
42
60
|
Self::SessionGate => "tick.session_gate",
|
|
@@ -50,6 +68,10 @@ impl TickStepGroup {
|
|
|
50
68
|
|
|
51
69
|
///
|
|
52
70
|
/// Canonical ordering as a const slice — exhaustive over the enum.
|
|
71
|
+
/// ---
|
|
72
|
+
/// purpose: 给出步骤组的规范调用顺序
|
|
73
|
+
/// returns: 穷尽覆盖本 enum 全部变体的静态切片,session_gate 在首、persist 在尾;编排器按此序调用,持久化才能反映之前每一步的结果
|
|
74
|
+
/// ---
|
|
53
75
|
pub fn ordered() -> &'static [TickStepGroup] {
|
|
54
76
|
&[
|
|
55
77
|
TickStepGroup::SessionGate,
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: coordinator tick persist 步骤组的占位命名空间——实现仍在 tick.rs
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides: []
|
|
5
|
+
//! depends: []
|
|
6
|
+
//! boundary:
|
|
7
|
+
//! - 本文件当前不含任何 item:tick 末尾的持久化步骤未来迁入处
|
|
8
|
+
//! - 迁移落地前不要在此新增逻辑,否则步骤顺序会分裂成两处
|
|
9
|
+
//! maturity: signature_only
|
|
10
|
+
//! ---
|
|
1
11
|
//!
|
|
2
12
|
//! unit-11 (Stage 4) — coordinator tick `persist` step group.
|
|
3
13
|
//!
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: coordinator tick runtime_prompts 步骤组的占位命名空间——实现仍在 tick.rs
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides: []
|
|
5
|
+
//! depends: []
|
|
6
|
+
//! boundary:
|
|
7
|
+
//! - 本文件当前不含任何 item:startup / approval / abnormal-exit 提示步骤未来迁入处
|
|
8
|
+
//! - 迁移落地前不要在此新增逻辑,否则步骤顺序会分裂成两处
|
|
9
|
+
//! maturity: signature_only
|
|
10
|
+
//! ---
|
|
1
11
|
//!
|
|
2
12
|
//! unit-11 (Stage 4) — coordinator tick `runtime_prompts` step group.
|
|
3
13
|
//!
|