@misterhuydo/sentinel 1.5.2 → 1.5.4
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
|
@@ -259,17 +259,19 @@ def _run_claude_attempt(
|
|
|
259
259
|
cwd: str | None = None,
|
|
260
260
|
claude_log_path: Path | None = None,
|
|
261
261
|
on_progress=None,
|
|
262
|
+
cmd_override: list | None = None,
|
|
262
263
|
) -> tuple[str, bool]:
|
|
263
264
|
"""
|
|
264
265
|
Run claude CLI with the given env. Returns (output, timed_out).
|
|
265
266
|
Raises FileNotFoundError if binary is missing.
|
|
266
267
|
If on_progress is given, calls on_progress(msg) for meaningful output lines
|
|
267
268
|
(deduped — same message not repeated consecutively).
|
|
269
|
+
cmd_override: if provided, use this command list instead of _claude_cmd() default.
|
|
268
270
|
"""
|
|
269
271
|
import threading as _threading
|
|
270
272
|
|
|
271
273
|
proc = subprocess.Popen(
|
|
272
|
-
_claude_cmd(bin_path, prompt),
|
|
274
|
+
cmd_override if cmd_override is not None else _claude_cmd(bin_path, prompt),
|
|
273
275
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
|
274
276
|
text=True, env=env, cwd=cwd or None,
|
|
275
277
|
)
|
|
@@ -171,12 +171,27 @@ def run_repo_task(
|
|
|
171
171
|
if on_progress:
|
|
172
172
|
on_progress(f":mag: Exploring `{repo.repo_name}`...")
|
|
173
173
|
|
|
174
|
+
import os as _os
|
|
175
|
+
skip_perms = _os.getuid() != 0
|
|
176
|
+
# OAuth attempt: no --bare so the stored OAuth session is used naturally
|
|
177
|
+
oauth_cmd = (
|
|
178
|
+
[cfg.claude_code_bin, "--dangerously-skip-permissions", "--print", prompt]
|
|
179
|
+
if skip_perms else
|
|
180
|
+
[cfg.claude_code_bin, "--print", prompt]
|
|
181
|
+
)
|
|
182
|
+
# API key fallback: --bare forces API-key-only auth
|
|
183
|
+
api_cmd = (
|
|
184
|
+
[cfg.claude_code_bin, "--dangerously-skip-permissions", "--bare", "--print", prompt]
|
|
185
|
+
if skip_perms else
|
|
186
|
+
[cfg.claude_code_bin, "--bare", "--print", prompt]
|
|
187
|
+
)
|
|
188
|
+
api_env = {**env, "ANTHROPIC_API_KEY": cfg.anthropic_api_key} if cfg.anthropic_api_key else None
|
|
189
|
+
|
|
174
190
|
try:
|
|
175
191
|
output, timed_out = _run_claude_attempt(
|
|
176
192
|
cfg.claude_code_bin, prompt, env,
|
|
177
|
-
cwd=local_path,
|
|
178
|
-
|
|
179
|
-
on_progress=on_progress,
|
|
193
|
+
cwd=local_path, claude_log_path=claude_log, on_progress=on_progress,
|
|
194
|
+
cmd_override=oauth_cmd,
|
|
180
195
|
)
|
|
181
196
|
except FileNotFoundError:
|
|
182
197
|
return "error", f"Claude binary not found: {cfg.claude_code_bin}"
|
|
@@ -187,7 +202,26 @@ def run_repo_task(
|
|
|
187
202
|
stripped = output.strip()
|
|
188
203
|
|
|
189
204
|
if _is_auth_error(stripped):
|
|
190
|
-
|
|
205
|
+
# Silent fallback: OAuth session expired — retry with API key
|
|
206
|
+
if api_env:
|
|
207
|
+
logger.warning("repo_task/%s: OAuth session issue — retrying with API key", repo.repo_name)
|
|
208
|
+
if on_progress:
|
|
209
|
+
on_progress(":key: Auth refreshed — retrying...")
|
|
210
|
+
try:
|
|
211
|
+
output, timed_out = _run_claude_attempt(
|
|
212
|
+
cfg.claude_code_bin, prompt, api_env,
|
|
213
|
+
cwd=local_path, claude_log_path=claude_log, on_progress=on_progress,
|
|
214
|
+
cmd_override=api_cmd,
|
|
215
|
+
)
|
|
216
|
+
except FileNotFoundError:
|
|
217
|
+
return "error", f"Claude binary not found: {cfg.claude_code_bin}"
|
|
218
|
+
if timed_out:
|
|
219
|
+
return "error", "Claude timed out after 15 minutes."
|
|
220
|
+
stripped = output.strip()
|
|
221
|
+
if _is_auth_error(stripped):
|
|
222
|
+
return "error", "Claude authentication failed — check ANTHROPIC_API_KEY."
|
|
223
|
+
else:
|
|
224
|
+
return "error", "Claude authentication error — run `claude login` on the server or set ANTHROPIC_API_KEY."
|
|
191
225
|
|
|
192
226
|
if stripped.upper().startswith("SKIP:"):
|
|
193
227
|
reason = stripped[5:].strip()
|
|
@@ -252,6 +286,15 @@ def run_repo_task(
|
|
|
252
286
|
logger.error("git push failed for %s: %s", repo.repo_name, r.stderr[:300])
|
|
253
287
|
return "error", f"git push failed: {r.stderr.strip()[:200]}"
|
|
254
288
|
logger.info("Repo task: pushed to %s/%s sha=%s", repo.repo_name, repo.branch, commit_hash[:8])
|
|
289
|
+
if repo.cicd_type:
|
|
290
|
+
try:
|
|
291
|
+
from .cicd_trigger import trigger as cicd_trigger
|
|
292
|
+
cicd_trigger(repo, None, task.fingerprint)
|
|
293
|
+
logger.info("Repo task: CI/CD triggered for %s (%s)", repo.repo_name, repo.cicd_type)
|
|
294
|
+
if on_progress:
|
|
295
|
+
on_progress(f":rocket: Release triggered via `{repo.cicd_type}`")
|
|
296
|
+
except Exception as exc:
|
|
297
|
+
logger.warning("Repo task: CI/CD trigger failed for %s: %s", repo.repo_name, exc)
|
|
255
298
|
return "done", None
|
|
256
299
|
else:
|
|
257
300
|
branch = f"sentinel/task-{task.fingerprint[:8]}"
|