@goodandready/dsh-cron 0.3.24 → 0.3.26
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/lib/api-actions.js +1 -317
- package/lib/api-collection.js +1 -250
- package/lib/api-helpers.js +1 -100
- package/lib/api-import-export.js +1 -155
- package/lib/api-item.js +1 -190
- package/lib/api-task-webhook.js +1 -247
- package/lib/api-webhook.js +1 -183
- package/lib/api.js +1 -178
- package/lib/artifacts.js +1 -200
- package/lib/chain-checkpoints.js +1 -223
- package/lib/client-src/00-open.js +62 -0
- package/lib/client-src/10-locales.js +484 -0
- package/lib/client-src/20-styles.js +64 -0
- package/lib/client-src/30-utils.js +248 -0
- package/lib/client-src/40-delivery-settings.js +96 -0
- package/lib/client-src/45-dag-graph-view.js +287 -0
- package/lib/client-src/46-live-logs-modal.js +108 -0
- package/lib/client-src/47-analytics-digest-modal.js +166 -0
- package/lib/client-src/48-timeline-heatmap-view.js +176 -0
- package/lib/client-src/50-cron-screen-state.js +447 -0
- package/lib/client-src/52-cron-screen-actions.js +330 -0
- package/lib/client-src/53-cron-screen-modal-actions.js +640 -0
- package/lib/client-src/54-cron-screen-analytics-actions.js +68 -0
- package/lib/client-src/55-cron-screen-view.js +378 -0
- package/lib/client-src/60-modal-task-form-head.js +580 -0
- package/lib/client-src/62-modal-task-form-tail.js +466 -0
- package/lib/client-src/65-modal-dialogs.js +350 -0
- package/lib/client-src/70-settings-card.js +420 -0
- package/lib/client-src/80-sidebar-jobs.js +200 -0
- package/lib/client-src/90-close.js +200 -0
- package/lib/client.js +48 -3
- package/lib/commands.js +200 -0
- package/lib/durable-journal.js +1 -188
- package/lib/external-api.js +1 -74
- package/lib/index.js +17 -0
- package/lib/log-streamer.js +10 -2
- package/lib/metrics.js +1 -125
- package/lib/routes/api-actions.js +317 -0
- package/lib/routes/api-collection.js +250 -0
- package/lib/routes/api-helpers.js +100 -0
- package/lib/routes/api-import-export.js +155 -0
- package/lib/routes/api-item.js +191 -0
- package/lib/routes/api-task-webhook.js +247 -0
- package/lib/routes/api-webhook.js +183 -0
- package/lib/routes/api.js +178 -0
- package/lib/routes/external-api.js +74 -0
- package/lib/routes/index.js +11 -0
- package/lib/routes/metrics.js +125 -0
- package/lib/routes/routes.js +549 -0
- package/lib/routes.js +1 -549
- package/lib/runner-external.js +1 -352
- package/lib/runner-worktree.js +1 -90
- package/lib/runner.js +1 -881
- package/lib/runtimes/index.js +4 -0
- package/lib/runtimes/runner-external.js +352 -0
- package/lib/runtimes/runner-worktree.js +90 -0
- package/lib/runtimes/runner.js +881 -0
- package/lib/runtimes/runtimes.js +198 -0
- package/lib/runtimes.js +1 -198
- package/lib/scheduler/index.js +6 -0
- package/lib/scheduler/scheduler-assists.js +142 -0
- package/lib/scheduler/scheduler-completion.js +417 -0
- package/lib/scheduler/scheduler-execution.js +360 -0
- package/lib/scheduler/scheduler-lifecycle.js +157 -0
- package/lib/scheduler/scheduler-preflight.js +195 -0
- package/lib/scheduler/scheduler.js +751 -0
- package/lib/scheduler-assists.js +1 -142
- package/lib/scheduler-completion.js +1 -417
- package/lib/scheduler-execution.js +1 -360
- package/lib/scheduler-lifecycle.js +1 -157
- package/lib/scheduler-preflight.js +1 -195
- package/lib/scheduler.js +1 -751
- package/lib/store/artifacts.js +200 -0
- package/lib/store/chain-checkpoints.js +223 -0
- package/lib/store/durable-journal.js +188 -0
- package/lib/store/index.js +6 -0
- package/lib/store/store.js +1179 -0
- package/lib/store/task-schema.js +180 -0
- package/lib/store/task-transfer.js +310 -0
- package/lib/store.js +2 -1179
- package/lib/task-schema.js +1 -180
- package/lib/task-transfer.js +1 -310
- package/lib/tui-settings.js +157 -0
- package/package.json +6 -3
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
const STRINGS = {
|
|
2
|
+
en: {
|
|
3
|
+
'sidebar.label': 'Scheduled tasks', 'sidebar.jobsTitle': 'Active jobs',
|
|
4
|
+
'sidebar.noActiveJobs': 'No active jobs', 'sidebar.moreJobs': 'and {count} more',
|
|
5
|
+
'chip.title': 'Scheduled tasks (Cron)', 'panel.back': 'Back to chat',
|
|
6
|
+
'panel.title': 'Scheduled tasks',
|
|
7
|
+
'panel.subtitle': 'Ask DSH to plan tasks, set reminders or track updates',
|
|
8
|
+
'actions.create': 'Create', 'actions.createWithDsh': '💬 Create with DSH',
|
|
9
|
+
'actions.setupManually': '✏️ Set up manually', 'actions.runNow': 'Run now',
|
|
10
|
+
'actions.runNowShort': 'Run', 'actions.edit': 'Edit / Details',
|
|
11
|
+
'actions.duplicate': 'Duplicate task', 'actions.tuneWithDsh': 'Tune with DSH',
|
|
12
|
+
'tune.startFailed': 'Could not start the tuning dialogue: {error}',
|
|
13
|
+
'actions.delete': 'Delete task',
|
|
14
|
+
'duplicate.done': 'Copy created and paused: review its schedule before resuming it.',
|
|
15
|
+
'duplicate.oneShotHint': 'The copy is one-shot and paused — its original time has likely passed, so set a new time before resuming.',
|
|
16
|
+
'duplicate.failed': 'Could not duplicate the task: {error}',
|
|
17
|
+
'transfer.exportTitle': 'Export tasks', 'transfer.importTitle': 'Import tasks',
|
|
18
|
+
'transfer.exported': 'Exported {count} task(s).',
|
|
19
|
+
'transfer.exportFailed': 'Export failed: {error}', 'transfer.importTitleModal': 'Import tasks',
|
|
20
|
+
'transfer.importHint': 'Exported task configuration only: no run history, no counters. Channel configurations reference credentials by name; note that raw exports retain custom env variables and HTTP request headers.',
|
|
21
|
+
'transfer.exportPrompt': 'Choose export mode:\nOK = Sanitized (removes custom env vars & headers)\nCancel = Full raw export',
|
|
22
|
+
'transfer.strategyAdd': 'Add as new tasks (new ids, existing ones stay untouched)',
|
|
23
|
+
'transfer.strategyReplace': 'Replace tasks with the same id',
|
|
24
|
+
'transfer.strategySkip': 'Skip tasks whose id already exists',
|
|
25
|
+
'transfer.summary': 'This file contains {total} task(s): {add} new, {replace} matching an existing id, {skip} already skipped.',
|
|
26
|
+
'transfer.confirm': 'Import', 'transfer.imported': 'Imported {count} task(s).',
|
|
27
|
+
'transfer.importFailed': 'Import failed: {error}',
|
|
28
|
+
'transfer.badFile': 'The selected file is not a valid JSON export: {error}',
|
|
29
|
+
'actions.pause': 'Pause', 'actions.resume': 'Resume',
|
|
30
|
+
'actions.settings': 'Notifications & channels', 'search.placeholder': 'Search scheduled tasks',
|
|
31
|
+
'filters.title': 'Filters', 'filters.type': 'Type',
|
|
32
|
+
'filters.model': 'Model', 'filters.channel': 'Channel',
|
|
33
|
+
'filters.any': 'Any', 'filters.reset': 'Reset filters',
|
|
34
|
+
'filters.empty': 'No task matches the current filters.',
|
|
35
|
+
'filters.showing': 'Showing {shown} of {total}', 'stats.activeTasks': 'Active tasks',
|
|
36
|
+
'stats.totalRuns': 'Total runs', 'stats.totalTokens': 'Tokens spent',
|
|
37
|
+
'stats.totalCost': 'Estimated cost', 'tabs.all': 'All',
|
|
38
|
+
'tabs.active': 'Active', 'tabs.paused': 'Paused',
|
|
39
|
+
'tabs.completed': 'Completed', 'banner.loadError': 'Failed to load tasks: {error}',
|
|
40
|
+
'banner.retry': 'Retry', 'list.loading': 'Loading scheduled tasks...',
|
|
41
|
+
'list.empty': 'No scheduled tasks yet', 'list.typeShell': 'Shell',
|
|
42
|
+
'list.typeLlm': 'LLM', 'list.oneShot': 'One-shot',
|
|
43
|
+
'list.configManaged': 'Config',
|
|
44
|
+
'list.configManagedHint': 'Declared in config.jobs in the profile config file; edit the file to change or remove it',
|
|
45
|
+
'list.next': ' · next: {time}', 'recs.title': 'Recommended tasks',
|
|
46
|
+
'recs.hint': 'Ready-to-use recipes. Clicking one opens the form with its fields filled in — nothing is created until you save.',
|
|
47
|
+
'modal.editTitle': 'Edit task', 'modal.newTitle': 'New scheduled task',
|
|
48
|
+
'modal.statusActive': '● Active', 'modal.statusPaused': '○ Paused',
|
|
49
|
+
'modal.params': 'Parameters', 'modal.history': 'Run history ({count})',
|
|
50
|
+
'modal.cancel': 'Cancel', 'modal.confirmDiscard': 'Discard unsaved changes?',
|
|
51
|
+
'modal.save': 'Save changes', 'modal.create': 'Create task',
|
|
52
|
+
'modal.close': 'Close', 'history.loading': 'Loading history...',
|
|
53
|
+
'history.empty': 'No runs recorded yet', 'history.stoppedReasonTitle': 'Stopped reason:',
|
|
54
|
+
'history.retryDelivery': 'Retry delivery', 'history.retryingDelivery': 'Retrying...',
|
|
55
|
+
'history.statusValidationFailed': 'validation failed', 'history.stage_queue': 'Queue',
|
|
56
|
+
'history.stage_preflight': 'Preflight', 'history.stage_execution': 'Execution',
|
|
57
|
+
'history.stage_validation': 'Validation', 'history.stage_delivery': 'Delivery',
|
|
58
|
+
'history.refresh': 'Refresh history',
|
|
59
|
+
'history.statusSuccess': 'Success', 'history.statusUncertain': 'Uncertain',
|
|
60
|
+
'history.artifacts': 'Artifacts',
|
|
61
|
+
'history.resolveCompleted': 'Mark Completed', 'history.resolveFailed': 'Mark Failed',
|
|
62
|
+
'history.statusUncertainHint': 'Interrupted by restart — verify outcome',
|
|
63
|
+
'history.statusSkipped': 'Skipped', 'history.statusMissed': 'Missed',
|
|
64
|
+
'history.statusTimeout': 'Timeout', 'history.statusFailed': 'Failed',
|
|
65
|
+
'form.nameLabel': 'Task name', 'form.namePlaceholder': 'For example: dsh-tags-watch',
|
|
66
|
+
'form.typeLabel': 'Execution type', 'form.typeLlm': 'LLM (AI agent)',
|
|
67
|
+
'form.typeScript': 'Shell command / script', 'form.typeNode': 'Node.js',
|
|
68
|
+
'form.typePython': 'Python', 'form.typeHttp': 'HTTP request / webhook',
|
|
69
|
+
'form.typeSsh': 'Remote SSH', 'form.typeDocker': 'Docker container',
|
|
70
|
+
'form.typeSkill': 'DSH Skill', 'form.typeWorkflow': 'DSH Workflow',
|
|
71
|
+
'form.envLabel': 'Environment variables (KEY=VALUE per line)',
|
|
72
|
+
'form.envPlaceholder': 'NODE_ENV=production\nTZ=Europe/Berlin',
|
|
73
|
+
'form.envHint': 'Applied to non-LLM runtimes only. Do not store secrets here.',
|
|
74
|
+
'form.cwdLabel': 'Working directory (optional)',
|
|
75
|
+
'form.workspaceLabel': 'Workspace id or path (optional)',
|
|
76
|
+
'form.worktreeLabel': 'Run in an isolated git worktree',
|
|
77
|
+
'form.keepWorktreeLabel': 'Keep the worktree after the run',
|
|
78
|
+
'form.httpMethodLabel': 'HTTP method', 'form.httpUrlLabel': 'URL',
|
|
79
|
+
'form.httpHeadersLabel': 'Headers (JSON, optional)', 'form.httpBodyLabel': 'Body (optional)',
|
|
80
|
+
'form.sshProfileLabel': 'dsh-remote-workspace profile id',
|
|
81
|
+
'form.sshProfileHint': 'Preferred: host and credentials stay in the remote-workspace plugin.',
|
|
82
|
+
'form.sshTargetLabel': 'Fallback target (user@host, optional)',
|
|
83
|
+
'form.sshKeyLabel': 'Private key path (fallback, optional)',
|
|
84
|
+
'form.dockerImageLabel': 'Container image', 'form.skillNameLabel': 'Skill name',
|
|
85
|
+
'form.workflowNameLabel': 'Workflow name', 'form.scheduleLabel': 'Schedule (cron or interval)',
|
|
86
|
+
'form.schedulePlaceholder': '0 */6 * * * or every 2h or in 30m or at: 2026-09-05T15:00:00Z',
|
|
87
|
+
'form.timeoutLabel': 'Execution timeout (seconds)', 'form.overlapLabel': 'Overlap policy',
|
|
88
|
+
'form.overlapSkip': 'Skip the new run (skip)',
|
|
89
|
+
'form.overlapQueue': 'Queue the next run (queue)',
|
|
90
|
+
'form.overlapReplace': 'Cancel current run and restart (replace)',
|
|
91
|
+
'form.kanbanLabel': 'Kanban card creation (dsh-kanban)',
|
|
92
|
+
'form.kanbanNone': 'Do not create cards (disabled)',
|
|
93
|
+
'form.kanbanOnFailure': 'Create a ticket on failure (into Backlog)',
|
|
94
|
+
'form.kanbanAlways': 'Create a card on every completion (Done / Backlog)',
|
|
95
|
+
'form.providerLabel': 'LLM provider', 'form.providerDefault': 'Default (DSH)',
|
|
96
|
+
'form.modelLabel': 'LLM model', 'form.modelDefault': 'Default',
|
|
97
|
+
'form.silentRuleLabel': 'Silent rule (optional)',
|
|
98
|
+
'form.silentRulePlaceholder': 'Stay silent when no filesystem is above 80%',
|
|
99
|
+
'form.silentRuleHint': 'For tasks with output: a cheap model judges the run against this rule and the report is skipped when it says to stay silent. If the model is unavailable or unsure, the report is delivered.',
|
|
100
|
+
'history.silentSkip': 'stayed silent:', 'history.diagnosis': 'Diagnosis',
|
|
101
|
+
'history.applySuggestion': 'Open the edit form with this suggestion',
|
|
102
|
+
'form.inspectOnFailureLabel': 'Diagnose failures with a model',
|
|
103
|
+
'form.inspectOnFailureHint': 'After a failed run a model reads the prompt, the error and the output, and the diagnosis with a proposed prompt change is stored with the run. Nothing is applied automatically.',
|
|
104
|
+
'settings.inspectorModelLabel': 'Model for failure diagnosis',
|
|
105
|
+
'form.fallbackModelLabel': 'Fallback model (optional)',
|
|
106
|
+
'form.fallbackModelPlaceholder': 'e.g. deepseek-reasoner',
|
|
107
|
+
'form.fallbackModelHint': 'If the run fails on the model above, it is retried once on this model. Both attempts are counted in the cost.',
|
|
108
|
+
'form.promptLabelScript': 'Shell command or script',
|
|
109
|
+
'form.promptLabelLlm': 'Instruction / Prompt for the agent',
|
|
110
|
+
'form.promptPlaceholderScript': 'curl -fsSL https://... || exit 1',
|
|
111
|
+
'form.promptPlaceholderLlm': 'Describe exactly what the agent should do...',
|
|
112
|
+
'form.timezoneLabel': 'Time zone (IANA, optional)',
|
|
113
|
+
'form.timezonePlaceholder': 'e.g. Europe/Berlin (empty = server local)',
|
|
114
|
+
'form.misfireLabel': 'On missed run (after downtime)',
|
|
115
|
+
'form.misfireSkip': 'Skip the missed run (skip)',
|
|
116
|
+
'form.misfireRunOnce': 'Run once late (runOnce)',
|
|
117
|
+
'form.misfireCatchUp': 'Run late once and record the gap (catchUpAll)',
|
|
118
|
+
'form.retriesLabel': 'Automatic retries on failure (0 = off)',
|
|
119
|
+
'form.permissionLabel': 'Session permissions',
|
|
120
|
+
'form.permissionDefault': 'Default (as configured in DSH)',
|
|
121
|
+
'form.permissionReadonly': 'Read-only', 'form.permissionWrite': 'Workspace write',
|
|
122
|
+
'form.permissionFull': 'Full', 'list.runningNow': 'Running now',
|
|
123
|
+
'history.openSession': 'Open session', 'form.notifyTitle': 'Telegram notifications',
|
|
124
|
+
'form.notifyTelegram': 'Send the run report to Telegram',
|
|
125
|
+
'form.notifyOnlyFailure': 'Only on failures (onlyOnFailure / silent on success)',
|
|
126
|
+
'form.channelsTitle': 'Delivery channels',
|
|
127
|
+
'form.channelsHint': 'Pick the channels for this task. An explicit selection overrides the Telegram switch above; leave everything unchecked to fall back to it.',
|
|
128
|
+
'form.templateLabel': 'Message template (optional)',
|
|
129
|
+
'form.templatePlaceholder': '⏰ {title} — {status} in {duration}',
|
|
130
|
+
'form.templateHint': 'Variables: {title} {id} {status} {output} {error} {duration} {schedule} {time} {tokens} {cost} {model}. Empty = built-in text.',
|
|
131
|
+
'form.channelTelegram': 'Telegram', 'form.channelKanban': 'dsh-kanban card',
|
|
132
|
+
'form.channelDiscord': 'Discord', 'form.channelSlack': 'Slack',
|
|
133
|
+
'form.channelNtfy': 'ntfy', 'form.channelBark': 'Bark',
|
|
134
|
+
'form.channelPushplus': 'PushPlus', 'form.channelTts': 'Voice (dsh-tts)',
|
|
135
|
+
'form.channelGitea': 'Gitea issue', 'settings.deliverySection': 'Delivery channels',
|
|
136
|
+
'settings.secretsSection': 'Credentials (references)',
|
|
137
|
+
'settings.secretsHint': 'Enter the NAME of a DSH credential, not the secret itself. Secrets stay in the credentials store.',
|
|
138
|
+
'settings.telegramSection': 'Telegram', 'settings.templatesSection': 'Message templates',
|
|
139
|
+
'settings.channelTemplateLabel': 'Template for {channel}',
|
|
140
|
+
'settings.botTokenRefLabel': 'Bot token credential name',
|
|
141
|
+
'settings.botTokenRefPlaceholder': 'e.g. TELEGRAM_BOT_TOKEN',
|
|
142
|
+
'settings.apiTokenLabel': 'External API token',
|
|
143
|
+
'settings.apiTokenPlaceholder': 'Bearer token for /dsh-cron/api/* (empty = disabled)',
|
|
144
|
+
'settings.discordLabel': 'Discord webhook URL', 'settings.slackLabel': 'Slack webhook URL',
|
|
145
|
+
'settings.ntfyUrlLabel': 'ntfy server URL', 'settings.ntfyTopicLabel': 'ntfy topic',
|
|
146
|
+
'settings.ntfyTokenRefLabel': 'ntfy token credential name',
|
|
147
|
+
'settings.barkServerLabel': 'Bark server URL', 'settings.barkKeyLabel': 'Bark device key',
|
|
148
|
+
'settings.pushplusTokenRefLabel': 'PushPlus token credential name',
|
|
149
|
+
'settings.pushplusUrlLabel': 'PushPlus endpoint',
|
|
150
|
+
'settings.ttsBaseUrlLabel': 'dsh-tts base URL', 'settings.giteaBaseUrlLabel': 'Gitea base URL',
|
|
151
|
+
'settings.giteaRepoLabel': 'Gitea repository (owner/repo)',
|
|
152
|
+
'settings.giteaTokenRefLabel': 'Gitea token credential name',
|
|
153
|
+
'settings.templateLabel': 'Default message template',
|
|
154
|
+
'settings.templateHint': 'Applies to every channel without its own template. Empty = built-in text.',
|
|
155
|
+
'settings.deliveryTimeoutMsLabel': 'Delivery timeout per channel (ms)',
|
|
156
|
+
'settings.automationSection': 'Automation models',
|
|
157
|
+
'settings.automationHint': 'Models used for the small helper calls (rule evaluation, failure analysis). Leave empty to use the task model.',
|
|
158
|
+
'settings.silentRuleModelLabel': 'Model for silent rules',
|
|
159
|
+
'settings.secretsOnCard': 'Credentials referenced from the settings panel are shown masked and stored by name.',
|
|
160
|
+
'form.nextRunLabel': 'Next run: ', 'form.notScheduled': 'not scheduled',
|
|
161
|
+
'settings.loading': 'Loading settings...',
|
|
162
|
+
'settings.unavailable': 'Settings are unavailable right now.', 'settings.retry': 'Retry',
|
|
163
|
+
'settings.cardTitle': '⏰ Task scheduler (Cron)',
|
|
164
|
+
'settings.cardDesc': 'Scheduled task execution (cron/intervals), background agent scenarios, and delivery of run reports to Telegram, Discord, Slack, ntfy, Bark, PushPlus, voice and Gitea.',
|
|
165
|
+
'settings.openPanel': 'Open task panel',
|
|
166
|
+
'settings.modalTitle': 'Notifications & delivery channels',
|
|
167
|
+
'settings.tokenLabel': 'Telegram Bot Token',
|
|
168
|
+
'settings.tokenPlaceholder': '123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ',
|
|
169
|
+
'settings.tokenPlaceholderDefault': 'Using the bot configured in DSH settings (or enter your own)',
|
|
170
|
+
'settings.defaultHint': '✓ A configured bot was found in the DSH profile',
|
|
171
|
+
'settings.chatIdLabel': 'Telegram Chat ID',
|
|
172
|
+
'settings.chatIdPlaceholder': 'For example: 345678901',
|
|
173
|
+
'settings.kanbanUrlLabel': 'Kanban Base URL',
|
|
174
|
+
'settings.globalNotify': 'Deliver reports of all tasks to Telegram globally',
|
|
175
|
+
'settings.globalOnlyFailure': 'Global mode: only on failures (silent on success)',
|
|
176
|
+
'settings.dynamicCredentials': 'Dynamic Credentials Resolution (credential://...)',
|
|
177
|
+
'settings.dynamicCredentialsHint': 'Resolve credential://... in memory from harness credentials at runtime (#335)',
|
|
178
|
+
'settings.testTelegram': '🔔 Test Telegram delivery', 'settings.testKanban': '📋 Test Kanban',
|
|
179
|
+
'settings.sending': 'Sending...', 'settings.checkingKanban': 'Checking Kanban...',
|
|
180
|
+
'settings.testOk': '✅ Test message delivered to Telegram!', 'settings.testFail': '❌ {error}',
|
|
181
|
+
'settings.kanbanOk': '✅ Kanban card created', 'settings.kanbanFail': '❌ {error}',
|
|
182
|
+
'settings.save': 'Save settings', 'settings.saved': '✓ Saved',
|
|
183
|
+
'settings.saveError': 'Save failed: {error}', 'settings.saveErrorUnknown': 'unknown error',
|
|
184
|
+
'updater.title': 'Plugin Auto-Updater', 'updater.btnCheck': 'Check for updates',
|
|
185
|
+
'updater.checking': 'Checking...', 'updater.btnUpdate': 'Update to v{version}',
|
|
186
|
+
'updater.updating': 'Updating...',
|
|
187
|
+
'updater.desc': 'Check npm registry and install plugin updates in-place without SSH access.',
|
|
188
|
+
'updater.current': 'Current version: v{version}',
|
|
189
|
+
'updater.available': 'Update available: v{version}', 'updater.upToDate': 'Up to date',
|
|
190
|
+
'updater.success': 'Successfully updated to v{version}. Please restart DSH or reload profile to apply changes.',
|
|
191
|
+
'dsh.modalTitle': 'Schedule a task with the DSH agent',
|
|
192
|
+
'dsh.descLabel': 'Describe the task and the desired frequency:',
|
|
193
|
+
'dsh.placeholder': 'For example: check free disk space and failed systemd services every 2 hours, and alert only if something is wrong...',
|
|
194
|
+
'dsh.sendHint': 'Ctrl+Enter to send', 'dsh.sendTitle': 'Send to agent',
|
|
195
|
+
'dsh.startFailed': 'Failed to start the agent dialog: {error}',
|
|
196
|
+
'dsh.launchError': 'Launch failed: {error}', 'confirm.delete': 'Delete this task?',
|
|
197
|
+
'list.loadErrorPrefix': 'Failed to load tasks', 'actions.dryRun': 'Dry run',
|
|
198
|
+
'actions.dryRunTitle': 'Dry run (test execution without side effects or notifications)',
|
|
199
|
+
'actions.archive': 'Archive', 'actions.archiveTitle': 'Execution archive and logs',
|
|
200
|
+
'dryRun.title': '🧪 Dry Run Simulation', 'dryRun.task': 'Task',
|
|
201
|
+
'dryRun.status': 'Simulation Status', 'dryRun.duration': 'Duration',
|
|
202
|
+
'dryRun.output': 'Simulated Output', 'dryRun.preflight': 'Preflight Check',
|
|
203
|
+
'dryRun.close': 'Close', 'archive.title': '📜 Execution Archive',
|
|
204
|
+
'archive.totalRuns': '{total} total runs recorded',
|
|
205
|
+
'archive.empty': 'No archived runs recorded for this task yet.',
|
|
206
|
+
'archive.loadMore': 'Load more ({shown} of {total})', 'archive.close': 'Close',
|
|
207
|
+
'form.reliabilityTitle': '🛡️ Reliability, Heartbeat & Self-Healing',
|
|
208
|
+
'form.preflightLabel': 'Pre-flight check', 'form.preflightNone': 'None',
|
|
209
|
+
'form.preflightHttp': 'HTTP (2xx probe)', 'form.preflightShell': 'Shell command (exit code 0)',
|
|
210
|
+
'form.preflightDisk': 'Disk space (path:minPercent)',
|
|
211
|
+
'form.preflightTargetLabel': 'Pre-flight target',
|
|
212
|
+
'form.preflightTargetPlaceholder': 'https://example.com/healthz OR ls /data OR /:10%',
|
|
213
|
+
'form.heartbeatIntervalLabel': 'Heartbeat deadline (seconds, 0 = disabled)',
|
|
214
|
+
'form.gracePeriodLabel': 'Heartbeat grace period (seconds)',
|
|
215
|
+
'form.priorityLabel': 'Queue priority (1-10, higher runs first)',
|
|
216
|
+
'form.concurrencyGroupLabel': 'Concurrency group',
|
|
217
|
+
'form.selfHealingLabel': 'Self-healing runbook command (shell)',
|
|
218
|
+
'form.selfHealingPlaceholder': 'systemctl restart app || true',
|
|
219
|
+
'form.autoDiagnoseLabel': 'Auto-diagnose failures with AI agent',
|
|
220
|
+
'form.agentPresetLabel': 'Agent preset',
|
|
221
|
+
'form.agentPresetPlaceholder': 'standard (leave empty for configured default)',
|
|
222
|
+
'form.agentPresetHint': 'Agent preset from dsh-agent-presets (e.g. standard, minimal, cordis, ptc). Mounts workspace and coding tools.',
|
|
223
|
+
'form.sessionTitleLabel': 'Session Title Template',
|
|
224
|
+
'form.sessionTitlePlaceholder': 'e.g. {{date}} a-share-review (supports {{date}})',
|
|
225
|
+
'form.sessionTitleHint': 'Name given to agent sessions created by this task. Supports {{date}} for YYYY-MM-DD. Defaults to "<YYYY-MM-DD> <title>".',
|
|
226
|
+
'form.targetSessionIdLabel': 'Target persistent session ID',
|
|
227
|
+
'form.targetSessionIdPlaceholder': 'e.g. audit-chat or dev-summary (empty = isolated run)',
|
|
228
|
+
'form.targetSessionIdHint': 'When specified, scheduled runs resume this session to maintain conversation context across runs instead of creating a new isolated session.',
|
|
229
|
+
'form.targetSessionResetLabel': 'Session context rotation',
|
|
230
|
+
'form.targetSessionResetNever': 'Continuous (never reset)',
|
|
231
|
+
'form.targetSessionResetDaily': 'Daily rotation (new session each day)',
|
|
232
|
+
'form.targetSessionResetWeekly': 'Weekly rotation (new session each week)',
|
|
233
|
+
'form.targetSessionResetHint': 'Automatically rotates the session identifier to prevent context window explosion over long periods.',
|
|
234
|
+
'form.requireApprovalLabel': 'Require human approval before execution',
|
|
235
|
+
'form.requireApprovalHint': 'When enabled, the task will not execute until an authorized user approves the run proposal (#318).',
|
|
236
|
+
'actions.approve': 'Approve', 'actions.reject': 'Reject',
|
|
237
|
+
'approval.waiting': 'Awaiting human approval',
|
|
238
|
+
'approval.approved': 'Approved', 'approval.rejected': 'Rejected',
|
|
239
|
+
'chainGraph.modalTitle': 'Visual Chain & Checkpoint Graph', 'chainGraph.viewGraph': 'Chain Graph',
|
|
240
|
+
'chainGraph.noNodes': 'No chained steps found for this task or run.', 'chainGraph.retryStep': 'Retry Step',
|
|
241
|
+
'chainGraph.stepSuccess': 'Success', 'chainGraph.stepFailed': 'Failed', 'chainGraph.stepPending': 'Pending', 'chainGraph.close': 'Close', 'chainGraph.decisionNode': 'Decision Node', 'chainGraph.stepSkipped': 'Skipped', 'history.doctorDiagnosis': 'Doctor Diagnosis & Suggested Fix', 'history.doctorApply': '1-Click Apply Fix', 'history.doctorRevert': 'Revert to Previous Code', 'history.autoHealed': 'Auto-Healed by Doctor', 'form.autoHealLabel': 'Autonomous Self-Healing Doctor', 'form.autoHealHint': 'Automatically diagnose and apply safe fixes upon failure (max 1 auto-patch/day)', 'form.elseTaskLabel': 'Default Fallback Task (elseTask)', 'form.elseTaskHint': 'Target task to trigger if no conditional branch rules matched', 'form.elseTaskPlaceholder': 'e.g. task-fallback',
|
|
242
|
+
'adaptive.badge': 'Adaptive', 'adaptive.idle': 'idle', 'adaptive.backoff': 'backoff',
|
|
243
|
+
'form.adaptiveEnabled': 'Adaptive Polling', 'form.adaptiveHint': 'Exponential backoff when no changes are detected',
|
|
244
|
+
'liveLog.modalTitle': 'Real-Time Streaming Execution Logs', 'liveLog.viewLog': 'Live Stream',
|
|
245
|
+
'liveLog.autoScroll': 'Auto-scroll', 'liveLog.connecting': 'Connecting to log stream...', 'liveLog.waiting': 'Waiting for runner output...', 'liveLog.completed': 'Execution stream completed', 'liveLog.close': 'Close Stream',
|
|
246
|
+
'timeline.modalTitle': '24-Hour Schedule Timeline', 'timeline.buttonLabel': 'Timeline',
|
|
247
|
+
'timeline.buttonTitle': 'View 24-hour projected schedule and concurrency timeline',
|
|
248
|
+
'timeline.tabTimeline': 'Schedule Timeline', 'timeline.legendDesc': 'Projected run distribution across 24 hourly buckets:',
|
|
249
|
+
'timeline.peakWarning': 'Peak concurrency warning',
|
|
250
|
+
'heatmap.modalTitle': 'Cost & Token Burn Heatmap', 'heatmap.buttonLabel': 'Heatmap',
|
|
251
|
+
'heatmap.tabHeatmap': 'Cost Heatmap', 'heatmap.matrixDesc': 'Weekly hour-of-day cost concentration (7 days × 24 hours):',
|
|
252
|
+
'digest.modalTitle': 'Automation & Cost Digest', 'digest.buttonLabel': 'Digest',
|
|
253
|
+
'digest.buttonTitle': 'View 7-day or 30-day automation analytics and cost digest',
|
|
254
|
+
'digest.period7': 'Last 7 Days', 'digest.period30': 'Last 30 Days',
|
|
255
|
+
'digest.executions': 'Executions', 'digest.tokens': 'Tokens', 'digest.cost': 'Cost (USD)', 'digest.fleet': 'Automations',
|
|
256
|
+
'digest.unstableTitle': 'Top Unstable Automations', 'digest.expensiveTitle': 'Top Resource Consumers',
|
|
257
|
+
'digest.sendTelegram': 'Send to Telegram', 'digest.copyMarkdown': 'Copy Markdown', 'digest.copied': 'Copied!',
|
|
258
|
+
'digest.sentSuccess': 'Sent to Telegram successfully!',
|
|
259
|
+
'prompt.version': 'Prompt Version', 'prompt.rollback': 'Restore v', 'prompt.history': 'Prompt History', 'prompt.successRate': 'SR',
|
|
260
|
+
|
|
261
|
+
'form.chainingTitle': 'Chaining & DAG Orchestration', 'form.onSuccessLabel': 'On Success Trigger (Task IDs)',
|
|
262
|
+
'form.onSuccessHint': 'Comma-separated task IDs to execute upon success (Fan-Out)',
|
|
263
|
+
'form.onFailureLabel': 'On Failure Trigger (Task IDs)', 'form.onFailureHint': 'Comma-separated task IDs to execute upon failure',
|
|
264
|
+
'form.dependsOnLabel': 'Dependencies (dependsOn)', 'form.dependsOnHint': 'Wait for these task IDs before executing (Fan-In barrier)',
|
|
265
|
+
'form.joinPolicyLabel': 'Join Policy', 'form.joinPolicyAll': 'All Prerequisites (all_success)', 'form.joinPolicyAny': 'Any Prerequisite (any_success)',
|
|
266
|
+
'recipe.dependenciesMissing': 'Missing required integrations or credentials',
|
|
267
|
+
'form.previewSchedule': 'Preview next runs',
|
|
268
|
+
'form.previewScheduleTitle': 'Next 5 scheduled runs:',
|
|
269
|
+
},
|
|
270
|
+
zh: {
|
|
271
|
+
'sidebar.label': '定时任务', 'sidebar.jobsTitle': '运行中任务',
|
|
272
|
+
'sidebar.noActiveJobs': '无运行中任务', 'sidebar.moreJobs': '及另外 {count} 个',
|
|
273
|
+
'chip.title': '定时任务 (Cron)', 'panel.back': '返回对话',
|
|
274
|
+
'panel.title': '定时任务', 'panel.subtitle': '让 DSH 规划任务、设置提醒或跟踪状态',
|
|
275
|
+
'actions.create': '新建', 'actions.createWithDsh': '💬 让 DSH 创建',
|
|
276
|
+
'actions.setupManually': '✏️ 手动配置', 'actions.runNow': '立即运行',
|
|
277
|
+
'actions.runNowShort': '运行', 'actions.edit': '编辑 / 详情',
|
|
278
|
+
'actions.duplicate': '复制任务', 'actions.tuneWithDsh': '让 DSH 优化',
|
|
279
|
+
'tune.startFailed': '无法启动优化会话: {error}', 'actions.delete': '删除任务',
|
|
280
|
+
'duplicate.done': '已创建副本并处于暂停状态:恢复前请先核对调度时间。', 'duplicate.oneShotHint': '该副本为一次性任务且已暂停,请设定新的执行时间后再启用。',
|
|
281
|
+
'duplicate.failed': '复制任务失败: {error}', 'transfer.exportTitle': '导出任务',
|
|
282
|
+
'transfer.importTitle': '导入任务', 'transfer.exported': '已成功导出 {count} 个任务。',
|
|
283
|
+
'transfer.exportFailed': '导出失败: {error}', 'transfer.importTitleModal': '导入任务',
|
|
284
|
+
'transfer.importHint': '仅导出任务静态配置:不包含历史记录与计数器。渠道通过凭据名称引用;注意完整导出保留自定义环境变量和 HTTP 请求头。', 'transfer.exportPrompt': '选择导出模式:\n确定 = 净化导出(移除自定义环境变量与请求头)\n取消 = 完整原始导出',
|
|
285
|
+
'transfer.strategyAdd': '作为新任务导入(分配新 ID)', 'transfer.strategyReplace': '覆盖同 ID 任务',
|
|
286
|
+
'transfer.strategySkip': '跳过已存在的同 ID 任务', 'transfer.summary': '该文件包含 {total} 个任务:{add} 个新增,{replace} 个覆盖,{skip} 个跳过。',
|
|
287
|
+
'transfer.confirm': '开始导入', 'transfer.imported': '已成功导入 {count} 个任务。',
|
|
288
|
+
'transfer.importFailed': '导入失败: {error}', 'transfer.badFile': '所选文件不是有效的 JSON 导出文件: {error}',
|
|
289
|
+
'actions.pause': '暂停', 'actions.resume': '恢复',
|
|
290
|
+
'actions.settings': '通知与渠道设置', 'search.placeholder': '搜索定时任务',
|
|
291
|
+
'filters.title': '筛选', 'filters.type': '类型',
|
|
292
|
+
'filters.model': '模型', 'filters.channel': '渠道',
|
|
293
|
+
'filters.any': '全部', 'filters.reset': '重置筛选',
|
|
294
|
+
'filters.empty': '没有匹配当前筛选条件的任务。', 'filters.showing': '显示 {shown} / 共 {total}',
|
|
295
|
+
'stats.activeTasks': '活跃任务', 'stats.totalRuns': '总运行次数',
|
|
296
|
+
'stats.totalTokens': '消耗 Token', 'stats.totalCost': '预估成本',
|
|
297
|
+
'tabs.all': '全部', 'tabs.active': '运行中',
|
|
298
|
+
'tabs.paused': '已暂停', 'tabs.completed': '已完成',
|
|
299
|
+
'banner.loadError': '加载任务失败: {error}', 'banner.retry': '重试',
|
|
300
|
+
'list.loading': '正在加载定时任务...', 'list.empty': '暂无定时任务',
|
|
301
|
+
'list.typeShell': 'Shell 脚本', 'list.typeLlm': 'LLM 智能体',
|
|
302
|
+
'list.oneShot': '一次性', 'list.configManaged': '配置只读',
|
|
303
|
+
'list.configManagedHint': '由配置文件中的 config.jobs 声明;要修改或删除请编辑该文件', 'list.next': ' · 下次: {time}',
|
|
304
|
+
'recs.title': '推荐任务', 'recs.hint': '开箱即用的配方。点一下就会把表单填好——保存之前不会创建任何任务。',
|
|
305
|
+
'modal.editTitle': '编辑任务', 'modal.newTitle': '新建定时任务',
|
|
306
|
+
'modal.statusActive': '活跃', 'modal.statusPaused': '已暂停',
|
|
307
|
+
'modal.params': '配置参数', 'modal.history': '运行历史 ({count})',
|
|
308
|
+
'modal.cancel': '取消', 'modal.confirmDiscard': '放弃未保存的内容?',
|
|
309
|
+
'modal.save': '保存修改', 'modal.create': '创建任务',
|
|
310
|
+
'modal.close': '关闭', 'history.loading': '正在加载历史记录...',
|
|
311
|
+
'history.empty': '暂无运行记录', 'history.stoppedReasonTitle': '停止原因:',
|
|
312
|
+
'history.retryDelivery': '重试推送', 'history.retryingDelivery': '正在重试...',
|
|
313
|
+
'history.statusValidationFailed': '校验失败', 'history.stage_queue': '排队',
|
|
314
|
+
'history.stage_preflight': '预检', 'history.stage_execution': '执行',
|
|
315
|
+
'history.stage_validation': '校验', 'history.stage_delivery': '推送',
|
|
316
|
+
'history.refresh': '刷新历史', 'history.statusSuccess': '成功',
|
|
317
|
+
'history.statusUncertain': '不确定', 'history.artifacts': '产物文件',
|
|
318
|
+
'history.resolveCompleted': '标记已完成', 'history.resolveFailed': '标记失败',
|
|
319
|
+
'history.statusUncertainHint': '服务重启中断 — 请确认结果', 'history.statusSkipped': '已跳过',
|
|
320
|
+
'history.statusMissed': '已错过', 'history.statusTimeout': '超时',
|
|
321
|
+
'history.statusFailed': '失败', 'form.nameLabel': '任务名称',
|
|
322
|
+
'form.namePlaceholder': '例如: dsh-tags-watch', 'form.typeLabel': '执行类型 *',
|
|
323
|
+
'form.typeLlm': 'LLM(AI 智能体)', 'form.typeScript': 'Shell 命令 / 脚本',
|
|
324
|
+
'form.typeNode': 'Node.js', 'form.typePython': 'Python',
|
|
325
|
+
'form.typeHttp': 'HTTP 请求 / Webhook', 'form.typeSsh': '远程 SSH',
|
|
326
|
+
'form.typeDocker': 'Docker 容器', 'form.typeSkill': 'DSH 技能',
|
|
327
|
+
'form.typeWorkflow': 'DSH 工作流', 'form.envLabel': '环境变量 (KEY=VALUE, 每行一个)',
|
|
328
|
+
'form.envPlaceholder': 'NODE_ENV=production\nTZ=Europe/Berlin', 'form.envHint': '仅对非 LLM 运行时生效。不要在这里存放密钥。',
|
|
329
|
+
'form.cwdLabel': '工作目录 (绝对路径)', 'form.workspaceLabel': '工作区 ID 或路径(可选)',
|
|
330
|
+
'form.worktreeLabel': '在独立的临时 Git Worktree 中执行', 'form.keepWorktreeLabel': '执行结束后保留 Git Worktree (不自动清理)',
|
|
331
|
+
'form.httpMethodLabel': 'HTTP 方法', 'form.httpUrlLabel': 'URL',
|
|
332
|
+
'form.httpHeadersLabel': '请求头(JSON,可选)', 'form.httpBodyLabel': '请求体(可选)',
|
|
333
|
+
'form.sshProfileLabel': 'dsh-remote-workspace 配置 ID', 'form.sshProfileHint': '推荐用法:主机与凭据都放在 remote-workspace 插件里。',
|
|
334
|
+
'form.sshTargetLabel': '备用目标(user@host,可选)', 'form.sshKeyLabel': '私钥路径(备用,可选)',
|
|
335
|
+
'form.dockerImageLabel': '容器镜像', 'form.skillNameLabel': '技能名称',
|
|
336
|
+
'form.workflowNameLabel': '工作流名称', 'form.scheduleLabel': '调度计划 (Cron 或相对时间) *',
|
|
337
|
+
'form.schedulePlaceholder': '例如: 0 9 * * 1-5 或 15m 或 in 2 hours', 'form.timeoutLabel': '超时时间 (秒)',
|
|
338
|
+
'form.overlapLabel': '并发策略', 'form.overlapSkip': '跳过 (默认)',
|
|
339
|
+
'form.overlapQueue': '排队等待', 'form.overlapReplace': '取消当前运行并重新开始 (replace)',
|
|
340
|
+
'form.kanbanLabel': '看板同步模式', 'form.kanbanNone': '不同步到看板',
|
|
341
|
+
'form.kanbanOnFailure': '失败时创建工单(进 Backlog)', 'form.kanbanAlways': '每次完成都建卡片(Done / Backlog)',
|
|
342
|
+
'form.providerLabel': 'LLM 服务商', 'form.providerDefault': '默认(DSH)',
|
|
343
|
+
'form.modelLabel': 'AI 模型', 'form.modelDefault': '默认模型',
|
|
344
|
+
'form.silentRuleLabel': '静默规则 (可选)', 'form.silentRulePlaceholder': '例如: ALL_OK 或 status == 200',
|
|
345
|
+
'form.silentRuleHint': '若输出符合此规则,将不发送任何通知。', 'history.silentSkip': '保持静默:',
|
|
346
|
+
'history.diagnosis': '诊断', 'history.applySuggestion': '用这条建议打开编辑表单',
|
|
347
|
+
'form.inspectOnFailureLabel': '用模型诊断失败原因', 'form.inspectOnFailureHint': '运行失败后,由模型读一遍提示词、错误和输出,把诊断结论和修改建议随这次运行一起保存。不会自动应用任何改动。',
|
|
348
|
+
'settings.inspectorModelLabel': '失败诊断模型', 'form.fallbackModelLabel': '备用模型 (主模型失败时使用)',
|
|
349
|
+
'form.fallbackModelPlaceholder': '例如: deepseek-reasoner', 'form.fallbackModelHint': '主模型运行失败时,用这个模型再试一次。两次尝试都计入成本。',
|
|
350
|
+
'form.promptLabelScript': 'Shell 命令或脚本', 'form.promptLabelLlm': '给智能体的指令 / 提示词',
|
|
351
|
+
'form.promptPlaceholderScript': 'curl -fsSL https://... || exit 1', 'form.promptPlaceholderLlm': '精确描述智能体要做什么...',
|
|
352
|
+
'form.timezoneLabel': '时区 (IANA 时区名)', 'form.timezonePlaceholder': '例如: Asia/Shanghai 或 UTC (留空使用服务器时区)',
|
|
353
|
+
'form.misfireLabel': '错过执行策略 (Misfire Policy)', 'form.misfireSkip': '跳过 (默认)',
|
|
354
|
+
'form.misfireRunOnce': '补跑一次', 'form.misfireCatchUp': '迟到时补跑一次并记录缺口 (catchUpAll)',
|
|
355
|
+
'form.retriesLabel': '失败自动重试次数(0 = 关闭)', 'form.permissionLabel': '会话权限',
|
|
356
|
+
'form.permissionDefault': '默认 (继承主配置)', 'form.permissionReadonly': '只读',
|
|
357
|
+
'form.permissionWrite': '工作区写入', 'form.permissionFull': '完全访问权限',
|
|
358
|
+
'list.runningNow': '正在运行', 'history.openSession': '打开会话',
|
|
359
|
+
'form.notifyTitle': 'Telegram 通知', 'form.notifyTelegram': '把运行报告发送到 Telegram',
|
|
360
|
+
'form.notifyOnlyFailure': '仅失败时发送(onlyOnFailure / 成功静默)', 'form.channelsTitle': '推送渠道',
|
|
361
|
+
'form.channelsHint': '任务执行完毕后推送报告的目标渠道。', 'form.templateLabel': '自定义消息模板',
|
|
362
|
+
'form.templatePlaceholder': '⏰ {title} — {status},耗时 {duration}', 'form.templateHint': '可用变量: {title} {id} {status} {output} {error} {duration} {schedule} {time} {tokens} {cost} {model}。留空使用内置文案。',
|
|
363
|
+
'form.channelTelegram': 'Telegram', 'form.channelKanban': 'dsh-kanban 卡片',
|
|
364
|
+
'form.channelDiscord': 'Discord', 'form.channelSlack': 'Slack',
|
|
365
|
+
'form.channelNtfy': 'ntfy', 'form.channelBark': 'Bark',
|
|
366
|
+
'form.channelPushplus': 'PushPlus', 'form.channelTts': '语音(dsh-tts)',
|
|
367
|
+
'form.channelGitea': 'Gitea Issue', 'settings.deliverySection': '推送渠道',
|
|
368
|
+
'settings.secretsSection': '凭据(引用)', 'settings.secretsHint': '这里填 DSH 凭据的「名称」,不是密钥本身。密钥保存在凭据服务里。',
|
|
369
|
+
'settings.telegramSection': 'Telegram', 'settings.templatesSection': '消息模板',
|
|
370
|
+
'settings.channelTemplateLabel': '{channel} 的消息模板', 'settings.botTokenRefLabel': 'Bot Token 凭据名称',
|
|
371
|
+
'settings.botTokenRefPlaceholder': '例如: TELEGRAM_BOT_TOKEN', 'settings.apiTokenLabel': '外部 API Token',
|
|
372
|
+
'settings.apiTokenPlaceholder': '用于 /dsh-cron/api/* 的 Bearer token(留空 = 关闭)', 'settings.discordLabel': 'Discord Webhook URL',
|
|
373
|
+
'settings.slackLabel': 'Slack Webhook URL', 'settings.ntfyUrlLabel': 'ntfy 服务器地址',
|
|
374
|
+
'settings.ntfyTopicLabel': 'ntfy 主题', 'settings.ntfyTokenRefLabel': 'ntfy Token 凭据名称',
|
|
375
|
+
'settings.barkServerLabel': 'Bark 服务器地址', 'settings.barkKeyLabel': 'Bark 设备 Key',
|
|
376
|
+
'settings.pushplusTokenRefLabel': 'PushPlus Token 凭据名称', 'settings.pushplusUrlLabel': 'PushPlus 接口地址',
|
|
377
|
+
'settings.ttsBaseUrlLabel': 'dsh-tts 服务地址', 'settings.giteaBaseUrlLabel': 'Gitea 服务地址',
|
|
378
|
+
'settings.giteaRepoLabel': 'Gitea 仓库(owner/repo)', 'settings.giteaTokenRefLabel': 'Gitea Token 凭据名称',
|
|
379
|
+
'settings.templateLabel': '默认消息模板', 'settings.templateHint': '作用于所有没有单独模板的渠道。留空用内置文案。',
|
|
380
|
+
'settings.deliveryTimeoutMsLabel': '每个渠道的推送超时(毫秒)', 'settings.automationSection': '自动化模型',
|
|
381
|
+
'settings.automationHint': '用于静默规则研判和故障诊断的辅助模型。留空沿用任务自身模型。', 'settings.silentRuleModelLabel': '静默规则研判模型',
|
|
382
|
+
'settings.secretsOnCard': '设置中引用的凭据将在前端脱敏展示,并通过名称引用。', 'form.nextRunLabel': '下次执行: ',
|
|
383
|
+
'form.notScheduled': '未安排计划', 'settings.loading': '正在加载设置...',
|
|
384
|
+
'settings.unavailable': '设置当前不可用。', 'settings.retry': '重试',
|
|
385
|
+
'settings.cardTitle': '⏰ 定时任务调度器 (Cron)', 'settings.cardDesc': '定时计划任务(Cron/间隔)、后台智能体场景以及支持 Telegram、Discord、Slack、ntfy、Bark、PushPlus、语音和 Gitea 的通知推送。',
|
|
386
|
+
'settings.openPanel': '打开任务管理看板', 'settings.modalTitle': '通知与渠道设置',
|
|
387
|
+
'settings.tokenLabel': 'Telegram Bot Token', 'settings.tokenPlaceholder': '123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ',
|
|
388
|
+
'settings.tokenPlaceholderDefault': '使用 DSH 全局配置的机器人 (或在此输入自定义 Token)', 'settings.defaultHint': '✓ 检测到 DSH 环境已配置默认 Bot',
|
|
389
|
+
'settings.chatIdLabel': 'Telegram Chat ID', 'settings.chatIdPlaceholder': '例如: 345678901',
|
|
390
|
+
'settings.kanbanUrlLabel': 'Kanban 服务基础地址', 'settings.globalNotify': '全局开启所有任务结果推送至 Telegram',
|
|
391
|
+
'settings.globalOnlyFailure': '全局模式:仅在失败时推送 (成功静默)', 'settings.dynamicCredentials': '动态凭据解析 (credential://...)',
|
|
392
|
+
'settings.dynamicCredentialsHint': '运行时从凭据服务动态解析 credential://... 且不泄露到存储 (#335)', 'settings.testTelegram': '🔔 测试 Telegram 发送',
|
|
393
|
+
'settings.testKanban': '📋 测试 Kanban', 'settings.sending': '正在发送...',
|
|
394
|
+
'settings.checkingKanban': '正在连接 Kanban...', 'settings.testOk': '✅ 测试消息已成功发送至 Telegram!',
|
|
395
|
+
'settings.testFail': '❌ 发送失败: {error}', 'settings.kanbanOk': '✅ Kanban 卡片创建成功',
|
|
396
|
+
'settings.kanbanFail': '❌ {error}', 'settings.save': '保存设置',
|
|
397
|
+
'settings.saved': '✓ 已保存', 'settings.saveError': '保存失败: {error}',
|
|
398
|
+
'settings.saveErrorUnknown': '未知错误', 'updater.title': '插件自更新',
|
|
399
|
+
'updater.btnCheck': '检查更新', 'updater.checking': '正在检查...',
|
|
400
|
+
'updater.btnUpdate': '升级至 v{version}', 'updater.updating': '正在更新...',
|
|
401
|
+
'updater.desc': '通过 npm 仓库在线检查并就地升级插件,无需 SSH 终端操作。', 'updater.current': '当前版本: v{version}',
|
|
402
|
+
'updater.available': '发现新版本: v{version}', 'updater.upToDate': '已是最新版本',
|
|
403
|
+
'updater.success': '已成功升级至 v{version}。请重启 DSH 或重载配置以应用更新。', 'dsh.modalTitle': '让 DSH 智能体创建任务',
|
|
404
|
+
'dsh.descLabel': '请描述你的任务目标和执行频率:', 'dsh.placeholder': '例如: 每两小时检查一次磁盘空间和失败的 systemd 守护进程,并在异常时报警...',
|
|
405
|
+
'dsh.sendHint': '按 Ctrl+Enter 发送', 'dsh.sendTitle': '提交给智能体',
|
|
406
|
+
'dsh.startFailed': '启动智能体对话失败: {error}', 'dsh.launchError': '执行错误: {error}',
|
|
407
|
+
'confirm.delete': '确定删除该任务吗?', 'list.loadErrorPrefix': '加载任务列表失败',
|
|
408
|
+
'actions.dryRun': '空跑测试', 'actions.dryRunTitle': '空跑测试(模拟执行,不产生副作用且不发送通知)',
|
|
409
|
+
'actions.archive': '历史归档', 'actions.archiveTitle': '查看执行历史与日志归档',
|
|
410
|
+
'dryRun.title': '🧪 空跑模拟结果', 'dryRun.task': '任务',
|
|
411
|
+
'dryRun.status': '模拟状态', 'dryRun.duration': '耗时',
|
|
412
|
+
'dryRun.output': '模拟输出', 'dryRun.preflight': '预检结果',
|
|
413
|
+
'dryRun.close': '关闭', 'archive.title': '📜 运行历史归档',
|
|
414
|
+
'archive.totalRuns': '共记录 {total} 次运行', 'archive.empty': '该任务暂无历史运行归档。',
|
|
415
|
+
'archive.loadMore': '加载更多 ({shown} / {total})', 'archive.close': '关闭',
|
|
416
|
+
'form.reliabilityTitle': '🛡️ 可靠性、心跳监听与自愈', 'form.preflightLabel': '预检健康探测',
|
|
417
|
+
'form.preflightNone': '无', 'form.preflightHttp': 'HTTP (2xx 探测)',
|
|
418
|
+
'form.preflightShell': 'Shell 探测 (退出码 0)', 'form.preflightDisk': '磁盘空间探测 (挂载点:最小百分比)',
|
|
419
|
+
'form.preflightTargetLabel': '预检目标参数', 'form.preflightTargetPlaceholder': 'https://example.com/healthz 或 ls /data 或 /:10%',
|
|
420
|
+
'form.heartbeatIntervalLabel': '心跳打卡时限 (秒, 0 = 禁用)', 'form.gracePeriodLabel': '心跳宽限期 (秒)',
|
|
421
|
+
'form.priorityLabel': '队列优先级 (1-10,数值越大越先执行)', 'form.concurrencyGroupLabel': '并发分组名称',
|
|
422
|
+
'form.selfHealingLabel': '故障自愈脚本 (Shell)', 'form.selfHealingPlaceholder': 'systemctl restart app || true',
|
|
423
|
+
'form.autoDiagnoseLabel': '任务失败时启用 AI 智能分析诊断', 'form.agentPresetLabel': '智能体预设 (Agent Preset)',
|
|
424
|
+
'form.agentPresetPlaceholder': 'standard (留空使用全局默认预设)', 'form.agentPresetHint': '来自 dsh-agent-presets 的智能体预设(如 standard, minimal, cordis, ptc),挂载工作区工具与文件读写能力。',
|
|
425
|
+
'form.sessionTitleLabel': '会话标题模板 (Session Title)', 'form.sessionTitlePlaceholder': '如 {{date}} 市场早报 (支持 {{date}} 变量)',
|
|
426
|
+
'form.sessionTitleHint': '此任务运行生成的会话标题。支持 {{date}} (年-月-日)。留空默认为 "<YYYY-MM-DD> <任务名>"。', 'form.targetSessionIdLabel': '目标常驻会话 ID (Target Session ID)',
|
|
427
|
+
'form.targetSessionIdPlaceholder': '如 audit-chat 或 dev-summary(留空为单次隔离运行)', 'form.targetSessionIdHint': '配置后定时任务将在此常驻会话中持续交互,跨周期保留历史上下文对话记忆,不再每次新建孤立会话。',
|
|
428
|
+
'form.targetSessionResetLabel': '上下文轮转策略 (Session Rotation)', 'form.targetSessionResetNever': '永不轮转(单一会话持续累积)',
|
|
429
|
+
'form.targetSessionResetDaily': '每日轮转(每日自动开启新会话)', 'form.targetSessionResetWeekly': '每周轮转(每周自动开启新会话)',
|
|
430
|
+
'form.targetSessionResetHint': '自动按周期加注日期后缀轮转会话,有效防止长时间运行导致的模型上下文窗口超限与 Token 浪费。', 'form.requireApprovalLabel': '执行前需人工确认审批',
|
|
431
|
+
'form.requireApprovalHint': '开启后,任务执行前将挂起并等待授权用户批准提议 (#318)。', 'actions.approve': '批准',
|
|
432
|
+
'actions.reject': '拒绝', 'approval.waiting': '等待人工审批',
|
|
433
|
+
'approval.approved': '已批准', 'approval.rejected': '已拒绝',
|
|
434
|
+
'chainGraph.modalTitle': '任务链与检查点依赖图', 'chainGraph.viewGraph': '任务链图',
|
|
435
|
+
'chainGraph.noNodes': '未找到该任务或运行的关联步骤。', 'chainGraph.retryStep': '重试此步骤',
|
|
436
|
+
'chainGraph.stepSuccess': '成功', 'chainGraph.stepFailed': '失败',
|
|
437
|
+
'chainGraph.stepPending': '等待中', 'chainGraph.close': '关闭',
|
|
438
|
+
'chainGraph.decisionNode': '条件决策节点', 'chainGraph.stepSkipped': '已跳过',
|
|
439
|
+
'history.doctorDiagnosis': 'Doctor 诊断与建议修复', 'history.doctorApply': '一键应用修复',
|
|
440
|
+
'history.doctorRevert': '恢复上一版本代码', 'history.autoHealed': '已由 Doctor 自动修复',
|
|
441
|
+
'form.autoHealLabel': '自主 Self-Healing Doctor 自动修复', 'form.autoHealHint': '当任务失败时自动诊断并安全修复(每天上限 1 次)',
|
|
442
|
+
'form.elseTaskLabel': '默认后备任务 (elseTask)', 'form.elseTaskHint': '当没有分支条件匹配时触发的目标任务',
|
|
443
|
+
'form.elseTaskPlaceholder': '如 task-fallback', 'adaptive.badge': '自适应',
|
|
444
|
+
'adaptive.idle': '空闲', 'adaptive.backoff': '避让中',
|
|
445
|
+
'form.adaptiveEnabled': '自适应轮询 (Adaptive Polling)', 'form.adaptiveHint': '数据无变化时指数级延长执行间隔',
|
|
446
|
+
'liveLog.modalTitle': '实时任务执行日志流', 'liveLog.viewLog': '实时日志',
|
|
447
|
+
'liveLog.autoScroll': '自动滚动', 'liveLog.connecting': '正在连接日志流...',
|
|
448
|
+
'liveLog.waiting': '等待运行器输出...', 'liveLog.completed': '日志流已结束',
|
|
449
|
+
'liveLog.close': '关闭日志流', 'timeline.modalTitle': '24小时调度时间线',
|
|
450
|
+
'timeline.buttonLabel': '时间线', 'timeline.buttonTitle': '查看24小时预测任务调度与并发时间线',
|
|
451
|
+
'timeline.tabTimeline': '调度时间线', 'timeline.legendDesc': '未来24小时各时段任务预计执行分布:',
|
|
452
|
+
'timeline.peakWarning': '并发峰值预警', 'heatmap.modalTitle': '成本与Token消耗热力图',
|
|
453
|
+
'heatmap.buttonLabel': '热力图', 'heatmap.tabHeatmap': '成本热力图',
|
|
454
|
+
'heatmap.matrixDesc': '每周各时段成本分布矩阵(7天 × 24小时):', 'digest.modalTitle': '自动化与成本分析摘要',
|
|
455
|
+
'digest.buttonLabel': '分析摘要', 'digest.buttonTitle': '查看 7 天或 30 天运行统计与花费摘要',
|
|
456
|
+
'digest.period7': '最近 7 天', 'digest.period30': '最近 30 天',
|
|
457
|
+
'digest.executions': '执行次数', 'digest.tokens': 'Token 消耗',
|
|
458
|
+
'digest.cost': '花费 (USD)', 'digest.fleet': '任务总览',
|
|
459
|
+
'digest.unstableTitle': '最不稳定任务排行', 'digest.expensiveTitle': '资源消耗排行',
|
|
460
|
+
'digest.sendTelegram': '发送至 Telegram', 'digest.copyMarkdown': '复制 Markdown',
|
|
461
|
+
'digest.copied': '已复制!', 'digest.sentSuccess': '已成功发送至 Telegram!',
|
|
462
|
+
'prompt.version': '提示词版本', 'prompt.rollback': '回退至 v',
|
|
463
|
+
'prompt.history': '提示词历史', 'prompt.successRate': '成功率',
|
|
464
|
+
'form.chainingTitle': '任务链与 DAG 编排', 'form.onSuccessLabel': '成功后触发 (任务 ID)',
|
|
465
|
+
'form.onSuccessHint': '成功后并发触发的任务 ID,逗号分隔 (Fan-Out)', 'form.onFailureLabel': '失败后触发 (任务 ID)',
|
|
466
|
+
'form.onFailureHint': '失败后触发的任务 ID,逗号分隔', 'form.dependsOnLabel': '依赖任务 (dependsOn)',
|
|
467
|
+
'form.dependsOnHint': '执行前需等待的前置任务 ID,逗号分隔 (Fan-In)', 'form.joinPolicyLabel': '合并策略',
|
|
468
|
+
'form.joinPolicyAll': '所有前置均成功 (all_success)', 'form.joinPolicyAny': '任一前置成功即可 (any_success)',
|
|
469
|
+
'recipe.dependenciesMissing': '缺少必要集成服务或凭据', 'form.previewSchedule': '预测下次运行时间',
|
|
470
|
+
'form.previewScheduleTitle': '未来 5 次计划运行时间:',
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
let translate = (key, vars) => {
|
|
475
|
+
let s = (STRINGS.en && STRINGS.en[key]) || key;
|
|
476
|
+
if (vars) {
|
|
477
|
+
for (const k of Object.keys(vars)) {
|
|
478
|
+
s = s.split('{' + k + '}').join(String(vars[k]));
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
return s;
|
|
482
|
+
};
|
|
483
|
+
const T = (key, vars) => translate(key, vars);
|
|
484
|
+
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
const STYLE_ID = 'dsh-cron-styles';
|
|
2
|
+
const CSS_HREF = '/dsh-cron/client.css';
|
|
3
|
+
|
|
4
|
+
function ensureStyles() {
|
|
5
|
+
if (typeof document === 'undefined') return null;
|
|
6
|
+
let el = document.getElementById(STYLE_ID);
|
|
7
|
+
if (el === null) {
|
|
8
|
+
const head = document.head || document.documentElement;
|
|
9
|
+
if (!head) return null;
|
|
10
|
+
el = document.createElement('link');
|
|
11
|
+
el.id = STYLE_ID;
|
|
12
|
+
el.rel = 'stylesheet';
|
|
13
|
+
el.href = CSS_HREF;
|
|
14
|
+
// Mark ownership before insertion so neighbor cleanups leave it alone (#91)
|
|
15
|
+
el.dataset.dshPlugin = 'dsh-cron';
|
|
16
|
+
head.appendChild(el);
|
|
17
|
+
return el;
|
|
18
|
+
}
|
|
19
|
+
if (el.getAttribute('href') !== CSS_HREF) {
|
|
20
|
+
el.setAttribute('href', CSS_HREF);
|
|
21
|
+
el.href = CSS_HREF;
|
|
22
|
+
}
|
|
23
|
+
return el;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Registry is shared across hot reloads so the newest instance owns exactly
|
|
27
|
+
// one watcher instead of stacking one per module evaluation.
|
|
28
|
+
const STYLE_HEAL_KEY = '__dshCronStyleHeal';
|
|
29
|
+
const STYLE_HEAL_INTERVAL_MS = 2000;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Keep the stylesheet attached: watch <head> (and <html>, which catches a
|
|
33
|
+
* replaced <head>) and re-attach on demand, with a slow interval as the
|
|
34
|
+
* backstop. heal() is idempotent and writes nothing while healthy.
|
|
35
|
+
*/
|
|
36
|
+
function startStyleSelfHeal() {
|
|
37
|
+
if (typeof document === 'undefined') return () => {};
|
|
38
|
+
if (typeof window !== 'undefined' && typeof window[STYLE_HEAL_KEY] === 'function') {
|
|
39
|
+
try { window[STYLE_HEAL_KEY](); } catch (_err) { void _err; }
|
|
40
|
+
}
|
|
41
|
+
const heal = () => { try { ensureStyles(); } catch (_err) { void _err; } };
|
|
42
|
+
heal();
|
|
43
|
+
let observer = null;
|
|
44
|
+
try {
|
|
45
|
+
if (typeof MutationObserver === 'function') {
|
|
46
|
+
observer = new MutationObserver(heal);
|
|
47
|
+
if (document.head) observer.observe(document.head, { childList: true });
|
|
48
|
+
if (document.documentElement) observer.observe(document.documentElement, { childList: true });
|
|
49
|
+
}
|
|
50
|
+
} catch (_err) { observer = null; }
|
|
51
|
+
let timer = null;
|
|
52
|
+
try { timer = setInterval(heal, STYLE_HEAL_INTERVAL_MS); } catch (_err) { timer = null; }
|
|
53
|
+
const onVisibility = () => { if (document.visibilityState !== 'hidden') heal(); };
|
|
54
|
+
try { document.addEventListener('visibilitychange', onVisibility); } catch (_err) { void _err; }
|
|
55
|
+
const stop = () => {
|
|
56
|
+
try { if (observer) observer.disconnect(); } catch (_err) { void _err; }
|
|
57
|
+
try { if (timer !== null) clearInterval(timer); } catch (_err) { void _err; }
|
|
58
|
+
try { document.removeEventListener('visibilitychange', onVisibility); } catch (_err) { void _err; }
|
|
59
|
+
if (typeof window !== 'undefined' && window[STYLE_HEAL_KEY] === stop) window[STYLE_HEAL_KEY] = undefined;
|
|
60
|
+
};
|
|
61
|
+
if (typeof window !== 'undefined') window[STYLE_HEAL_KEY] = stop;
|
|
62
|
+
return stop;
|
|
63
|
+
}
|
|
64
|
+
|