@misterhuydo/sentinel 1.5.33 → 1.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@misterhuydo/sentinel",
3
- "version": "1.5.33",
3
+ "version": "1.5.34",
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.33"
1
+ __version__ = "1.5.34"
@@ -181,6 +181,28 @@ import uuid as _uuid
181
181
  from pathlib import Path as _Path
182
182
 
183
183
 
184
+ def _infer_target_repo(text: str, repos: dict) -> str:
185
+ """
186
+ Try to infer a target repo from bot message content.
187
+ Looks for 'Service: <name>' or 'service: <name>' patterns and fuzzy-matches
188
+ the extracted name against known repo names. Returns the repo name on a unique
189
+ match, empty string if ambiguous or no match found.
190
+ """
191
+ import re as _re
192
+ # Extract service hints: "Service: STS", "service: SSOLWA", etc.
193
+ hints = _re.findall(r'(?i)service:\s*(\S+)', text)
194
+ # Also try class names: "Class: SomeService" — extract first word segment
195
+ hints += _re.findall(r'(?i)class:\s*(\w+)', text)
196
+
197
+ for hint in hints:
198
+ hint_lower = hint.lower().rstrip(".,:")
199
+ matches = [r for r in repos if hint_lower in r.lower()]
200
+ if len(matches) == 1:
201
+ return matches[0]
202
+
203
+ return ""
204
+
205
+
184
206
  async def _handle_bot_message(event: dict, client, cfg_loader, store) -> None:
185
207
  """
186
208
  Called when a watched bot posts a message.
@@ -216,6 +238,26 @@ async def _handle_bot_message(event: dict, client, cfg_loader, store) -> None:
216
238
  project_name = (bot_info or {}).get("project_name") or ""
217
239
  target_repo = (bot_info or {}).get("target_repo") or ""
218
240
 
241
+ # Auto-detect target_repo from message content when not pre-configured
242
+ if not target_repo and hasattr(cfg_loader, "repos") and cfg_loader.repos:
243
+ target_repo = _infer_target_repo(text, cfg_loader.repos)
244
+ if not target_repo and len(cfg_loader.repos) > 1:
245
+ # Can't determine — ask in the channel where the bot posted
246
+ bot_name = (bot_info or {}).get("bot_name") or bot_id
247
+ repo_names = ", ".join(f"`{r}`" for r in sorted(cfg_loader.repos))
248
+ try:
249
+ await client.chat_postMessage(
250
+ channel=channel,
251
+ text=(
252
+ f":mag: I got an alert from *{bot_name}* but can't tell which repo to route it to.\n"
253
+ f"Available repos: {repo_names}\n"
254
+ f"Re-register with: `@Sentinel watch @{bot_name} for <repo-name>`"
255
+ ),
256
+ )
257
+ except Exception as _e:
258
+ logger.warning("Bot watcher: could not post routing question: %s", _e)
259
+ return # drop this message — don't queue an unroutable issue
260
+
219
261
  # Resolve the project issues directory
220
262
  workspace = _Path(cfg_loader.sentinel.workspace_dir).parent
221
263
  if project_name: