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.
Files changed (2) hide show
  1. package/dist/cli/dashboard.js +163 -86
  2. package/package.json +1 -1
@@ -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
- <div class="cron-tab-pane active" id="cron-tab-configure">
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 &amp; 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 &amp; 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
- <!-- Advanced: tier + workdir + mode + max-hours + retries + after -->
20128
- <details class="cron-section-card" style="padding:0">
20129
- <summary style="padding:14px 16px;cursor:pointer;list-style:none;display:flex;align-items:center;justify-content:space-between">
20130
- <span><strong style="font-size:11px;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.6px">Advanced</strong> <span style="color:var(--text-muted);font-size:11px;margin-left:6px">tier, mode, retries, project context</span></span>
20131
- <span style="color:var(--text-muted);font-size:11px">▾</span>
20132
- </summary>
20133
- <div style="padding:0 16px 14px">
20134
- <div class="form-row">
20135
- <div class="form-group">
20136
- <label class="form-label">Tier</label>
20137
- <select id="cron-tier">
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
- <!-- PRD Phase 1: read scope beyond cwd. One absolute path per line. -->
20152
- <div class="form-row">
20153
- <div class="form-group" style="flex:1">
20154
- <label class="form-label">Additional read directories <span style="color:var(--text-muted);font-weight:normal">(optional)</span></label>
20155
- <textarea id="cron-add-dirs" rows="2" placeholder="/Users/me/notes&#10;/Users/me/clients/acme" style="font-family:'JetBrains Mono',monospace;font-size:11px"></textarea>
20156
- <div class="form-hint">One absolute path per line. The agent gets read access to these in addition to the Project Context cwd.</div>
20157
- </div>
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&#10;/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
- <div class="form-row">
20160
- <div class="form-group">
20161
- <label class="form-label">Mode</label>
20162
- <select id="cron-mode" onchange="toggleUnleashedOptions()">
20163
- <option value="standard">Standard</option>
20164
- <option value="unleashed">Unleashed (long-running)</option>
20165
- </select>
20166
- <div class="form-hint">Unleashed runs in phases with checkpointing for hour-scale tasks.</div>
20167
- </div>
20168
- <div class="form-group" id="cron-maxhours-group" style="display:none">
20169
- <label class="form-label">Max Hours</label>
20170
- <select id="cron-maxhours">
20171
- <option value="1">1 hour</option>
20172
- <option value="2">2 hours</option>
20173
- <option value="4">4 hours</option>
20174
- <option value="6" selected>6 hours (default)</option>
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-row">
20182
- <div class="form-group">
20183
- <label class="form-label">Max Retries <span style="color:var(--text-muted);font-weight:normal">(optional)</span></label>
20184
- <select id="cron-max-retries">
20185
- <option value="">Auto (based on error history)</option>
20186
- <option value="0">0 — No retries</option>
20187
- <option value="1">1</option>
20188
- <option value="2">2</option>
20189
- <option value="3">3</option>
20190
- <option value="5">5</option>
20191
- </select>
20192
- <div class="form-hint">Override automatic retry count for transient errors.</div>
20193
- </div>
20194
- <div class="form-group">
20195
- <label class="form-label">After Job <span style="color:var(--text-muted);font-weight:normal">(chain)</span></label>
20196
- <select id="cron-after">
20197
- <option value="">None runs on schedule</option>
20198
- </select>
20199
- <div class="form-hint">Trigger after another job succeeds (ignores schedule).</div>
20200
- </div>
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
- </details>
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
- if (!name) { toast('Task name is required', 'error'); document.getElementById('cron-name').focus(); return; }
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
- document.getElementById('cron-name').focus();
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'); document.getElementById('cron-name').focus(); return; }
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'); document.getElementById('cron-prompt').focus(); return; }
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
- document.getElementById('cron-success-schema').focus();
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
- document.getElementById('cron-success-schema').focus();
25659
+ focusOnConfigTab('cron-success-schema', 'prompt');
25583
25660
  return;
25584
25661
  }
25585
25662
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clementine-agent",
3
- "version": "1.18.79",
3
+ "version": "1.18.80",
4
4
  "description": "Clementine — Personal AI Assistant (TypeScript)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",