clementine-agent 1.18.79 → 1.18.80
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/dist/cli/dashboard.js +163 -86
- package/package.json +1 -1
package/dist/cli/dashboard.js
CHANGED
|
@@ -15124,6 +15124,44 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
15124
15124
|
0%, 100% { opacity: 0.4; transform: scale(0.85); }
|
|
15125
15125
|
50% { opacity: 1; transform: scale(1); }
|
|
15126
15126
|
}
|
|
15127
|
+
/* PRD Phase 1.3a: inner config-tab strip — switches which Configure
|
|
15128
|
+
section blocks are visible without changing the outer Configure /
|
|
15129
|
+
What-will-run / Last-run tabs. Visual: pill chips along the top of
|
|
15130
|
+
the Configure pane. */
|
|
15131
|
+
.cron-config-tabs {
|
|
15132
|
+
display: flex;
|
|
15133
|
+
gap: 4px;
|
|
15134
|
+
margin: 0 0 14px;
|
|
15135
|
+
border-bottom: 1px solid var(--border);
|
|
15136
|
+
padding-bottom: 0;
|
|
15137
|
+
}
|
|
15138
|
+
.cron-config-tab-btn {
|
|
15139
|
+
background: none;
|
|
15140
|
+
border: none;
|
|
15141
|
+
color: var(--text-muted);
|
|
15142
|
+
font-size: 12px;
|
|
15143
|
+
font-weight: 500;
|
|
15144
|
+
padding: 8px 12px;
|
|
15145
|
+
cursor: pointer;
|
|
15146
|
+
border-bottom: 2px solid transparent;
|
|
15147
|
+
transition: color 0.15s, border-color 0.15s;
|
|
15148
|
+
margin-bottom: -1px;
|
|
15149
|
+
}
|
|
15150
|
+
.cron-config-tab-btn:hover { color: var(--text-primary); }
|
|
15151
|
+
.cron-config-tab-btn.active {
|
|
15152
|
+
color: var(--accent);
|
|
15153
|
+
border-bottom-color: var(--accent);
|
|
15154
|
+
}
|
|
15155
|
+
/* Sections are tagged with data-config-tab; the active tab attr on the
|
|
15156
|
+
Configure pane controls visibility. .force-show overrides for power-user
|
|
15157
|
+
"show everything" later. */
|
|
15158
|
+
#cron-tab-configure[data-active-config-tab="basics"] [data-config-tab]:not([data-config-tab="basics"]),
|
|
15159
|
+
#cron-tab-configure[data-active-config-tab="prompt"] [data-config-tab]:not([data-config-tab="prompt"]),
|
|
15160
|
+
#cron-tab-configure[data-active-config-tab="tools"] [data-config-tab]:not([data-config-tab="tools"]),
|
|
15161
|
+
#cron-tab-configure[data-active-config-tab="scope"] [data-config-tab]:not([data-config-tab="scope"]),
|
|
15162
|
+
#cron-tab-configure[data-active-config-tab="limits"] [data-config-tab]:not([data-config-tab="limits"]) {
|
|
15163
|
+
display: none;
|
|
15164
|
+
}
|
|
15127
15165
|
/* ── Trick capability strip (skills + MCP + tools at a glance) ─── */
|
|
15128
15166
|
.task-cap-strip {
|
|
15129
15167
|
border-top: 1px solid var(--border-light);
|
|
@@ -19912,12 +19950,24 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
19912
19950
|
</div>
|
|
19913
19951
|
<div class="modal-body">
|
|
19914
19952
|
<!-- ── Tab: Configure ─────────────────────────────────────────── -->
|
|
19915
|
-
|
|
19953
|
+
<!-- PRD §5.1 right-inspector pattern lives here as inner tabs (1.3a).
|
|
19954
|
+
data-active-config-tab controls which section blocks render via
|
|
19955
|
+
CSS — no JS show/hide needed beyond setting the attribute. -->
|
|
19956
|
+
<div class="cron-tab-pane active" id="cron-tab-configure" data-active-config-tab="basics">
|
|
19916
19957
|
<!-- Legacy / mismatch banner (populated by openEditCronModal) -->
|
|
19917
19958
|
<div id="cron-legacy-banner-host"></div>
|
|
19918
19959
|
|
|
19960
|
+
<!-- Inner tab strip — pill nav swapping which section blocks show -->
|
|
19961
|
+
<div class="cron-config-tabs" role="tablist">
|
|
19962
|
+
<button type="button" class="cron-config-tab-btn active" data-config-tab-btn="basics" onclick="switchCronConfigTab('basics')">Basics</button>
|
|
19963
|
+
<button type="button" class="cron-config-tab-btn" data-config-tab-btn="prompt" onclick="switchCronConfigTab('prompt')">Prompt</button>
|
|
19964
|
+
<button type="button" class="cron-config-tab-btn" data-config-tab-btn="tools" onclick="switchCronConfigTab('tools')">Tools & MCP</button>
|
|
19965
|
+
<button type="button" class="cron-config-tab-btn" data-config-tab-btn="scope" onclick="switchCronConfigTab('scope')">Scope</button>
|
|
19966
|
+
<button type="button" class="cron-config-tab-btn" data-config-tab-btn="limits" onclick="switchCronConfigTab('limits')">Limits</button>
|
|
19967
|
+
</div>
|
|
19968
|
+
|
|
19919
19969
|
<!-- Identity: name + category + tags -->
|
|
19920
|
-
<div class="cron-section-card">
|
|
19970
|
+
<div class="cron-section-card" data-config-tab="basics">
|
|
19921
19971
|
<h4>Identity</h4>
|
|
19922
19972
|
<p class="cron-section-desc">A unique name and optional grouping for the dashboard.</p>
|
|
19923
19973
|
<div class="form-group">
|
|
@@ -19933,7 +19983,7 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
19933
19983
|
</div>
|
|
19934
19984
|
|
|
19935
19985
|
<!-- Schedule -->
|
|
19936
|
-
<div class="cron-section-card">
|
|
19986
|
+
<div class="cron-section-card" data-config-tab="basics">
|
|
19937
19987
|
<h4>Schedule</h4>
|
|
19938
19988
|
<p class="cron-section-desc">When this task fires. Pick a frequency or write a cron expression.</p>
|
|
19939
19989
|
<div class="form-group" style="margin:0">
|
|
@@ -20022,7 +20072,7 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
20022
20072
|
</div>
|
|
20023
20073
|
|
|
20024
20074
|
<!-- What it does: prompt + context + reference files -->
|
|
20025
|
-
<div class="cron-section-card">
|
|
20075
|
+
<div class="cron-section-card" data-config-tab="prompt">
|
|
20026
20076
|
<h4>What it does</h4>
|
|
20027
20077
|
<p class="cron-section-desc">The instruction the agent receives. Long prompts are fine — drag the corner to resize.</p>
|
|
20028
20078
|
<div class="form-group">
|
|
@@ -20050,7 +20100,7 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
20050
20100
|
The single most important new field set. Without one of these, a
|
|
20051
20101
|
run "finished"; with one, a run "accomplished what it was meant
|
|
20052
20102
|
to". Banner warns (does not block) when neither is set. -->
|
|
20053
|
-
<div class="cron-section-card">
|
|
20103
|
+
<div class="cron-section-card" data-config-tab="prompt">
|
|
20054
20104
|
<h4>Goal <span style="color:var(--text-muted);font-weight:normal;font-size:12px">— how do you know this task succeeded?</span></h4>
|
|
20055
20105
|
<p class="cron-section-desc">Optional but strongly recommended. Use plain English (an evaluator agent grades the run) or a JSON Schema (validated against the agent's structured output).</p>
|
|
20056
20106
|
<div id="cron-goal-warning" style="display:none;margin-bottom:12px;padding:10px 12px;border-radius:6px;background:rgba(245,158,11,0.10);border:1px solid rgba(245,158,11,0.30);color:var(--yellow);font-size:12px">
|
|
@@ -20073,7 +20123,7 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
20073
20123
|
</div>
|
|
20074
20124
|
|
|
20075
20125
|
<!-- Skills & tools: pinned skills + MCP + tools + tags -->
|
|
20076
|
-
<div class="cron-section-card">
|
|
20126
|
+
<div class="cron-section-card" data-config-tab="tools">
|
|
20077
20127
|
<h4>Skills & tools</h4>
|
|
20078
20128
|
<p class="cron-section-desc">Pin the skills and tools this task should use. Switch to the <strong>What will run</strong> tab to see exactly what the agent receives.</p>
|
|
20079
20129
|
|
|
@@ -20124,85 +20174,90 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
20124
20174
|
</div>
|
|
20125
20175
|
</div>
|
|
20126
20176
|
|
|
20127
|
-
<!--
|
|
20128
|
-
<
|
|
20129
|
-
<
|
|
20130
|
-
|
|
20131
|
-
|
|
20132
|
-
|
|
20133
|
-
|
|
20134
|
-
|
|
20135
|
-
|
|
20136
|
-
|
|
20137
|
-
|
|
20138
|
-
<option value="1">Tier 1 — Read-only (vault, search, web)</option>
|
|
20139
|
-
<option value="2">Tier 2 — Read + Write (Bash, files, sub-agents)</option>
|
|
20140
|
-
<option value="3">Tier 3 — Full access (use with caution)</option>
|
|
20141
|
-
</select>
|
|
20142
|
-
</div>
|
|
20143
|
-
<div class="form-group">
|
|
20144
|
-
<label class="form-label">Project Context <span style="color:var(--text-muted);font-weight:normal">(optional)</span></label>
|
|
20145
|
-
<select id="cron-workdir">
|
|
20146
|
-
<option value="">None — runs in default context</option>
|
|
20147
|
-
</select>
|
|
20148
|
-
<div class="form-hint">Run inside a project directory. Agent gets that project's CLAUDE.md.</div>
|
|
20149
|
-
</div>
|
|
20177
|
+
<!-- ── Scope: where the task can read/write ── -->
|
|
20178
|
+
<div class="cron-section-card" data-config-tab="scope">
|
|
20179
|
+
<h4>Scope</h4>
|
|
20180
|
+
<p class="cron-section-desc">Where the agent runs and what files it can read.</p>
|
|
20181
|
+
<div class="form-row">
|
|
20182
|
+
<div class="form-group">
|
|
20183
|
+
<label class="form-label">Project Context <span style="color:var(--text-muted);font-weight:normal">(optional)</span></label>
|
|
20184
|
+
<select id="cron-workdir">
|
|
20185
|
+
<option value="">None — runs in default context</option>
|
|
20186
|
+
</select>
|
|
20187
|
+
<div class="form-hint">Run inside a project directory. Agent gets that project's CLAUDE.md.</div>
|
|
20150
20188
|
</div>
|
|
20151
|
-
|
|
20152
|
-
|
|
20153
|
-
|
|
20154
|
-
|
|
20155
|
-
|
|
20156
|
-
|
|
20157
|
-
|
|
20189
|
+
</div>
|
|
20190
|
+
<!-- PRD Phase 1: read scope beyond cwd. One absolute path per line. -->
|
|
20191
|
+
<div class="form-row">
|
|
20192
|
+
<div class="form-group" style="flex:1">
|
|
20193
|
+
<label class="form-label">Additional read directories <span style="color:var(--text-muted);font-weight:normal">(optional)</span></label>
|
|
20194
|
+
<textarea id="cron-add-dirs" rows="2" placeholder="/Users/me/notes /Users/me/clients/acme" style="font-family:'JetBrains Mono',monospace;font-size:11px"></textarea>
|
|
20195
|
+
<div class="form-hint">One absolute path per line. The agent gets read access to these in addition to the Project Context cwd.</div>
|
|
20158
20196
|
</div>
|
|
20159
|
-
|
|
20160
|
-
|
|
20161
|
-
|
|
20162
|
-
|
|
20163
|
-
|
|
20164
|
-
|
|
20165
|
-
|
|
20166
|
-
|
|
20167
|
-
|
|
20168
|
-
<
|
|
20169
|
-
|
|
20170
|
-
<
|
|
20171
|
-
|
|
20172
|
-
|
|
20173
|
-
|
|
20174
|
-
|
|
20175
|
-
<option value="8">8 hours</option>
|
|
20176
|
-
<option value="12">12 hours</option>
|
|
20177
|
-
<option value="24">24 hours</option>
|
|
20178
|
-
</select>
|
|
20179
|
-
</div>
|
|
20197
|
+
</div>
|
|
20198
|
+
</div>
|
|
20199
|
+
|
|
20200
|
+
<!-- ── Limits: budgets, mode, retries, chain triggers ── -->
|
|
20201
|
+
<div class="cron-section-card" data-config-tab="limits">
|
|
20202
|
+
<h4>Limits</h4>
|
|
20203
|
+
<p class="cron-section-desc">Permission level, runtime mode, and retry/chain rules.</p>
|
|
20204
|
+
<div class="form-row">
|
|
20205
|
+
<div class="form-group">
|
|
20206
|
+
<label class="form-label">Tier</label>
|
|
20207
|
+
<select id="cron-tier">
|
|
20208
|
+
<option value="1">Tier 1 — Read-only (vault, search, web)</option>
|
|
20209
|
+
<option value="2">Tier 2 — Read + Write (Bash, files, sub-agents)</option>
|
|
20210
|
+
<option value="3">Tier 3 — Full access (use with caution)</option>
|
|
20211
|
+
</select>
|
|
20212
|
+
<div class="form-hint">Permission level. Higher tiers can do more but require trust.</div>
|
|
20180
20213
|
</div>
|
|
20181
|
-
<div class="form-
|
|
20182
|
-
<
|
|
20183
|
-
|
|
20184
|
-
<
|
|
20185
|
-
|
|
20186
|
-
|
|
20187
|
-
|
|
20188
|
-
|
|
20189
|
-
|
|
20190
|
-
|
|
20191
|
-
|
|
20192
|
-
|
|
20193
|
-
|
|
20194
|
-
|
|
20195
|
-
<
|
|
20196
|
-
<
|
|
20197
|
-
|
|
20198
|
-
</
|
|
20199
|
-
<
|
|
20200
|
-
|
|
20214
|
+
<div class="form-group">
|
|
20215
|
+
<label class="form-label">Mode</label>
|
|
20216
|
+
<select id="cron-mode" onchange="toggleUnleashedOptions()">
|
|
20217
|
+
<option value="standard">Standard</option>
|
|
20218
|
+
<option value="unleashed">Unleashed (long-running)</option>
|
|
20219
|
+
</select>
|
|
20220
|
+
<div class="form-hint">Unleashed runs in phases with checkpointing for hour-scale tasks.</div>
|
|
20221
|
+
</div>
|
|
20222
|
+
</div>
|
|
20223
|
+
<div class="form-row">
|
|
20224
|
+
<div class="form-group" id="cron-maxhours-group" style="display:none">
|
|
20225
|
+
<label class="form-label">Max Hours</label>
|
|
20226
|
+
<select id="cron-maxhours">
|
|
20227
|
+
<option value="1">1 hour</option>
|
|
20228
|
+
<option value="2">2 hours</option>
|
|
20229
|
+
<option value="4">4 hours</option>
|
|
20230
|
+
<option value="6" selected>6 hours (default)</option>
|
|
20231
|
+
<option value="8">8 hours</option>
|
|
20232
|
+
<option value="12">12 hours</option>
|
|
20233
|
+
<option value="24">24 hours</option>
|
|
20234
|
+
</select>
|
|
20235
|
+
</div>
|
|
20236
|
+
<div class="form-group">
|
|
20237
|
+
<label class="form-label">Max Retries <span style="color:var(--text-muted);font-weight:normal">(optional)</span></label>
|
|
20238
|
+
<select id="cron-max-retries">
|
|
20239
|
+
<option value="">Auto (based on error history)</option>
|
|
20240
|
+
<option value="0">0 — No retries</option>
|
|
20241
|
+
<option value="1">1</option>
|
|
20242
|
+
<option value="2">2</option>
|
|
20243
|
+
<option value="3">3</option>
|
|
20244
|
+
<option value="5">5</option>
|
|
20245
|
+
</select>
|
|
20246
|
+
<div class="form-hint">Override automatic retry count for transient errors.</div>
|
|
20247
|
+
</div>
|
|
20248
|
+
</div>
|
|
20249
|
+
<div class="form-row">
|
|
20250
|
+
<div class="form-group">
|
|
20251
|
+
<label class="form-label">After Job <span style="color:var(--text-muted);font-weight:normal">(chain)</span></label>
|
|
20252
|
+
<select id="cron-after">
|
|
20253
|
+
<option value="">None — runs on schedule</option>
|
|
20254
|
+
</select>
|
|
20255
|
+
<div class="form-hint">Trigger after another job succeeds (ignores schedule).</div>
|
|
20201
20256
|
</div>
|
|
20202
20257
|
</div>
|
|
20203
|
-
</
|
|
20258
|
+
</div>
|
|
20204
20259
|
|
|
20205
|
-
<!-- Training Chat -->
|
|
20260
|
+
<!-- Training Chat — visible across all config tabs (it's a tool, not a field group) -->
|
|
20206
20261
|
<div class="form-group" id="cron-training-section" style="display:none">
|
|
20207
20262
|
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px">
|
|
20208
20263
|
<label class="form-label" style="margin:0">Training Chat</label>
|
|
@@ -24809,6 +24864,18 @@ async function loadCronPreviewIntoTab(jobName) {
|
|
|
24809
24864
|
// Mark the preview as stale (call after save so next tab visit refetches).
|
|
24810
24865
|
function markCronPreviewDirty() { _cronPreviewLoadedFor = null; }
|
|
24811
24866
|
|
|
24867
|
+
// PRD Phase 1.3a: inner Configure pane tabs. Sets the data-active-config-tab
|
|
24868
|
+
// attribute on #cron-tab-configure; CSS handles section visibility via
|
|
24869
|
+
// data-config-tab attributes on each section. JS-light by design.
|
|
24870
|
+
function switchCronConfigTab(tab) {
|
|
24871
|
+
var pane = document.getElementById('cron-tab-configure');
|
|
24872
|
+
if (!pane) return;
|
|
24873
|
+
pane.setAttribute('data-active-config-tab', tab);
|
|
24874
|
+
document.querySelectorAll('.cron-config-tab-btn').forEach(function(b) {
|
|
24875
|
+
b.classList.toggle('active', b.getAttribute('data-config-tab-btn') === tab);
|
|
24876
|
+
});
|
|
24877
|
+
}
|
|
24878
|
+
|
|
24812
24879
|
// ── PRD Phase 1.2: "Run task once" — inline run + Last run tab ───────────
|
|
24813
24880
|
// Tracks an in-flight run triggered FROM the modal so the SSE listeners
|
|
24814
24881
|
// know when a cron_complete event belongs to "the run I just kicked off"
|
|
@@ -25098,6 +25165,7 @@ function openCreateCronModal(agentSlug) {
|
|
|
25098
25165
|
var schedLink = document.getElementById('sched-cron-link');
|
|
25099
25166
|
if (schedLink) schedLink.style.display = '';
|
|
25100
25167
|
switchCronTab('configure');
|
|
25168
|
+
switchCronConfigTab('basics'); // PRD 1.3a: always start on Basics for new tasks
|
|
25101
25169
|
onPredictableChange();
|
|
25102
25170
|
document.getElementById('cron-modal').classList.add('show');
|
|
25103
25171
|
// Snapshot AFTER all defaults are populated so an immediate close with no
|
|
@@ -25196,6 +25264,7 @@ function openEditCronModal(jobName) {
|
|
|
25196
25264
|
// dead empty pane). The pane updates live when Run task once fires.
|
|
25197
25265
|
renderCronLastRunPane(job);
|
|
25198
25266
|
switchCronTab('configure');
|
|
25267
|
+
switchCronConfigTab('basics'); // PRD 1.3a: always start on Basics
|
|
25199
25268
|
document.getElementById('cron-modal').classList.add('show');
|
|
25200
25269
|
setTimeout(captureCronModalSnapshot, 0);
|
|
25201
25270
|
}
|
|
@@ -25542,26 +25611,34 @@ async function saveCronJob() {
|
|
|
25542
25611
|
// Field-specific validation. Toasting one message per problem is more
|
|
25543
25612
|
// actionable than the old "Please fill in all fields" — and we bail before
|
|
25544
25613
|
// hitting the API so the user sees the issue without a round-trip.
|
|
25545
|
-
|
|
25614
|
+
// Helper: focus a field on a possibly-hidden inner config tab. Switches
|
|
25615
|
+
// to the tab that owns the field first so the user sees the cursor land.
|
|
25616
|
+
function focusOnConfigTab(fieldId, configTab) {
|
|
25617
|
+
if (typeof switchCronConfigTab === 'function') switchCronConfigTab(configTab);
|
|
25618
|
+
var el = document.getElementById(fieldId);
|
|
25619
|
+
if (el) el.focus();
|
|
25620
|
+
}
|
|
25621
|
+
if (!name) { toast('Task name is required', 'error'); focusOnConfigTab('cron-name', 'basics'); return; }
|
|
25546
25622
|
if (!/^[a-z][a-z0-9-]{0,63}$/.test(name)) {
|
|
25547
25623
|
toast('Task name must start with a lowercase letter and contain only a–z, 0–9, and hyphens (max 64 chars)', 'error');
|
|
25548
|
-
|
|
25624
|
+
focusOnConfigTab('cron-name', 'basics');
|
|
25549
25625
|
return;
|
|
25550
25626
|
}
|
|
25551
25627
|
if (!editingCronJob && Array.isArray(cronJobsData)) {
|
|
25552
25628
|
var dup = cronJobsData.find(function(j) { return String(j.name || '').toLowerCase() === name.toLowerCase(); });
|
|
25553
|
-
if (dup) { toast('A task named "' + name + '" already exists', 'error');
|
|
25629
|
+
if (dup) { toast('A task named "' + name + '" already exists', 'error'); focusOnConfigTab('cron-name', 'basics'); return; }
|
|
25554
25630
|
}
|
|
25555
|
-
if (!schedule) { toast('Schedule is required', 'error'); return; }
|
|
25631
|
+
if (!schedule) { toast('Schedule is required', 'error'); switchCronConfigTab('basics'); return; }
|
|
25556
25632
|
// Light client-side cron sanity check — server uses real cron-parser.
|
|
25557
25633
|
// Catches obvious garbage like "foo bar" without making a round-trip.
|
|
25558
25634
|
// Note: the hyphen sits at the END of the character class to avoid being
|
|
25559
25635
|
// interpreted as a range. \\\\s in source → \\s in served JS → \s in regex.
|
|
25560
25636
|
if (!/^([0-9*/, -]+|@(yearly|annually|monthly|weekly|daily|hourly|reboot))$/i.test(schedule) && schedule.split(/\\s+/).length < 5) {
|
|
25561
25637
|
toast('Schedule does not look like a valid cron expression', 'error');
|
|
25638
|
+
switchCronConfigTab('basics');
|
|
25562
25639
|
return;
|
|
25563
25640
|
}
|
|
25564
|
-
if (!prompt) { toast('Prompt is required — tell the agent what to do', 'error');
|
|
25641
|
+
if (!prompt) { toast('Prompt is required — tell the agent what to do', 'error'); focusOnConfigTab('cron-prompt', 'prompt'); return; }
|
|
25565
25642
|
|
|
25566
25643
|
// PRD Phase 1 goal fields. successCriteriaText is freeform; successSchema
|
|
25567
25644
|
// is parsed JSON. Validate JSON early so the user gets a clean error before
|
|
@@ -25574,12 +25651,12 @@ async function saveCronJob() {
|
|
|
25574
25651
|
successSchema = JSON.parse(successSchemaRaw);
|
|
25575
25652
|
if (!successSchema || typeof successSchema !== 'object' || Array.isArray(successSchema)) {
|
|
25576
25653
|
toast('Success schema must be a JSON object', 'error');
|
|
25577
|
-
|
|
25654
|
+
focusOnConfigTab('cron-success-schema', 'prompt');
|
|
25578
25655
|
return;
|
|
25579
25656
|
}
|
|
25580
25657
|
} catch (e) {
|
|
25581
25658
|
toast('Success schema is not valid JSON: ' + (e.message || String(e)), 'error');
|
|
25582
|
-
|
|
25659
|
+
focusOnConfigTab('cron-success-schema', 'prompt');
|
|
25583
25660
|
return;
|
|
25584
25661
|
}
|
|
25585
25662
|
}
|