@goodandready/dsh-cron 0.2.29 → 0.2.30

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.
@@ -1,3 +1,4 @@
1
+ import { logger } from './logger.js';
1
2
  import { randomUUID } from 'node:crypto';
2
3
  import {
3
4
  buildTaskExport,
@@ -49,7 +50,7 @@ export async function handleTaskImport({ store, scheduler, req, res }) {
49
50
  }
50
51
  }
51
52
  if (droppedChannels.length) {
52
- console.warn('[dsh-cron] import: unknown channel ids were dropped: ' + droppedChannels.join(', '));
53
+ logger.warn('[dsh-cron] import: unknown channel ids were dropped: ' + droppedChannels.join(', '));
53
54
  }
54
55
  const existingIds = store.list({ status: 'all' }).map((x) => x.id);
55
56
  const plan = planImport(checked.tasks, existingIds, strategy);
@@ -126,7 +127,7 @@ export function applyImportPlan({ store, scheduler, plan }) {
126
127
  if (entry.previous) store.set(entry.previous);
127
128
  else store.delete(entry.id);
128
129
  } catch (rollbackErr) {
129
- console.warn(`[dsh-cron] import rollback failed for task "${entry.id}":`, rollbackErr?.message || rollbackErr);
130
+ logger.warn(`[dsh-cron] import rollback failed for task "${entry.id}":`, rollbackErr?.message || rollbackErr);
130
131
  }
131
132
  }
132
133
  return { imported: [], error: `Import failed and was rolled back: ${writeErr.message}` };
@@ -137,7 +138,7 @@ export function applyImportPlan({ store, scheduler, plan }) {
137
138
  try {
138
139
  scheduler.pauseTask(id);
139
140
  } catch (err) {
140
- console.error('[dsh-cron] import: could not pause task', id + ':', err.message);
141
+ logger.error('[dsh-cron] import: could not pause task', id + ':', err.message);
141
142
  }
142
143
  }
143
144
  return { imported };
@@ -1,3 +1,4 @@
1
+ import { logger } from './logger.js';
1
2
  import { sendJson, readBody } from './http-utils.js';
2
3
  import { answerTelegramCallbackQuery, sendTelegramMessage, getDshDefaultTelegramCredentials } from './telegram.js';
3
4
  import { handleTelegramCommand } from './telegram-commands.js';
@@ -24,7 +25,7 @@ export async function handleTelegramWebhook({ store, scheduler, req, res }) {
24
25
  const fromId = String(message.from?.id || '');
25
26
  const chatId = String(message.chat?.id || fromId);
26
27
  if (allowedChatId && chatId !== allowedChatId && fromId !== allowedChatId) {
27
- console.warn(`[dsh-cron] unauthorized telegram command from chat ${chatId} / user ${fromId}`);
28
+ logger.warn(`[dsh-cron] unauthorized telegram command from chat ${chatId} / user ${fromId}`);
28
29
  sendJson(res, 403, { ok: false, error: 'Forbidden' });
29
30
  return;
30
31
  }
@@ -52,7 +53,7 @@ export async function handleTelegramWebhook({ store, scheduler, req, res }) {
52
53
  const chatId = String(callbackQuery.message?.chat?.id || fromId);
53
54
 
54
55
  if (allowedChatId && chatId !== allowedChatId && fromId !== allowedChatId) {
55
- console.warn(`[dsh-cron] unauthorized telegram callback from chat ${chatId} / user ${fromId}`);
56
+ logger.warn(`[dsh-cron] unauthorized telegram callback from chat ${chatId} / user ${fromId}`);
56
57
  if (botToken) {
57
58
  await answerTelegramCallbackQuery({ botToken, callbackQueryId: queryId, text: 'Unauthorized', showAlert: true });
58
59
  }
package/lib/api.js CHANGED
@@ -95,11 +95,19 @@ export function createCronApiHandler(store, scheduler, collection) {
95
95
 
96
96
  // Export/import are collection operations that live under /tasks/:id/…,
97
97
  // so they are matched before the generic id handling below.
98
- if (id === 'export' && req.method === 'GET') {
98
+ if (id === 'export') {
99
+ if (req.method !== 'GET') {
100
+ sendJson(res, 405, NOT_ALLOWED);
101
+ return;
102
+ }
99
103
  handleTaskExport({ store, res });
100
104
  return;
101
105
  }
102
- if (id === 'import' && req.method === 'POST') {
106
+ if (id === 'import') {
107
+ if (req.method !== 'POST') {
108
+ sendJson(res, 405, NOT_ALLOWED);
109
+ return;
110
+ }
103
111
  await handleTaskImport({ store, scheduler, req, res });
104
112
  return;
105
113
  }
package/lib/burn-guard.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { logger } from './logger.js';
1
2
  import { bestEffort } from './best-effort.js';
2
3
 
3
4
  /**
@@ -128,7 +129,7 @@ export async function checkAndApplyBurnGuard(scheduler, taskId, outcome) {
128
129
  const guard = checkTaskBudgetLimits(task, runs);
129
130
  if (!guard.exceeded) return null;
130
131
 
131
- console.warn(`[dsh-cron] Burn Guard triggered for task "${task.title}" (${taskId}): ${guard.reason}`);
132
+ logger.warn(`[dsh-cron] Burn Guard triggered for task "${task.title}" (${taskId}): ${guard.reason}`);
132
133
  scheduler.pauseTask(taskId, guard.reason);
133
134
 
134
135
  const alertMessage = formatBurnGuardAlert(task, guard);
package/lib/client.js CHANGED
@@ -626,23 +626,23 @@ window.__ModuleLoader__.load({
626
626
 
627
627
  const STYLES = `
628
628
  :root {
629
- --dsh-cron-success: var(--dsw-alias-state-success-primary, #10b981);
630
- --dsh-cron-success-bg: color-mix(in srgb, var(--dsh-cron-success, #10b981) 10%, transparent);
631
- --dsh-cron-danger: var(--dsw-alias-state-error-primary, #ef4444);
632
- --dsh-cron-danger-bg: color-mix(in srgb, var(--dsh-cron-danger, #ef4444) 10%, transparent);
633
- --dsh-cron-info: var(--dsw-alias-state-brand-primary, #60a5fa);
634
- --dsh-cron-info-bg: color-mix(in srgb, var(--dsh-cron-info, #60a5fa) 12%, transparent);
635
- --dsh-cron-accent: var(--dsw-alias-state-info-primary, #c084fc);
636
- --dsh-cron-accent-bg: color-mix(in srgb, var(--dsh-cron-accent, #a855f7) 12%, transparent);
637
- --dsh-cron-warning: var(--dsw-alias-state-warning-primary, #eab308);
638
- --dsh-cron-warning-bg: color-mix(in srgb, var(--dsh-cron-warning, #eab308) 12%, transparent);
629
+ --dsh-cron-success: var(--dsw-alias-state-success-primary);
630
+ --dsh-cron-success-bg: color-mix(in srgb, var(--dsh-cron-success) 10%, transparent);
631
+ --dsh-cron-danger: var(--dsw-alias-state-error-primary);
632
+ --dsh-cron-danger-bg: color-mix(in srgb, var(--dsh-cron-danger) 10%, transparent);
633
+ --dsh-cron-info: var(--dsw-alias-state-brand-primary);
634
+ --dsh-cron-info-bg: color-mix(in srgb, var(--dsh-cron-info) 12%, transparent);
635
+ --dsh-cron-accent: var(--dsw-alias-state-info-primary);
636
+ --dsh-cron-accent-bg: color-mix(in srgb, var(--dsh-cron-accent) 12%, transparent);
637
+ --dsh-cron-warning: var(--dsw-alias-state-warning-primary);
638
+ --dsh-cron-warning-bg: color-mix(in srgb, var(--dsh-cron-warning) 12%, transparent);
639
639
  }
640
640
  [data-pane=conversation], [class*=centerCol] {
641
641
  position: relative !important;
642
642
  }
643
643
  [${VIEW_ATTR}] {
644
644
  z-index: 60;
645
- background: var(--dsw-alias-bg-base, #171717);
645
+ background: var(--dsw-alias-bg-base);
646
646
  display: none;
647
647
  position: absolute;
648
648
  inset: 0;
@@ -660,139 +660,139 @@ window.__ModuleLoader__.load({
660
660
  .dsh-cron-entry-label { text-overflow: ellipsis; overflow: hidden; }
661
661
  [data-dsh-frame][data-sidebar-collapsed] .dsh-cron-entry-label { display: none; }
662
662
 
663
- .dsh-cron-overlay { position: absolute; inset: 0; display: flex; flex-direction: column; background: var(--dsw-alias-bg-base, #171717); color: var(--dsw-alias-label-primary, #ededed); overflow-y: auto; padding: 24px 48px 32px; z-index: 100; box-sizing: border-box; }
663
+ .dsh-cron-overlay { position: absolute; inset: 0; display: flex; flex-direction: column; background: var(--dsw-alias-bg-base); color: var(--dsw-alias-label-primary); overflow-y: auto; padding: 24px 48px 32px; z-index: 100; box-sizing: border-box; }
664
664
  .dsh-cron-container { max-width: 960px; width: 100%; margin: 0 auto; display: flex; flex-direction: column; gap: 20px; padding: 8px 0 32px; box-sizing: border-box; }
665
665
 
666
666
  .dsh-cron-top-bar { display: flex; align-items: center; gap: 12px; }
667
- .dsh-cron-back-btn { appearance: none; font: inherit; cursor: pointer; color: var(--dsw-alias-label-secondary, #9ca3af); background: 0 0; border: 1px solid var(--dsw-alias-border-l2, #383838); border-radius: 8px; align-items: center; gap: 6px; padding: 4px 12px; font-size: 13px; display: inline-flex; flex: none; height: 32px; box-sizing: border-box; }
668
- .dsh-cron-back-btn:hover { color: var(--dsw-alias-label-primary, #ededed); background: var(--dsw-alias-bg-layer-4, var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, var(--dsw-alias-label-primary, #fff) 6%, transparent))); }
667
+ .dsh-cron-back-btn { appearance: none; font: inherit; cursor: pointer; color: var(--dsw-alias-label-secondary); background: 0 0; border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px; align-items: center; gap: 6px; padding: 4px 12px; font-size: 13px; display: inline-flex; flex: none; height: 32px; box-sizing: border-box; }
668
+ .dsh-cron-back-btn:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-4, var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent))); }
669
669
 
670
- .dsh-cron-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; padding-bottom: 16px; border-bottom: 1px solid var(--dsw-alias-border-l2, #383838); }
670
+ .dsh-cron-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; padding-bottom: 16px; border-bottom: 1px solid var(--dsw-alias-border-l2); }
671
671
  .dsh-cron-title { font-size: 22px; font-weight: 700; letter-spacing: -0.02em; margin-bottom: 6px; }
672
- .dsh-cron-subtitle { font-size: 14px; color: var(--dsw-alias-label-secondary, #9ca3af); line-height: 1.5; }
673
- .dsh-cron-create-btn { appearance: none; display: inline-flex; align-items: center; gap: 6px; background: var(--dsw-alias-bg-layer-2, #262626); color: var(--dsw-alias-label-primary, #fff); border: 1px solid var(--dsw-alias-border-l2, #383838); border-radius: 9999px; padding: 8px 16px; font-size: 14px; font-weight: 500; cursor: pointer; position: relative; }
674
- .dsh-cron-create-btn:hover { background: var(--dsw-alias-bg-layer-hover, var(--dsw-alias-interactive-bg-hover, #333)); }
675
- .dsh-cron-dropdown { position: absolute; top: calc(100% + 6px); right: 0; width: 200px; background: var(--dsw-alias-bg-layer-3, #212121); border: 1px solid var(--dsw-alias-border-l2, #383838); border-radius: 12px; padding: 6px; box-shadow: 0 10px 25px color-mix(in srgb, var(--dsw-alias-bg-mask, #000) 50%, transparent); z-index: 200; }
676
- .dsh-cron-dropdown-item { display: flex; align-items: center; gap: 10px; width: 100%; padding: 10px 12px; background: transparent; border: none; border-radius: 8px; color: var(--dsw-alias-label-primary, #ededed); font-size: 13.5px; text-align: left; cursor: pointer; }
677
- .dsh-cron-dropdown-item:hover { background: var(--dsw-alias-interactive-bg-hover, #2a2a2a); }
672
+ .dsh-cron-subtitle { font-size: 14px; color: var(--dsw-alias-label-secondary); line-height: 1.5; }
673
+ .dsh-cron-create-btn { appearance: none; display: inline-flex; align-items: center; gap: 6px; background: var(--dsw-alias-bg-layer-2); color: var(--dsw-alias-label-primary); border: 1px solid var(--dsw-alias-border-l2); border-radius: 9999px; padding: 8px 16px; font-size: 14px; font-weight: 500; cursor: pointer; position: relative; }
674
+ .dsh-cron-create-btn:hover { background: var(--dsw-alias-bg-layer-hover, var(--dsw-alias-interactive-bg-hover)); }
675
+ .dsh-cron-dropdown { position: absolute; top: calc(100% + 6px); right: 0; width: 200px; background: var(--dsw-alias-bg-layer-3); border: 1px solid var(--dsw-alias-border-l2); border-radius: 12px; padding: 6px; box-shadow: 0 10px 25px color-mix(in srgb, var(--dsw-alias-bg-mask) 50%, transparent); z-index: 200; }
676
+ .dsh-cron-dropdown-item { display: flex; align-items: center; gap: 10px; width: 100%; padding: 10px 12px; background: transparent; border: none; border-radius: 8px; color: var(--dsw-alias-label-primary); font-size: 13.5px; text-align: left; cursor: pointer; }
677
+ .dsh-cron-dropdown-item:hover { background: var(--dsw-alias-interactive-bg-hover); }
678
678
  .dsh-cron-search-bar { position: relative; margin-bottom: 0; }
679
- .dsh-cron-search-input { width: 100%; height: 36px; background: var(--dsw-alias-bg-layer-2, #1f1f1f); border: 1px solid var(--dsw-alias-border-l2, #333); border-radius: 8px; padding: 0 12px 0 38px; color: var(--dsw-alias-label-primary, inherit); font-size: 13px; outline: none; box-sizing: border-box; }
679
+ .dsh-cron-search-input { width: 100%; height: 36px; background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px; padding: 0 12px 0 38px; color: var(--dsw-alias-label-primary, inherit); font-size: 13px; outline: none; box-sizing: border-box; }
680
680
  .dsh-cron-search-input:focus { outline: none; border-color: var(--dsh-cron-info); }
681
- .dsh-cron-search-icon { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--dsw-alias-label-tertiary, #666); }
681
+ .dsh-cron-search-icon { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--dsw-alias-label-tertiary); }
682
682
  .dsh-cron-filters { margin-top: 8px; }
683
- .dsh-cron-filter-toggle { background: none; border: 1px solid var(--dsw-alias-border-l2, #333); color: var(--dsw-alias-label-secondary, #aaa); border-radius: 8px; padding: 4px 10px; font-size: 12px; cursor: pointer; }
684
- .dsh-cron-filter-toggle:hover { color: var(--dsw-alias-label-primary, #eee); border-color: var(--dsh-cron-info); }
685
- .dsh-cron-filter-panel { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; margin-top: 10px; padding: 10px 12px; border: 1px solid var(--dsw-alias-border-l2, #2e2e2e); border-radius: 8px; background: var(--dsw-alias-bg-layer-3, color-mix(in srgb, var(--dsw-alias-label-primary, #fff) 2%, transparent)); }
686
- .dsh-cron-filter-field { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #888); }
687
- .dsh-cron-filter-field select { background: var(--dsw-alias-bg-layer-2, #1f1f1f); border: 1px solid var(--dsw-alias-border-l2, #333); color: var(--dsw-alias-label-primary, inherit); border-radius: 6px; padding: 5px 8px; font-size: 12.5px; }
683
+ .dsh-cron-filter-toggle { background: none; border: 1px solid var(--dsw-alias-border-l2); color: var(--dsw-alias-label-secondary); border-radius: 8px; padding: 4px 10px; font-size: 12px; cursor: pointer; }
684
+ .dsh-cron-filter-toggle:hover { color: var(--dsw-alias-label-primary); border-color: var(--dsh-cron-info); }
685
+ .dsh-cron-filter-panel { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; margin-top: 10px; padding: 10px 12px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px; background: var(--dsw-alias-bg-layer-3, color-mix(in srgb, var(--dsw-alias-label-primary) 2%, transparent)); }
686
+ .dsh-cron-filter-field { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary); }
687
+ .dsh-cron-filter-field select { background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l2); color: var(--dsw-alias-label-primary, inherit); border-radius: 6px; padding: 5px 8px; font-size: 12.5px; }
688
688
  .dsh-cron-tabs { display: flex; flex-wrap: wrap; gap: 8px; }
689
- .dsh-cron-tab { appearance: none; background: transparent; border: 1px solid var(--dsw-alias-border-l2, #383838); padding: 4px 12px; border-radius: 999px; color: var(--dsw-alias-label-secondary, #9ca3af); font-size: 12px; font-weight: 500; cursor: pointer; }
690
- .dsh-cron-tab[data-active="true"] { background: var(--dsw-alias-bg-layer-4, #2a2a2a); color: var(--dsw-alias-label-primary, #fff); border-color: var(--dsw-alias-label-dimmed, var(--dsw-alias-border-l2, #383838)); }
689
+ .dsh-cron-tab { appearance: none; background: transparent; border: 1px solid var(--dsw-alias-border-l2); padding: 4px 12px; border-radius: 999px; color: var(--dsw-alias-label-secondary); font-size: 12px; font-weight: 500; cursor: pointer; }
690
+ .dsh-cron-tab[data-active="true"] { background: var(--dsw-alias-bg-layer-4); color: var(--dsw-alias-label-primary); border-color: var(--dsw-alias-label-dimmed, var(--dsw-alias-border-l2)); }
691
691
  .dsh-cron-task-list { display: flex; flex-direction: column; gap: 12px; margin-bottom: 0; }
692
- .dsh-cron-task-item { display: flex; align-items: center; gap: 16px; padding: 14px 18px; background: var(--dsw-alias-bg-layer-3, #1e1e1e); border: 1px solid var(--dsw-alias-border-l2, #2e2e2e); border-radius: 12px; cursor: pointer; transition: background 0.15s, border-color 0.15s; }
693
- .dsh-cron-task-item:hover, .dsh-cron-task-item:focus-visible { background: var(--dsw-alias-bg-layer-4, #242424); border-color: var(--dsw-alias-label-dimmed, var(--dsw-alias-border-l1, #444)); outline: none; }
694
- .dsh-cron-task-prompt-preview { font-size: 12.5px; color: var(--dsw-alias-label-secondary, #888); margin-top: 5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 520px; line-height: 1.3; }
695
- .dsh-cron-type-tag { display: inline-flex; align-items: center; font-size: 11px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--dsw-alias-border-l2, #383838); text-transform: uppercase; font-weight: 500; margin-left: 8px; vertical-align: middle; }
692
+ .dsh-cron-task-item { display: flex; align-items: center; gap: 16px; padding: 14px 18px; background: var(--dsw-alias-bg-layer-3); border: 1px solid var(--dsw-alias-border-l2); border-radius: 12px; cursor: pointer; transition: background 0.15s, border-color 0.15s; }
693
+ .dsh-cron-task-item:hover, .dsh-cron-task-item:focus-visible { background: var(--dsw-alias-bg-layer-4); border-color: var(--dsw-alias-label-dimmed, var(--dsw-alias-border-l1)); outline: none; }
694
+ .dsh-cron-task-prompt-preview { font-size: 12.5px; color: var(--dsw-alias-label-secondary); margin-top: 5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 520px; line-height: 1.3; }
695
+ .dsh-cron-type-tag { display: inline-flex; align-items: center; font-size: 11px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--dsw-alias-border-l2); text-transform: uppercase; font-weight: 500; margin-left: 8px; vertical-align: middle; }
696
696
  .dsh-cron-tag-success { background: var(--dsh-cron-info-bg); color: var(--dsh-cron-info); border-color: var(--dsh-cron-info); }
697
697
  .dsh-cron-tag-failure { background: var(--dsh-cron-danger-bg); color: var(--dsh-cron-danger); border-color: var(--dsh-cron-danger); }
698
698
  .dsh-cron-tag-heartbeat { background: var(--dsh-cron-accent-bg); color: var(--dsh-cron-accent); border-color: var(--dsh-cron-accent); }
699
699
  .dsh-cron-tag-session { background: var(--dsh-cron-info-bg); color: var(--dsh-cron-info); border-color: var(--dsh-cron-info); }
700
700
  .dsh-cron-tag-preflight { background: var(--dsh-cron-warning-bg); color: var(--dsh-cron-warning); border-color: var(--dsh-cron-warning); }
701
701
 
702
- .dsh-cron-task-model-tag { display: inline-flex; align-items: center; font-size: 11px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--dsw-alias-border-l2, #383838); background: var(--dsw-alias-bg-layer-2, color-mix(in srgb, var(--dsw-alias-label-primary, #fff) 6%, transparent)); color: var(--dsw-alias-label-secondary, #aaa); margin-left: 8px; vertical-align: middle; }
702
+ .dsh-cron-task-model-tag { display: inline-flex; align-items: center; font-size: 11px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--dsw-alias-border-l2); background: var(--dsw-alias-bg-layer-2, color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent)); color: var(--dsw-alias-label-secondary); margin-left: 8px; vertical-align: middle; }
703
703
  .dsh-cron-task-actions { display: flex; gap: 8px; }
704
- .dsh-cron-icon-btn { appearance: none; font: inherit; background: var(--dsw-alias-bg-layer-2, transparent); border: 1px solid var(--dsw-alias-border-l2, #333); border-radius: 8px; padding: 6px 12px; font-size: 12.5px; font-weight: 500; color: var(--dsw-alias-label-primary, #aaa); cursor: pointer; display: inline-flex; align-items: center; gap: 6px; transition: all 0.15s ease; }
705
- .dsh-cron-icon-btn:hover { background: var(--dsw-alias-bg-layer-4, #2a2a2a); border-color: var(--dsw-alias-label-dimmed, var(--dsw-alias-border-l2, #444)); }
704
+ .dsh-cron-icon-btn { appearance: none; font: inherit; background: var(--dsw-alias-bg-layer-2, transparent); border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px; padding: 6px 12px; font-size: 12.5px; font-weight: 500; color: var(--dsw-alias-label-primary); cursor: pointer; display: inline-flex; align-items: center; gap: 6px; transition: all 0.15s ease; }
705
+ .dsh-cron-icon-btn:hover { background: var(--dsw-alias-bg-layer-4); border-color: var(--dsw-alias-label-dimmed, var(--dsw-alias-border-l2)); }
706
706
  .dsh-cron-icon-btn.dsh-cron-danger { color: var(--dsh-cron-danger); border-color: var(--dsh-cron-danger-bg); }
707
707
  .dsh-cron-icon-btn.dsh-cron-danger:hover { background: var(--dsh-cron-danger-bg); border-color: var(--dsh-cron-danger); }
708
- .dsh-cron-task-status-btn { background: none; border: 1px solid var(--dsw-alias-border-l2, #444); border-radius: 50%; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; color: var(--dsw-alias-label-tertiary, #888); cursor: pointer; flex-shrink: 0; }
708
+ .dsh-cron-task-status-btn { background: none; border: 1px solid var(--dsw-alias-border-l2); border-radius: 50%; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; color: var(--dsw-alias-label-tertiary); cursor: pointer; flex-shrink: 0; }
709
709
  .dsh-cron-task-status-btn[data-active="true"] { color: var(--dsh-cron-success); border-color: var(--dsh-cron-success); }
710
710
  .dsh-cron-recs-title { font-size: 16px; font-weight: 600; margin-bottom: 14px; }
711
711
  .dsh-cron-recs-list { display: flex; flex-direction: column; gap: 10px; }
712
- .dsh-cron-rec-card { display: flex; align-items: center; gap: 16px; padding: 14px 18px; background: var(--dsw-alias-bg-layer-3, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #282828); border-radius: 12px; cursor: pointer; transition: background 0.15s; }
713
- .dsh-cron-rec-card:hover, .dsh-cron-rec-card:focus-visible { background: var(--dsw-alias-bg-layer-4, #242424); border-color: var(--dsw-alias-label-dimmed, var(--dsw-alias-border-l2, #383838)); outline: none; }
714
- .dsh-cron-rec-icon { width: 36px; height: 36px; border-radius: 10px; background: var(--dsw-alias-bg-layer-2, color-mix(in srgb, var(--dsw-alias-label-primary, #fff) 3%, transparent)); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
712
+ .dsh-cron-rec-card { display: flex; align-items: center; gap: 16px; padding: 14px 18px; background: var(--dsw-alias-bg-layer-3); border: 1px solid var(--dsw-alias-border-l2); border-radius: 12px; cursor: pointer; transition: background 0.15s; }
713
+ .dsh-cron-rec-card:hover, .dsh-cron-rec-card:focus-visible { background: var(--dsw-alias-bg-layer-4); border-color: var(--dsw-alias-label-dimmed, var(--dsw-alias-border-l2)); outline: none; }
714
+ .dsh-cron-rec-icon { width: 36px; height: 36px; border-radius: 10px; background: var(--dsw-alias-bg-layer-2, color-mix(in srgb, var(--dsw-alias-label-primary) 3%, transparent)); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
715
715
  .dsh-cron-rec-content { flex: 1; min-width: 0; }
716
716
  .dsh-cron-rec-title { font-size: 14.5px; font-weight: 500; margin-bottom: 4px; }
717
- .dsh-cron-rec-time { font-size: 13px; color: var(--dsw-alias-label-secondary, #9ca3af); font-weight: normal; margin-left: 8px; }
718
- .dsh-cron-rec-desc { font-size: 13px; color: var(--dsw-alias-label-tertiary, #71717a); }
717
+ .dsh-cron-rec-time { font-size: 13px; color: var(--dsw-alias-label-secondary); font-weight: normal; margin-left: 8px; }
718
+ .dsh-cron-rec-desc { font-size: 13px; color: var(--dsw-alias-label-tertiary); }
719
719
 
720
720
  .dsh-cron-modal-overlay { position: fixed; inset: 0; background: var(--dsw-alias-bg-mask, color-mix(in srgb, #000 75%, transparent)); backdrop-filter: blur(4px); display: flex; align-items: center; justify-content: center; z-index: 1000; padding: 16px; box-sizing: border-box; overflow-y: auto; }
721
- .dsh-cron-modal { background: var(--dsw-alias-bg-layer-2, #1f1f1f); border: 1px solid var(--dsw-alias-border-l2, #333); border-radius: 16px; width: 100%; max-width: 540px; max-height: min(90vh, calc(100vh - 36px)); overflow-y: auto; padding: 24px; box-shadow: 0 20px 40px color-mix(in srgb, var(--dsw-alias-bg-mask, #000) 60%, transparent); box-sizing: border-box; }
721
+ .dsh-cron-modal { background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l2); border-radius: 16px; width: 100%; max-width: 540px; max-height: min(90vh, calc(100vh - 36px)); overflow-y: auto; padding: 24px; box-shadow: 0 20px 40px color-mix(in srgb, var(--dsw-alias-bg-mask) 60%, transparent); box-sizing: border-box; }
722
722
  .dsh-cron-modal-scroll { max-width: 640px; max-height: min(90vh, calc(100vh - 36px)); overflow-y: auto; }
723
723
  .dsh-cron-modal::-webkit-scrollbar { width: 6px; }
724
724
  .dsh-cron-modal::-webkit-scrollbar-track { background: transparent; }
725
- .dsh-cron-modal::-webkit-scrollbar-thumb { background: var(--dsw-alias-border-l2, #383838); border-radius: 3px; }
726
- .dsh-cron-modal::-webkit-scrollbar-thumb:hover { background: var(--dsw-alias-label-tertiary, #555); }
727
- .dsh-cron-section-head { display: flex; align-items: center; justify-content: space-between; width: 100%; background: none; border: none; padding: 0; margin-bottom: 10px; font: inherit; font-weight: 500; font-size: 12.5px; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; }
728
- .dsh-cron-section-head:hover { color: var(--dsw-alias-label-primary, #eee); }
725
+ .dsh-cron-modal::-webkit-scrollbar-thumb { background: var(--dsw-alias-border-l2); border-radius: 3px; }
726
+ .dsh-cron-modal::-webkit-scrollbar-thumb:hover { background: var(--dsw-alias-label-tertiary); }
727
+ .dsh-cron-section-head { display: flex; align-items: center; justify-content: space-between; width: 100%; background: none; border: none; padding: 0; margin-bottom: 10px; font: inherit; font-weight: 500; font-size: 12.5px; color: var(--dsw-alias-label-secondary); cursor: pointer; }
728
+ .dsh-cron-section-head:hover { color: var(--dsw-alias-label-primary); }
729
729
  .dsh-cron-section-chevron { transition: transform 0.15s ease; display: inline-block; }
730
730
  .dsh-cron-section-chevron[data-open="false"] { transform: rotate(-90deg); }
731
731
  .dsh-cron-section-body { padding-bottom: 4px; }
732
732
  .dsh-cron-modal-title { font-size: 18px; font-weight: 600; margin-bottom: 18px; }
733
733
  .dsh-cron-form-group { margin-bottom: 16px; }
734
- .dsh-cron-form-group label { display: block; font-size: 13px; color: var(--dsw-alias-label-secondary, #aaa); margin-bottom: 6px; }
735
- .dsh-cron-form-group input, .dsh-cron-form-group textarea, .dsh-cron-form-group select { width: 100%; background: var(--dsw-alias-bg-layer-2, #141414); border: 1px solid var(--dsw-alias-border-l2, #333); border-radius: 8px; padding: 8px 12px; color: var(--dsw-alias-label-primary, #fff); font-size: 13px; outline: none; box-sizing: border-box; }
734
+ .dsh-cron-form-group label { display: block; font-size: 13px; color: var(--dsw-alias-label-secondary); margin-bottom: 6px; }
735
+ .dsh-cron-form-group input, .dsh-cron-form-group textarea, .dsh-cron-form-group select { width: 100%; background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px; padding: 8px 12px; color: var(--dsw-alias-label-primary); font-size: 13px; outline: none; box-sizing: border-box; }
736
736
  .dsh-cron-form-group input:focus, .dsh-cron-form-group textarea:focus, .dsh-cron-form-group select:focus { outline: none; border-color: var(--dsh-cron-info); }
737
737
  .dsh-cron-form-group select { cursor: pointer; }
738
738
  .dsh-cron-form-group textarea { min-height: 80px; resize: vertical; }
739
739
  .dsh-cron-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
740
- .dsh-cron-modal-foot { display: flex; justify-content: flex-end; align-items: center; gap: 10px; margin-top: 20px; position: sticky; bottom: -24px; background: var(--dsw-alias-bg-layer-2, #1f1f1f); border-top: 1px solid var(--dsw-alias-border-l2, #2e2e2e); padding-top: 14px; padding-bottom: 4px; margin-left: -24px; margin-right: -24px; padding-left: 24px; padding-right: 24px; z-index: 10; }
741
- .dsh-cron-btn-primary { background: var(--dsw-alias-label-primary, #ededed); color: var(--dsw-alias-bg-layer-3, #111); border: 1px solid transparent; border-radius: 8px; padding: 7px 14px; font-size: 13px; font-weight: 500; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; }
740
+ .dsh-cron-modal-foot { display: flex; justify-content: flex-end; align-items: center; gap: 10px; margin-top: 20px; position: sticky; bottom: -24px; background: var(--dsw-alias-bg-layer-2); border-top: 1px solid var(--dsw-alias-border-l2); padding-top: 14px; padding-bottom: 4px; margin-left: -24px; margin-right: -24px; padding-left: 24px; padding-right: 24px; z-index: 10; }
741
+ .dsh-cron-btn-primary { background: var(--dsw-alias-label-primary); color: var(--dsw-alias-bg-layer-3); border: 1px solid transparent; border-radius: 8px; padding: 7px 14px; font-size: 13px; font-weight: 500; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; }
742
742
  .dsh-cron-btn-primary:hover:not(:disabled) { opacity: 0.88; }
743
743
  .dsh-cron-btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }
744
- .dsh-cron-btn-secondary { appearance: none; font: inherit; background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-label-primary, #999); border: 1px solid var(--dsw-alias-border-l2, #383838); border-radius: 8px; padding: 7px 14px; font-size: 13px; font-weight: 500; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; transition: all 0.15s ease; }
745
- .dsh-cron-btn-secondary:hover:not(:disabled) { background: var(--dsw-alias-bg-layer-4, #2a2a2a); border-color: var(--dsw-alias-label-dimmed, var(--dsw-alias-border-l2, #444)); }
746
- .dsh-cron-chat-box { position: relative; background: var(--dsw-alias-bg-base, #141414); border: 1px solid var(--dsw-alias-border-l2, #333); border-radius: 12px; padding: 12px; }
747
- .dsh-cron-chat-input { width: 100%; background: transparent; border: none; color: var(--dsw-alias-label-primary, #fff); font-size: 14px; min-height: 100px; resize: vertical; outline: none; box-sizing: border-box; line-height: 1.5; }
748
- .dsh-cron-chat-foot { display: flex; justify-content: space-between; align-items: center; margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--dsw-alias-border-l1, #222); }
749
- .dsh-cron-chat-hint { font-size: 12px; color: var(--dsw-alias-label-tertiary, #666); }
750
- .dsh-cron-send-btn { width: 34px; height: 34px; border-radius: 8px; background: var(--dsw-alias-label-primary, #ededed); color: var(--dsw-alias-bg-base, #111); border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: transform 0.1s, background 0.15s; }
744
+ .dsh-cron-btn-secondary { appearance: none; font: inherit; background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-label-primary); border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px; padding: 7px 14px; font-size: 13px; font-weight: 500; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; transition: all 0.15s ease; }
745
+ .dsh-cron-btn-secondary:hover:not(:disabled) { background: var(--dsw-alias-bg-layer-4); border-color: var(--dsw-alias-label-dimmed, var(--dsw-alias-border-l2)); }
746
+ .dsh-cron-chat-box { position: relative; background: var(--dsw-alias-bg-base); border: 1px solid var(--dsw-alias-border-l2); border-radius: 12px; padding: 12px; }
747
+ .dsh-cron-chat-input { width: 100%; background: transparent; border: none; color: var(--dsw-alias-label-primary); font-size: 14px; min-height: 100px; resize: vertical; outline: none; box-sizing: border-box; line-height: 1.5; }
748
+ .dsh-cron-chat-foot { display: flex; justify-content: space-between; align-items: center; margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--dsw-alias-border-l1); }
749
+ .dsh-cron-chat-hint { font-size: 12px; color: var(--dsw-alias-label-tertiary); }
750
+ .dsh-cron-send-btn { width: 34px; height: 34px; border-radius: 8px; background: var(--dsw-alias-label-primary); color: var(--dsw-alias-bg-base); border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: transform 0.1s, background 0.15s; }
751
751
  .dsh-cron-send-btn:hover:not(:disabled) { transform: translateY(-1px); }
752
752
  .dsh-cron-send-btn:disabled { opacity: 0.4; cursor: not-allowed; }
753
753
 
754
- .dsh-cron-card { background: var(--dsw-alias-bg-layer-3, #1f1f1f); border: 1px solid var(--dsw-alias-border-l2, #333); border-radius: 12px; padding: 18px 20px; margin-bottom: 0; display: flex; flex-direction: column; gap: 14px; }
754
+ .dsh-cron-card { background: var(--dsw-alias-bg-layer-3); border: 1px solid var(--dsw-alias-border-l2); border-radius: 12px; padding: 18px 20px; margin-bottom: 0; display: flex; flex-direction: column; gap: 14px; }
755
755
  .dsh-cron-card-head-btn { appearance: none; width: 100%; font: inherit; color: inherit; text-align: left; cursor: pointer; background: 0 0; border: 0; border-radius: 12px; display: flex; align-items: center; gap: 12px; padding: 0; }
756
756
  .dsh-cron-card-head-btn .dsh-cron-card-title { flex: 1; }
757
- .dsh-cron-card-title { font-size: 16px; font-weight: 600; color: var(--dsw-alias-label-primary, #fff); }
758
- .dsh-cron-chev { margin-left: auto; flex: none; color: var(--dsw-alias-label-tertiary, #888); transition: transform 0.16s; display: flex; align-items: center; }
757
+ .dsh-cron-card-title { font-size: 16px; font-weight: 600; color: var(--dsw-alias-label-primary); }
758
+ .dsh-cron-chev { margin-left: auto; flex: none; color: var(--dsw-alias-label-tertiary); transition: transform 0.16s; display: flex; align-items: center; }
759
759
  .dsh-cron-chev-open { transform: rotate(180deg); }
760
- .dsh-cron-card-body { border-top: 1px solid var(--dsw-alias-border-l2, #333); margin-top: 2px; padding-top: 14px; }
760
+ .dsh-cron-card-body { border-top: 1px solid var(--dsw-alias-border-l2); margin-top: 2px; padding-top: 14px; }
761
761
  .dsh-cron-card-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
762
- .dsh-cron-card-desc { font-size: 13px; color: var(--dsw-alias-label-secondary, #888); line-height: 1.4; }
762
+ .dsh-cron-card-desc { font-size: 13px; color: var(--dsw-alias-label-secondary); line-height: 1.4; }
763
763
 
764
- .dsh-cron-modal-nav { display: flex; gap: 4px; border-bottom: 1px solid var(--dsw-alias-border-l2, #2e2e2e); margin-bottom: 18px; padding-bottom: 2px; }
765
- .dsh-cron-modal-tab { appearance: none; background: transparent; border: none; border-bottom: 2px solid transparent; padding: 8px 14px; font-size: 13.5px; color: var(--dsw-alias-label-tertiary, #888); cursor: pointer; font-weight: 500; transition: color 0.15s, border-color 0.15s; }
766
- .dsh-cron-modal-tab:hover { color: var(--dsw-alias-label-secondary, #ccc); }
767
- .dsh-cron-modal-tab[data-active="true"] { color: var(--dsw-alias-label-primary, #fff); border-bottom-color: var(--dsw-alias-label-primary, #ededed); }
764
+ .dsh-cron-modal-nav { display: flex; gap: 4px; border-bottom: 1px solid var(--dsw-alias-border-l2); margin-bottom: 18px; padding-bottom: 2px; }
765
+ .dsh-cron-modal-tab { appearance: none; background: transparent; border: none; border-bottom: 2px solid transparent; padding: 8px 14px; font-size: 13.5px; color: var(--dsw-alias-label-tertiary); cursor: pointer; font-weight: 500; transition: color 0.15s, border-color 0.15s; }
766
+ .dsh-cron-modal-tab:hover { color: var(--dsw-alias-label-secondary); }
767
+ .dsh-cron-modal-tab[data-active="true"] { color: var(--dsw-alias-label-primary); border-bottom-color: var(--dsw-alias-label-primary); }
768
768
  .dsh-cron-history-list { display: flex; flex-direction: column; gap: 10px; max-height: 420px; overflow-y: auto; padding-right: 4px; }
769
- .dsh-cron-history-item { background: var(--dsw-alias-bg-base, #161616); border: 1px solid var(--dsw-alias-border-l1, #2a2a2a); border-radius: 8px; padding: 12px 14px; font-size: 12.5px; }
769
+ .dsh-cron-history-item { background: var(--dsw-alias-bg-base); border: 1px solid var(--dsw-alias-border-l1); border-radius: 8px; padding: 12px 14px; font-size: 12.5px; }
770
770
  .dsh-cron-history-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
771
- .dsh-cron-history-status { font-weight: 500; font-size: 11px; text-transform: uppercase; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--dsw-alias-border-l2, #383838); }
771
+ .dsh-cron-history-status { font-weight: 500; font-size: 11px; text-transform: uppercase; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--dsw-alias-border-l2); }
772
772
  .dsh-cron-history-status[data-status="success"] { background: var(--dsh-cron-success-bg); color: var(--dsh-cron-success); border-color: var(--dsh-cron-success); }
773
773
  .dsh-cron-history-status[data-status="error"], .dsh-cron-history-status[data-status="timeout"] { background: var(--dsh-cron-danger-bg); color: var(--dsh-cron-danger); border-color: var(--dsh-cron-danger); }
774
774
  .dsh-cron-history-status[data-status="skipped"], .dsh-cron-history-status[data-status="missed"] { background: var(--dsh-cron-warning-bg); color: var(--dsh-cron-warning); border-color: var(--dsh-cron-warning); }
775
- .dsh-cron-history-time { color: var(--dsw-alias-label-tertiary, #777); font-size: 12px; }
776
- .dsh-cron-history-output { background: var(--dsw-alias-bg-base, #0c0c0c); border: 1px solid var(--dsw-alias-border-l1, #222); border-radius: 6px; padding: 8px 10px; font-family: monospace; font-size: 12px; color: var(--dsw-alias-label-secondary, #bbb); max-height: 140px; overflow-y: auto; white-space: pre-wrap; word-break: break-all; margin-top: 6px; }
777
- .dsh-cron-history-empty { text-align: center; padding: 36px 0; color: var(--dsw-alias-label-tertiary, #666); font-size: 13.5px; }
775
+ .dsh-cron-history-time { color: var(--dsw-alias-label-tertiary); font-size: 12px; }
776
+ .dsh-cron-history-output { background: var(--dsw-alias-bg-base); border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; padding: 8px 10px; font-family: monospace; font-size: 12px; color: var(--dsw-alias-label-secondary); max-height: 140px; overflow-y: auto; white-space: pre-wrap; word-break: break-all; margin-top: 6px; }
777
+ .dsh-cron-history-empty { text-align: center; padding: 36px 0; color: var(--dsw-alias-label-tertiary); font-size: 13.5px; }
778
778
 
779
779
  .dsh-cron-stats-bar { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin-bottom: 0; }
780
- .dsh-cron-stat-card { background: var(--dsw-alias-bg-layer-2, color-mix(in srgb, var(--dsw-alias-label-primary, #fff) 2%, transparent)); border: 1px solid var(--dsw-alias-border-l2, #222); border-radius: 8px; padding: 12px 14px; display: flex; flex-direction: column; gap: 4px; }
781
- .dsh-cron-stat-val { font-size: 18px; font-weight: 700; color: var(--dsw-alias-label-primary, #fff); }
782
- .dsh-cron-stat-lbl { font-size: 12px; color: var(--dsw-alias-label-secondary, #777); margin-top: 0; }
780
+ .dsh-cron-stat-card { background: var(--dsw-alias-bg-layer-2, color-mix(in srgb, var(--dsw-alias-label-primary) 2%, transparent)); border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px; padding: 12px 14px; display: flex; flex-direction: column; gap: 4px; }
781
+ .dsh-cron-stat-val { font-size: 18px; font-weight: 700; color: var(--dsw-alias-label-primary); }
782
+ .dsh-cron-stat-lbl { font-size: 12px; color: var(--dsw-alias-label-secondary); margin-top: 0; }
783
783
  .dsh-cron-oneshot-tag { display: inline-flex; align-items: center; font-size: 11px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--dsh-cron-accent); background: var(--dsh-cron-accent-bg); color: var(--dsh-cron-accent); font-weight: 500; }
784
- .dsh-cron-config-tag { display: inline-flex; align-items: center; font-size: 11px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--dsw-alias-border-l2, #444); color: var(--dsw-alias-label-secondary, #ccc); font-weight: 500; }
784
+ .dsh-cron-config-tag { display: inline-flex; align-items: center; font-size: 11px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--dsw-alias-border-l2); color: var(--dsw-alias-label-secondary); font-weight: 500; }
785
785
  .dsh-cron-cost-tag { display: inline-flex; align-items: center; font-size: 11px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--dsh-cron-success); background: var(--dsh-cron-success-bg); color: var(--dsh-cron-success); font-weight: 500; }
786
786
  .dsh-cron-tokens-tag { display: inline-flex; align-items: center; font-size: 11px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--dsh-cron-info); background: var(--dsh-cron-info-bg); color: var(--dsh-cron-info); }
787
- .dsh-cron-checkbox-row { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--dsw-alias-label-secondary, #ccc); cursor: pointer; user-select: none; }
788
- .dsh-cron-checkbox-row input { width: 15px; height: 15px; margin: 0; cursor: pointer; accent-color: var(--dsw-alias-label-primary, #ededed); }
789
- .dsh-cron-hint { font-size: 12px; color: var(--dsw-alias-label-tertiary, #888); margin-top: 4px; }
787
+ .dsh-cron-checkbox-row { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--dsw-alias-label-secondary); cursor: pointer; user-select: none; }
788
+ .dsh-cron-checkbox-row input { width: 15px; height: 15px; margin: 0; cursor: pointer; accent-color: var(--dsw-alias-label-primary); }
789
+ .dsh-cron-hint { font-size: 12px; color: var(--dsw-alias-label-tertiary); margin-top: 4px; }
790
790
  .dsh-cron-channel-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 6px 12px; }
791
- .dsh-cron-section { border-top: 1px solid var(--dsw-alias-border-l2, #2e2e2e); margin-top: 16px; padding-top: 12px; }
792
- .dsh-cron-section-title { font-weight: 500; font-size: 12.5px; color: var(--dsw-alias-label-secondary, #aaa); margin-bottom: 10px; }
791
+ .dsh-cron-section { border-top: 1px solid var(--dsw-alias-border-l2); margin-top: 16px; padding-top: 12px; }
792
+ .dsh-cron-section-title { font-weight: 500; font-size: 12.5px; color: var(--dsw-alias-label-secondary); margin-bottom: 10px; }
793
793
  .dsh-cron-secret-row { display: flex; align-items: center; gap: 8px; }
794
794
  .dsh-cron-secret-row input { flex: 1; }
795
- .dsh-cron-badge-ref { font-size: 11px; padding: 2px 6px; border-radius: 4px; background: var(--dsw-alias-bg-layer-3, color-mix(in srgb, var(--dsw-alias-label-primary, #fff) 6%, transparent)); color: var(--dsw-alias-label-tertiary, #888); white-space: nowrap; }
795
+ .dsh-cron-badge-ref { font-size: 11px; padding: 2px 6px; border-radius: 4px; background: var(--dsw-alias-bg-layer-3, color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent)); color: var(--dsw-alias-label-tertiary); white-space: nowrap; }
796
796
  .dsh-cron-status-banner { padding: 10px 14px; border-radius: 8px; font-size: 13px; margin-top: 12px; }
797
797
  .dsh-cron-status-banner[data-type="success"] { background: var(--dsh-cron-success-bg); border: 1px solid var(--dsh-cron-success); color: var(--dsh-cron-success); }
798
798
  .dsh-cron-status-banner[data-type="error"] { background: var(--dsh-cron-danger-bg); border: 1px solid var(--dsh-cron-danger); color: var(--dsh-cron-danger); }
@@ -802,17 +802,17 @@ window.__ModuleLoader__.load({
802
802
 
803
803
  /* #34: sidebar job list */
804
804
  .dsh-cron-sidebar-jobs { display: flex; flex-direction: column; gap: 2px; margin: 2px 0 6px 0; }
805
- .dsh-cron-sidebar-jobs-head { display: flex; align-items: center; justify-content: space-between; width: 100%; background: none; border: none; padding: 4px 8px; font: inherit; font-size: 12px; color: var(--dsw-alias-label-tertiary, #888); cursor: pointer; border-radius: 6px; text-align: left; }
806
- .dsh-cron-sidebar-jobs-head:hover { color: var(--dsw-alias-label-primary, #eee); background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, var(--dsw-alias-label-primary, #fff) 4%, transparent)); }
805
+ .dsh-cron-sidebar-jobs-head { display: flex; align-items: center; justify-content: space-between; width: 100%; background: none; border: none; padding: 4px 8px; font: inherit; font-size: 12px; color: var(--dsw-alias-label-tertiary); cursor: pointer; border-radius: 6px; text-align: left; }
806
+ .dsh-cron-sidebar-jobs-head:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, var(--dsw-alias-label-primary) 4%, transparent)); }
807
807
  .dsh-cron-sidebar-jobs-head::after { content: '▾'; font-size: 10px; transition: transform 0.15s ease; }
808
808
  .dsh-cron-sidebar-jobs[data-open="false"] .dsh-cron-sidebar-jobs-head::after { transform: rotate(-90deg); }
809
809
  .dsh-cron-sidebar-jobs[data-open="false"] .dsh-cron-sidebar-jobs-list { display: none; }
810
810
  .dsh-cron-sidebar-jobs-list { display: flex; flex-direction: column; gap: 2px; padding-left: 10px; }
811
811
  .dsh-cron-sidebar-job { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; width: 100%; background: none; border: none; border-left: 2px solid transparent; padding: 3px 8px; font: inherit; cursor: pointer; border-radius: 0 6px 6px 0; text-align: left; }
812
- .dsh-cron-sidebar-job:hover { background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, var(--dsw-alias-label-primary, #fff) 4%, transparent)); border-left-color: var(--dsh-cron-info); }
813
- .dsh-cron-sidebar-job-title { font-size: 12px; color: var(--dsw-alias-label-secondary, #ccc); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
814
- .dsh-cron-sidebar-job-meta { font-size: 11px; color: var(--dsw-alias-label-tertiary, #777); }
815
- .dsh-cron-sidebar-empty, .dsh-cron-sidebar-more { font-size: 11px; color: var(--dsw-alias-label-tertiary, #777); padding: 2px 8px; }
812
+ .dsh-cron-sidebar-job:hover { background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, var(--dsw-alias-label-primary) 4%, transparent)); border-left-color: var(--dsh-cron-info); }
813
+ .dsh-cron-sidebar-job-title { font-size: 12px; color: var(--dsw-alias-label-secondary); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
814
+ .dsh-cron-sidebar-job-meta { font-size: 11px; color: var(--dsw-alias-label-tertiary); }
815
+ .dsh-cron-sidebar-empty, .dsh-cron-sidebar-more { font-size: 11px; color: var(--dsw-alias-label-tertiary); padding: 2px 8px; }
816
816
  .dsh-cron-task-highlight { border-color: var(--dsh-cron-info) !important; box-shadow: 0 0 0 2px var(--dsh-cron-info-bg); }
817
817
 
818
818
  /* #39: narrow screens. Only layout changes — no information is hidden. */
@@ -2862,8 +2862,8 @@ window.__ModuleLoader__.load({
2862
2862
  ),
2863
2863
  React.createElement('div', {
2864
2864
  style: {
2865
- background: 'var(--dsw-alias-bg-layer-3, color-mix(in srgb, var(--dsw-alias-label-primary, #fff) 2%, transparent))',
2866
- border: '1px solid var(--dsw-alias-border-l2, #2e2e2e)',
2865
+ background: 'var(--dsw-alias-bg-layer-3, color-mix(in srgb, var(--dsw-alias-label-primary) 2%, transparent))',
2866
+ border: '1px solid var(--dsw-alias-border-l2)',
2867
2867
  borderRadius: '8px',
2868
2868
  padding: '12px 14px',
2869
2869
  marginBottom: '16px'
@@ -2889,7 +2889,7 @@ window.__ModuleLoader__.load({
2889
2889
  }),
2890
2890
  React.createElement('span', null, T_KEY(t, 'form.notifyOnlyFailure'))
2891
2891
  ),
2892
- React.createElement('div', { style: { marginTop: '12px', paddingTop: '10px', borderTop: '1px solid var(--dsw-alias-border-l2, #2e2e2e)' } },
2892
+ React.createElement('div', { style: { marginTop: '12px', paddingTop: '10px', borderTop: '1px solid var(--dsw-alias-border-l2)' } },
2893
2893
  React.createElement('div', { style: { fontWeight: 500, fontSize: '12.5px', color: 'var(--dsw-alias-label-secondary, #aaa)', marginBottom: '8px' } }, T_KEY(t, 'form.channelsTitle')),
2894
2894
  React.createElement('div', { className: 'dsh-cron-channel-grid' },
2895
2895
  ...DELIVERY_CHANNELS.map((id) => React.createElement('label', { key: id, className: 'dsh-cron-checkbox-row' },
@@ -2937,7 +2937,7 @@ window.__ModuleLoader__.load({
2937
2937
  style: {
2938
2938
  marginTop: '16px',
2939
2939
  paddingTop: '14px',
2940
- borderTop: '1px solid var(--dsw-alias-border-l2, #2e2e2e)'
2940
+ borderTop: '1px solid var(--dsw-alias-border-l2)'
2941
2941
  }
2942
2942
  },
2943
2943
  React.createElement('div', { style: { fontWeight: '600', fontSize: '13px', marginBottom: '10px' } }, T_KEY(t, 'form.reliabilityTitle')),
@@ -3025,8 +3025,8 @@ window.__ModuleLoader__.load({
3025
3025
  ),
3026
3026
  selectedTaskMeta && React.createElement('div', {
3027
3027
  style: {
3028
- background: 'var(--dsw-alias-bg-layer-3, color-mix(in srgb, var(--dsw-alias-label-primary, #fff) 3%, transparent))',
3029
- border: '1px solid var(--dsw-alias-border-l2, #2e2e2e)',
3028
+ background: 'var(--dsw-alias-bg-layer-3, color-mix(in srgb, var(--dsw-alias-label-primary) 3%, transparent))',
3029
+ border: '1px solid var(--dsw-alias-border-l2)',
3030
3030
  borderRadius: '8px',
3031
3031
  padding: '10px 14px',
3032
3032
  fontSize: '12.5px',
@@ -3085,14 +3085,14 @@ window.__ModuleLoader__.load({
3085
3085
  }, '✕')
3086
3086
  ),
3087
3087
  React.createElement('div', { style: { marginTop: '12px', display: 'flex', flexDirection: 'column', gap: '8px', fontSize: '13px' } },
3088
- React.createElement('div', null, React.createElement('strong', null, T_KEY(t, 'dryRun.status') + ': '), React.createElement('span', { style: { color: dryRunResult.ok ? 'var(--dsh-cron-success, #22c55e)' : 'var(--dsh-cron-danger, #ef4444)' } }, dryRunResult.ok ? (dryRunResult.result && dryRunResult.result.status || 'success') : 'failed')),
3088
+ React.createElement('div', null, React.createElement('strong', null, T_KEY(t, 'dryRun.status') + ': '), React.createElement('span', { style: { color: dryRunResult.ok ? 'var(--dsh-cron-success)' : 'var(--dsh-cron-danger)' } }, dryRunResult.ok ? (dryRunResult.result && dryRunResult.result.status || 'success') : 'failed')),
3089
3089
  dryRunResult.result && dryRunResult.result.preflight && React.createElement('div', null, React.createElement('strong', null, T_KEY(t, 'dryRun.preflight') + ': '), React.createElement('span', null, dryRunResult.result.preflight.passed ? '✓ Passed' : '✗ Failed (' + (dryRunResult.result.preflight.reason || '') + ')')),
3090
3090
  dryRunResult.result && React.createElement('div', null, React.createElement('strong', null, T_KEY(t, 'dryRun.duration') + ': '), React.createElement('span', null, (dryRunResult.result.durationMs || 0) + 'ms')),
3091
3091
  React.createElement('div', { style: { marginTop: '6px' } }, React.createElement('strong', null, T_KEY(t, 'dryRun.output') + ':')),
3092
3092
  React.createElement('pre', {
3093
3093
  style: {
3094
- background: 'var(--dsw-alias-bg-layer-2, #18181b)',
3095
- border: '1px solid var(--dsw-alias-border-l2, #2e2e2e)',
3094
+ background: 'var(--dsw-alias-bg-layer-2)',
3095
+ border: '1px solid var(--dsw-alias-border-l2)',
3096
3096
  borderRadius: '6px',
3097
3097
  padding: '10px',
3098
3098
  maxHeight: '220px',
@@ -3100,7 +3100,7 @@ window.__ModuleLoader__.load({
3100
3100
  fontSize: '12px',
3101
3101
  whiteSpace: 'pre-wrap',
3102
3102
  wordBreak: 'break-word',
3103
- color: 'var(--dsw-alias-label-primary, #e4e4e7)'
3103
+ color: 'var(--dsw-alias-label-primary)'
3104
3104
  }
3105
3105
  }, (dryRunResult.result && dryRunResult.result.output) || (dryRunResult.error) || '(no output)')
3106
3106
  ),
@@ -3140,19 +3140,19 @@ window.__ModuleLoader__.load({
3140
3140
  archiveRuns.map((r, idx) => React.createElement('div', {
3141
3141
  key: idx,
3142
3142
  style: {
3143
- background: 'var(--dsw-alias-bg-layer-2, #18181b)',
3144
- border: '1px solid var(--dsw-alias-border-l2, #2e2e2e)',
3143
+ background: 'var(--dsw-alias-bg-layer-2)',
3144
+ border: '1px solid var(--dsw-alias-border-l2)',
3145
3145
  borderRadius: '6px',
3146
3146
  padding: '8px 12px',
3147
3147
  fontSize: '12px'
3148
3148
  }
3149
3149
  },
3150
3150
  React.createElement('div', { style: { display: 'flex', justifyContent: 'space-between', marginBottom: '4px' } },
3151
- React.createElement('span', { style: { fontWeight: '600', color: r.status === 'success' ? 'var(--dsh-cron-success, #22c55e)' : 'var(--dsh-cron-danger, #ef4444)' } }, (r.status || 'unknown').toUpperCase()),
3151
+ React.createElement('span', { style: { fontWeight: '600', color: r.status === 'success' ? 'var(--dsh-cron-success)' : 'var(--dsh-cron-danger)' } }, (r.status || 'unknown').toUpperCase()),
3152
3152
  React.createElement('span', { style: { color: 'var(--dsw-alias-label-secondary, #888)' } }, new Date(r.timestamp || r.startedAt || Date.now()).toLocaleString())
3153
3153
  ),
3154
3154
  r.durationMs > 0 && React.createElement('div', { style: { color: 'var(--dsw-alias-label-secondary, #888)', marginBottom: '4px' } }, 'Duration: ' + r.durationMs + 'ms'),
3155
- r.error && React.createElement('div', { style: { color: 'var(--dsh-cron-danger, #ef4444)', marginBottom: '4px' } }, 'Error: ' + r.error),
3155
+ r.error && React.createElement('div', { style: { color: 'var(--dsh-cron-danger)', marginBottom: '4px' } }, 'Error: ' + r.error),
3156
3156
  r.output && React.createElement('div', {
3157
3157
  style: {
3158
3158
  color: 'var(--dsw-alias-label-primary, #ccc)',
@@ -3215,7 +3215,7 @@ window.__ModuleLoader__.load({
3215
3215
  onChange: (e) => setSettingsChatId(e.target.value)
3216
3216
  })
3217
3217
  ),
3218
- React.createElement('div', { style: { background: 'var(--dsw-alias-bg-layer-3, color-mix(in srgb, var(--dsw-alias-label-primary, #fff) 2%, transparent))', border: '1px solid var(--dsw-alias-border-l2, #2e2e2e)', borderRadius: '8px', padding: '12px 14px', marginBottom: '16px' } },
3218
+ React.createElement('div', { style: { background: 'var(--dsw-alias-bg-layer-3, color-mix(in srgb, var(--dsw-alias-label-primary) 2%, transparent))', border: '1px solid var(--dsw-alias-border-l2)', borderRadius: '8px', padding: '12px 14px', marginBottom: '16px' } },
3219
3219
  React.createElement('label', { className: 'dsh-cron-checkbox-row', style: { marginBottom: '8px' } },
3220
3220
  React.createElement('input', {
3221
3221
  type: 'checkbox',
@@ -3380,7 +3380,7 @@ window.__ModuleLoader__.load({
3380
3380
  const [updateState, setUpdateState] = React.useState({
3381
3381
  checking: false,
3382
3382
  updating: false,
3383
- currentVersion: '0.2.24',
3383
+ currentVersion: '',
3384
3384
  latestVersion: undefined,
3385
3385
  updateAvailable: false,
3386
3386
  notice: null,
@@ -3458,6 +3458,9 @@ window.__ModuleLoader__.load({
3458
3458
  setKanbanUrl(data.settings.kanbanBaseUrl || 'http://127.0.0.1:3000');
3459
3459
  setDelivery(pickDeliverySettings(data.settings));
3460
3460
  setHasDefault(Boolean(data.settings.hasDefaultCredentials));
3461
+ if (data.settings.version) {
3462
+ setUpdateState(prev => ({ ...prev, currentVersion: data.settings.version }));
3463
+ }
3461
3464
  setLoadState('ready');
3462
3465
  } else {
3463
3466
  setLoadState('error');
@@ -3601,7 +3604,7 @@ window.__ModuleLoader__.load({
3601
3604
  onChange: (e) => setKanbanUrl(e.target.value)
3602
3605
  })
3603
3606
  ),
3604
- React.createElement('div', { style: { background: 'var(--dsw-alias-bg-layer-3, color-mix(in srgb, var(--dsw-alias-label-primary, #fff) 2%, transparent))', border: '1px solid var(--dsw-alias-border-l2, #2e2e2e)', borderRadius: '6px', padding: '10px 12px', display: 'flex', flexDirection: 'column', gap: '8px' } },
3607
+ React.createElement('div', { style: { background: 'var(--dsw-alias-bg-layer-3, color-mix(in srgb, var(--dsw-alias-label-primary) 2%, transparent))', border: '1px solid var(--dsw-alias-border-l2)', borderRadius: '6px', padding: '10px 12px', display: 'flex', flexDirection: 'column', gap: '8px' } },
3605
3608
  React.createElement('label', { className: 'dsh-cron-checkbox-row' },
3606
3609
  React.createElement('input', {
3607
3610
  type: 'checkbox',
@@ -3653,8 +3656,8 @@ window.__ModuleLoader__.load({
3653
3656
  React.createElement('div', {
3654
3657
  className: 'dsh-cron-form-group',
3655
3658
  style: {
3656
- background: 'var(--dsw-alias-bg-layer-2, color-mix(in srgb, var(--dsw-alias-label-primary, #fff) 3%, transparent))',
3657
- border: '1px solid var(--dsw-alias-border-l2, color-mix(in srgb, var(--dsw-alias-label-primary, #fff) 8%, transparent))',
3659
+ background: 'var(--dsw-alias-bg-layer-2, color-mix(in srgb, var(--dsw-alias-label-primary) 3%, transparent))',
3660
+ border: '1px solid var(--dsw-alias-border-l2, color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent))',
3658
3661
  borderRadius: '8px',
3659
3662
  padding: '14px',
3660
3663
  marginBottom: '16px'
@@ -3688,17 +3691,17 @@ window.__ModuleLoader__.load({
3688
3691
  style: { display: 'flex', alignItems: 'center', gap: '12px', fontSize: '13px' }
3689
3692
  },
3690
3693
  React.createElement('span', { style: { color: 'var(--dsw-alias-label-secondary, #aaa)' } },
3691
- T_KEY(t, 'updater.current', { version: updateState.currentVersion })
3694
+ updateState.currentVersion ? T_KEY(t, 'updater.current', { version: updateState.currentVersion }) : ''
3692
3695
  ),
3693
3696
  updateState.checking ? React.createElement('span', { className: 'dsh-cron-badge dsh-cron-badge-info' }, T_KEY(t, 'updater.checking')) :
3694
3697
  updateState.updateAvailable ? React.createElement('span', { className: 'dsh-cron-badge dsh-cron-badge-warn' }, T_KEY(t, 'updater.available', { version: updateState.latestVersion })) :
3695
- updateState.currentVersion && !updateState.error ? React.createElement('span', { className: 'dsh-cron-badge dsh-cron-badge-ok' }, `✓ ${T_KEY(t, 'updater.upToDate')}`) : null
3698
+ updateState.currentVersion && !updateState.error && !updateState.checking ? React.createElement('span', { className: 'dsh-cron-badge dsh-cron-badge-ok' }, `✓ ${T_KEY(t, 'updater.upToDate')}`) : null
3696
3699
  ),
3697
3700
  updateState.notice ? React.createElement('div', {
3698
- style: { marginTop: '8px', color: 'var(--dsw-alias-success, #10b981)', fontSize: '12px' }
3701
+ style: { marginTop: '8px', color: 'var(--dsw-alias-success)', fontSize: '12px' }
3699
3702
  }, updateState.notice) : null,
3700
3703
  updateState.error ? React.createElement('div', {
3701
- style: { marginTop: '8px', color: 'var(--dsw-alias-error, #ef4444)', fontSize: '12px' }
3704
+ style: { marginTop: '8px', color: 'var(--dsw-alias-error)', fontSize: '12px' }
3702
3705
  }, updateState.error) : null
3703
3706
  ),
3704
3707
  React.createElement('div', { style: { display: 'flex', gap: '8px', alignItems: 'center', flexWrap: 'wrap', marginTop: '4px' } },