@misterhuydo/sentinel 1.5.61 → 1.5.62

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.
@@ -1,6 +1,6 @@
1
1
  {
2
- "message": "Auto-checkpoint at 2026-04-21T09:17:19.216Z",
3
- "checkpoint_at": "2026-04-21T09:17:19.218Z",
2
+ "message": "Auto-checkpoint at 2026-04-21T09:35:34.502Z",
3
+ "checkpoint_at": "2026-04-21T09:35:34.503Z",
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@misterhuydo/sentinel",
3
- "version": "1.5.61",
3
+ "version": "1.5.62",
4
4
  "description": "Sentinel — Autonomous DevOps Agent installer and manager",
5
5
  "bin": {
6
6
  "sentinel": "./bin/sentinel.js"
@@ -1 +1 @@
1
- __version__ = "1.5.61"
1
+ __version__ = "1.5.62"
@@ -1770,6 +1770,44 @@ def _format_monitor_step_output(tool: str, raw: str) -> str | None:
1770
1770
  text += f"\n_…and {len(matches) - 200} more_"
1771
1771
  return f"```\n{text}\n```"
1772
1772
 
1773
+ # ── search_logs ───────────────────────────────────────────────────────────
1774
+ if tool == "search_logs":
1775
+ hits = data.get("results") or data.get("matches") or []
1776
+ if not hits:
1777
+ return None
1778
+ lines = [
1779
+ f"[{h.get('source','?')}] {h.get('line', h)}" if isinstance(h, dict) else str(h)
1780
+ for h in hits[:200]
1781
+ ]
1782
+ text = "\n".join(lines)
1783
+ if len(hits) > 200:
1784
+ text += f"\n_…and {len(hits) - 200} more_"
1785
+ return f"```\n{text}\n```"
1786
+
1787
+ # ── list_pending_prs ──────────────────────────────────────────────────────
1788
+ if tool == "list_pending_prs":
1789
+ prs = data.get("prs") or data.get("results") or []
1790
+ if not prs:
1791
+ return None
1792
+ lines = [
1793
+ f"• [{p.get('repo','?')}] {p.get('title','?')} — {p.get('url') or p.get('pr_url','')}"
1794
+ if isinstance(p, dict) else str(p)
1795
+ for p in prs
1796
+ ]
1797
+ return "\n".join(lines)
1798
+
1799
+ # ── get_repo_status ───────────────────────────────────────────────────────
1800
+ if tool == "get_repo_status":
1801
+ repos = data.get("repos") or (data.get("repo") and [data]) or []
1802
+ if not repos:
1803
+ return raw.strip() or None
1804
+ lines = []
1805
+ for r in repos:
1806
+ name = r.get("repo") or r.get("name", "?")
1807
+ status = r.get("status") or r.get("summary", "")
1808
+ lines.append(f"• *{name}*: {status}")
1809
+ return "\n".join(lines) or None
1810
+
1773
1811
  # ── get_status / check_health / others — always show ─────────────────────
1774
1812
  if "error" in data:
1775
1813
  return f":warning: `{tool}` error: {data['error']}"
@@ -374,8 +374,18 @@ reply with a grouped summary like this:
374
374
  – "every X min for Y hours/days" → calculate stop_at = now + duration
375
375
  – "every X min for N times" → set max_runs=N
376
376
  – "every X min until <datetime>" → set stop_at
377
- Minimum interval: 60 seconds. Allowed tools: fetch_logs, filter_logs, get_status,
378
- ask_logs, list_recent_commits, check_health.
377
+ Minimum interval: 60 seconds.
378
+ When a user asks what monitors can do or what tools are available for monitors, list all
379
+ allowed tools with a one-line description of each use case:
380
+ • fetch_logs — pull fresh logs from SSH servers (with optional filter/grep)
381
+ • filter_logs — search already-fetched logs by pattern
382
+ • ask_logs — ask an AI question about fetched log content
383
+ • get_status — Sentinel's error/fix summary for the last N hours
384
+ • check_health — health check on a service or repo
385
+ • list_recent_commits — recent commits across monitored repos
386
+ • search_logs — search indexed log history for a pattern across all sources
387
+ • list_pending_prs — show open Sentinel PRs waiting for review
388
+ • get_repo_status — git status of a repo (behind main, diverged, dirty, etc.)
379
389
  Always confirm to the user with the monitor ID and stop condition before creating.
380
390
  • `stop_monitor` — delete a monitor by ID (stops it if active); pass "all" to delete all in this channel
381
391
  • `list_monitors` — show active monitors plus completed/cancelled ones from the last 24 hours
@@ -1347,14 +1357,16 @@ _TOOLS = [
1347
1357
  "results to this Slack channel. Supports: run indefinitely (until stopped), run for "
1348
1358
  "a fixed duration (stop_at), or run N times (max_runs). "
1349
1359
  "steps is a list of {tool, inputs} objects — most monitors are a single step. "
1350
- "Allowed tools: fetch_logs, filter_logs, get_status, ask_logs, list_recent_commits, check_health. "
1360
+ "Allowed tools: fetch_logs, filter_logs, get_status, ask_logs, list_recent_commits, "
1361
+ "check_health, search_logs, list_pending_prs, get_repo_status. "
1351
1362
  "Boss calculates stop_at from phrases like 'within 2 hours' / 'for 30 minutes' using "
1352
1363
  "the current UTC time in the system prompt. "
1353
1364
  "IMPORTANT: ALWAYS call list_monitors FIRST to get the live DB state before calling "
1354
1365
  "this tool — never infer active monitors from conversation history, as finished monitors "
1355
1366
  "are deleted and context window state will be stale. "
1356
1367
  "Examples: 'fetch SSOLWA logs filtered by provision/phone every 5 min for 2 hours', "
1357
- "'check STS health every 10 min until I say stop', 'get status every hour for 3 times'."
1368
+ "'check STS health every 10 min until I say stop', 'search logs for OOM every 10 min', "
1369
+ "'watch for pending PRs every 30 min', 'monitor repo drift every hour'."
1358
1370
  ),
1359
1371
  "input_schema": {
1360
1372
  "type": "object",
@@ -3534,7 +3546,8 @@ async def _run_tool(name: str, inputs: dict, cfg_loader, store, slack_client=Non
3534
3546
  return json.dumps({"error": f"interval_seconds must be >= 60 (minimum 1 minute), got {interval_s}"})
3535
3547
 
3536
3548
  _MONITOR_ALLOWED = {"fetch_logs", "filter_logs", "get_status", "ask_logs",
3537
- "list_recent_commits", "check_health"}
3549
+ "list_recent_commits", "check_health",
3550
+ "search_logs", "list_pending_prs", "get_repo_status"}
3538
3551
  for _step in steps:
3539
3552
  _t = _step.get("tool", "")
3540
3553
  if _t not in _MONITOR_ALLOWED: