@misterhuydo/sentinel 1.4.32 → 1.4.34

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/.cairn/.hint-lock CHANGED
@@ -1 +1 @@
1
- 2026-03-25T04:25:39.345Z
1
+ 2026-03-25T06:03:05.073Z
@@ -1,6 +1,6 @@
1
1
  {
2
- "message": "Auto-checkpoint at 2026-03-25T04:33:16.269Z",
3
- "checkpoint_at": "2026-03-25T04:33:16.270Z",
2
+ "message": "Auto-checkpoint at 2026-03-25T05:23:02.308Z",
3
+ "checkpoint_at": "2026-03-25T05:23:02.309Z",
4
4
  "active_files": [],
5
5
  "notes": [],
6
6
  "mtime_snapshot": {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@misterhuydo/sentinel",
3
- "version": "1.4.32",
3
+ "version": "1.4.34",
4
4
  "description": "Sentinel — Autonomous DevOps Agent installer and manager",
5
5
  "bin": {
6
6
  "sentinel": "./bin/sentinel.js"
@@ -446,6 +446,25 @@ async def _send_startup_email_delayed(cfg, results: dict, delay: int = 300):
446
446
 
447
447
  # ── Config repo polling ──────────────────────────────────────────────────────────────────────────
448
448
 
449
+ def _config_repo_git_env() -> dict:
450
+ """Return env with GIT_SSH_COMMAND pointing to ~/.ssh/<slug>.key if it exists."""
451
+ env = os.environ.copy()
452
+ try:
453
+ r = subprocess.run(
454
+ ["git", "remote", "get-url", "origin"],
455
+ capture_output=True, text=True, timeout=5,
456
+ )
457
+ remote = r.stdout.strip()
458
+ # Extract slug: git@github.com:org/repo.git or https://github.com/org/repo.git
459
+ slug = remote.rstrip(".git").rsplit("/", 1)[-1].rsplit(":", 1)[-1].rsplit("/", 1)[-1]
460
+ key = Path.home() / ".ssh" / f"{slug}.key"
461
+ if key.exists():
462
+ env["GIT_SSH_COMMAND"] = f"ssh -i {key} -o StrictHostKeyChecking=no -o BatchMode=yes"
463
+ except Exception:
464
+ pass
465
+ return env
466
+
467
+
449
468
  def _poll_config_repo(cfg_loader: ConfigLoader) -> bool:
450
469
  """git pull the project directory if it is a git repo. Returns True if changes were pulled."""
451
470
  project_dir = Path(".")
@@ -457,6 +476,7 @@ def _poll_config_repo(cfg_loader: ConfigLoader) -> bool:
457
476
  ["git", "pull", "--rebase", "--autostash"],
458
477
  cwd=str(project_dir),
459
478
  capture_output=True, text=True, timeout=30,
479
+ env=_config_repo_git_env(),
460
480
  )
461
481
  if result.returncode != 0:
462
482
  logger.warning("Config repo git pull failed: %s", result.stderr.strip())
@@ -49,6 +49,7 @@ class _Session:
49
49
  history: list = field(default_factory=list)
50
50
  history_loaded: bool = False
51
51
  busy: bool = False # True while a turn is being processed
52
+ thinking_ts: str = "" # ts of the current thinking-status message
52
53
 
53
54
 
54
55
  _sessions: dict[str, _Session] = {}
@@ -356,9 +357,16 @@ async def _dispatch(event: dict, client, cfg_loader, store) -> None:
356
357
  is_admin = (not admin_users) or (user_id in admin_users)
357
358
 
358
359
  if session.busy:
359
- # Still processing a previous turn from this user — drop the duplicate
360
+ # Still processing a previous turn from this user — update the existing status in-place
360
361
  logger.info("Boss: %s sent a message while still processing, ignoring", user_id)
361
- await _post(client, channel, f"_{random.choice(_THINKING_STATUS)} (still on it...)_")
362
+ if session.thinking_ts:
363
+ try:
364
+ await client.chat_update(
365
+ channel=channel, ts=session.thinking_ts,
366
+ text=f"_{random.choice(_THINKING_STATUS)} (still on it...)_",
367
+ )
368
+ except Exception:
369
+ pass # silently drop — no orphaned message
362
370
  return
363
371
 
364
372
  # Fetch any attached files (screenshots, logs, docs)
@@ -440,7 +448,8 @@ async def _run_turn(session: _Session, message: str, client, cfg_loader, store,
440
448
 
441
449
  # Post a random status and keep its ts so we can replace it with the real reply
442
450
  session.busy = True
443
- thinking_ts = await _post(client, channel, f"_{random.choice(_THINKING_STATUS)}_")
451
+ session.thinking_ts = await _post(client, channel, f"_{random.choice(_THINKING_STATUS)}_")
452
+ thinking_ts = session.thinking_ts
444
453
 
445
454
  attach_note = f" (+{len(attachments)} file(s))" if attachments else ""
446
455
  logger.info("Boss [%s] >> %s%s", session.user_name, message[:300], attach_note)
@@ -462,6 +471,7 @@ async def _run_turn(session: _Session, message: str, client, cfg_loader, store,
462
471
  reply = f":warning: Unhandled error: {e}"
463
472
  finally:
464
473
  session.busy = False
474
+ session.thinking_ts = ""
465
475
 
466
476
  logger.info("Boss [%s] << %s", session.user_name, reply[:300])
467
477