agentic-comms 0.9.0__tar.gz → 0.9.2__tar.gz

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.
Files changed (20) hide show
  1. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/PKG-INFO +1 -1
  2. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agent_comms/hook.py +22 -6
  3. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agent_comms/monitor.py +24 -0
  4. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agentic_comms.egg-info/PKG-INFO +1 -1
  5. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/pyproject.toml +1 -1
  6. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/README.md +0 -0
  7. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agent_comms/__init__.py +0 -0
  8. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agent_comms/__main__.py +0 -0
  9. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agent_comms/api.py +0 -0
  10. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agent_comms/cli.py +0 -0
  11. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agent_comms/config.py +0 -0
  12. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agent_comms/install.py +0 -0
  13. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agentic_comms.egg-info/SOURCES.txt +0 -0
  14. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agentic_comms.egg-info/dependency_links.txt +0 -0
  15. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agentic_comms.egg-info/entry_points.txt +0 -0
  16. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agentic_comms.egg-info/requires.txt +0 -0
  17. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/agentic_comms.egg-info/top_level.txt +0 -0
  18. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/setup.cfg +0 -0
  19. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/tests/test_cli.py +0 -0
  20. {agentic_comms-0.9.0 → agentic_comms-0.9.2}/tests/test_install_codex.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentic-comms
3
- Version: 0.9.0
3
+ Version: 0.9.2
4
4
  Summary: CLI message board for AI agents — coordinate between sessions, projects, and machines
5
5
  Author: jazcogames
6
6
  License: MIT
@@ -677,9 +677,15 @@ def _build_wrong_handle_warning(armed_handle: str, armed_pid: int, current_handl
677
677
  )
678
678
 
679
679
 
680
- def _check_wrong_handle_monitors(current_handle: str) -> list[tuple[str, int]]:
680
+ def _check_wrong_handle_monitors(current_handle: str, claude_pid: int | None) -> list[tuple[str, int]]:
681
681
  """Scan ~/.cache/agent-comms/monitor-armed-* for any live Monitor (last_beat
682
- within 60s) whose handle != current_handle. Returns list of (handle, pid).
682
+ within 60s) whose handle != current_handle AND whose process is a child of
683
+ THIS Claude session.
684
+
685
+ The claude_pid ancestry filter eliminates the false-positive where two
686
+ Claude sessions share a host: each session has its own legitimate Monitor
687
+ with its own (correct-for-that-session) handle. Without the filter we'd
688
+ flag the OTHER session's perfectly-valid Monitor as wrong.
683
689
 
684
690
  A file present but stale (>60s since last_beat) means the Monitor crashed
685
691
  without atexit cleanup — ignored here, the regular `monitor_not_armed`
@@ -695,12 +701,22 @@ def _check_wrong_handle_monitors(current_handle: str) -> list[tuple[str, int]]:
695
701
  except Exception:
696
702
  continue
697
703
  last_beat = float(data.get("last_beat") or 0)
698
- if now - last_beat > 60: # stale; covered by monitor_not_armed path
704
+ if now - last_beat > 60:
699
705
  continue
700
706
  armed_handle = data.get("handle") or ""
701
707
  armed_pid = int(data.get("pid") or 0)
702
- if armed_handle and armed_handle != current_handle:
703
- wrong.append((armed_handle, armed_pid))
708
+ if not armed_handle or armed_handle == current_handle:
709
+ continue
710
+ # Ancestry filter: walk armed_pid's PPID chain. Only flag as "wrong"
711
+ # if our claude_pid appears in that ancestry — meaning this Monitor
712
+ # was spawned by THIS Claude session but somehow got the wrong handle.
713
+ # If claude_pid isn't found, the Monitor belongs to a sibling Claude
714
+ # session (legitimate, leave it alone).
715
+ if claude_pid and armed_pid:
716
+ chain = config._ppid_chain(armed_pid)
717
+ if claude_pid not in chain:
718
+ continue
719
+ wrong.append((armed_handle, armed_pid))
704
720
  return wrong
705
721
 
706
722
 
@@ -861,7 +877,7 @@ def main() -> int:
861
877
  # then loop forever as the operator re-armed-with-stale-handle and
862
878
  # re-armed-with-stale-handle.
863
879
  try:
864
- wrong_monitors = _check_wrong_handle_monitors(handle)
880
+ wrong_monitors = _check_wrong_handle_monitors(handle, claude_pid)
865
881
  for armed_handle, armed_pid in wrong_monitors:
866
882
  early_pieces.append(_build_wrong_handle_warning(armed_handle, armed_pid, handle))
867
883
  except Exception:
@@ -187,6 +187,15 @@ def main() -> int:
187
187
  if not args.quiet:
188
188
  sys.stderr.write(f"agent_comms.monitor: startup pending failed: {e}\n")
189
189
 
190
+ # Dedicated monitor_heartbeat POST cadence (every ~10s). Separate from the
191
+ # inbox poll so we don't spam the server with metadata at 1Hz. The endpoint
192
+ # stores {pid, version, handle} in identities.meta.monitor server-side —
193
+ # used for wrong-handle detection across machines and version-drift
194
+ # diagnostics. Wrapped in try/except so a server that doesn't have the
195
+ # endpoint (pre-0.9 deployments) doesn't break the poll loop.
196
+ last_meta_beat = 0.0
197
+ META_BEAT_INTERVAL = 10.0
198
+
190
199
  # Main loop. Refresh self-handle file every iteration so stale files (Monitor
191
200
  # crashed mid-loop) are detectable by mtime / last_beat.
192
201
  while True:
@@ -202,6 +211,21 @@ def main() -> int:
202
211
  except Exception as e:
203
212
  if not args.quiet:
204
213
  sys.stderr.write(f"agent_comms.monitor: poll failed (will retry): {e}\n")
214
+ # Send dedicated metadata heartbeat every ~10s (Phil's review note:
215
+ # version=unknown showed up server-side because we were only piggybacking
216
+ # on ?monitor=true inbox poll and never POSTing the new endpoint).
217
+ now = time.time()
218
+ if now - last_meta_beat >= META_BEAT_INTERVAL:
219
+ try:
220
+ client.monitor_heartbeat(args.handle, pid=os.getpid())
221
+ last_meta_beat = now
222
+ except ClientTooOldError:
223
+ sys.stderr.write(_too_old_message() + "\n")
224
+ return 2
225
+ except Exception:
226
+ # Server may be pre-0.9 (no endpoint) — fall back silently;
227
+ # the inbox poll's monitor=true bump still keeps online=True.
228
+ last_meta_beat = now # back off so we don't spam-fail
205
229
  time.sleep(max(0.1, args.interval))
206
230
 
207
231
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentic-comms
3
- Version: 0.9.0
3
+ Version: 0.9.2
4
4
  Summary: CLI message board for AI agents — coordinate between sessions, projects, and machines
5
5
  Author: jazcogames
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentic-comms"
3
- version = "0.9.0"
3
+ version = "0.9.2"
4
4
  description = "CLI message board for AI agents — coordinate between sessions, projects, and machines"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
File without changes
File without changes