{
  "id": "cron-tool",
  "name": "Cron-Uebersetzer",
  "version": "1.0.0",
  "type": "agent-tool",
  "author": "Astoris",
  "premium": false,
  "description": "Uebersetzt einen 5-Feld-Cron-Ausdruck in Klartext und berechnet die naechsten 5 Laufzeiten.",
  "inputHint": "{ \"cron\": \"*/15 9-17 * * 1-5\" }",
  "code": "// Cron-Uebersetzer. 5 Felder: min hour dom mon dow. Klartext + naechste 5 Laufzeiten (ISO).\nasync function run(input) {\n  var cron = String((input && input.cron) || '').trim();\n  var fields = cron.split(/\\s+/);\n  if (fields.length !== 5) return { fehler: 'Erwartet 5 Felder: Minute Stunde Tag Monat Wochentag.' };\n  var ranges = [[0, 59], [0, 23], [1, 31], [1, 12], [0, 6]];\n  function parseField(spec, lo, hi) {\n    var allowed = {};\n    var ok = true;\n    spec.split(',').forEach(function (part) {\n      var step = 1;\n      var slash = part.split('/');\n      if (slash.length === 2) { step = parseInt(slash[1], 10); part = slash[0]; }\n      var a = lo, b = hi;\n      if (part === '*' || part === '') { a = lo; b = hi; }\n      else if (part.indexOf('-') >= 0) {\n        var seg = part.split('-'); a = parseInt(seg[0], 10); b = parseInt(seg[1], 10);\n      } else { a = b = parseInt(part, 10); }\n      if (isNaN(a) || isNaN(b) || isNaN(step) || step < 1) { ok = false; return; }\n      for (var v = a; v <= b; v += step) { if (v >= lo && v <= hi) allowed[v] = true; }\n    });\n    if (!ok) return null;\n    return allowed;\n  }\n  var sets = [];\n  for (var i = 0; i < 5; i++) {\n    var s = parseField(fields[i], ranges[i][0], ranges[i][1]);\n    if (!s) return { fehler: 'Ungueltiges Feld: ' + fields[i] };\n    sets.push(s);\n  }\n  var minSet = sets[0], hourSet = sets[1], domSet = sets[2], monSet = sets[3], dowSet = sets[4];\n  var domStar = fields[2] === '*';\n  var dowStar = fields[4] === '*';\n  function matches(d) {\n    if (!minSet[d.getMinutes()]) return false;\n    if (!hourSet[d.getHours()]) return false;\n    if (!monSet[d.getMonth() + 1]) return false;\n    var domOk = !!domSet[d.getDate()];\n    var dowOk = !!dowSet[d.getDay()];\n    if (domStar && dowStar) return true;\n    if (domStar) return dowOk;\n    if (dowStar) return domOk;\n    return domOk || dowOk;\n  }\n  var next = [];\n  var t = new Date();\n  t.setSeconds(0, 0);\n  t.setMinutes(t.getMinutes() + 1);\n  var guard = 0;\n  var maxIter = 367 * 24 * 60;\n  while (next.length < 5 && guard < maxIter) {\n    if (matches(t)) next.push(new Date(t.getTime()).toISOString());\n    t.setMinutes(t.getMinutes() + 1);\n    guard++;\n  }\n  var dayNames = ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'];\n  function sortedKeys(set) { return Object.keys(set).map(Number).sort(function (a, b) { return a - b; }); }\n  function desc() {\n    var p = [];\n    p.push(fields[1] === '*' ? 'jede Stunde' : 'um Stunde ' + sortedKeys(hourSet).join(','));\n    p.push(fields[0] === '*' ? 'jede Minute' : 'zur Minute ' + sortedKeys(minSet).join(','));\n    if (fields[2] !== '*') p.push('am Monatstag ' + sortedKeys(domSet).join(','));\n    if (fields[3] !== '*') p.push('im Monat ' + sortedKeys(monSet).join(','));\n    if (fields[4] !== '*') p.push('an Wochentagen ' + sortedKeys(dowSet).map(function (n) { return dayNames[n]; }).join(','));\n    return p.join(', ');\n  }\n  return { cron: cron, beschreibung: desc(), naechsteLaeufe: next };\n}"
}