@team-agent/installer 0.5.8 → 0.5.10

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.
@@ -263,11 +263,21 @@ fn ensure_coordinator_after_collect(
263
263
  }
264
264
 
265
265
  /// `_coordinator_should_run`(`results.py:187-188`)。
266
+ ///
267
+ /// The top-level `state.leader_receiver` read below is a coordinator-scope
268
+ /// legacy compat bridge (pre-teams-map single-team layout) — deliberately
269
+ /// NOT team-scoped because this predicate answers "is a coordinator worth
270
+ /// starting for this workspace at all?" and does not itself route any
271
+ /// message. The `ALLOWED-LEGACY-READ` marker documents the exception and
272
+ /// keeps grep sweeps honest; delete once B1 canonical layout lands and
273
+ /// every state carries a `teams` map
274
+ /// (`.team/artifacts/next-version-staged-plan.md §5 Phase-Foundation-1`).
266
275
  fn coordinator_should_run(state: &serde_json::Value) -> bool {
267
276
  let has_session = state
268
277
  .get("session_name")
269
278
  .and_then(serde_json::Value::as_str)
270
279
  .is_some_and(|s| !s.is_empty());
280
+ // ALLOWED-LEGACY-READ: pre-teams-map coordinator-scope existence probe; never used for routing.
271
281
  has_session || leader_receiver_is_direct(state.get("leader_receiver"))
272
282
  }
273
283
 
@@ -942,6 +952,12 @@ fn report_result_for_owner_team_inner(
942
952
  );
943
953
  }
944
954
  out.insert("notification_event_id".to_string(), serde_json::Value::Null);
955
+ if let Some(warnings) = report_result_array(envelope, "warnings") {
956
+ out.insert(
957
+ "warnings".to_string(),
958
+ serde_json::Value::Array(warnings.clone()),
959
+ );
960
+ }
945
961
  Ok(serde_json::Value::Object(out))
946
962
  }
947
963
 
@@ -1036,6 +1052,9 @@ fn format_report_result_notification(
1036
1052
  if let Some(tests) = format_report_result_tests(envelope) {
1037
1053
  lines.push(tests);
1038
1054
  }
1055
+ if let Some(warnings) = format_report_result_warnings(envelope) {
1056
+ lines.push(warnings);
1057
+ }
1039
1058
  if let Some(changes) = format_report_result_changes(envelope) {
1040
1059
  lines.push(changes);
1041
1060
  }
@@ -1075,6 +1094,29 @@ fn format_report_result_tests(envelope: &serde_json::Value) -> Option<String> {
1075
1094
  }
1076
1095
  }
1077
1096
 
1097
+ fn format_report_result_warnings(envelope: &serde_json::Value) -> Option<String> {
1098
+ let parts = report_result_array(envelope, "warnings")?
1099
+ .iter()
1100
+ .filter_map(|warning| {
1101
+ let code = report_field(warning, "code")?;
1102
+ let field = report_field(warning, "field").unwrap_or("result");
1103
+ let severity = report_field(warning, "severity").unwrap_or("warning");
1104
+ let advisory =
1105
+ if warning.get("advisory").and_then(serde_json::Value::as_bool) == Some(true) {
1106
+ " advisory"
1107
+ } else {
1108
+ ""
1109
+ };
1110
+ Some(format!("{severity}{advisory} {field}: {code}"))
1111
+ })
1112
+ .collect::<Vec<_>>();
1113
+ if parts.is_empty() {
1114
+ None
1115
+ } else {
1116
+ Some(format!("Verification warnings: {}", parts.join(", ")))
1117
+ }
1118
+ }
1119
+
1078
1120
  fn report_result_array<'a>(
1079
1121
  envelope: &'a serde_json::Value,
1080
1122
  key: &str,
@@ -1203,6 +1245,14 @@ mod tests {
1203
1245
  "tests": [
1204
1246
  {"command": "cargo test", "status": "passed"}
1205
1247
  ],
1248
+ "warnings": [
1249
+ {
1250
+ "code": "result_success_without_executed_tests",
1251
+ "field": "tests",
1252
+ "severity": "warning",
1253
+ "advisory": true
1254
+ }
1255
+ ],
1206
1256
  "risks": [
1207
1257
  {"severity": "low", "description": "none known"}
1208
1258
  ],
@@ -1217,6 +1267,9 @@ mod tests {
1217
1267
  format_report_result_notification("res_1", "task-1", "worker", "success", &envelope);
1218
1268
  assert!(notification.contains("Task task-1 reported success from worker: done"));
1219
1269
  assert!(notification.contains("Tests: cargo test=passed"));
1270
+ assert!(notification.contains(
1271
+ "Verification warnings: warning advisory tests: result_success_without_executed_tests"
1272
+ ));
1220
1273
  assert!(notification.contains("Changes: modified src/a.rs: patched delivery"));
1221
1274
  assert!(notification.contains("Risks: low: none known"));
1222
1275
  assert!(notification.contains("Artifacts: .team/artifacts/evidence.md: evidence"));
@@ -459,15 +459,25 @@ pub(crate) fn requeue_blocked_leader_messages(
459
459
  owner_team_id: &TeamKey,
460
460
  claimed_pane_id: &PaneId,
461
461
  ) -> Result<usize, MessagingError> {
462
+ // E6 (0.5.9 offline-mailbox §6.5): also requeue rows that a third-party
463
+ // sender left in `queued_until_leader_attach` via the leader mailbox.
464
+ // Same idempotent requeue funnel (row/message_id/leader_notification_log
465
+ // PK are all preserved) — after attach/claim the coordinator's normal
466
+ // `deliver_pending_messages` picks them up as `accepted` and injects
467
+ // exactly once. status `queued_until_leader_attach` is deliberately NOT
468
+ // in the `claim_for_delivery` eligible set (see message_store.rs) so it
469
+ // could not have churned while the leader was unattached.
462
470
  let requeued = conn.execute(
463
471
  "update messages
464
472
  set status = 'accepted',
465
473
  error = null,
466
474
  updated_at = ?2
467
475
  where recipient = 'leader'
468
- and status = 'failed'
469
- and error = 'leader_not_attached'
470
- and owner_team_id = ?1",
476
+ and owner_team_id = ?1
477
+ and (
478
+ (status = 'failed' and error = 'leader_not_attached')
479
+ or status = 'queued_until_leader_attach'
480
+ )",
471
481
  params![owner_team_id.as_str(), chrono::Utc::now().to_rfc3339()],
472
482
  )?;
473
483
  if requeued > 0 {
@@ -108,6 +108,7 @@
108
108
  PaneField::PaneCurrentCommand => "sh",
109
109
  PaneField::PaneCurrentPath => "/tmp/ws",
110
110
  PaneField::SessionName => "team-sess",
111
+ PaneField::PaneTty => "/dev/ttys000",
111
112
  };
112
113
  Ok(Some(value.to_string()))
113
114
  }
@@ -201,6 +201,11 @@ pub enum PaneField {
201
201
  PaneCurrentCommand,
202
202
  PaneCurrentPath,
203
203
  SessionName,
204
+ /// pane's controlling tty (e.g. `/dev/ttys015`). Consumers use it to
205
+ /// flip terminal driver bits like `stty -f <tty> -echo` from outside
206
+ /// tmux's control channel — the query itself still goes through the
207
+ /// backend so N16/CP-1 (single tmux entry point) stays intact.
208
+ PaneTty,
204
209
  }
205
210
 
206
211
  /// 后端种类(诊断/事件用)。
@@ -843,6 +848,7 @@ pub fn tmux_query_argv(pane: &PaneId, field: PaneField) -> Vec<String> {
843
848
  PaneField::PaneCurrentCommand => "#{pane_current_command}",
844
849
  PaneField::PaneCurrentPath => "#{pane_current_path}",
845
850
  PaneField::SessionName => "#{session_name}",
851
+ PaneField::PaneTty => "#{pane_tty}",
846
852
  };
847
853
  let mut argv = vec![
848
854
  "tmux".to_string(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-agent/installer",
3
- "version": "0.5.8",
3
+ "version": "0.5.10",
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.8",
24
- "@team-agent/cli-darwin-x64": "0.5.8",
25
- "@team-agent/cli-linux-x64": "0.5.8"
23
+ "@team-agent/cli-darwin-arm64": "0.5.10",
24
+ "@team-agent/cli-darwin-x64": "0.5.10",
25
+ "@team-agent/cli-linux-x64": "0.5.10"
26
26
  },
27
27
  "scripts": {
28
28
  "postinstall": "node npm/bincheck.mjs",