@misterhuydo/sentinel 1.1.7 → 1.1.8

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-03-23T09:08:47.973Z",
3
- "checkpoint_at": "2026-03-23T09:08:47.974Z",
2
+ "message": "Auto-checkpoint at 2026-03-23T09:16:11.394Z",
3
+ "checkpoint_at": "2026-03-23T09:16:11.395Z",
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.1.7",
3
+ "version": "1.1.8",
4
4
  "description": "Sentinel — Autonomous DevOps Agent installer and manager",
5
5
  "bin": {
6
6
  "sentinel": "./bin/sentinel.js"
@@ -187,6 +187,11 @@ Session context — critical rules:
187
187
  - When handling a new request, call the tools fresh. Do not assume any prior tool result is still current or that any prior step "counts" toward the current task.
188
188
  - The only exception: if the user explicitly asks about something from the history ("what did you find earlier?"), you may reference it — but note it is from a prior session.
189
189
 
190
+ Avoid redundant tool calls:
191
+ - If a broad search (e.g. search_logs with no source filter) already returned results for a query, do NOT repeat the same search with a source filter to "refine" — use the results you already have.
192
+ - If a tool call fails (wrong source name, config not found), do NOT retry the entire search from scratch. Continue with what succeeded, and note the failure in your reply.
193
+ - One pass per task: gather all needed data in a single round of tool calls, then produce the final answer.
194
+
190
195
  Issue identification — before calling create_issue:
191
196
  1. Determine if the message is a REAL issue/task (bug report, feature request, investigation ask)
192
197
  vs. a status question, tool query, or casual chat. If not an issue, just answer normally.
@@ -779,6 +784,48 @@ def _git_pull(path: Path) -> dict:
779
784
  return {"status": "error", "detail": str(e)}
780
785
 
781
786
 
787
+ # ── Log-source name resolver ──────────────────────────────────────────────────
788
+
789
+ def _filter_log_sources(props_files: list, source_hint: str) -> list:
790
+ """
791
+ Return the subset of props_files whose log source matches source_hint.
792
+
793
+ Matching is tried in order (first match wins per file):
794
+ 1. Substring of the filename stem (e.g. "sts" → STS.properties)
795
+ 2. Substring of REMOTE_SERVICE_USER (e.g. "ssolwa" → ...SSOLoginWebApp...)
796
+ 3. Substring of HOSTS (e.g. hostname fragment)
797
+
798
+ Case-insensitive throughout. An empty source_hint returns all files unchanged.
799
+ """
800
+ if not source_hint:
801
+ return props_files
802
+ hint = source_hint.lower()
803
+
804
+ def _props_contains(path: Path, key: str, hint: str) -> bool:
805
+ try:
806
+ for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
807
+ stripped = line.strip()
808
+ if stripped.startswith("#"):
809
+ continue
810
+ if stripped.upper().startswith(key + "="):
811
+ val = stripped.split("=", 1)[1].partition("#")[0].strip().lower()
812
+ if hint in val:
813
+ return True
814
+ except OSError:
815
+ pass
816
+ return False
817
+
818
+ matched = []
819
+ for p in props_files:
820
+ if hint in p.stem.lower():
821
+ matched.append(p)
822
+ elif _props_contains(p, "REMOTE_SERVICE_USER", hint):
823
+ matched.append(p)
824
+ elif _props_contains(p, "HOSTS", hint):
825
+ matched.append(p)
826
+ return matched
827
+
828
+
782
829
  # ── Tool execution ────────────────────────────────────────────────────────────
783
830
 
784
831
  async def _run_tool(name: str, inputs: dict, cfg_loader, store, slack_client=None, user_id: str = "", channel: str = "", is_admin: bool = False) -> str:
@@ -1016,9 +1063,7 @@ async def _run_tool(name: str, inputs: dict, cfg_loader, store, slack_client=Non
1016
1063
  script = Path(__file__).resolve().parent.parent / "scripts" / "fetch_log.sh"
1017
1064
  log_cfg_dir = Path("config") / "log-configs"
1018
1065
  if script.exists() and log_cfg_dir.exists():
1019
- props_files = sorted(log_cfg_dir.glob("*.properties"))
1020
- if source:
1021
- props_files = [p for p in props_files if source in p.stem.lower()]
1066
+ props_files = _filter_log_sources(sorted(log_cfg_dir.glob("*.properties")), source)
1022
1067
  if props_files:
1023
1068
  live_results = []
1024
1069
  for props in props_files:
@@ -1165,9 +1210,7 @@ async def _run_tool(name: str, inputs: dict, cfg_loader, store, slack_client=Non
1165
1210
  if not log_cfg_dir.exists():
1166
1211
  return json.dumps({"error": "config/log-configs/ not found"})
1167
1212
 
1168
- props_files = sorted(log_cfg_dir.glob("*.properties"))
1169
- if source_filter:
1170
- props_files = [p for p in props_files if source_filter in p.stem.lower()]
1213
+ props_files = _filter_log_sources(sorted(log_cfg_dir.glob("*.properties")), source_filter)
1171
1214
  if not props_files:
1172
1215
  return json.dumps({"error": f"No log-config found matching '{source_filter}'"})
1173
1216