@misterhuydo/sentinel 1.5.55 → 1.5.57
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-04-
|
|
1
|
+
2026-04-21T07:25:38.460Z
|
package/.cairn/session.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"message": "Auto-checkpoint at 2026-04-
|
|
3
|
-
"checkpoint_at": "2026-04-
|
|
2
|
+
"message": "Auto-checkpoint at 2026-04-21T07:32:04.414Z",
|
|
3
|
+
"checkpoint_at": "2026-04-21T07:32:04.416Z",
|
|
4
4
|
"active_files": [
|
|
5
5
|
"J:\\Projects\\Sentinel\\cli\\bin\\sentinel.js",
|
|
6
6
|
"J:\\Projects\\Sentinel\\cli\\lib\\test.js",
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "1.5.
|
|
1
|
+
__version__ = "1.5.57"
|
|
@@ -377,8 +377,8 @@ reply with a grouped summary like this:
|
|
|
377
377
|
Minimum interval: 60 seconds. Allowed tools: fetch_logs, filter_logs, get_status,
|
|
378
378
|
ask_logs, list_recent_commits, check_health.
|
|
379
379
|
Always confirm to the user with the monitor ID and stop condition before creating.
|
|
380
|
-
• `stop_monitor` —
|
|
381
|
-
• `list_monitors` — show
|
|
380
|
+
• `stop_monitor` — delete a monitor by ID (stops it if active); pass "all" to delete all in this channel
|
|
381
|
+
• `list_monitors` — show active monitors plus completed/cancelled ones from the last 24 hours
|
|
382
382
|
|
|
383
383
|
*File sharing*
|
|
384
384
|
• `post_file` — upload any output as a Slack file (logs, diffs, reports)
|
|
@@ -1350,6 +1350,9 @@ _TOOLS = [
|
|
|
1350
1350
|
"Allowed tools: fetch_logs, filter_logs, get_status, ask_logs, list_recent_commits, check_health. "
|
|
1351
1351
|
"Boss calculates stop_at from phrases like 'within 2 hours' / 'for 30 minutes' using "
|
|
1352
1352
|
"the current UTC time in the system prompt. "
|
|
1353
|
+
"IMPORTANT: ALWAYS call list_monitors FIRST to get the live DB state before calling "
|
|
1354
|
+
"this tool — never infer active monitors from conversation history, as finished monitors "
|
|
1355
|
+
"are deleted and context window state will be stale. "
|
|
1353
1356
|
"Examples: 'fetch SSOLWA logs filtered by provision/phone every 5 min for 2 hours', "
|
|
1354
1357
|
"'check STS health every 10 min until I say stop', 'get status every hour for 3 times'."
|
|
1355
1358
|
),
|
|
@@ -1391,8 +1394,12 @@ _TOOLS = [
|
|
|
1391
1394
|
{
|
|
1392
1395
|
"name": "stop_monitor",
|
|
1393
1396
|
"description": (
|
|
1394
|
-
"
|
|
1395
|
-
"
|
|
1397
|
+
"Delete a monitor by ID — removes it from the list immediately. "
|
|
1398
|
+
"Works on any monitor regardless of status (active, done, or cancelled). "
|
|
1399
|
+
"For active monitors this also stops it from running. "
|
|
1400
|
+
"Pass 'all' to delete every monitor in this channel. "
|
|
1401
|
+
"Use for: 'delete monitor m-abc123', 'stop monitor m-abc123', 'delete all monitors', "
|
|
1402
|
+
"'clear monitors', 'cancel the log watch'."
|
|
1396
1403
|
),
|
|
1397
1404
|
"input_schema": {
|
|
1398
1405
|
"type": "object",
|
|
@@ -1408,8 +1415,9 @@ _TOOLS = [
|
|
|
1408
1415
|
{
|
|
1409
1416
|
"name": "list_monitors",
|
|
1410
1417
|
"description": (
|
|
1411
|
-
"List all active
|
|
1412
|
-
"Use for: 'what monitors are running?', 'show scheduled tasks', 'list
|
|
1418
|
+
"List all monitors — active ones plus completed/cancelled ones from the last 24 hours. "
|
|
1419
|
+
"Use for: 'what monitors are running?', 'show scheduled tasks', 'list monitors', "
|
|
1420
|
+
"'show recent monitors'. Each entry includes status (active/done/cancelled)."
|
|
1413
1421
|
),
|
|
1414
1422
|
"input_schema": {"type": "object", "properties": {}},
|
|
1415
1423
|
},
|
|
@@ -3586,32 +3594,33 @@ async def _run_tool(name: str, inputs: dict, cfg_loader, store, slack_client=Non
|
|
|
3586
3594
|
if not mon_id:
|
|
3587
3595
|
return json.dumps({"error": "monitor_id is required"})
|
|
3588
3596
|
if mon_id.lower() == "all":
|
|
3589
|
-
count = store.
|
|
3590
|
-
return json.dumps({"
|
|
3591
|
-
ok = store.
|
|
3597
|
+
count = store.delete_all_monitors(channel=channel)
|
|
3598
|
+
return json.dumps({"deleted": count, "message": f"Deleted {count} monitor(s)."})
|
|
3599
|
+
ok = store.delete_monitor(mon_id)
|
|
3592
3600
|
if ok:
|
|
3593
|
-
return json.dumps({"status": "
|
|
3594
|
-
return json.dumps({"error": f"Monitor '{mon_id}' not found
|
|
3601
|
+
return json.dumps({"status": "deleted", "monitor_id": mon_id})
|
|
3602
|
+
return json.dumps({"error": f"Monitor '{mon_id}' not found."})
|
|
3595
3603
|
|
|
3596
3604
|
if name == "list_monitors":
|
|
3597
3605
|
monitors = store.list_active_monitors()
|
|
3598
3606
|
if not monitors:
|
|
3599
|
-
return json.dumps({"monitors": [], "message": "No
|
|
3607
|
+
return json.dumps({"monitors": [], "message": "No monitors in the last 24 hours."})
|
|
3600
3608
|
result = []
|
|
3601
3609
|
for _m in monitors:
|
|
3602
3610
|
_runs_left = None
|
|
3603
3611
|
if _m.get("max_runs"):
|
|
3604
3612
|
_runs_left = _m["max_runs"] - _m["runs_so_far"]
|
|
3605
3613
|
result.append({
|
|
3606
|
-
"id":
|
|
3607
|
-
"name":
|
|
3608
|
-
"status":
|
|
3609
|
-
"interval":
|
|
3610
|
-
"runs_so_far":
|
|
3611
|
-
"runs_left":
|
|
3612
|
-
"next_run_at":
|
|
3613
|
-
"stop_at":
|
|
3614
|
-
"
|
|
3614
|
+
"id": _m["id"],
|
|
3615
|
+
"name": _m.get("name") or "",
|
|
3616
|
+
"status": _m["status"],
|
|
3617
|
+
"interval": _format_duration(_m["interval_seconds"]),
|
|
3618
|
+
"runs_so_far": _m["runs_so_far"],
|
|
3619
|
+
"runs_left": _runs_left,
|
|
3620
|
+
"next_run_at": _m.get("next_run_at") or "",
|
|
3621
|
+
"stop_at": _m.get("stop_at") or "",
|
|
3622
|
+
"completed_at": _m.get("completed_at") or "",
|
|
3623
|
+
"steps": json.loads(_m.get("steps_json") or "[]"),
|
|
3615
3624
|
})
|
|
3616
3625
|
return json.dumps({"monitors": result})
|
|
3617
3626
|
|
|
@@ -450,8 +450,14 @@ class StateStore:
|
|
|
450
450
|
"channel TEXT, "
|
|
451
451
|
"user_id TEXT, "
|
|
452
452
|
"status TEXT DEFAULT 'active', "
|
|
453
|
+
"completed_at TEXT, "
|
|
453
454
|
"created_at TEXT)"
|
|
454
455
|
)
|
|
456
|
+
# Migration: add completed_at to existing tables
|
|
457
|
+
try:
|
|
458
|
+
conn.execute("ALTER TABLE monitors ADD COLUMN completed_at TEXT")
|
|
459
|
+
except Exception:
|
|
460
|
+
pass
|
|
455
461
|
|
|
456
462
|
def create_monitor(self, id: str, name: str, steps_json: str,
|
|
457
463
|
interval_seconds: int, stop_at, max_runs,
|
|
@@ -486,10 +492,21 @@ class StateStore:
|
|
|
486
492
|
return dict(row) if row else None
|
|
487
493
|
|
|
488
494
|
def list_active_monitors(self) -> list[dict]:
|
|
495
|
+
from datetime import datetime, timezone, timedelta
|
|
496
|
+
now = datetime.now(timezone.utc)
|
|
497
|
+
cutoff = (now - timedelta(hours=24)).isoformat()
|
|
489
498
|
with self._conn() as conn:
|
|
490
499
|
self._ensure_monitors_table(conn)
|
|
500
|
+
# Auto-clean completed/done monitors older than 24 h
|
|
501
|
+
conn.execute(
|
|
502
|
+
"DELETE FROM monitors WHERE status != 'active' AND completed_at < ?",
|
|
503
|
+
(cutoff,),
|
|
504
|
+
)
|
|
491
505
|
rows = conn.execute(
|
|
492
|
-
"SELECT * FROM monitors
|
|
506
|
+
"SELECT * FROM monitors "
|
|
507
|
+
"WHERE status = 'active' OR (status != 'active' AND completed_at >= ?) "
|
|
508
|
+
"ORDER BY created_at DESC",
|
|
509
|
+
(cutoff,),
|
|
493
510
|
).fetchall()
|
|
494
511
|
return [dict(r) for r in rows]
|
|
495
512
|
|
|
@@ -505,7 +522,12 @@ class StateStore:
|
|
|
505
522
|
with self._conn() as conn:
|
|
506
523
|
self._ensure_monitors_table(conn)
|
|
507
524
|
if done:
|
|
508
|
-
|
|
525
|
+
# Keep done monitors visible for 24 h; user can delete explicitly via stop_monitor
|
|
526
|
+
conn.execute(
|
|
527
|
+
"UPDATE monitors SET runs_so_far = runs_so_far + 1, last_run_at = ?, "
|
|
528
|
+
"status = 'done', completed_at = ? WHERE id = ?",
|
|
529
|
+
(_now(), _now(), id),
|
|
530
|
+
)
|
|
509
531
|
else:
|
|
510
532
|
conn.execute(
|
|
511
533
|
"UPDATE monitors SET runs_so_far = runs_so_far + 1, last_run_at = ?, "
|
|
@@ -513,26 +535,31 @@ class StateStore:
|
|
|
513
535
|
(_now(), next_run_at, id),
|
|
514
536
|
)
|
|
515
537
|
|
|
516
|
-
def
|
|
538
|
+
def delete_monitor(self, id: str) -> bool:
|
|
539
|
+
"""Delete any monitor regardless of status (cancel + remove for active ones)."""
|
|
517
540
|
with self._conn() as conn:
|
|
518
541
|
self._ensure_monitors_table(conn)
|
|
519
|
-
cur = conn.execute(
|
|
520
|
-
"DELETE FROM monitors WHERE id = ? AND status = 'active'", (id,)
|
|
521
|
-
)
|
|
542
|
+
cur = conn.execute("DELETE FROM monitors WHERE id = ?", (id,))
|
|
522
543
|
return cur.rowcount > 0
|
|
523
544
|
|
|
524
|
-
def
|
|
545
|
+
def delete_all_monitors(self, channel: str = "") -> int:
|
|
546
|
+
"""Delete all monitors in a channel (or globally if channel is empty)."""
|
|
525
547
|
with self._conn() as conn:
|
|
526
548
|
self._ensure_monitors_table(conn)
|
|
527
549
|
if channel:
|
|
528
|
-
cur = conn.execute(
|
|
529
|
-
"DELETE FROM monitors WHERE status = 'active' AND channel = ?",
|
|
530
|
-
(channel,),
|
|
531
|
-
)
|
|
550
|
+
cur = conn.execute("DELETE FROM monitors WHERE channel = ?", (channel,))
|
|
532
551
|
else:
|
|
533
|
-
cur = conn.execute("DELETE FROM monitors
|
|
552
|
+
cur = conn.execute("DELETE FROM monitors")
|
|
534
553
|
return cur.rowcount
|
|
535
554
|
|
|
555
|
+
def cancel_monitor(self, id: str) -> bool:
|
|
556
|
+
"""Alias for delete_monitor — kept for compatibility."""
|
|
557
|
+
return self.delete_monitor(id)
|
|
558
|
+
|
|
559
|
+
def cancel_all_monitors(self, channel: str = "") -> int:
|
|
560
|
+
"""Alias for delete_all_monitors — kept for compatibility."""
|
|
561
|
+
return self.delete_all_monitors(channel)
|
|
562
|
+
|
|
536
563
|
# ── Pending bot-message routing questions ─────────────────────────────────
|
|
537
564
|
|
|
538
565
|
def _ensure_pending_routings_table(self, conn):
|