@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 +1 -1
- package/.cairn/session.json +2 -2
- package/package.json +1 -1
- package/python/sentinel/main.py +20 -0
- package/python/sentinel/slack_bot.py +13 -3
package/.cairn/.hint-lock
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2026-03-
|
|
1
|
+
2026-03-25T06:03:05.073Z
|
package/.cairn/session.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"message": "Auto-checkpoint at 2026-03-
|
|
3
|
-
"checkpoint_at": "2026-03-
|
|
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
package/python/sentinel/main.py
CHANGED
|
@@ -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 —
|
|
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
|
-
|
|
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
|
|