@team-agent/installer 0.5.66 → 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 +1 -0
- package/crates/team-agent/src/cli/adapters.rs +5 -0
- 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/missing_subcommands.rs +129 -19
- 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/communication_mode/mod.rs +6 -4
- package/crates/team-agent/src/compiler.rs +59 -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 +920 -63
- 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 -12
- package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +62 -0
- package/crates/team-agent/src/lifecycle/launch/agent_state.rs +59 -0
- 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 -456
- 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 +62 -2
- package/crates/team-agent/src/lifecycle/launch/spec_state.rs +139 -0
- package/crates/team-agent/src/lifecycle/launch/state_projection.rs +109 -0
- package/crates/team-agent/src/lifecycle/launch/worker_env.rs +214 -1
- package/crates/team-agent/src/lifecycle/launch.rs +99 -29
- 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 +124 -0
- package/crates/team-agent/src/lifecycle/restart/common.rs +369 -11
- 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 +106 -0
- 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/agent_ops.rs +2 -3
- 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 +150 -157
- package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/core.rs +4 -0
- 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/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/lane_ops.rs +63 -38
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +3 -2
- package/crates/team-agent/src/lifecycle/tests/lifecycle_rollback_red.rs +16 -8
- 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 +20 -19
- package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +97 -61
- package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +2 -0
- package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +40 -7
- package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +59 -1
- package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +69 -26
- package/crates/team-agent/src/lifecycle/tests.rs +23 -13
- package/crates/team-agent/src/lifecycle/types.rs +61 -0
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +85 -11
- 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/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/os_probe.rs +73 -2
- package/crates/team-agent/src/provider/adapter.rs +231 -4
- 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 +46 -2
- 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 +11 -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 +1064 -75
- package/crates/team-agent/src/transport/tests/wire.rs +28 -2
- package/crates/team-agent/src/transport.rs +248 -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/fork_agent/completion.rs +0 -59
- package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +0 -488
- package/crates/team-agent/src/lifecycle/launch/fork_pending.rs +0 -109
- package/crates/team-agent/src/lifecycle/launch/fork_state.rs +0 -447
|
@@ -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
|
//!
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: coordinator tick session_gate 步骤组的占位命名空间——实现仍在 tick.rs
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides: []
|
|
5
|
+
//! depends: []
|
|
6
|
+
//! boundary:
|
|
7
|
+
//! - 本文件当前不含任何 item:provider session 捕获与就绪门步骤未来迁入处
|
|
8
|
+
//! - 迁移落地前不要在此新增逻辑,否则步骤顺序会分裂成两处
|
|
9
|
+
//! maturity: signature_only
|
|
10
|
+
//! ---
|
|
1
11
|
//!
|
|
2
12
|
//! unit-11 (Stage 4) — coordinator tick `session_gate` step group.
|
|
3
13
|
//!
|
|
@@ -1,3 +1,37 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: coordinator 的核心——Coordinator 本体与单次 tick 的固定顺序编排,外加心跳 sidecar 与 worker 运行态解析
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: tick
|
|
6
|
+
//! what: 跑一轮固定顺序的编排:会话门 → 捕获缺失 session → 启动/审批提示 → 健康对账 → 投递与到期事件 → 只读探测 → 原子持久化 → 回收结果
|
|
7
|
+
//! - name: write_coordinator_heartbeat
|
|
8
|
+
//! what: 写 runtime/coordinator_tick.json 心跳 sidecar(阶段、状态、boot id、迭代计数)
|
|
9
|
+
//! - name: read_coordinator_heartbeat
|
|
10
|
+
//! what: 只读取出最近一次心跳,供 status/diagnose 消费
|
|
11
|
+
//! - name: resolve_worker_runtime_state_with_fg_pgrp
|
|
12
|
+
//! what: 由 agent JSON 与活动分类结果解析 worker 运行态,缺信号时判 Unknown 而非 Idle
|
|
13
|
+
//! depends:
|
|
14
|
+
//! - super::health
|
|
15
|
+
//! - super::types
|
|
16
|
+
//! - super::steps
|
|
17
|
+
//! - super::steps::abnormal
|
|
18
|
+
//! - super::runtime_observation
|
|
19
|
+
//! - crate::state
|
|
20
|
+
//! - crate::message_store
|
|
21
|
+
//! - crate::messaging
|
|
22
|
+
//! - crate::leader
|
|
23
|
+
//! - crate::provider
|
|
24
|
+
//! - crate::transport
|
|
25
|
+
//! - crate::event_log
|
|
26
|
+
//! - crate::os_probe
|
|
27
|
+
//! boundary:
|
|
28
|
+
//! - 不实现投递、到期事件与结果回收的本体,那些在 crate::messaging,本模块只按序调用
|
|
29
|
+
//! - 无 pending obligation 时不注入任何探索性 prompt;无既定义务时唯一会投递的是 should_ping 成立时的一条中性提示。例外:屏上出现审批提示且策略允许时,runtime_approval 会经 transport.send_keys 注入应答按键(不是 prompt,是对已观测提示的应答)
|
|
30
|
+
//! - 监测步骤失败降级并继续,TickReport.ok=true 不代表每一步都成功——各步失败只在事件里
|
|
31
|
+
//! - 持久化失败走 degraded 报告而不是 panic,也不是 Err
|
|
32
|
+
//! - 不直接依赖 provider client crate,provider 一律经注入的 ProviderAdapter
|
|
33
|
+
//! maturity: wired
|
|
34
|
+
//! ---
|
|
1
35
|
//!
|
|
2
36
|
//! Coordinator core:daemon lifecycle 宿主 + 单次 tick 编排(19 步固定顺序)+ health/start/stop。
|
|
3
37
|
|
|
@@ -166,6 +200,14 @@ pub struct Coordinator {
|
|
|
166
200
|
|
|
167
201
|
impl Coordinator {
|
|
168
202
|
/// 构造(注入 provider registry + transport)。spawn 出的 daemon 在 `run` 前装配它。
|
|
203
|
+
/// ---
|
|
204
|
+
/// purpose: 装配一个 Coordinator——注入 provider registry 与 transport,两者都是 trait object 以便替换与 mock
|
|
205
|
+
/// params:
|
|
206
|
+
/// workspace: 本实例服务的 workspace 根
|
|
207
|
+
/// provider_registry: provider adapter 解析器;provider 一律经它取,绝不直连 provider client crate
|
|
208
|
+
/// transport: 会话/pane 控制面,用于存活探测与注入
|
|
209
|
+
/// returns: 未绑定 team_key、无 save 钩子、无顺序探针的实例
|
|
210
|
+
/// ---
|
|
169
211
|
pub fn new(
|
|
170
212
|
workspace: WorkspacePath,
|
|
171
213
|
provider_registry: Box<dyn ProviderRegistry>,
|
|
@@ -181,6 +223,12 @@ impl Coordinator {
|
|
|
181
223
|
}
|
|
182
224
|
}
|
|
183
225
|
|
|
226
|
+
/// ---
|
|
227
|
+
/// purpose: 绑定 daemon 侧选定的 team_key,让 tick 的状态投影用它而不是可能过期的根 active_team_key
|
|
228
|
+
/// params:
|
|
229
|
+
/// team_key: 目标 team;None 或空串都视为未绑定,tick 会回落到 state 推导
|
|
230
|
+
/// returns: 绑定后的自身
|
|
231
|
+
/// ---
|
|
184
232
|
pub(crate) fn with_team_key(mut self, team_key: Option<String>) -> Self {
|
|
185
233
|
self.daemon_team_key = team_key.filter(|key| !key.is_empty());
|
|
186
234
|
self
|
|
@@ -190,6 +238,17 @@ impl Coordinator {
|
|
|
190
238
|
/// transport + mock provider registry + 可选 save 注入钩 + ORDER 探针。**纯 test-support
|
|
191
239
|
/// 脚手架**(真实 impl,非 `unimplemented!()`):它只装配字段,不执行任何 daemon 逻辑;
|
|
192
240
|
/// tick/health/start/stop 仍是 `unimplemented!()` 生产体,因此调它们的契约仍 RED。
|
|
241
|
+
/// ---
|
|
242
|
+
/// purpose: 测试装配口——直接构出实例并注入 save 钩子与步骤顺序探针
|
|
243
|
+
/// params:
|
|
244
|
+
/// workspace: workspace 根
|
|
245
|
+
/// provider_registry: 可 mock 的 provider adapter 解析器
|
|
246
|
+
/// transport: 可 mock 的传输控制面
|
|
247
|
+
/// save_hook: 替换真实持久化,用于制造持久化失败
|
|
248
|
+
/// order_recorder: 记录 tick 内各步骤名,用于断言固定顺序
|
|
249
|
+
/// returns: 只装配字段的实例,本函数自身不执行任何 daemon 逻辑
|
|
250
|
+
/// cfg: test
|
|
251
|
+
/// ---
|
|
193
252
|
#[cfg(test)]
|
|
194
253
|
pub(crate) fn for_test(
|
|
195
254
|
workspace: WorkspacePath,
|
|
@@ -226,6 +285,11 @@ impl Coordinator {
|
|
|
226
285
|
/// `state::save_runtime_state`,bug-084 测试注入失败);在每个 step8-11 原子调用点
|
|
227
286
|
/// `if let Some(rec) = &self.order_recorder { rec.lock()...push(STEP_NAME) }`(tick
|
|
228
287
|
/// 副作用 ORDER 测试断言固定序列)。生产两者均 `None`,零开销。
|
|
288
|
+
/// ---
|
|
289
|
+
/// purpose: 跑一轮 tick——按固定顺序把各步骤串起来,只投递既定义务,绝不凭空注入
|
|
290
|
+
/// returns: TickReport。传输会话不在了 → stop=true 且 reason=TmuxSessionMissing,主循环据此退出;持久化失败 → ok=false、reason=PersistenceDegraded、persisted=Some(false),但仍是 Ok;正常 → ok=true 并带本轮投递、到期事件、回收结果等清单。注意 ok=true 只说明主干走完,监测类步骤失败已被降级吞掉,真相只在事件日志里
|
|
291
|
+
/// errors: 加载状态、打开 message store、传输探测或事件写入这些主干操作失败时返回 TickError,由主循环 catch 后退避
|
|
292
|
+
/// ---
|
|
229
293
|
pub fn tick(&self) -> Result<TickReport, TickError> {
|
|
230
294
|
self.record_step(TickStepGroup::SessionGate, "load_state");
|
|
231
295
|
let raw_state = crate::state::persist::load_runtime_state(self.workspace.as_path())?;
|
|
@@ -271,17 +335,12 @@ impl Coordinator {
|
|
|
271
335
|
}
|
|
272
336
|
|
|
273
337
|
self.record_step(TickStepGroup::SessionGate, "capture_missing");
|
|
274
|
-
let
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
serde_json::json!({"error": error.to_string()}),
|
|
281
|
-
);
|
|
282
|
-
Vec::new()
|
|
283
|
-
}
|
|
284
|
-
};
|
|
338
|
+
if let Err(error) = self.capture_missing_sessions(&mut state, &event_log) {
|
|
339
|
+
let _ = event_log.write(
|
|
340
|
+
"coordinator.tick.capture_missing_failed",
|
|
341
|
+
serde_json::json!({"error": error.to_string()}),
|
|
342
|
+
);
|
|
343
|
+
}
|
|
285
344
|
|
|
286
345
|
// Slice 1 energy gate: one pane snapshot per tick feeds probe eligibility,
|
|
287
346
|
// health sync, and abnormal-exit detection. Missing panes are filtered
|
|
@@ -461,15 +520,6 @@ impl Coordinator {
|
|
|
461
520
|
collections,
|
|
462
521
|
));
|
|
463
522
|
}
|
|
464
|
-
for context_fork in &pending_context_fork_audits {
|
|
465
|
-
context_fork.write_audit(&event_log).map_err(|error| {
|
|
466
|
-
eprintln!(
|
|
467
|
-
"[coordinator] context_fork audit publish failed after state commit: {error}"
|
|
468
|
-
);
|
|
469
|
-
TickError::EventLog(error)
|
|
470
|
-
})?;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
523
|
self.record_step(TickStepGroup::Delivery, "collect_results");
|
|
474
524
|
collections.results =
|
|
475
525
|
collect_results(crate::messaging::collect_results_and_notify_watchers(
|
|
@@ -489,7 +539,7 @@ impl Coordinator {
|
|
|
489
539
|
&self,
|
|
490
540
|
state: &mut Value,
|
|
491
541
|
event_log: &EventLog,
|
|
492
|
-
) -> Result<
|
|
542
|
+
) -> Result<(), TickError> {
|
|
493
543
|
let report = crate::session_capture::capture_missing_provider_sessions_once(
|
|
494
544
|
state,
|
|
495
545
|
&mut |provider| self.provider_registry.adapter_for(provider),
|
|
@@ -653,7 +703,7 @@ impl Coordinator {
|
|
|
653
703
|
}),
|
|
654
704
|
)?;
|
|
655
705
|
}
|
|
656
|
-
Ok(
|
|
706
|
+
Ok(())
|
|
657
707
|
}
|
|
658
708
|
|
|
659
709
|
fn sync_agent_health(
|
|
@@ -1371,6 +1421,11 @@ impl Coordinator {
|
|
|
1371
1421
|
|
|
1372
1422
|
/// `coordinator_health`(`lifecycle.py:26`)。pid + meta + schema 三合一健康。
|
|
1373
1423
|
/// doctor / start 前置调它。`ok = running ∧ metadata_ok ∧ schema_ok`。
|
|
1424
|
+
/// ---
|
|
1425
|
+
/// purpose: 取本 workspace 的 coordinator 健康报告
|
|
1426
|
+
/// returns: 与 health::coordinator_health 完全一致的报告
|
|
1427
|
+
/// errors: 当前实现恒为 Ok;返回类型保留 Result 以便未来健康判定引入可失败路径
|
|
1428
|
+
/// ---
|
|
1374
1429
|
pub fn health(&self) -> Result<HealthReport, TickError> {
|
|
1375
1430
|
Ok(super::health::coordinator_health(&self.workspace))
|
|
1376
1431
|
}
|
|
@@ -1379,11 +1434,23 @@ impl Coordinator {
|
|
|
1379
1434
|
/// schema 不兼容拒启给 hint;否则 spawn 自身二进制子命令(`team-agent coordinator --workspace ..`,
|
|
1380
1435
|
/// Python 是 `python -m team_agent.coordinator`,`lifecycle.py:108`)。
|
|
1381
1436
|
/// **schema 兼容门**:三元任一不匹配 → restart_incompatible,**不可静默继续**(card §89)。
|
|
1437
|
+
/// ---
|
|
1438
|
+
/// purpose: 幂等启动本 workspace 的 daemon 子进程
|
|
1439
|
+
/// returns: 与 health::start_coordinator 完全一致的报告;「拒启」体现为 ok=false 而非 Err
|
|
1440
|
+
/// errors: 建目录、开日志、spawn 或写 pid/metadata 失败时返回 StartError
|
|
1441
|
+
/// ---
|
|
1382
1442
|
pub fn start(&self) -> Result<StartReport, StartError> {
|
|
1383
1443
|
super::health::start_coordinator(&self.workspace)
|
|
1384
1444
|
}
|
|
1385
1445
|
|
|
1386
1446
|
/// `stop_coordinator`(`lifecycle.py:229`)。SIGTERM + 清 pid/meta。pid 非整数 → 清文件返回。
|
|
1447
|
+
/// ---
|
|
1448
|
+
/// purpose: 清掉本 workspace 的 coordinator pid/meta 文件
|
|
1449
|
+
/// returns: pid 文件不存在 → Missing;文件在且内容可解析 → Stopped 并带该 pid;文件在但内容非法 → InvalidPidRemoved
|
|
1450
|
+
/// errors: 删文件失败时返回 StopError
|
|
1451
|
+
/// ---
|
|
1452
|
+
/// 注意:本方法只删文件,**不向 daemon 发任何信号**——与 health::stop_coordinator
|
|
1453
|
+
/// 的「真终止进程」语义不同。调它之后 daemon 仍会继续 tick,而健康探测会报 Missing。
|
|
1387
1454
|
pub fn stop(&self) -> Result<StopReport, StopError> {
|
|
1388
1455
|
let pid_path = coordinator_pid_path(&self.workspace);
|
|
1389
1456
|
if !pid_path.exists() {
|
|
@@ -1412,6 +1479,10 @@ impl Coordinator {
|
|
|
1412
1479
|
|
|
1413
1480
|
/// `message_store_schema_health`(`lifecycle.py:197`)。DB 列兼容门:区分 pre-init 必需列缺失
|
|
1414
1481
|
/// (拒启)vs migratable 列缺失(可迁移)。`doctor --fix-schema` 用其 action hint。
|
|
1482
|
+
/// ---
|
|
1483
|
+
/// purpose: 查本队 message store 的 schema 兼容门
|
|
1484
|
+
/// returns: 与 health::message_store_schema_health 一致;打不开库时 ok=false 并带原文与修复 hint
|
|
1485
|
+
/// ---
|
|
1415
1486
|
pub fn schema_health(&self) -> SchemaHealth {
|
|
1416
1487
|
// A-8: the gate must inspect the REAL team.db (Python lifecycle.py:197+
|
|
1417
1488
|
// message_store_schema_health); a hardcoded ok:true left the card §89
|
|
@@ -1525,6 +1596,21 @@ fn increment_coordinator_tick_iteration_count(workspace: &WorkspacePath) {
|
|
|
1525
1596
|
);
|
|
1526
1597
|
}
|
|
1527
1598
|
|
|
1599
|
+
/// ---
|
|
1600
|
+
/// purpose: 写心跳 sidecar runtime/coordinator_tick.json,让外部不必进程内也能看到 daemon 走到哪一步
|
|
1601
|
+
/// params:
|
|
1602
|
+
/// workspace: workspace 根
|
|
1603
|
+
/// pid: 当前 daemon pid
|
|
1604
|
+
/// boot_id: daemon 世代 id;None 时沿用文件里已有值,都没有则用 coord_unknown_<pid>
|
|
1605
|
+
/// last_phase: 本次写入代表的阶段名;值为 tick_running 时刷新 last_tick_started_at,否则刷新 last_tick_finished_at
|
|
1606
|
+
/// last_tick_status: 上一轮 tick 的状态串
|
|
1607
|
+
/// last_error: 上一轮的错误串
|
|
1608
|
+
/// increment_count: 是否把迭代计数加一
|
|
1609
|
+
/// returns: 写成功返回 ();先写临时文件再 rename,读方不会看到半份
|
|
1610
|
+
/// errors: 建目录、写临时文件或 rename 失败时返回 io::Error
|
|
1611
|
+
/// ---
|
|
1612
|
+
/// ⚠ 字段 `host_boot_time` 写的是**本次写入时刻的墙钟**,不是主机启动时间——
|
|
1613
|
+
/// 每次心跳都会变。主机启动身份在 `host_boot_id`,按名消费 host_boot_time 会拿到假事实。
|
|
1528
1614
|
pub(crate) fn write_coordinator_heartbeat(
|
|
1529
1615
|
workspace: &WorkspacePath,
|
|
1530
1616
|
pid: Pid,
|
|
@@ -1597,6 +1683,10 @@ fn coordinator_heartbeat_path(workspace: &WorkspacePath) -> PathBuf {
|
|
|
1597
1683
|
/// falls back to a formatted timestamp. Returns None when the platform
|
|
1598
1684
|
/// signal cannot be read — the caller MUST NOT guess; downstream
|
|
1599
1685
|
/// treats a missing/mismatched host boot separately from a matched one.
|
|
1686
|
+
/// ---
|
|
1687
|
+
/// purpose: 探测当前主机的启动身份,用来识别「所有 pane/pid/会话绑定都早于本次开机」
|
|
1688
|
+
/// returns: Linux 读 boot_id 得 linux-<uuid>;macOS 读 kern.boottime 得 macos-<...>;测试可用 TEAM_AGENT_TEST_HOST_BOOT_ID 覆盖。平台信号读不到时为 None——调用方必须把「读不到」与「不匹配」分开处理,不许猜
|
|
1689
|
+
/// ---
|
|
1600
1690
|
pub(crate) fn probe_host_boot_id() -> Option<String> {
|
|
1601
1691
|
if let Ok(override_id) = std::env::var("TEAM_AGENT_TEST_HOST_BOOT_ID") {
|
|
1602
1692
|
if !override_id.is_empty() {
|
|
@@ -1634,6 +1724,12 @@ pub(crate) fn probe_host_boot_id() -> Option<String> {
|
|
|
1634
1724
|
/// error (missing file, malformed JSON) returns None — callers treat
|
|
1635
1725
|
/// that as "unknown, fall back to existing facts" per locate §8 risk
|
|
1636
1726
|
/// note, they must never guess a stale/fresh verdict from absence.
|
|
1727
|
+
/// ---
|
|
1728
|
+
/// purpose: 只读取出最近一次写入的心跳 sidecar
|
|
1729
|
+
/// params:
|
|
1730
|
+
/// workspace: workspace 根
|
|
1731
|
+
/// returns: 解析成功才有值;文件缺失或 JSON 损坏一律 None。调用方须把 None 当作「未知」回落到既有事实,不得据此断定新鲜或陈旧
|
|
1732
|
+
/// ---
|
|
1637
1733
|
pub fn read_coordinator_heartbeat(workspace: &WorkspacePath) -> Option<Value> {
|
|
1638
1734
|
let path = coordinator_heartbeat_path(workspace);
|
|
1639
1735
|
let text = std::fs::read_to_string(path).ok()?;
|
|
@@ -2529,6 +2625,13 @@ fn write_activity(
|
|
|
2529
2625
|
/// conflict (or probe unavailable + activity idle).
|
|
2530
2626
|
/// 5. Unknown — missing pane_pid, probe error, or no decisive
|
|
2531
2627
|
/// signal. Iron law: never silently Idle.
|
|
2628
|
+
/// ---
|
|
2629
|
+
/// purpose: 由 agent 状态与活动分类结果解析出 worker 的运行态
|
|
2630
|
+
/// params:
|
|
2631
|
+
/// agent: agent 状态对象;读 pane_pid、awaiting_human_confirm 与审批/信任标志
|
|
2632
|
+
/// activity: JSONL 活动分类结果;None 表示本轮没有分类信号
|
|
2633
|
+
/// returns: 按优先级判定——先 Blocked(等人确认/等信任提示),再用前台进程组探测判 Busy,再由活动分类给 Busy/ProbablyIdle;任何一步缺信号都落到 Unknown。铁律是绝不在信息不足时静默判 Idle
|
|
2634
|
+
/// ---
|
|
2532
2635
|
pub(crate) fn resolve_worker_runtime_state_with_fg_pgrp(
|
|
2533
2636
|
agent: &Value,
|
|
2534
2637
|
activity: Option<&crate::messaging::AgentActivity>,
|
|
@@ -2612,6 +2715,14 @@ fn agent_health_status_wire(status: crate::messaging::ActivityStatus) -> &'stati
|
|
|
2612
2715
|
/// 0.4.x Phase 1: read the worker_state wire string that `write_activity`
|
|
2613
2716
|
/// persisted alongside the legacy activity. Returns None when no worker_state
|
|
2614
2717
|
/// has been written yet (older state row pre-upgrade).
|
|
2718
|
+
/// ---
|
|
2719
|
+
/// purpose: 读回 write_activity 与活动一起持久化的 worker_state 线字符串
|
|
2720
|
+
/// params:
|
|
2721
|
+
/// agent: agent 状态对象
|
|
2722
|
+
/// returns: 已写过 worker_state 时解析出运行态;升级前的旧状态行没有该字段,返回 None
|
|
2723
|
+
/// ---
|
|
2724
|
+
/// 现状:本仓内没有任何调用点(仅定义),与其他 pub(crate) 项不同——按机器事实记录,
|
|
2725
|
+
/// 不据此推断它「已接线」。
|
|
2615
2726
|
pub(crate) fn agent_worker_state(agent: &Value) -> Option<crate::messaging::WorkerRuntimeState> {
|
|
2616
2727
|
agent
|
|
2617
2728
|
.get("worker_state")
|