@team-agent/installer 0.5.32 → 0.5.33

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.32"
578
+ version = "0.5.33"
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.32"
12
+ version = "0.5.33"
13
13
  license = "AGPL-3.0"
14
14
  rust-version = "1.95"
15
15
 
@@ -764,9 +764,31 @@ impl Coordinator {
764
764
  // refreshed BEFORE classification (the classifier sees the updated value).
765
765
  // A non-empty but UNCHANGED capture must not dirty the state every tick
766
766
  // (P3 umbrella: steady second tick is a zero state write).
767
+ //
768
+ // 0.5.32 follow-up (`.team/artifacts/0532-r1-real-fail-triage.md` §6):
769
+ // fresh-cohort startup-output guard. After the restart clear helper wipes
770
+ // `activity`/`worker_state`/`last_output_at`/`last_output_hash`, the first
771
+ // non-empty pane capture (fake worker's READY line, provider startup
772
+ // banner) is trivially different from the missing digest. If we let it
773
+ // set `last_output_at=now`, classify_agent_activity falls through to
774
+ // `recent_provider_output => Working` even though no structural signal
775
+ // exists — that's the R1 real-machine false busy.
776
+ //
777
+ // Narrow gate: fresh cohort (no activity/worker_state/last_output_at
778
+ // /last_output_hash/current turn/task fields), no work obligation
779
+ // arming a real send, and no structural prompt/working signal in the
780
+ // capture → still update `last_output_hash` (dedup) but do NOT write
781
+ // `last_output_at`. The classifier then returns Uncertain=UNKNOWN,
782
+ // which is the honest post-clear observation. Preserves recent_provider_output
783
+ // for non-startup normal output (later capture has prior last_output_at
784
+ // or last_output_hash, so `fresh_cohort` false → gate skipped).
785
+ let fresh_cohort = agent_is_fresh_cohort(agent);
786
+ let has_structural_signal = latest_pane_signal_is_structural(&captured.text);
767
787
  let output_advanced =
768
788
  !captured.text.is_empty() && scrollback_digest_advanced(agent, &captured.text);
769
- if output_advanced {
789
+ let suppress_last_output_at =
790
+ output_advanced && fresh_cohort && !has_work_obligation && !has_structural_signal;
791
+ if output_advanced && !suppress_last_output_at {
770
792
  if let Some(agent_obj) = agent.as_object_mut() {
771
793
  agent_obj.insert(
772
794
  "last_output_at".to_string(),
@@ -1808,11 +1830,21 @@ fn parse_rfc3339_utc(raw: &str) -> Option<chrono::DateTime<chrono::Utc>> {
1808
1830
  }
1809
1831
 
1810
1832
  /// 0.5.32 (`.team/artifacts/restart-resumed-stale-activity-locate.md` §5):
1811
- /// return true when the rollout file's modification time is not newer than
1812
- /// the agent's current `spawned_at`. Used by `jsonl_activity_for_agent` to
1813
- /// refuse classifying a pre-spawn transcript tail into fresh-cohort activity.
1814
- /// Missing `spawned_at`, missing mtime, or unparseable timestamp → false
1815
- /// (do not block classification; the caller keeps the pre-0.5.32 behavior).
1833
+ /// return true when the rollout file's modification time is strictly older
1834
+ /// than the agent's current `spawned_at`. Used by `jsonl_activity_for_agent`
1835
+ /// to refuse classifying a pre-spawn transcript tail into fresh-cohort
1836
+ /// activity. Missing `spawned_at`, missing mtime, or unparseable timestamp
1837
+ /// → false (do not block classification; the caller keeps the pre-0.5.32
1838
+ /// behavior).
1839
+ ///
1840
+ /// 0.5.33 boundary tightening (leader 派单 msg_42dbad7f2938 / earlier cr
1841
+ /// batch older-or-equal 预警): use strict `<` not `<=`. Fast machines can
1842
+ /// produce a fresh post-spawn rollout whose mtime shares the second-resolution
1843
+ /// `spawned_at`; treating "equal" as pre-spawn would wrongly reject the
1844
+ /// first post-spawn transcript record. Genuinely pre-spawn transcripts have
1845
+ /// mtime strictly before `spawned_at` and remain rejected. The equal case
1846
+ /// falls back to the classifier + pane fallback, which is the ambiguous-
1847
+ /// but-safe path.
1816
1848
  fn jsonl_older_than_spawn_boundary(agent: &Value, metadata: &std::fs::Metadata) -> bool {
1817
1849
  let Some(spawned_at) = agent
1818
1850
  .get("spawned_at")
@@ -1829,7 +1861,7 @@ fn jsonl_older_than_spawn_boundary(agent: &Value, metadata: &std::fs::Metadata)
1829
1861
  };
1830
1862
  let mtime_utc =
1831
1863
  chrono::DateTime::<chrono::Utc>::from(std::time::UNIX_EPOCH + mtime_since_epoch);
1832
- mtime_utc <= spawned_at
1864
+ mtime_utc < spawned_at
1833
1865
  }
1834
1866
 
1835
1867
  fn matching_capture_pane_info(
@@ -2246,6 +2278,48 @@ fn clear_awaiting_human_confirm(agent: &mut Value) {
2246
2278
  }
2247
2279
  }
2248
2280
 
2281
+ /// 0.5.32 follow-up (`.team/artifacts/0532-r1-real-fail-triage.md` §6/§7):
2282
+ /// "fresh cohort" = the state a restart / start-agent clear helper leaves
2283
+ /// behind, before any post-spawn tick has repopulated observations.
2284
+ /// Requires `spawned_at` present so the gate fires only for real
2285
+ /// restart/start cohorts; coordinator-only fixtures without a spawn
2286
+ /// boundary keep pre-0.5.32 pane fallback behavior (spine2 sync_health
2287
+ /// tests seed bare provider/window/pane_id and expect `last_output_at`
2288
+ /// to be recorded on the first delta).
2289
+ fn agent_is_fresh_cohort(agent: &Value) -> bool {
2290
+ let spawned_at_present = agent
2291
+ .get("spawned_at")
2292
+ .and_then(Value::as_str)
2293
+ .is_some_and(|s| !s.is_empty());
2294
+ if !spawned_at_present {
2295
+ return false;
2296
+ }
2297
+ const CLEARED_FIELDS: &[&str] = &[
2298
+ "activity",
2299
+ "worker_state",
2300
+ "last_output_at",
2301
+ "last_output_hash",
2302
+ "current_turn_message_id",
2303
+ "current_task_id",
2304
+ "task_id",
2305
+ ];
2306
+ CLEARED_FIELDS.iter().all(|field| {
2307
+ agent
2308
+ .get(*field)
2309
+ .map(|value| value.is_null())
2310
+ .unwrap_or(true)
2311
+ })
2312
+ }
2313
+
2314
+ /// 0.5.32 follow-up: is there a structural pane signal in `text`?
2315
+ /// True when `latest_prompt_signal` recognizes anything (idle prompt char,
2316
+ /// working spinner/keyword, or fake READY/WORKING marker). When true, the
2317
+ /// classifier will produce a definite non-`recent_provider_output` activity
2318
+ /// on its own, so the freshness gate must not suppress `last_output_at`.
2319
+ fn latest_pane_signal_is_structural(text: &str) -> bool {
2320
+ crate::messaging::helpers::latest_prompt_signal(text).is_some()
2321
+ }
2322
+
2249
2323
  /// Python approvals/status.py:68-72 — sha256 the scrollback, compare to the stored
2250
2324
  /// `last_output_hash`; only a CHANGED digest counts as advanced output (and stores
2251
2325
  /// the new digest).
@@ -168,6 +168,19 @@ pub(crate) fn latest_prompt_signal(scrollback: &str) -> Option<AgentActivity> {
168
168
  if line.contains('❯') || line.contains('›') {
169
169
  has_idle_prompt = true;
170
170
  }
171
+ // 0.5.32 follow-up (`0532-r1-real-fail-triage.md` §6/§7):
172
+ // fake provider owns explicit READY/WORKING markers (fake_worker.rs:47/59).
173
+ // Recognize them here as STRUCTURAL bottom-region signals so restart's
174
+ // first-capture READY does not fall through to `recent_provider_output`
175
+ // false busy. Scope: literal `TEAM_AGENT_FAKE_READY`/`TEAM_AGENT_FAKE_WORKING`
176
+ // tokens only — do NOT infer that arbitrary "ready" prose from real
177
+ // providers means idle.
178
+ if line.contains("TEAM_AGENT_FAKE_READY") {
179
+ has_idle_prompt = true;
180
+ }
181
+ if line.contains("TEAM_AGENT_FAKE_WORKING") {
182
+ has_live_working_indicator = true;
183
+ }
171
184
  // codex live spinner shapes (provider/adapter.rs:875-876 markers):
172
185
  // braille spinner, `• Working (`, `Thinking`; claude `✶`/`✢`/`✻`
173
186
  // and Claude Code tool-progress verbs. We look for STRUCTURAL
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-agent/installer",
3
- "version": "0.5.32",
3
+ "version": "0.5.33",
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.32",
24
- "@team-agent/cli-darwin-x64": "0.5.32",
25
- "@team-agent/cli-linux-x64": "0.5.32"
23
+ "@team-agent/cli-darwin-arm64": "0.5.33",
24
+ "@team-agent/cli-darwin-x64": "0.5.33",
25
+ "@team-agent/cli-linux-x64": "0.5.33"
26
26
  },
27
27
  "scripts": {
28
28
  "postinstall": "node npm/bincheck.mjs",