@team-agent/installer 0.5.18 → 0.5.19

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 CHANGED
@@ -575,7 +575,7 @@ dependencies = [
575
575
 
576
576
  [[package]]
577
577
  name = "team-agent"
578
- version = "0.5.18"
578
+ version = "0.5.19"
579
579
  dependencies = [
580
580
  "anyhow",
581
581
  "chrono",
package/Cargo.toml CHANGED
@@ -9,7 +9,7 @@ members = ["crates/team-agent", "crates/win-conpty-phase0", "crates/conpty-trans
9
9
 
10
10
  [workspace.package]
11
11
  edition = "2021"
12
- version = "0.5.18"
12
+ version = "0.5.19"
13
13
  license = "AGPL-3.0"
14
14
  rust-version = "1.95"
15
15
 
@@ -732,7 +732,8 @@ pub fn cmd_diagnose(args: &DiagnoseArgs) -> Result<CmdResult, CliError> {
732
732
  &selected.run_workspace,
733
733
  )),
734
734
  };
735
- let (issues, suggested_repairs) = diagnose_runtime(&state, backend.as_ref());
735
+ let (issues, suggested_repairs) =
736
+ diagnose_runtime_for_workspace(&selected.run_workspace, &state, backend.as_ref());
736
737
  let ok = issues.as_array().is_some_and(Vec::is_empty);
737
738
  Ok(CmdResult::from_json(
738
739
  json!({
@@ -165,6 +165,125 @@ pub(crate) fn diagnose_runtime(state: &Value, backend: &dyn Transport) -> (Value
165
165
  (Value::Array(issues), Value::Array(repairs))
166
166
  }
167
167
 
168
+ pub(crate) fn diagnose_runtime_for_workspace(
169
+ workspace: &std::path::Path,
170
+ state: &Value,
171
+ backend: &dyn Transport,
172
+ ) -> (Value, Value) {
173
+ let (mut issues, mut repairs) = diagnose_runtime(state, backend);
174
+ append_coordinator_health_issue(workspace, state, &mut issues, &mut repairs);
175
+ (issues, repairs)
176
+ }
177
+
178
+ fn append_coordinator_health_issue(
179
+ workspace: &std::path::Path,
180
+ state: &Value,
181
+ issues: &mut Value,
182
+ repairs: &mut Value,
183
+ ) {
184
+ let workspace = crate::coordinator::WorkspacePath::new(workspace.to_path_buf());
185
+ let health = crate::coordinator::coordinator_health(&workspace);
186
+ let Some(id) = coordinator_issue_id(state, &health) else {
187
+ return;
188
+ };
189
+ if let Some(items) = issues.as_array_mut() {
190
+ items.push(coordinator_issue_value(id, &health, workspace.as_path()));
191
+ }
192
+ if let Some(items) = repairs.as_array_mut() {
193
+ items.push(coordinator_repair_hint(id, &health));
194
+ }
195
+ }
196
+
197
+ fn coordinator_issue_id(
198
+ state: &Value,
199
+ health: &crate::coordinator::HealthReport,
200
+ ) -> Option<&'static str> {
201
+ match health.status {
202
+ crate::coordinator::CoordinatorHealthStatus::Stale
203
+ | crate::coordinator::CoordinatorHealthStatus::InvalidPid => {
204
+ Some("coordinator_unavailable")
205
+ }
206
+ crate::coordinator::CoordinatorHealthStatus::Running => {
207
+ if !health.metadata_ok {
208
+ return match health.metadata_mismatch_reason.as_deref() {
209
+ Some(
210
+ "binary_identity_missing"
211
+ | "binary_version_mismatch"
212
+ | "binary_path_mismatch",
213
+ ) => Some("coordinator_stale_identity"),
214
+ Some(_) | None => Some("coordinator_unavailable"),
215
+ };
216
+ }
217
+ if !health.schema.ok {
218
+ Some("coordinator_schema_incompatible")
219
+ } else {
220
+ None
221
+ }
222
+ }
223
+ crate::coordinator::CoordinatorHealthStatus::Missing => {
224
+ coordinator_expected(state).then_some("coordinator_unavailable")
225
+ }
226
+ }
227
+ }
228
+
229
+ fn coordinator_issue_value(
230
+ id: &str,
231
+ health: &crate::coordinator::HealthReport,
232
+ workspace: &std::path::Path,
233
+ ) -> Value {
234
+ json!({
235
+ "id": id,
236
+ "status": coordinator_status_wire(health.status),
237
+ "pid": health.pid.map(|pid| pid.get()),
238
+ "metadata_ok": health.metadata_ok,
239
+ "metadata_mismatch_reason": health.metadata_mismatch_reason.clone(),
240
+ "binary_path": health.current_binary_identity.binary_path.clone(),
241
+ "binary_version": health.current_binary_identity.binary_version.clone(),
242
+ "schema_ok": health.schema.ok,
243
+ "coordinator_log": crate::coordinator::coordinator_log_path(
244
+ &crate::coordinator::WorkspacePath::new(workspace.to_path_buf())
245
+ )
246
+ .to_string_lossy()
247
+ .to_string(),
248
+ })
249
+ }
250
+
251
+ fn coordinator_repair_hint(id: &str, _health: &crate::coordinator::HealthReport) -> Value {
252
+ let hint_action = match id {
253
+ "coordinator_schema_incompatible" => "team-agent repair-state --schema",
254
+ _ => "team-agent restart",
255
+ };
256
+ json!({
257
+ "issue": id,
258
+ "action_required": true,
259
+ "advisory": true,
260
+ "broken_class": id,
261
+ "hint_action": hint_action,
262
+ "dedupe_key": id,
263
+ "action": format!("{hint_action} # diagnose only reports coordinator health; it does not start, stop, or rotate the coordinator"),
264
+ })
265
+ }
266
+
267
+ fn coordinator_expected(state: &Value) -> bool {
268
+ state
269
+ .get("session_name")
270
+ .and_then(Value::as_str)
271
+ .is_some_and(|session| !session.is_empty())
272
+ || state
273
+ .get("agents")
274
+ .and_then(Value::as_object)
275
+ .is_some_and(|agents| !agents.is_empty())
276
+ }
277
+
278
+ fn coordinator_status_wire(status: crate::coordinator::CoordinatorHealthStatus) -> &'static str {
279
+ match status {
280
+ crate::coordinator::CoordinatorHealthStatus::Missing => "missing",
281
+ crate::coordinator::CoordinatorHealthStatus::InvalidPid => "invalid_pid",
282
+ crate::coordinator::CoordinatorHealthStatus::Running => "running",
283
+ crate::coordinator::CoordinatorHealthStatus::Stale => "stale",
284
+ }
285
+ }
286
+
168
287
  fn topology_repair_hint(issue: &str) -> Value {
169
288
  json!({
170
289
  "issue": issue,
@@ -246,6 +365,72 @@ mod tests {
246
365
  path
247
366
  }
248
367
 
368
+ fn coordinator_health_fixture(
369
+ status: crate::coordinator::CoordinatorHealthStatus,
370
+ metadata_mismatch_reason: Option<&str>,
371
+ schema_ok: bool,
372
+ ) -> crate::coordinator::HealthReport {
373
+ crate::coordinator::HealthReport {
374
+ ok: matches!(status, crate::coordinator::CoordinatorHealthStatus::Running)
375
+ && metadata_mismatch_reason.is_none()
376
+ && schema_ok,
377
+ status,
378
+ pid: Some(crate::coordinator::Pid::new(std::process::id())),
379
+ metadata: None,
380
+ metadata_ok: metadata_mismatch_reason.is_none(),
381
+ metadata_mismatch_reason: metadata_mismatch_reason.map(ToString::to_string),
382
+ current_binary_identity: crate::coordinator::CoordinatorBinaryIdentity {
383
+ binary_path: "/current/team-agent".to_string(),
384
+ binary_version: env!("CARGO_PKG_VERSION").to_string(),
385
+ },
386
+ schema: crate::coordinator::SchemaHealth {
387
+ ok: schema_ok,
388
+ schema_version: crate::db::schema::SCHEMA_VERSION,
389
+ error: None,
390
+ action: None,
391
+ },
392
+ }
393
+ }
394
+
395
+ #[test]
396
+ fn coordinator_issue_id_maps_stale_pid_to_unavailable() {
397
+ let health = coordinator_health_fixture(
398
+ crate::coordinator::CoordinatorHealthStatus::Stale,
399
+ None,
400
+ true,
401
+ );
402
+ assert_eq!(
403
+ coordinator_issue_id(&json!({"session_name": "team-fixture"}), &health),
404
+ Some("coordinator_unavailable")
405
+ );
406
+ }
407
+
408
+ #[test]
409
+ fn coordinator_issue_id_maps_binary_identity_to_stale_identity() {
410
+ let health = coordinator_health_fixture(
411
+ crate::coordinator::CoordinatorHealthStatus::Running,
412
+ Some("binary_version_mismatch"),
413
+ true,
414
+ );
415
+ assert_eq!(
416
+ coordinator_issue_id(&json!({"session_name": "team-fixture"}), &health),
417
+ Some("coordinator_stale_identity")
418
+ );
419
+ }
420
+
421
+ #[test]
422
+ fn coordinator_issue_id_maps_schema_failure_to_schema_incompatible() {
423
+ let health = coordinator_health_fixture(
424
+ crate::coordinator::CoordinatorHealthStatus::Running,
425
+ None,
426
+ false,
427
+ );
428
+ assert_eq!(
429
+ coordinator_issue_id(&json!({"session_name": "team-fixture"}), &health),
430
+ Some("coordinator_schema_incompatible")
431
+ );
432
+ }
433
+
249
434
  #[test]
250
435
  fn diagnose_surfaces_codex_session_identity_mismatch() {
251
436
  let workspace =
@@ -695,6 +695,9 @@ pub enum RestartReport {
695
695
  Restarted {
696
696
  session_name: SessionName,
697
697
  agents: Vec<RestartedAgent>,
698
+ /// Compatibility field: true means the coordinator requirement is
699
+ /// satisfied. The structured `coordinator` summary carries started vs
700
+ /// already-running vs rotated detail.
698
701
  coordinator_started: bool,
699
702
  coordinator: CoordinatorStartSummary,
700
703
  next_actions: Vec<String>,
@@ -706,6 +709,9 @@ pub enum RestartReport {
706
709
  session_name: SessionName,
707
710
  agents: Vec<RestartedAgent>,
708
711
  failed_agents: Vec<RestartFailedAgent>,
712
+ /// Compatibility field: true means the coordinator requirement is
713
+ /// satisfied. The structured `coordinator` summary carries started vs
714
+ /// already-running vs rotated detail.
709
715
  coordinator_started: bool,
710
716
  coordinator: CoordinatorStartSummary,
711
717
  next_actions: Vec<String>,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-agent/installer",
3
- "version": "0.5.18",
3
+ "version": "0.5.19",
4
4
  "description": "npx installer for Team Agent",
5
5
  "keywords": [
6
6
  "codex",
@@ -20,9 +20,9 @@
20
20
  "team-agent-installer": "npm/install.mjs"
21
21
  },
22
22
  "optionalDependencies": {
23
- "@team-agent/cli-darwin-arm64": "0.5.18",
24
- "@team-agent/cli-darwin-x64": "0.5.18",
25
- "@team-agent/cli-linux-x64": "0.5.18"
23
+ "@team-agent/cli-darwin-arm64": "0.5.19",
24
+ "@team-agent/cli-darwin-x64": "0.5.19",
25
+ "@team-agent/cli-linux-x64": "0.5.19"
26
26
  },
27
27
  "scripts": {
28
28
  "postinstall": "node npm/bincheck.mjs",