@misterhuydo/sentinel 1.4.57 → 1.4.59

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-25T11:51:07.142Z
1
+ 2026-03-25T12:30:48.361Z
@@ -1,6 +1,6 @@
1
1
  {
2
- "message": "Auto-checkpoint at 2026-03-25T12:11:43.792Z",
3
- "checkpoint_at": "2026-03-25T12:11:43.793Z",
2
+ "message": "Auto-checkpoint at 2026-03-25T12:25:21.116Z",
3
+ "checkpoint_at": "2026-03-25T12:25:21.118Z",
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.57",
3
+ "version": "1.4.59",
4
4
  "description": "Sentinel — Autonomous DevOps Agent installer and manager",
5
5
  "bin": {
6
6
  "sentinel": "./bin/sentinel.js"
@@ -74,6 +74,7 @@ class SentinelConfig:
74
74
  sync_interval_seconds: int = 300
75
75
  sync_retention_days: int = 30 # delete synced log files older than this many days
76
76
  sync_max_file_mb: int = 200 # truncate synced log files exceeding this size (MB)
77
+ boss_mode: str = "standard" # standard | strict | fun
77
78
 
78
79
 
79
80
  @dataclass
@@ -190,6 +191,8 @@ class ConfigLoader:
190
191
  c.sync_interval_seconds = int(d.get("SYNC_INTERVAL_SECONDS", 300))
191
192
  c.sync_retention_days = int(d.get("SYNC_RETENTION_DAYS", 30))
192
193
  c.sync_max_file_mb = int(d.get("SYNC_MAX_FILE_MB", 200))
194
+ raw_mode = d.get("BOSS_MODE", "standard").lower().strip()
195
+ c.boss_mode = raw_mode if raw_mode in ("standard", "strict", "fun") else "standard"
193
196
  self.sentinel = c
194
197
 
195
198
  def _load_log_sources(self):
@@ -238,6 +238,7 @@ Events to subscribe: app_mention, message.im, message.channels
238
238
  Tone: direct, professional, like a senior engineer who owns the system.
239
239
  Don't pad responses. Don't say "Great question!" or "Certainly!".
240
240
  If you don't know something, use a tool to find out before saying you don't know.
241
+ {BOSS_MODE_HINT}
241
242
 
242
243
  When to act vs. when to ask:
243
244
  - Any read/investigate tool (ask_codebase, filter_logs, search_logs, get_status, tail_log, ask_logs,
@@ -325,6 +326,31 @@ For greetings like "hello" or empty messages, introduce yourself briefly and off
325
326
  If you need a follow-up from them, do NOT include [DONE] — wait for their next message.
326
327
  """
327
328
 
329
+ _BOSS_MODE_HINTS = {
330
+ "standard": (
331
+ "For requests that are clearly not DevOps tasks (jokes, stories, SVGs, general questions, "
332
+ "creative tasks) — just answer helpfully and naturally. No need to redirect back to "
333
+ "Sentinel's purpose."
334
+ ),
335
+ "strict": (
336
+ "You are a DevOps-only assistant. If the user asks for something unrelated to software "
337
+ "engineering, infrastructure, or this project's operations (e.g. jokes, stories, creative "
338
+ "writing), politely decline and steer back to DevOps topics. Keep it brief and friendly."
339
+ ),
340
+ "fun": (
341
+ "For requests that are clearly not DevOps tasks (jokes, stories, SVGs, creative writing, "
342
+ "trivia, anything fun) — engage fully and enthusiastically. You're a senior engineer who "
343
+ "also happens to be great company. Have fun with it, keep your personality, and don't "
344
+ "over-explain. Then offer to help with DevOps if relevant."
345
+ ),
346
+ }
347
+
348
+
349
+ def _resolve_system(boss_mode: str = "standard") -> str:
350
+ hint = _BOSS_MODE_HINTS.get(boss_mode, _BOSS_MODE_HINTS["standard"])
351
+ return _SYSTEM.replace("{BOSS_MODE_HINT}", hint)
352
+
353
+
328
354
  # ── Tool definitions ─────────────────────────────────────────────────────────
329
355
 
330
356
  _TOOLS = [
@@ -2641,7 +2667,7 @@ async def _handle_with_cli(
2641
2667
  known_users = store.get_all_users()
2642
2668
  users_hint = ", ".join(f"<@{uid}> = {name}" for uid, name in known_users.items())
2643
2669
  prompt = (
2644
- _SYSTEM
2670
+ _resolve_system(getattr(cfg_loader.sentinel, "boss_mode", "standard"))
2645
2671
  + (f"\nYou are speaking with: {user_name} (Slack mention: {slack_mention})" if user_name else "")
2646
2672
  + "\nAlways start your reply by addressing the user directly using their Slack mention, e.g. \"<@U123> here is what I found...\"."
2647
2673
  + " Never use their plain name — always use the <@USER_ID> format so Slack highlights it."
@@ -2840,7 +2866,7 @@ async def _handle_with_api(
2840
2866
  else:
2841
2867
  user_time_hint = ""
2842
2868
  system = (
2843
- _SYSTEM
2869
+ _resolve_system(getattr(cfg_loader.sentinel, "boss_mode", "standard"))
2844
2870
  + (f"\nYou are speaking with: {user_name} (Slack mention: {slack_mention})" if user_name else "")
2845
2871
  + "\nAlways start your reply by addressing the user directly using their Slack mention, e.g. \"<@U123> here is what I found...\"."
2846
2872
  + " Never use their plain name — always use the <@USER_ID> format so Slack highlights it."
@@ -59,3 +59,9 @@ WORKSPACE_DIR=./workspace
59
59
  # Use "@Sentinel list watched bots" to see the current list.
60
60
  # Comma-separated list of Slack bot IDs (starts with B, not U).
61
61
  # SLACK_WATCH_BOT_IDS=B12345678, B87654321
62
+
63
+ # Boss conversation mode — controls how Boss handles off-topic requests (default: standard)
64
+ # standard — professional DevOps agent; off-topic questions answered helpfully but concisely
65
+ # strict — DevOps only; politely redirects off-topic requests (recommended for shared/enterprise workspaces)
66
+ # fun — fully open; jokes, stories, SVGs, creative tasks — Boss engages enthusiastically
67
+ # BOSS_MODE=standard