@misterhuydo/sentinel 1.4.6 → 1.4.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.
package/.cairn/.hint-lock CHANGED
@@ -1 +1 @@
1
- 2026-03-24T14:40:34.199Z
1
+ 2026-03-24T15:11:56.267Z
@@ -1,6 +1,6 @@
1
1
  {
2
- "message": "Auto-checkpoint at 2026-03-24T15:07:23.955Z",
3
- "checkpoint_at": "2026-03-24T15:07:23.956Z",
2
+ "message": "Auto-checkpoint at 2026-03-24T15:14:13.070Z",
3
+ "checkpoint_at": "2026-03-24T15:14:13.071Z",
4
4
  "active_files": [],
5
5
  "notes": [],
6
6
  "mtime_snapshot": {}
package/lib/generate.js CHANGED
@@ -64,12 +64,14 @@ if echo "$AUTH_OUT" | grep -Eqi "not logged in|/login"; then
64
64
  fi
65
65
 
66
66
  WORKSPACE="$(dirname "$DIR")"
67
- mkdir -p "$WORKSPACE/logs" "$DIR/workspace/fetched" "$DIR/workspace/patches" "$DIR/issues"
67
+ mkdir -p "$DIR/logs" "$WORKSPACE/logs" "$DIR/workspace/fetched" "$DIR/workspace/patches" "$DIR/issues"
68
68
  cd "$DIR"
69
69
  PYTHONPATH="${codeDir}" "${pythonBin}" -m sentinel.main --config ./config \\
70
- >> "$WORKSPACE/logs/sentinel.log" 2>&1 &
70
+ >> "$DIR/logs/sentinel.log" 2>&1 &
71
71
  echo $! > "$PID_FILE"
72
- echo "[sentinel] ${name} started (PID $!) — log: $WORKSPACE/logs/sentinel.log"
72
+ echo "[sentinel] ${name} started (PID $!)"
73
+ echo " project log : $DIR/logs/sentinel.log"
74
+ echo " workspace log: $WORKSPACE/logs/sentinel.log"
73
75
  `, { mode: 0o755 });
74
76
 
75
77
  // stop.sh
@@ -186,12 +188,14 @@ if echo "$AUTH_OUT" | grep -Eqi "not logged in|/login"; then
186
188
  exit 1
187
189
  fi
188
190
  WORKSPACE="$(dirname "$DIR")"
189
- mkdir -p "$WORKSPACE/logs" "$DIR/workspace/fetched" "$DIR/workspace/patches" "$DIR/issues"
191
+ mkdir -p "$DIR/logs" "$WORKSPACE/logs" "$DIR/workspace/fetched" "$DIR/workspace/patches" "$DIR/issues"
190
192
  cd "$DIR"
191
193
  PYTHONPATH="__CODE_DIR__" "__PYTHON_BIN__" -m sentinel.main --config ./config \
192
- >> "$WORKSPACE/logs/sentinel.log" 2>&1 &
194
+ >> "$DIR/logs/sentinel.log" 2>&1 &
193
195
  echo $! > "$PID_FILE"
194
- echo "[sentinel] __NAME__ started (PID $!) — log: $WORKSPACE/logs/sentinel.log"
196
+ echo "[sentinel] __NAME__ started (PID $!)"
197
+ echo " project log : $DIR/logs/sentinel.log"
198
+ echo " workspace log: $WORKSPACE/logs/sentinel.log"
195
199
  STARTSH
196
200
  chmod +x "$project_dir/start.sh"
197
201
  echo "[sentinel] Auto-generated start.sh for $name"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@misterhuydo/sentinel",
3
- "version": "1.4.6",
3
+ "version": "1.4.8",
4
4
  "description": "Sentinel — Autonomous DevOps Agent installer and manager",
5
5
  "bin": {
6
6
  "sentinel": "./bin/sentinel.js"
@@ -138,12 +138,14 @@ class ConfigLoader:
138
138
  d.update(_parse_properties(str(workspace_props)))
139
139
  logger.debug("Loaded workspace config from %s", workspace_props)
140
140
 
141
+ project_d: dict[str, str] = {}
141
142
  path = self.config_dir / "sentinel.properties"
142
143
  if not path.exists():
143
144
  if not d:
144
145
  logger.warning("sentinel.properties not found at %s", path)
145
146
  else:
146
- d.update(_parse_properties(str(path)))
147
+ project_d = _parse_properties(str(path))
148
+ d.update(project_d)
147
149
 
148
150
  c = SentinelConfig()
149
151
  c.poll_interval_seconds = int(d.get("POLL_INTERVAL_SECONDS", 120))
@@ -173,7 +175,15 @@ class ConfigLoader:
173
175
  c.slack_allowed_users = _csv(d.get("SLACK_ALLOWED_USERS", ""))
174
176
  c.slack_admin_users = _csv(d.get("SLACK_ADMIN_USERS", ""))
175
177
  c.project_name = d.get("PROJECT_NAME", "") or Path(self.config_dir).resolve().parent.name
176
- c.claude_pro_for_tasks = d.get("CLAUDE_PRO_FOR_TASKS", "true").lower() != "false"
178
+ # If CLAUDE_PRO_FOR_TASKS is explicitly set anywhere, respect it.
179
+ # Otherwise: if the project supplies its own ANTHROPIC_API_KEY, default to False
180
+ # (bill against their key, not the Claude Pro subscription).
181
+ if "CLAUDE_PRO_FOR_TASKS" in d:
182
+ c.claude_pro_for_tasks = d["CLAUDE_PRO_FOR_TASKS"].lower() != "false"
183
+ elif project_d.get("ANTHROPIC_API_KEY", "").strip():
184
+ c.claude_pro_for_tasks = False
185
+ else:
186
+ c.claude_pro_for_tasks = True
177
187
  c.sync_enabled = d.get("SYNC_ENABLED", "true").lower() != "false"
178
188
  c.sync_interval_seconds = int(d.get("SYNC_INTERVAL_SECONDS", 300))
179
189
  c.sync_retention_days = int(d.get("SYNC_RETENTION_DAYS", 30))
@@ -702,12 +702,34 @@ async def run_loop(cfg_loader: ConfigLoader, store: StateStore):
702
702
  break
703
703
 
704
704
 
705
+ def _setup_workspace_log() -> None:
706
+ """
707
+ Add a file handler that writes Boss/Slack/startup events to the workspace-level
708
+ sentinel.log (one level above the project dir, next to sentinel.properties).
709
+ The project-level sentinel.log (stdout redirect from start.sh) gets everything.
710
+ """
711
+ workspace_log = Path("..") / "logs" / "sentinel.log"
712
+ try:
713
+ workspace_log.parent.mkdir(parents=True, exist_ok=True)
714
+ fmt = logging.Formatter("%(asctime)s %(levelname)-7s %(name)s — %(message)s")
715
+ handler = logging.FileHandler(workspace_log, encoding="utf-8")
716
+ handler.setFormatter(fmt)
717
+ # Main sentinel logger → startup/shutdown messages
718
+ # Boss + Slack loggers → conversation activity
719
+ for name in ("sentinel", "sentinel.sentinel_boss", "sentinel.slack_bot"):
720
+ logging.getLogger(name).addHandler(handler)
721
+ except Exception as e:
722
+ logger.warning("Could not open workspace log %s: %s", workspace_log, e)
723
+
724
+
705
725
  def main():
706
726
  Path("logs").mkdir(exist_ok=True)
707
727
  Path("workspace/fetched").mkdir(parents=True, exist_ok=True)
708
728
  Path("workspace/patches").mkdir(parents=True, exist_ok=True)
709
729
  Path("issues").mkdir(exist_ok=True)
710
730
 
731
+ _setup_workspace_log()
732
+
711
733
  parser = argparse.ArgumentParser(description="Sentinel — Autonomous DevOps Agent")
712
734
  parser.add_argument("--config", default="./config", help="Config directory path")
713
735
  args = parser.parse_args()
@@ -26,10 +26,11 @@ MAILS=you@yourdomain.com
26
26
  STATE_DB=./sentinel.db
27
27
  WORKSPACE_DIR=./workspace
28
28
 
29
- # Claude authenticationsee workspace sentinel.properties for full documentation.
30
- # Override here only if this project needs different credentials than the workspace default.
29
+ # Anthropic API key override workspace default to bill this project separately.
30
+ # Use case: the project owner (e.g. a client) provides their own key so fix costs
31
+ # are charged to their account. When set here, the Fix Engine automatically uses
32
+ # this key instead of the shared Claude Pro subscription.
31
33
  # ANTHROPIC_API_KEY=sk-ant-...
32
- # CLAUDE_PRO_FOR_TASKS=true
33
34
 
34
35
  # Slack Bot (optional) — Sentinel Boss conversational interface
35
36
  # Create a Slack App at api.slack.com, enable Socket Mode, add scopes: