@team-agent/installer 0.2.10 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +744 -0
- package/Cargo.toml +34 -0
- package/crates/team-agent/Cargo.toml +33 -0
- package/crates/team-agent/src/cli/adapters.rs +1343 -0
- package/crates/team-agent/src/cli/diagnose.rs +554 -0
- package/crates/team-agent/src/cli/emit.rs +1077 -0
- package/crates/team-agent/src/cli/helpers.rs +88 -0
- package/crates/team-agent/src/cli/leader.rs +216 -0
- package/crates/team-agent/src/cli/mod.rs +1141 -0
- package/crates/team-agent/src/cli/profile.rs +306 -0
- package/crates/team-agent/src/cli/send.rs +215 -0
- package/crates/team-agent/src/cli/status.rs +179 -0
- package/crates/team-agent/src/cli/status_port.rs +502 -0
- package/crates/team-agent/src/cli/tests/base.rs +616 -0
- package/crates/team-agent/src/cli/tests/compile.rs +96 -0
- package/crates/team-agent/src/cli/tests/divergence.rs +509 -0
- package/crates/team-agent/src/cli/tests/lane_c.rs +333 -0
- package/crates/team-agent/src/cli/tests/leader_watch.rs +395 -0
- package/crates/team-agent/src/cli/tests/main_preserved.rs +675 -0
- package/crates/team-agent/src/cli/tests/missing_subcommands.rs +390 -0
- package/crates/team-agent/src/cli/tests/mod.rs +97 -0
- package/crates/team-agent/src/cli/tests/peer_allow.rs +137 -0
- package/crates/team-agent/src/cli/tests/repair_state_byte_lock.rs +302 -0
- package/crates/team-agent/src/cli/tests/run_delegation.rs +305 -0
- package/crates/team-agent/src/cli/tests/status_send.rs +385 -0
- package/crates/team-agent/src/cli/tests/verb_profile.rs +182 -0
- package/crates/team-agent/src/cli/tests/verb_settle.rs +236 -0
- package/crates/team-agent/src/cli/tests/verb_validate.rs +184 -0
- package/crates/team-agent/src/cli/types.rs +605 -0
- package/crates/team-agent/src/compiler/tests.rs +701 -0
- package/crates/team-agent/src/compiler.rs +489 -0
- package/crates/team-agent/src/coordinator/backoff.rs +153 -0
- package/crates/team-agent/src/coordinator/health.rs +436 -0
- package/crates/team-agent/src/coordinator/mod.rs +80 -0
- package/crates/team-agent/src/coordinator/orphan.rs +179 -0
- package/crates/team-agent/src/coordinator/tests/abnormal.rs +255 -0
- package/crates/team-agent/src/coordinator/tests/basics.rs +262 -0
- package/crates/team-agent/src/coordinator/tests/daemon.rs +323 -0
- package/crates/team-agent/src/coordinator/tests/health_sync.rs +263 -0
- package/crates/team-agent/src/coordinator/tests/main_preserved.rs +136 -0
- package/crates/team-agent/src/coordinator/tests/mod.rs +310 -0
- package/crates/team-agent/src/coordinator/tests/spine.rs +261 -0
- package/crates/team-agent/src/coordinator/tests/takeover.rs +227 -0
- package/crates/team-agent/src/coordinator/tests/tick_core.rs +256 -0
- package/crates/team-agent/src/coordinator/tests/watch.rs +167 -0
- package/crates/team-agent/src/coordinator/tick.rs +2032 -0
- package/crates/team-agent/src/coordinator/types.rs +584 -0
- package/crates/team-agent/src/db/migration.rs +716 -0
- package/crates/team-agent/src/db/mod.rs +23 -0
- package/crates/team-agent/src/db/schema.rs +378 -0
- package/crates/team-agent/src/event_log.rs +375 -0
- package/crates/team-agent/src/fake_worker.rs +253 -0
- package/crates/team-agent/src/leader/helpers.rs +190 -0
- package/crates/team-agent/src/leader/inject.rs +33 -0
- package/crates/team-agent/src/leader/lease.rs +1063 -0
- package/crates/team-agent/src/leader/mod.rs +99 -0
- package/crates/team-agent/src/leader/owner_bind.rs +292 -0
- package/crates/team-agent/src/leader/rediscover/tests.rs +525 -0
- package/crates/team-agent/src/leader/rediscover.rs +1099 -0
- package/crates/team-agent/src/leader/start.rs +273 -0
- package/crates/team-agent/src/leader/takeover.rs +235 -0
- package/crates/team-agent/src/leader/tests/basics.rs +183 -0
- package/crates/team-agent/src/leader/tests/byte_findings.rs +234 -0
- package/crates/team-agent/src/leader/tests/identity.rs +206 -0
- package/crates/team-agent/src/leader/tests/idle.rs +271 -0
- package/crates/team-agent/src/leader/tests/lease_api.rs +225 -0
- package/crates/team-agent/src/leader/tests/lease_claim.rs +253 -0
- package/crates/team-agent/src/leader/tests/mod.rs +125 -0
- package/crates/team-agent/src/leader/tests/rediscover.rs +351 -0
- package/crates/team-agent/src/leader/tests/wake_start_owner.rs +204 -0
- package/crates/team-agent/src/leader/types.rs +487 -0
- package/crates/team-agent/src/lib.rs +85 -0
- package/crates/team-agent/src/lifecycle/display.rs +228 -0
- package/crates/team-agent/src/lifecycle/helpers.rs +112 -0
- package/crates/team-agent/src/lifecycle/launch/plan.rs +227 -0
- package/crates/team-agent/src/lifecycle/launch.rs +1833 -0
- package/crates/team-agent/src/lifecycle/mod.rs +62 -0
- package/crates/team-agent/src/lifecycle/restart/agent.rs +533 -0
- package/crates/team-agent/src/lifecycle/restart/common.rs +517 -0
- package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +41 -0
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +268 -0
- package/crates/team-agent/src/lifecycle/restart/remove.rs +780 -0
- package/crates/team-agent/src/lifecycle/restart/selection.rs +208 -0
- package/crates/team-agent/src/lifecycle/restart/team_state.rs +242 -0
- package/crates/team-agent/src/lifecycle/restart.rs +76 -0
- package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +455 -0
- package/crates/team-agent/src/lifecycle/tests/core.rs +989 -0
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +583 -0
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +933 -0
- package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +265 -0
- package/crates/team-agent/src/lifecycle/tests.rs +27 -0
- package/crates/team-agent/src/lifecycle/types.rs +685 -0
- package/crates/team-agent/src/main.rs +41 -0
- package/crates/team-agent/src/mcp_server/helpers.rs +228 -0
- package/crates/team-agent/src/mcp_server/mod.rs +183 -0
- package/crates/team-agent/src/mcp_server/normalize.rs +312 -0
- package/crates/team-agent/src/mcp_server/tests/golden.rs +283 -0
- package/crates/team-agent/src/mcp_server/tests/normalize.rs +244 -0
- package/crates/team-agent/src/mcp_server/tests/scoped.rs +189 -0
- package/crates/team-agent/src/mcp_server/tests/send.rs +222 -0
- package/crates/team-agent/src/mcp_server/tests/tools.rs +158 -0
- package/crates/team-agent/src/mcp_server/tests/wire.rs +159 -0
- package/crates/team-agent/src/mcp_server/tests.rs +38 -0
- package/crates/team-agent/src/mcp_server/tools.rs +603 -0
- package/crates/team-agent/src/mcp_server/types.rs +421 -0
- package/crates/team-agent/src/mcp_server/wire.rs +388 -0
- package/crates/team-agent/src/message_store.rs +767 -0
- package/crates/team-agent/src/messaging/activity.rs +433 -0
- package/crates/team-agent/src/messaging/delivery.rs +542 -0
- package/crates/team-agent/src/messaging/helpers.rs +209 -0
- package/crates/team-agent/src/messaging/leader_receiver.rs +340 -0
- package/crates/team-agent/src/messaging/mod.rs +147 -0
- package/crates/team-agent/src/messaging/peers.rs +32 -0
- package/crates/team-agent/src/messaging/results.rs +537 -0
- package/crates/team-agent/src/messaging/scheduler.rs +344 -0
- package/crates/team-agent/src/messaging/selftest.rs +100 -0
- package/crates/team-agent/src/messaging/send.rs +582 -0
- package/crates/team-agent/src/messaging/tests/basic.rs +357 -0
- package/crates/team-agent/src/messaging/tests/main_preserved.rs +122 -0
- package/crates/team-agent/src/messaging/tests/mod.rs +293 -0
- package/crates/team-agent/src/messaging/tests/runtime.rs +1422 -0
- package/crates/team-agent/src/messaging/tests/spine.rs +437 -0
- package/crates/team-agent/src/messaging/trust.rs +192 -0
- package/crates/team-agent/src/messaging/types.rs +355 -0
- package/crates/team-agent/src/messaging/watchers.rs +591 -0
- package/crates/team-agent/src/model/enums.rs +311 -0
- package/crates/team-agent/src/model/errors.rs +17 -0
- package/crates/team-agent/src/model/ids.rs +155 -0
- package/crates/team-agent/src/model/mod.rs +22 -0
- package/crates/team-agent/src/model/paths.rs +228 -0
- package/crates/team-agent/src/model/permissions.rs +567 -0
- package/crates/team-agent/src/model/routing.rs +340 -0
- package/crates/team-agent/src/model/spec.rs +680 -0
- package/crates/team-agent/src/model/task_graph.rs +380 -0
- package/crates/team-agent/src/model/testdata/fuzz.golden.yaml +43 -0
- package/crates/team-agent/src/model/testdata/fuzz.yaml +43 -0
- package/crates/team-agent/src/model/testdata/spec_invalid_a.yaml +207 -0
- package/crates/team-agent/src/model/testdata/team.spec.golden.yaml +206 -0
- package/crates/team-agent/src/model/testdata/team.spec.yaml +206 -0
- package/crates/team-agent/src/model/yaml/tests.rs +288 -0
- package/crates/team-agent/src/model/yaml.rs +800 -0
- package/crates/team-agent/src/packaging/install.rs +305 -0
- package/crates/team-agent/src/packaging/migrate.rs +30 -0
- package/crates/team-agent/src/packaging/mod.rs +82 -0
- package/crates/team-agent/src/packaging/repair.rs +24 -0
- package/crates/team-agent/src/packaging/tests.rs +829 -0
- package/crates/team-agent/src/packaging/types.rs +369 -0
- package/crates/team-agent/src/provider/adapter.rs +801 -0
- package/crates/team-agent/src/provider/approvals/mod.rs +2 -0
- package/crates/team-agent/src/provider/approvals/parsing.rs +452 -0
- package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +163 -0
- package/crates/team-agent/src/provider/classify.rs +456 -0
- package/crates/team-agent/src/provider/faults.rs +136 -0
- package/crates/team-agent/src/provider/helpers.rs +41 -0
- package/crates/team-agent/src/provider/mod.rs +53 -0
- package/crates/team-agent/src/provider/startup_prompt.rs +423 -0
- package/crates/team-agent/src/provider/tests/adapter.rs +239 -0
- package/crates/team-agent/src/provider/tests/classify.rs +240 -0
- package/crates/team-agent/src/provider/tests/faults.rs +120 -0
- package/crates/team-agent/src/provider/tests/idle.rs +208 -0
- package/crates/team-agent/src/provider/tests/wire.rs +213 -0
- package/crates/team-agent/src/provider/tests.rs +31 -0
- package/crates/team-agent/src/provider/types.rs +424 -0
- package/crates/team-agent/src/state/identity.rs +656 -0
- package/crates/team-agent/src/state/mod.rs +58 -0
- package/crates/team-agent/src/state/owner_gate.rs +423 -0
- package/crates/team-agent/src/state/persist.rs +712 -0
- package/crates/team-agent/src/state/projection.rs +657 -0
- package/crates/team-agent/src/state/selector.rs +105 -0
- package/crates/team-agent/src/state/testdata/state-rich.canonical.json +133 -0
- package/crates/team-agent/src/tmux_backend/tests.rs +586 -0
- package/crates/team-agent/src/tmux_backend.rs +758 -0
- package/crates/team-agent/src/transport/test_support.rs +252 -0
- package/crates/team-agent/src/transport/tests/behavior.rs +327 -0
- package/crates/team-agent/src/transport/tests/mod.rs +199 -0
- package/crates/team-agent/src/transport/tests/wire.rs +527 -0
- package/crates/team-agent/src/transport.rs +774 -0
- package/npm/install.mjs +90 -106
- package/package.json +15 -13
- package/crates/team-agent-core/Cargo.toml +0 -12
- package/crates/team-agent-core/src/lib.rs +0 -332
- package/crates/team-agent-core/src/main.rs +0 -152
- package/pyproject.toml +0 -18
- package/scripts/install.py +0 -88
- package/scripts/run_regression_tests.py +0 -83
- package/src/team_agent/__init__.py +0 -3
- package/src/team_agent/__main__.py +0 -5
- package/src/team_agent/_legacy_pane_discovery.py +0 -186
- package/src/team_agent/abnormal_track.py +0 -253
- package/src/team_agent/approvals/__init__.py +0 -65
- package/src/team_agent/approvals/constants.py +0 -6
- package/src/team_agent/approvals/parsing.py +0 -176
- package/src/team_agent/approvals/runtime_prompts.py +0 -171
- package/src/team_agent/approvals/status.py +0 -176
- package/src/team_agent/cli/__init__.py +0 -137
- package/src/team_agent/cli/commands.py +0 -481
- package/src/team_agent/cli/e2e.py +0 -202
- package/src/team_agent/cli/helpers.py +0 -226
- package/src/team_agent/cli/parser.py +0 -540
- package/src/team_agent/compiler.py +0 -334
- package/src/team_agent/coordinator/__init__.py +0 -53
- package/src/team_agent/coordinator/__main__.py +0 -83
- package/src/team_agent/coordinator/lifecycle.py +0 -363
- package/src/team_agent/coordinator/metadata.py +0 -61
- package/src/team_agent/coordinator/paths.py +0 -17
- package/src/team_agent/diagnose/__init__.py +0 -48
- package/src/team_agent/diagnose/checks.py +0 -101
- package/src/team_agent/diagnose/comms.py +0 -213
- package/src/team_agent/diagnose/health.py +0 -241
- package/src/team_agent/diagnose/orphan_cleanup.py +0 -364
- package/src/team_agent/diagnose/preflight.py +0 -194
- package/src/team_agent/diagnose/quick_start.py +0 -324
- package/src/team_agent/display/__init__.py +0 -92
- package/src/team_agent/display/adaptive.py +0 -511
- package/src/team_agent/display/backend.py +0 -46
- package/src/team_agent/display/close.py +0 -154
- package/src/team_agent/display/ghostty.py +0 -77
- package/src/team_agent/display/rebuild.py +0 -102
- package/src/team_agent/display/tiling.py +0 -156
- package/src/team_agent/display/worker_window.py +0 -114
- package/src/team_agent/display/workspace.py +0 -382
- package/src/team_agent/errors.py +0 -10
- package/src/team_agent/events.py +0 -84
- package/src/team_agent/fake_worker.py +0 -80
- package/src/team_agent/idle_predicate.py +0 -200
- package/src/team_agent/idle_takeover.py +0 -59
- package/src/team_agent/idle_takeover_wiring.py +0 -111
- package/src/team_agent/launch/__init__.py +0 -41
- package/src/team_agent/launch/bootstrap.py +0 -85
- package/src/team_agent/launch/config.py +0 -106
- package/src/team_agent/launch/core.py +0 -301
- package/src/team_agent/launch/requirements.py +0 -57
- package/src/team_agent/leader/__init__.py +0 -926
- package/src/team_agent/leader_binding.py +0 -183
- package/src/team_agent/lifecycle/__init__.py +0 -5
- package/src/team_agent/lifecycle/agents.py +0 -278
- package/src/team_agent/lifecycle/operations.py +0 -411
- package/src/team_agent/lifecycle/paste_buffer_hygiene.py +0 -39
- package/src/team_agent/lifecycle/start.py +0 -363
- package/src/team_agent/mcp_server/__init__.py +0 -42
- package/src/team_agent/mcp_server/__main__.py +0 -7
- package/src/team_agent/mcp_server/contracts.py +0 -148
- package/src/team_agent/mcp_server/normalize.py +0 -257
- package/src/team_agent/mcp_server/server.py +0 -150
- package/src/team_agent/mcp_server/tools.py +0 -352
- package/src/team_agent/message_store/__init__.py +0 -23
- package/src/team_agent/message_store/agent_health.py +0 -113
- package/src/team_agent/message_store/core.py +0 -497
- package/src/team_agent/message_store/leader_notification_log.py +0 -198
- package/src/team_agent/message_store/result_watchers.py +0 -251
- package/src/team_agent/message_store/schema.py +0 -308
- package/src/team_agent/message_store/schema_migration.py +0 -448
- package/src/team_agent/messaging/__init__.py +0 -1
- package/src/team_agent/messaging/activity_detector.py +0 -254
- package/src/team_agent/messaging/delivery.py +0 -473
- package/src/team_agent/messaging/deps.py +0 -247
- package/src/team_agent/messaging/idle_alerts.py +0 -423
- package/src/team_agent/messaging/internal_delivery.py +0 -46
- package/src/team_agent/messaging/leader.py +0 -497
- package/src/team_agent/messaging/leader_api_errors.py +0 -216
- package/src/team_agent/messaging/leader_panes.py +0 -673
- package/src/team_agent/messaging/owner_bypass.py +0 -29
- package/src/team_agent/messaging/result_delivery.py +0 -539
- package/src/team_agent/messaging/results.py +0 -447
- package/src/team_agent/messaging/scheduler.py +0 -450
- package/src/team_agent/messaging/send.py +0 -532
- package/src/team_agent/messaging/session_drift.py +0 -94
- package/src/team_agent/messaging/tmux_io.py +0 -506
- package/src/team_agent/messaging/tmux_prompt.py +0 -338
- package/src/team_agent/messaging/trust_auto_answer.py +0 -52
- package/src/team_agent/orchestrator/__init__.py +0 -376
- package/src/team_agent/orchestrator/plan.py +0 -122
- package/src/team_agent/orchestrator/state.py +0 -128
- package/src/team_agent/paths.py +0 -45
- package/src/team_agent/permissions.py +0 -123
- package/src/team_agent/profiles/__init__.py +0 -82
- package/src/team_agent/profiles/constants.py +0 -19
- package/src/team_agent/profiles/core.py +0 -407
- package/src/team_agent/profiles/helpers.py +0 -69
- package/src/team_agent/profiles/provider_env.py +0 -188
- package/src/team_agent/profiles/smoke.py +0 -201
- package/src/team_agent/provider_cli/__init__.py +0 -43
- package/src/team_agent/provider_cli/adapter.py +0 -172
- package/src/team_agent/provider_cli/base.py +0 -48
- package/src/team_agent/provider_cli/claude.py +0 -457
- package/src/team_agent/provider_cli/codex.py +0 -336
- package/src/team_agent/provider_cli/copilot.py +0 -8
- package/src/team_agent/provider_cli/fake.py +0 -39
- package/src/team_agent/provider_cli/gemini.py +0 -95
- package/src/team_agent/provider_cli/opencode.py +0 -8
- package/src/team_agent/provider_cli/prompt.py +0 -62
- package/src/team_agent/provider_cli/registry.py +0 -18
- package/src/team_agent/provider_cli/unsupported.py +0 -32
- package/src/team_agent/provider_state/README.md +0 -78
- package/src/team_agent/provider_state/__init__.py +0 -86
- package/src/team_agent/provider_state/claude.py +0 -86
- package/src/team_agent/provider_state/codex.py +0 -84
- package/src/team_agent/provider_state/common.py +0 -207
- package/src/team_agent/provider_state/registry.py +0 -118
- package/src/team_agent/providers.py +0 -163
- package/src/team_agent/quality_gates.py +0 -104
- package/src/team_agent/restart/__init__.py +0 -34
- package/src/team_agent/restart/orchestration.py +0 -554
- package/src/team_agent/restart/selection.py +0 -89
- package/src/team_agent/restart/snapshot.py +0 -70
- package/src/team_agent/routing.py +0 -84
- package/src/team_agent/runtime.py +0 -1239
- package/src/team_agent/rust_core.py +0 -327
- package/src/team_agent/sessions/__init__.py +0 -25
- package/src/team_agent/sessions/capture.py +0 -143
- package/src/team_agent/sessions/inventory.py +0 -44
- package/src/team_agent/sessions/resume.py +0 -135
- package/src/team_agent/simple_yaml.py +0 -236
- package/src/team_agent/spec.py +0 -370
- package/src/team_agent/state.py +0 -602
- package/src/team_agent/status/__init__.py +0 -63
- package/src/team_agent/status/approvals.py +0 -52
- package/src/team_agent/status/compact.py +0 -158
- package/src/team_agent/status/constants.py +0 -18
- package/src/team_agent/status/inbox.py +0 -58
- package/src/team_agent/status/peek.py +0 -117
- package/src/team_agent/status/queries.py +0 -199
- package/src/team_agent/task_graph.py +0 -80
- package/src/team_agent/terminal.py +0 -57
- package/src/team_agent/wake.py +0 -58
- package/src/team_agent/watch/__init__.py +0 -145
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
use super::*;
|
|
2
|
+
|
|
3
|
+
// =========================================================================
|
|
4
|
+
// WAVE-2 LANE C — diagnose/status byte-parity DIVERGENCES + target-scan wiring.
|
|
5
|
+
// The status/diagnose handlers are IMPLEMENTED (status) or STUBBED (approvals/inbox/doctor/
|
|
6
|
+
// comms_selftest/orphan_gate/cleanup_orphans/fix_schema) — these REDs lock the EXACT golden JSON
|
|
7
|
+
// shapes (keys/values/insertion-order) each one DIVERGES from. Golden bytes captured via
|
|
8
|
+
// PYTHONPATH=.../src python3 /tmp/lanec_probe*.py on a fresh workspace.
|
|
9
|
+
// =========================================================================
|
|
10
|
+
|
|
11
|
+
/// Seed `.team/runtime/state.json` with `state` so `status_port::status` reads a real fixture.
|
|
12
|
+
fn seed_status_state(state: serde_json::Value) -> std::path::PathBuf {
|
|
13
|
+
let ws = tmp_workspace();
|
|
14
|
+
std::fs::write(
|
|
15
|
+
ws.join(".team").join("runtime").join("state.json"),
|
|
16
|
+
serde_json::to_vec_pretty(&state).unwrap(),
|
|
17
|
+
)
|
|
18
|
+
.unwrap();
|
|
19
|
+
ws
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// ── status #1: `team` = state["leader"]["id"] (default "leader"), NOT state["team"] ──────────────
|
|
23
|
+
// GOLDEN queries.py:66 `state.get("leader", {}).get("id", "leader")`. RUST mod.rs:94 reads
|
|
24
|
+
// `state.get("team")`. Seed BOTH distinct -> golden binds leader.id, Rust binds the team key. RED.
|
|
25
|
+
#[test]
|
|
26
|
+
fn status_team_is_leader_id_not_team_key() {
|
|
27
|
+
let ws = seed_status_state(json!({"team": "TEAMKEY", "leader": {"id": "LEADERID"}}));
|
|
28
|
+
let v = status_port::status(&ws, /*compact=*/ false, /*detail=*/ true).expect("status");
|
|
29
|
+
assert_eq!(
|
|
30
|
+
v["team"],
|
|
31
|
+
json!("LEADERID"),
|
|
32
|
+
"golden status.team = state['leader']['id'] (queries.py:66), NOT state['team']; got {:?}",
|
|
33
|
+
v["team"]
|
|
34
|
+
);
|
|
35
|
+
let _ = std::fs::remove_dir_all(&ws);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ── status #2: messages = store.message_counts() ({} when empty), results = store.result_counts()
|
|
39
|
+
// ({total,uncollected,collected,invalid,by_status}) — NOT the Rust {"count": N} placeholders. ──────
|
|
40
|
+
// GOLDEN queries.py:73,75. RUST mod.rs:101,103 emit `{"count": N}`. RED.
|
|
41
|
+
#[test]
|
|
42
|
+
fn status_counts_are_store_count_maps_not_count_int() {
|
|
43
|
+
let ws = tmp_workspace(); // empty store
|
|
44
|
+
let v = status_port::status(&ws, false, true).expect("status");
|
|
45
|
+
assert_eq!(
|
|
46
|
+
v["messages"],
|
|
47
|
+
json!({}),
|
|
48
|
+
"golden empty store.message_counts() == {{}} (queries.py:73), NOT {{count:0}}; got {:?}",
|
|
49
|
+
v["messages"]
|
|
50
|
+
);
|
|
51
|
+
assert_eq!(
|
|
52
|
+
v["results"],
|
|
53
|
+
json!({"total": 0, "uncollected": 0, "collected": 0, "invalid": 0, "by_status": {}}),
|
|
54
|
+
"golden store.result_counts() full shape (queries.py:75), NOT {{count:0}}; got {:?}",
|
|
55
|
+
v["results"]
|
|
56
|
+
);
|
|
57
|
+
let _ = std::fs::remove_dir_all(&ws);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ── status #3: coordinator = coordinator_health(ws) FULL 8-key shape in golden order ─────────────
|
|
61
|
+
// GOLDEN coordinator_health: {ok,status,pid,metadata,metadata_ok,schema_ok,schema_error,schema}.
|
|
62
|
+
// RUST mod.rs:105-112 emits a 6-key subset {status,ok,pid,metadata_ok,schema_ok,schema_version}
|
|
63
|
+
// (no metadata/schema_error; flat schema_version instead of nested schema). RED on key-order. ──────
|
|
64
|
+
#[test]
|
|
65
|
+
fn status_coordinator_is_full_health_eight_key_shape() {
|
|
66
|
+
let ws = tmp_workspace();
|
|
67
|
+
let v = status_port::status(&ws, false, true).expect("status");
|
|
68
|
+
let coord = v["coordinator"].as_object().expect("coordinator dict");
|
|
69
|
+
let order: Vec<&str> = coord.keys().map(String::as_str).collect();
|
|
70
|
+
assert_eq!(
|
|
71
|
+
order,
|
|
72
|
+
vec!["ok", "status", "pid", "metadata", "metadata_ok", "schema_ok", "schema_error", "schema"],
|
|
73
|
+
"golden coordinator_health 8-key insertion order; Rust emits a 6-key subset. got {order:?}"
|
|
74
|
+
);
|
|
75
|
+
assert!(
|
|
76
|
+
coord.get("schema_version").is_none(),
|
|
77
|
+
"golden coordinator has NO flat `schema_version` (it nests schema:{{message_store_schema_version}}); \
|
|
78
|
+
Rust emits the flat key. got {coord:?}"
|
|
79
|
+
);
|
|
80
|
+
let _ = std::fs::remove_dir_all(&ws);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ── status #4: last_events = EventLog.tail(10) ([] when no events), NOT the literal placeholder ──
|
|
84
|
+
// GOLDEN queries.py:78 `EventLog(workspace).tail(10)`. RUST mod.rs:113 (non-compact) emits the
|
|
85
|
+
// hardcoded placeholder `[{"event":"status.full"}]`. On a fresh log golden == []. RED. ────────────
|
|
86
|
+
#[test]
|
|
87
|
+
fn status_last_events_is_event_tail_not_status_full_placeholder() {
|
|
88
|
+
let ws = tmp_workspace(); // no events.jsonl
|
|
89
|
+
let v = status_port::status(&ws, false, true).expect("status");
|
|
90
|
+
assert_ne!(
|
|
91
|
+
v["last_events"],
|
|
92
|
+
json!([{"event": "status.full"}]),
|
|
93
|
+
"golden last_events = EventLog.tail(10), NOT the literal [{{event:status.full}}] placeholder"
|
|
94
|
+
);
|
|
95
|
+
assert_eq!(
|
|
96
|
+
v["last_events"],
|
|
97
|
+
json!([]),
|
|
98
|
+
"golden last_events on a fresh event log is [] (tail of empty); got {:?}",
|
|
99
|
+
v["last_events"]
|
|
100
|
+
);
|
|
101
|
+
let _ = std::fs::remove_dir_all(&ws);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ── status #5: the full (non-compact) status dict has NO `detail` key ────────────────────────────
|
|
105
|
+
// GOLDEN queries.py:65-79 builds exactly 13 keys; there is no `detail`. RUST mod.rs:115-119 injects
|
|
106
|
+
// `detail:true` whenever `!compact || detail`. The full --detail call MUST NOT carry detail. RED. ──
|
|
107
|
+
#[test]
|
|
108
|
+
fn status_noncompact_has_no_detail_key() {
|
|
109
|
+
let ws = tmp_workspace();
|
|
110
|
+
let v = status_port::status(&ws, /*compact=*/ false, /*detail=*/ true).expect("status");
|
|
111
|
+
assert!(
|
|
112
|
+
v.as_object().unwrap().get("detail").is_none(),
|
|
113
|
+
"golden status dict has NO `detail` key (queries.py:65-79); Rust injects detail:true. got {v:?}"
|
|
114
|
+
);
|
|
115
|
+
let _ = std::fs::remove_dir_all(&ws);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ── status #6: each agent entry is enriched with an `interacted` marker (C3, queries.py:53-64) ────
|
|
119
|
+
// GOLDEN: valid ISO first_send_at passes through; any other shape (invalid str / missing) -> the
|
|
120
|
+
// literal "never" (_interacted_marker, queries.py:15-30). RUST mod.rs:81-84 passes agents through
|
|
121
|
+
// RAW with no enrichment -> no `interacted` key. RED. ────────────────────────────────────────────
|
|
122
|
+
#[test]
|
|
123
|
+
fn status_agents_enriched_with_interacted_marker() {
|
|
124
|
+
let ws = seed_status_state(json!({
|
|
125
|
+
"leader": {"id": "leader"},
|
|
126
|
+
"agents": {
|
|
127
|
+
"alpha": {"provider": "codex", "first_send_at": "2026-05-27T10:00:00+00:00"},
|
|
128
|
+
"beta": {"provider": "claude", "first_send_at": "not-a-date"},
|
|
129
|
+
"gamma": {"provider": "claude"},
|
|
130
|
+
}
|
|
131
|
+
}));
|
|
132
|
+
let v = status_port::status(&ws, false, true).expect("status");
|
|
133
|
+
let agents = &v["agents"];
|
|
134
|
+
assert_eq!(
|
|
135
|
+
agents["alpha"]["interacted"],
|
|
136
|
+
json!("2026-05-27T10:00:00+00:00"),
|
|
137
|
+
"valid ISO first_send_at must pass through as the interacted marker (queries.py:24-29)"
|
|
138
|
+
);
|
|
139
|
+
assert_eq!(
|
|
140
|
+
agents["beta"]["interacted"],
|
|
141
|
+
json!("never"),
|
|
142
|
+
"an unparseable first_send_at must render as the literal 'never' (queries.py:27-28)"
|
|
143
|
+
);
|
|
144
|
+
assert_eq!(
|
|
145
|
+
agents["gamma"]["interacted"],
|
|
146
|
+
json!("never"),
|
|
147
|
+
"a missing first_send_at must render as 'never' (queries.py:30)"
|
|
148
|
+
);
|
|
149
|
+
let _ = std::fs::remove_dir_all(&ws);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ── status #7 (TARGET-SCAN WIRING, in-process): tmux_session_present uses a LIVE tmux probe ───────
|
|
153
|
+
// GOLDEN queries.py:52 `_tmux_session_exists(session_name)` (real `tmux has-session`). RUST mod.rs:96
|
|
154
|
+
// shortcuts to `session_name.is_some()`. Seed a present-but-nonexistent session -> golden False,
|
|
155
|
+
// Rust True. This is the status-level pane-discovery wiring the dangling list_targets feeds. RED. ──
|
|
156
|
+
#[test]
|
|
157
|
+
fn status_tmux_session_present_uses_live_tmux_probe_not_is_some() {
|
|
158
|
+
let absent = format!("ta-lanec-absent-{}", std::process::id());
|
|
159
|
+
let ws = seed_status_state(json!({"leader": {"id": "leader"}, "session_name": absent}));
|
|
160
|
+
let v = status_port::status(&ws, false, true).expect("status");
|
|
161
|
+
assert_eq!(
|
|
162
|
+
v["tmux_session_present"],
|
|
163
|
+
json!(false),
|
|
164
|
+
"golden tmux_session_present = _tmux_session_exists(name) (a live probe; queries.py:52); a \
|
|
165
|
+
present-but-nonexistent session name must be False, not is_some()==true. got {:?}",
|
|
166
|
+
v["tmux_session_present"]
|
|
167
|
+
);
|
|
168
|
+
let _ = std::fs::remove_dir_all(&ws);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ── approvals: golden 5-key {ok,waiting,waiting_count,approvals,scan} (status/approvals.py:30-36) ──
|
|
172
|
+
// RUST mod.rs:131-133 stub {ok,agent,approvals}. RED. ───────────────────────────────────────────
|
|
173
|
+
#[test]
|
|
174
|
+
fn approvals_golden_shape_has_waiting_count_and_scan_not_agent() {
|
|
175
|
+
let ws = tmp_workspace();
|
|
176
|
+
let v = status_port::approvals(&ws, None, true).expect("approvals");
|
|
177
|
+
let obj = v.as_object().expect("approvals dict");
|
|
178
|
+
let order: Vec<&str> = obj.keys().map(String::as_str).collect();
|
|
179
|
+
assert_eq!(
|
|
180
|
+
order,
|
|
181
|
+
vec!["ok", "waiting", "waiting_count", "approvals", "scan"],
|
|
182
|
+
"golden approvals 5-key order (approvals.py:30-36); Rust stub emits {{ok,agent,approvals}}. got {order:?}"
|
|
183
|
+
);
|
|
184
|
+
assert!(!obj.contains_key("agent"), "golden approvals has NO `agent` key");
|
|
185
|
+
assert_eq!(
|
|
186
|
+
v["scan"],
|
|
187
|
+
json!({"mode": "tail", "lines": 120, "raw_output": false}),
|
|
188
|
+
"golden scan == {{mode:tail,lines:120,raw_output:false}} (APPROVAL_SCAN_LINES=120); got {:?}",
|
|
189
|
+
v["scan"]
|
|
190
|
+
);
|
|
191
|
+
let _ = std::fs::remove_dir_all(&ws);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// ── inbox: golden {ok,agent_id,messages,since} (status/inbox.py:35-38) — key is `agent_id`, carries
|
|
195
|
+
// `since` (not `agent`/`limit`). RUST mod.rs:136-144 stub {ok,agent,limit,messages}. RED. ──────────
|
|
196
|
+
#[test]
|
|
197
|
+
fn inbox_golden_shape_is_agent_id_and_since_not_agent_limit() {
|
|
198
|
+
let ws = tmp_workspace();
|
|
199
|
+
let v = status_port::inbox(&ws, "alpha", 20, None, true).expect("inbox");
|
|
200
|
+
let obj = v.as_object().expect("inbox dict");
|
|
201
|
+
let order: Vec<&str> = obj.keys().map(String::as_str).collect();
|
|
202
|
+
assert_eq!(
|
|
203
|
+
order,
|
|
204
|
+
vec!["ok", "agent_id", "messages", "since"],
|
|
205
|
+
"golden inbox 4-key order {{ok,agent_id,messages,since}} (inbox.py:38); Rust stub uses agent/limit. got {order:?}"
|
|
206
|
+
);
|
|
207
|
+
assert_eq!(v["agent_id"], json!("alpha"), "golden key is `agent_id` (not `agent`)");
|
|
208
|
+
assert!(obj.contains_key("since"), "golden inbox carries `since` (echoed, null here)");
|
|
209
|
+
assert!(!obj.contains_key("agent"), "golden inbox has NO bare `agent` key");
|
|
210
|
+
assert!(!obj.contains_key("limit"), "golden inbox has NO `limit` key in the result dict");
|
|
211
|
+
let _ = std::fs::remove_dir_all(&ws);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// ── comms_selftest: golden {ok,status,run_id,scope,boundary,checks} (diagnose/comms.py:40-47) ─────
|
|
215
|
+
// RUST mod.rs:525-527 stub {ok,team,gate,provider_sdk_calls:int}. RED. Locks COMMS_BOUNDARY_TEXT +
|
|
216
|
+
// the deterministic check sub-shapes (run_id is a random uuid; not value-locked). ────────────────
|
|
217
|
+
#[test]
|
|
218
|
+
fn comms_selftest_golden_boundary_scope_and_check_shapes() {
|
|
219
|
+
let boundary = "validates live pane binding consistency. Does NOT perform live runtime message \
|
|
220
|
+
round-trip. comms contract suite deferred to 0.2.9 (test files not shipped). \
|
|
221
|
+
(zero token, zero pollution)";
|
|
222
|
+
let ws = tmp_workspace();
|
|
223
|
+
let v = diagnose_port::comms_selftest(&ws, None, None).expect("comms_selftest");
|
|
224
|
+
let obj = v.as_object().expect("comms dict");
|
|
225
|
+
assert_eq!(v["boundary"], json!(boundary), "golden COMMS_BOUNDARY_TEXT prefix (comms.py:11-14)");
|
|
226
|
+
assert_eq!(v["scope"], json!("binding_consistency"), "golden scope");
|
|
227
|
+
assert_eq!(v["status"], json!("pass"), "empty-state selftest passes (all checks pass/deferred)");
|
|
228
|
+
assert!(obj.contains_key("run_id"), "golden carries a run_id (uuid hex[:12])");
|
|
229
|
+
assert!(!obj.contains_key("team"), "golden has NO `team` key");
|
|
230
|
+
assert!(!obj.contains_key("gate"), "golden has NO `gate` key");
|
|
231
|
+
assert_eq!(
|
|
232
|
+
v["checks"]["contract_suite"],
|
|
233
|
+
json!({
|
|
234
|
+
"status": "deferred",
|
|
235
|
+
"deferred_to": "0.2.9",
|
|
236
|
+
"reason": "contract test files not shipped with package",
|
|
237
|
+
"message": "comms contract verification deferred to 0.2.9; contract test files not shipped with package",
|
|
238
|
+
}),
|
|
239
|
+
"golden contract_suite check (comms.py:132-139)"
|
|
240
|
+
);
|
|
241
|
+
assert_eq!(
|
|
242
|
+
v["checks"]["provider_sdk_calls"]["calls"],
|
|
243
|
+
json!({"anthropic": 0, "openai": 0, "httpx": 0}),
|
|
244
|
+
"golden provider_sdk_calls.calls (comms.py:142-151); Rust stub is a bare int 0"
|
|
245
|
+
);
|
|
246
|
+
let _ = std::fs::remove_dir_all(&ws);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// ── orphan_gate(fix=true,confirm=false): golden REFUSED envelope (orphan_cleanup.py:304-311) ──────
|
|
250
|
+
// {ok:false,gate:"orphans",status:"refused",reason:"fix_requires_confirm",action:...}. RUST mod.rs:
|
|
251
|
+
// 530-531 stub {ok:true,fix,confirm,orphans:[]}. Fully deterministic (no subprocess). RED. ─────────
|
|
252
|
+
#[test]
|
|
253
|
+
fn orphan_gate_fix_without_confirm_is_refused_envelope() {
|
|
254
|
+
let v = diagnose_port::orphan_gate(/*fix=*/ true, /*confirm=*/ false).expect("orphan_gate");
|
|
255
|
+
assert_eq!(
|
|
256
|
+
v,
|
|
257
|
+
json!({
|
|
258
|
+
"ok": false,
|
|
259
|
+
"gate": "orphans",
|
|
260
|
+
"status": "refused",
|
|
261
|
+
"reason": "fix_requires_confirm",
|
|
262
|
+
"action": "re-run with --gate orphans --fix --confirm",
|
|
263
|
+
}),
|
|
264
|
+
"golden orphan_gate fix-without-confirm refused envelope (orphan_cleanup.py:304-311); got {v:?}"
|
|
265
|
+
);
|
|
266
|
+
let order: Vec<&str> = v.as_object().unwrap().keys().map(String::as_str).collect();
|
|
267
|
+
assert_eq!(order, vec!["ok", "gate", "status", "reason", "action"], "golden refused key order");
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// ── cleanup_orphans(confirm=false): golden DRY-RUN envelope (orphan_cleanup.py cleanup_…) ─────────
|
|
271
|
+
// {ok,scanned,orphans,dry_run:true,scanned_at,action_required}. RUST mod.rs:534-535 stub
|
|
272
|
+
// {ok,confirm,cleaned}. scanned/scanned_at are machine/clock-derived; lock the deterministic ones. RED.
|
|
273
|
+
#[test]
|
|
274
|
+
fn cleanup_orphans_dryrun_golden_envelope() {
|
|
275
|
+
let v = diagnose_port::cleanup_orphans(/*confirm=*/ false).expect("cleanup_orphans");
|
|
276
|
+
let obj = v.as_object().expect("cleanup dict");
|
|
277
|
+
assert_eq!(v["dry_run"], json!(true), "no --confirm => dry_run:true (cleanup_orphan_coordinators)");
|
|
278
|
+
assert_eq!(v["orphans"], json!([]), "golden lists orphans (empty when none)");
|
|
279
|
+
assert_eq!(
|
|
280
|
+
v["action_required"],
|
|
281
|
+
json!("re-run with --confirm to send SIGTERM"),
|
|
282
|
+
"golden dry-run action_required text"
|
|
283
|
+
);
|
|
284
|
+
assert!(obj.contains_key("scanned_at"), "golden carries scanned_at timestamp");
|
|
285
|
+
assert!(obj.contains_key("scanned"), "golden carries scanned count");
|
|
286
|
+
assert!(!obj.contains_key("confirm"), "golden has NO `confirm` key");
|
|
287
|
+
assert!(!obj.contains_key("cleaned"), "golden has NO `cleaned` key (uses `orphans`)");
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ── fix_schema: golden fix_schema_layout diagnosis envelope (schema_migration.py:258) ─────────────
|
|
291
|
+
// {ok,status,db_path,schema_version,user_version,layout_diffs,recommended_action,would_backup_path,
|
|
292
|
+
// fixed,rebuilds}. RUST mod.rs:538-540 stub {ok,fixed:false}. db_path/would_backup_path are
|
|
293
|
+
// path/clock-derived; lock the deterministic fields. SCHEMA_VERSION==3. RED. ─────────────────────
|
|
294
|
+
#[test]
|
|
295
|
+
fn fix_schema_golden_layout_diagnosis_envelope() {
|
|
296
|
+
let ws = tmp_workspace();
|
|
297
|
+
let v = diagnose_port::fix_schema(&ws).expect("fix_schema");
|
|
298
|
+
let obj = v.as_object().expect("fix_schema dict");
|
|
299
|
+
assert_eq!(v["status"], json!("missing"), "missing db: status missing");
|
|
300
|
+
assert_eq!(v["schema_version"], json!(3), "golden schema_version == SCHEMA_VERSION (3)");
|
|
301
|
+
assert_eq!(v["user_version"], json!(0), "missing db user_version == 0");
|
|
302
|
+
assert_eq!(v["layout_diffs"], json!([]), "missing db => empty layout_diffs list");
|
|
303
|
+
assert_eq!(v["recommended_action"], json!("none"), "no drift => recommended_action 'none'");
|
|
304
|
+
assert_eq!(v["fixed"], json!(false), "missing db is diagnostic-only and does not create a db");
|
|
305
|
+
assert_eq!(v["rebuilds"], json!([]), "no rebuilds on a fresh db");
|
|
306
|
+
assert!(obj.contains_key("db_path"), "golden carries db_path");
|
|
307
|
+
assert!(obj.contains_key("would_backup_path"), "golden carries would_backup_path");
|
|
308
|
+
let _ = std::fs::remove_dir_all(&ws);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// ── doctor: golden checks dict (diagnose/health.py:179-241) — tmux/workspace/workspace_is_git_repo/
|
|
312
|
+
// providers/mcp/coordinator/ok. RUST mod.rs:520-522 stub {ok,spec,blockers}. Lock the golden
|
|
313
|
+
// top-level keys (values are machine-derived) + absence of the stub's spec/blockers. RED. ─────────
|
|
314
|
+
#[test]
|
|
315
|
+
fn doctor_golden_checks_shape_not_spec_blockers_stub() {
|
|
316
|
+
let ws = tmp_workspace();
|
|
317
|
+
let v = diagnose_port::doctor(&ws, None).expect("doctor");
|
|
318
|
+
let obj = v.as_object().expect("doctor dict");
|
|
319
|
+
let tmux = v["tmux"].as_object().expect("golden doctor.tmux is a dict {installed,path}");
|
|
320
|
+
assert!(tmux.contains_key("installed") && tmux.contains_key("path"), "tmux check shape");
|
|
321
|
+
assert!(v["workspace"].is_string(), "golden doctor.workspace is a string path");
|
|
322
|
+
assert!(v["workspace_is_git_repo"].is_boolean(), "golden doctor.workspace_is_git_repo bool");
|
|
323
|
+
assert!(v["providers"].is_object(), "golden doctor.providers is a dict");
|
|
324
|
+
assert_eq!(
|
|
325
|
+
v["mcp"]["local_module"],
|
|
326
|
+
json!(true),
|
|
327
|
+
"golden doctor.mcp.local_module == true (health.py:197-200)"
|
|
328
|
+
);
|
|
329
|
+
assert!(v["coordinator"].is_object(), "golden doctor.coordinator is the coordinator_health dict");
|
|
330
|
+
assert!(!obj.contains_key("spec"), "golden doctor has NO `spec` key (Rust stub adds it)");
|
|
331
|
+
assert!(!obj.contains_key("blockers"), "golden doctor has NO `blockers` key (Rust stub adds it)");
|
|
332
|
+
let _ = std::fs::remove_dir_all(&ws);
|
|
333
|
+
}
|