@misterhuydo/sentinel 1.4.50 → 1.4.51
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/session.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"message": "Auto-checkpoint at 2026-03-25T11:
|
|
3
|
-
"checkpoint_at": "2026-03-25T11:
|
|
2
|
+
"message": "Auto-checkpoint at 2026-03-25T11:34:55.696Z",
|
|
3
|
+
"checkpoint_at": "2026-03-25T11:34:55.697Z",
|
|
4
4
|
"active_files": [],
|
|
5
5
|
"notes": [],
|
|
6
6
|
"mtime_snapshot": {}
|
package/package.json
CHANGED
|
@@ -395,6 +395,30 @@ _TOOLS = [
|
|
|
395
395
|
"required": ["fingerprint"],
|
|
396
396
|
},
|
|
397
397
|
},
|
|
398
|
+
{
|
|
399
|
+
"name": "retry_issue",
|
|
400
|
+
"description": (
|
|
401
|
+
"Re-queue a previously failed or blocked issue from the archive without requiring the "
|
|
402
|
+
"user to re-type the context. Scans issues/.done/ for the most recent matching file "
|
|
403
|
+
"and re-submits it to Sentinel. "
|
|
404
|
+
"Use when the user says things like: 'retry the last issue', 're-raise the umlaut fix', "
|
|
405
|
+
"'try that again', 'retry Whydah-TypeLib', 'run the last failed fix again'."
|
|
406
|
+
),
|
|
407
|
+
"input_schema": {
|
|
408
|
+
"type": "object",
|
|
409
|
+
"properties": {
|
|
410
|
+
"project": {
|
|
411
|
+
"type": "string",
|
|
412
|
+
"description": "Project short name (e.g. '1881'). Required.",
|
|
413
|
+
},
|
|
414
|
+
"keyword": {
|
|
415
|
+
"type": "string",
|
|
416
|
+
"description": "Optional keyword to match against archived issue content (e.g. 'umlaut', 'Whydah-TypeLib')",
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
"required": ["project"],
|
|
420
|
+
},
|
|
421
|
+
},
|
|
398
422
|
{
|
|
399
423
|
"name": "list_pending_prs",
|
|
400
424
|
"description": "List all open Sentinel PRs awaiting admin review.",
|
|
@@ -1247,6 +1271,65 @@ async def _run_tool(name: str, inputs: dict, cfg_loader, store, slack_client=Non
|
|
|
1247
1271
|
"note": f"Delivered to '{project_label}'. Sentinel will process it on the next poll cycle.",
|
|
1248
1272
|
})
|
|
1249
1273
|
|
|
1274
|
+
if name == "retry_issue":
|
|
1275
|
+
project_arg = inputs.get("project", "").strip()
|
|
1276
|
+
keyword = inputs.get("keyword", "").strip().lower()
|
|
1277
|
+
|
|
1278
|
+
project_dirs = _find_project_dirs(project_arg) if project_arg else _find_project_dirs()
|
|
1279
|
+
if not project_dirs:
|
|
1280
|
+
return json.dumps({"error": f"No project found matching '{project_arg}'"})
|
|
1281
|
+
if len(project_dirs) > 1 and project_arg:
|
|
1282
|
+
return json.dumps({"error": f"Ambiguous project '{project_arg}' — matches: {[_read_project_name(d) for d in project_dirs]}"})
|
|
1283
|
+
|
|
1284
|
+
project_dir = project_dirs[0]
|
|
1285
|
+
done_dir = project_dir / "issues" / ".done"
|
|
1286
|
+
if not done_dir.exists():
|
|
1287
|
+
return json.dumps({"error": "No archived issues found — issues/.done/ does not exist"})
|
|
1288
|
+
|
|
1289
|
+
# Find all archived issue files, newest first
|
|
1290
|
+
candidates = sorted(
|
|
1291
|
+
[f for f in done_dir.iterdir() if f.is_file() and not f.name.startswith(".")],
|
|
1292
|
+
key=lambda f: f.stat().st_mtime,
|
|
1293
|
+
reverse=True,
|
|
1294
|
+
)
|
|
1295
|
+
if not candidates:
|
|
1296
|
+
return json.dumps({"error": "No archived issues found in issues/.done/"})
|
|
1297
|
+
|
|
1298
|
+
# Filter by keyword if provided
|
|
1299
|
+
if keyword:
|
|
1300
|
+
matched = []
|
|
1301
|
+
for f in candidates:
|
|
1302
|
+
try:
|
|
1303
|
+
content = f.read_text(encoding="utf-8", errors="replace")
|
|
1304
|
+
if keyword in content.lower():
|
|
1305
|
+
matched.append(f)
|
|
1306
|
+
except OSError:
|
|
1307
|
+
pass
|
|
1308
|
+
if not matched:
|
|
1309
|
+
return json.dumps({"error": f"No archived issues match keyword '{keyword}'"})
|
|
1310
|
+
candidates = matched
|
|
1311
|
+
|
|
1312
|
+
source_file = candidates[0]
|
|
1313
|
+
content = source_file.read_text(encoding="utf-8", errors="replace")
|
|
1314
|
+
|
|
1315
|
+
# Re-submit as a fresh issue file (new name = new fingerprint = no cooldown block)
|
|
1316
|
+
issues_dir = project_dir / "issues"
|
|
1317
|
+
issues_dir.mkdir(exist_ok=True)
|
|
1318
|
+
fname = f"retry-{source_file.stem[-8:]}-{uuid.uuid4().hex[:6]}.txt"
|
|
1319
|
+
(issues_dir / fname).write_text(content, encoding="utf-8")
|
|
1320
|
+
(project_dir / "SENTINEL_POLL_NOW").touch()
|
|
1321
|
+
|
|
1322
|
+
project_label = _read_project_name(project_dir.resolve())
|
|
1323
|
+
logger.info("Boss retry_issue: re-queued '%s' as '%s' for %s", source_file.name, fname, project_label)
|
|
1324
|
+
return json.dumps({
|
|
1325
|
+
"status": "re-queued",
|
|
1326
|
+
"project": project_label,
|
|
1327
|
+
"original_file": source_file.name,
|
|
1328
|
+
"new_file": fname,
|
|
1329
|
+
"note": f"Re-submitted '{source_file.name}' to '{project_label}'. Poll triggered.",
|
|
1330
|
+
})
|
|
1331
|
+
|
|
1332
|
+
|
|
1250
1333
|
if name == "get_fix_details":
|
|
1251
1334
|
fp = inputs["fingerprint"]
|
|
1252
1335
|
fix = store.get_confirmed_fix(fp) or store.get_marker_seen_fix(fp)
|