@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 +1 -1
- package/.cairn/session.json +2 -2
- package/lib/generate.js +10 -6
- package/package.json +1 -1
- package/python/sentinel/config_loader.py +12 -2
- package/python/sentinel/main.py +22 -0
- package/templates/sentinel.properties +4 -3
package/.cairn/.hint-lock
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2026-03-
|
|
1
|
+
2026-03-24T15:11:56.267Z
|
package/.cairn/session.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"message": "Auto-checkpoint at 2026-03-24T15:
|
|
3
|
-
"checkpoint_at": "2026-03-24T15:
|
|
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
|
-
>> "$
|
|
70
|
+
>> "$DIR/logs/sentinel.log" 2>&1 &
|
|
71
71
|
echo $! > "$PID_FILE"
|
|
72
|
-
echo "[sentinel] ${name} started (PID $!)
|
|
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
|
-
>> "$
|
|
194
|
+
>> "$DIR/logs/sentinel.log" 2>&1 &
|
|
193
195
|
echo $! > "$PID_FILE"
|
|
194
|
-
echo "[sentinel] __NAME__ started (PID $!)
|
|
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
|
@@ -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
|
-
|
|
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
|
-
|
|
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))
|
package/python/sentinel/main.py
CHANGED
|
@@ -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
|
-
#
|
|
30
|
-
#
|
|
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:
|