@goodandready/dsh-cron 0.2.49 → 0.2.50
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.js +2 -2
- package/lib/client.js +166 -18
- package/lib/cron-tool.js +1 -1
- package/lib/task-create.js +2 -2
- package/lib/task-patch.js +5 -1
- package/package.json +1 -1
package/lib/api.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { randomUUID, createHash } from 'node:crypto';
|
|
9
9
|
import { parseScheduleExpression } from './scheduler.js';
|
|
10
|
-
import { normalizeTaskType, CODE_EXECUTING_TYPES } from './runtimes.js';
|
|
10
|
+
import { normalizeTaskType, CODE_EXECUTING_TYPES, EXTERNAL_RUNTIMES } from './runtimes.js';
|
|
11
11
|
import { CHANNEL_IDS, unknownChannelIds } from './channels.js';
|
|
12
12
|
import { applyTaskPatch } from './task-patch.js';
|
|
13
13
|
import { MANAGED_BY_CONFIG, configOwnedMessage } from './config-jobs.js';
|
|
@@ -265,7 +265,7 @@ function buildTaskRecord(store, body, taskType, parsed) {
|
|
|
265
265
|
misfirePolicy: ['skip', 'runOnce', 'catchUpAll'].includes(body.misfirePolicy) ? body.misfirePolicy : (current ? (current.misfirePolicy || 'skip') : 'skip'),
|
|
266
266
|
maxRetries: body.maxRetries !== undefined ? Math.max(0, Number(body.maxRetries) || 0) : (current ? (Number(current.maxRetries) || 0) : 0),
|
|
267
267
|
retryBackoffMs: body.retryBackoffMs !== undefined ? Math.max(1000, Number(body.retryBackoffMs) || 30000) : (current ? (Number(current.retryBackoffMs) || 30000) : 30000),
|
|
268
|
-
permissionPreset: ['default', 'read-only', 'workspace-write', 'full'].includes(body.permissionPreset) ? body.permissionPreset : (current ? (current.permissionPreset || 'default') : 'default'),
|
|
268
|
+
permissionPreset: !EXTERNAL_RUNTIMES.includes(taskType) && ['default', 'read-only', 'workspace-write', 'full'].includes(body.permissionPreset) ? body.permissionPreset : (current && !EXTERNAL_RUNTIMES.includes(taskType) ? (current.permissionPreset || 'default') : 'default'),
|
|
269
269
|
...mergeExecutionFields(current, body, parsed),
|
|
270
270
|
};
|
|
271
271
|
}
|
package/lib/client.js
CHANGED
|
@@ -137,6 +137,7 @@ window.__ModuleLoader__.load({
|
|
|
137
137
|
'modal.params': 'Parameters',
|
|
138
138
|
'modal.history': 'Run history ({count})',
|
|
139
139
|
'modal.cancel': 'Cancel',
|
|
140
|
+
'modal.confirmDiscard': 'Discard unsaved changes?',
|
|
140
141
|
'modal.save': 'Save changes',
|
|
141
142
|
'modal.create': 'Create task',
|
|
142
143
|
'modal.close': 'Close',
|
|
@@ -492,6 +493,7 @@ window.__ModuleLoader__.load({
|
|
|
492
493
|
'modal.params': '配置参数',
|
|
493
494
|
'modal.history': '运行历史 ({count})',
|
|
494
495
|
'modal.cancel': '取消',
|
|
496
|
+
'modal.confirmDiscard': '放弃未保存的内容?',
|
|
495
497
|
'modal.save': '保存修改',
|
|
496
498
|
'modal.create': '创建任务',
|
|
497
499
|
'history.loading': '正在加载历史记录...',
|
|
@@ -1338,6 +1340,80 @@ window.__ModuleLoader__.load({
|
|
|
1338
1340
|
const [formWorkflowName, setFormWorkflowName] = React.useState('');
|
|
1339
1341
|
const [stats, setStats] = React.useState(null);
|
|
1340
1342
|
|
|
1343
|
+
const initialFormSnapshotRef = React.useRef(null);
|
|
1344
|
+
|
|
1345
|
+
const getFormSnapshot = () => JSON.stringify({
|
|
1346
|
+
title: String(formTitle || '').trim(),
|
|
1347
|
+
schedule: String(formSchedule || '').trim(),
|
|
1348
|
+
type: String(formType || 'llm'),
|
|
1349
|
+
prompt: String(formPrompt || '').trim(),
|
|
1350
|
+
provider: String(formProvider || ''),
|
|
1351
|
+
model: String(formModel || ''),
|
|
1352
|
+
fallbackModel: String(formFallbackModel || ''),
|
|
1353
|
+
silentRule: String(formSilentRule || ''),
|
|
1354
|
+
inspectOnFailure: Boolean(formInspectOnFailure),
|
|
1355
|
+
delivery: String(formDelivery || 'isolated'),
|
|
1356
|
+
notifyTelegram: Boolean(formNotifyTelegram),
|
|
1357
|
+
channels: Array.isArray(formChannels) ? [...formChannels].sort() : [],
|
|
1358
|
+
template: String(formTemplate || '').trim(),
|
|
1359
|
+
onlyOnFailure: Boolean(formOnlyOnFailure),
|
|
1360
|
+
timeoutSeconds: Number(formTimeoutSeconds) || 1800,
|
|
1361
|
+
overlapPolicy: String(formOverlapPolicy || 'skip'),
|
|
1362
|
+
kanbanMode: String(formKanbanMode || 'none'),
|
|
1363
|
+
onSuccess: String(formOnSuccess || '').trim(),
|
|
1364
|
+
onFailure: String(formOnFailure || '').trim(),
|
|
1365
|
+
heartbeatIntervalSeconds: Number(formHeartbeatIntervalSeconds) || 0,
|
|
1366
|
+
gracePeriodSeconds: Number(formGracePeriodSeconds) || 300,
|
|
1367
|
+
preflightType: String(formPreflightType || 'none'),
|
|
1368
|
+
preflightTarget: String(formPreflightTarget || '').trim(),
|
|
1369
|
+
priority: Number(formPriority) || 5,
|
|
1370
|
+
concurrencyGroup: String(formConcurrencyGroup || 'default').trim(),
|
|
1371
|
+
selfHealingCommand: String(formSelfHealingCommand || '').trim(),
|
|
1372
|
+
autoDiagnose: Boolean(formAutoDiagnose),
|
|
1373
|
+
timezone: String(formTimezone || '').trim(),
|
|
1374
|
+
misfirePolicy: String(formMisfirePolicy || 'skip'),
|
|
1375
|
+
maxRetries: Number(formMaxRetries) || 0,
|
|
1376
|
+
permissionPreset: String(formPermissionPreset || 'default'),
|
|
1377
|
+
agentPreset: String(formAgentPreset || '').trim(),
|
|
1378
|
+
targetSessionId: String(formTargetSessionId || '').trim(),
|
|
1379
|
+
targetSessionReset: String(formTargetSessionReset || 'never'),
|
|
1380
|
+
env: String(formEnv || '').trim(),
|
|
1381
|
+
cwd: String(formCwd || '').trim(),
|
|
1382
|
+
workspaceId: String(formWorkspaceId || '').trim(),
|
|
1383
|
+
worktree: Boolean(formWorktree),
|
|
1384
|
+
keepWorktree: Boolean(formKeepWorktree),
|
|
1385
|
+
httpMethod: String(formHttpMethod || 'GET'),
|
|
1386
|
+
httpUrl: String(formHttpUrl || '').trim(),
|
|
1387
|
+
httpHttpHeaders: String(formHttpHeaders || '').trim(),
|
|
1388
|
+
httpBody: String(formHttpBody || '').trim(),
|
|
1389
|
+
sshProfileId: String(formSshProfileId || '').trim(),
|
|
1390
|
+
sshTarget: String(formSshTarget || '').trim(),
|
|
1391
|
+
sshKeyPath: String(formSshKeyPath || '').trim(),
|
|
1392
|
+
dockerImage: String(formDockerImage || '').trim(),
|
|
1393
|
+
nodePath: String(formNodePath || '').trim(),
|
|
1394
|
+
pythonPath: String(formPythonPath || '').trim(),
|
|
1395
|
+
skillName: String(formSkillName || '').trim(),
|
|
1396
|
+
workflowName: String(formWorkflowName || '').trim(),
|
|
1397
|
+
});
|
|
1398
|
+
|
|
1399
|
+
const isFormDirty = () => {
|
|
1400
|
+
if (!manualModalOpen) return false;
|
|
1401
|
+
if (initialFormSnapshotRef.current !== null) {
|
|
1402
|
+
return getFormSnapshot() !== initialFormSnapshotRef.current;
|
|
1403
|
+
}
|
|
1404
|
+
return Boolean(formTitle.trim() || formPrompt.trim());
|
|
1405
|
+
};
|
|
1406
|
+
|
|
1407
|
+
const closeManualModalWithConfirm = () => {
|
|
1408
|
+
if (isFormDirty()) {
|
|
1409
|
+
if (!confirm(T_KEY(t, 'modal.confirmDiscard') || 'Discard unsaved changes?')) {
|
|
1410
|
+
return;
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
initialFormSnapshotRef.current = null;
|
|
1414
|
+
setManualModalOpen(false);
|
|
1415
|
+
};
|
|
1416
|
+
|
|
1341
1417
|
// Live execution indicator (#35): a light 1s tick only while some task
|
|
1342
1418
|
// is actually running.
|
|
1343
1419
|
const tasksRef = React.useRef([]);
|
|
@@ -1379,7 +1455,7 @@ window.__ModuleLoader__.load({
|
|
|
1379
1455
|
const onKey = (e) => {
|
|
1380
1456
|
if (e.key === 'Escape') {
|
|
1381
1457
|
if (dropdownOpen) { setDropdownOpen(false); return; }
|
|
1382
|
-
if (manualModalOpen) {
|
|
1458
|
+
if (manualModalOpen) { closeManualModalWithConfirm(); return; }
|
|
1383
1459
|
if (settingsModalOpen) { setSettingsModalOpen(false); return; }
|
|
1384
1460
|
if (dshModalOpen && !dshLoading) { setDshModalOpen(false); return; }
|
|
1385
1461
|
if (onClose) onClose();
|
|
@@ -2018,6 +2094,59 @@ window.__ModuleLoader__.load({
|
|
|
2018
2094
|
setFormModel(defaultModelInfo?.model || '');
|
|
2019
2095
|
if (defaultModelInfo?.provider) loadModels(defaultModelInfo.provider);
|
|
2020
2096
|
}
|
|
2097
|
+
initialFormSnapshotRef.current = JSON.stringify({
|
|
2098
|
+
title: String((preset && preset.title) || '').trim(),
|
|
2099
|
+
schedule: String((preset && preset.schedule) || (preset ? '' : '0 9 * * 1-5')).trim(),
|
|
2100
|
+
type: String((preset && preset.type) || 'llm'),
|
|
2101
|
+
prompt: String((preset && preset.prompt) || '').trim(),
|
|
2102
|
+
provider: String(defaultModelInfo?.provider || ''),
|
|
2103
|
+
model: String(defaultModelInfo?.model || ''),
|
|
2104
|
+
fallbackModel: String((preset && preset.fallbackModel) || '').trim(),
|
|
2105
|
+
silentRule: String((preset && preset.silentRule) || '').trim(),
|
|
2106
|
+
inspectOnFailure: Boolean(preset && preset.inspectOnFailure),
|
|
2107
|
+
delivery: 'isolated',
|
|
2108
|
+
notifyTelegram: false,
|
|
2109
|
+
channels: Array.isArray(preset && preset.channels) ? [...preset.channels].filter((c) => DELIVERY_CHANNELS.includes(c)).sort() : [],
|
|
2110
|
+
template: '',
|
|
2111
|
+
onlyOnFailure: Boolean(preset && preset.onlyOnFailure),
|
|
2112
|
+
timeoutSeconds: 1800,
|
|
2113
|
+
overlapPolicy: 'skip',
|
|
2114
|
+
kanbanMode: 'none',
|
|
2115
|
+
onSuccess: '',
|
|
2116
|
+
onFailure: '',
|
|
2117
|
+
heartbeatIntervalSeconds: 0,
|
|
2118
|
+
gracePeriodSeconds: 300,
|
|
2119
|
+
preflightType: 'none',
|
|
2120
|
+
preflightTarget: '',
|
|
2121
|
+
priority: 5,
|
|
2122
|
+
concurrencyGroup: 'default',
|
|
2123
|
+
selfHealingCommand: '',
|
|
2124
|
+
autoDiagnose: false,
|
|
2125
|
+
timezone: '',
|
|
2126
|
+
misfirePolicy: 'skip',
|
|
2127
|
+
maxRetries: 0,
|
|
2128
|
+
permissionPreset: 'default',
|
|
2129
|
+
agentPreset: '',
|
|
2130
|
+
targetSessionId: '',
|
|
2131
|
+
targetSessionReset: 'never',
|
|
2132
|
+
env: '',
|
|
2133
|
+
cwd: '',
|
|
2134
|
+
workspaceId: '',
|
|
2135
|
+
worktree: false,
|
|
2136
|
+
keepWorktree: false,
|
|
2137
|
+
httpMethod: 'GET',
|
|
2138
|
+
httpUrl: '',
|
|
2139
|
+
httpHttpHeaders: '',
|
|
2140
|
+
httpBody: '',
|
|
2141
|
+
sshProfileId: '',
|
|
2142
|
+
sshTarget: '',
|
|
2143
|
+
sshKeyPath: '',
|
|
2144
|
+
dockerImage: '',
|
|
2145
|
+
nodePath: '',
|
|
2146
|
+
pythonPath: '',
|
|
2147
|
+
skillName: '',
|
|
2148
|
+
workflowName: '',
|
|
2149
|
+
});
|
|
2021
2150
|
setManualModalOpen(true);
|
|
2022
2151
|
};
|
|
2023
2152
|
|
|
@@ -2131,7 +2260,7 @@ window.__ModuleLoader__.load({
|
|
|
2131
2260
|
timezone: formTimezone.trim(),
|
|
2132
2261
|
misfirePolicy: formMisfirePolicy,
|
|
2133
2262
|
maxRetries: Number(formMaxRetries) || 0,
|
|
2134
|
-
permissionPreset: formPermissionPreset,
|
|
2263
|
+
permissionPreset: isAgentType ? formPermissionPreset : 'default',
|
|
2135
2264
|
agentPreset: formAgentPreset.trim() || undefined,
|
|
2136
2265
|
targetSessionId: formTargetSessionId.trim() || undefined,
|
|
2137
2266
|
targetSessionReset: formTargetSessionReset || 'never',
|
|
@@ -2179,6 +2308,7 @@ window.__ModuleLoader__.load({
|
|
|
2179
2308
|
body: JSON.stringify(payload)
|
|
2180
2309
|
});
|
|
2181
2310
|
if (!data.ok) { alert(data.error || T_KEY(t, 'settings.saveError', { error: '' })); return; }
|
|
2311
|
+
initialFormSnapshotRef.current = null;
|
|
2182
2312
|
setManualModalOpen(false);
|
|
2183
2313
|
fetchTasks();
|
|
2184
2314
|
} catch (err) { alert(err.message); }
|
|
@@ -2563,7 +2693,12 @@ window.__ModuleLoader__.load({
|
|
|
2563
2693
|
),
|
|
2564
2694
|
|
|
2565
2695
|
// 1. Manual creation / Edit modal
|
|
2566
|
-
manualModalOpen && React.createElement('div', {
|
|
2696
|
+
manualModalOpen && React.createElement('div', {
|
|
2697
|
+
className: 'dsh-cron-modal-overlay',
|
|
2698
|
+
onClick: (e) => {
|
|
2699
|
+
if (e.target === e.currentTarget) closeManualModalWithConfirm();
|
|
2700
|
+
}
|
|
2701
|
+
},
|
|
2567
2702
|
React.createElement('div', {
|
|
2568
2703
|
className: 'dsh-cron-modal dsh-cron-modal-scroll',
|
|
2569
2704
|
style: { maxWidth: '640px' },
|
|
@@ -2666,7 +2801,7 @@ window.__ModuleLoader__.load({
|
|
|
2666
2801
|
React.createElement('button', {
|
|
2667
2802
|
type: 'button',
|
|
2668
2803
|
className: 'dsh-cron-btn-primary',
|
|
2669
|
-
onClick:
|
|
2804
|
+
onClick: closeManualModalWithConfirm
|
|
2670
2805
|
}, T_KEY(t, 'modal.close'))
|
|
2671
2806
|
)
|
|
2672
2807
|
) :
|
|
@@ -2780,7 +2915,32 @@ window.__ModuleLoader__.load({
|
|
|
2780
2915
|
)
|
|
2781
2916
|
)
|
|
2782
2917
|
),
|
|
2783
|
-
|
|
2918
|
+
AGENT_FORM_TYPES.includes(formType) ? (
|
|
2919
|
+
React.createElement('div', { className: 'dsh-cron-form-row' },
|
|
2920
|
+
React.createElement('div', { className: 'dsh-cron-form-group' },
|
|
2921
|
+
React.createElement('label', null, T_KEY(t, 'form.retriesLabel')),
|
|
2922
|
+
React.createElement('input', {
|
|
2923
|
+
type: 'number',
|
|
2924
|
+
min: 0,
|
|
2925
|
+
value: formMaxRetries,
|
|
2926
|
+
placeholder: '0',
|
|
2927
|
+
onChange: (e) => setFormMaxRetries(e.target.value)
|
|
2928
|
+
})
|
|
2929
|
+
),
|
|
2930
|
+
React.createElement('div', { className: 'dsh-cron-form-group' },
|
|
2931
|
+
React.createElement('label', null, T_KEY(t, 'form.permissionLabel')),
|
|
2932
|
+
React.createElement('select', {
|
|
2933
|
+
value: formPermissionPreset,
|
|
2934
|
+
onChange: (e) => setFormPermissionPreset(e.target.value)
|
|
2935
|
+
},
|
|
2936
|
+
React.createElement('option', { value: 'default' }, T_KEY(t, 'form.permissionDefault')),
|
|
2937
|
+
React.createElement('option', { value: 'read-only' }, T_KEY(t, 'form.permissionReadonly')),
|
|
2938
|
+
React.createElement('option', { value: 'workspace-write' }, T_KEY(t, 'form.permissionWrite')),
|
|
2939
|
+
React.createElement('option', { value: 'full' }, T_KEY(t, 'form.permissionFull'))
|
|
2940
|
+
)
|
|
2941
|
+
)
|
|
2942
|
+
)
|
|
2943
|
+
) : (
|
|
2784
2944
|
React.createElement('div', { className: 'dsh-cron-form-group' },
|
|
2785
2945
|
React.createElement('label', null, T_KEY(t, 'form.retriesLabel')),
|
|
2786
2946
|
React.createElement('input', {
|
|
@@ -2790,18 +2950,6 @@ window.__ModuleLoader__.load({
|
|
|
2790
2950
|
placeholder: '0',
|
|
2791
2951
|
onChange: (e) => setFormMaxRetries(e.target.value)
|
|
2792
2952
|
})
|
|
2793
|
-
),
|
|
2794
|
-
React.createElement('div', { className: 'dsh-cron-form-group' },
|
|
2795
|
-
React.createElement('label', null, T_KEY(t, 'form.permissionLabel')),
|
|
2796
|
-
React.createElement('select', {
|
|
2797
|
-
value: formPermissionPreset,
|
|
2798
|
-
onChange: (e) => setFormPermissionPreset(e.target.value)
|
|
2799
|
-
},
|
|
2800
|
-
React.createElement('option', { value: 'default' }, T_KEY(t, 'form.permissionDefault')),
|
|
2801
|
-
React.createElement('option', { value: 'read-only' }, T_KEY(t, 'form.permissionReadonly')),
|
|
2802
|
-
React.createElement('option', { value: 'workspace-write' }, T_KEY(t, 'form.permissionWrite')),
|
|
2803
|
-
React.createElement('option', { value: 'full' }, T_KEY(t, 'form.permissionFull'))
|
|
2804
|
-
)
|
|
2805
2953
|
)
|
|
2806
2954
|
),
|
|
2807
2955
|
React.createElement('div', { className: 'dsh-cron-form-group' },
|
|
@@ -3249,7 +3397,7 @@ window.__ModuleLoader__.load({
|
|
|
3249
3397
|
React.createElement('button', {
|
|
3250
3398
|
type: 'button',
|
|
3251
3399
|
className: 'dsh-cron-btn-secondary',
|
|
3252
|
-
onClick:
|
|
3400
|
+
onClick: closeManualModalWithConfirm
|
|
3253
3401
|
}, T_KEY(t, 'modal.cancel')),
|
|
3254
3402
|
React.createElement('button', {
|
|
3255
3403
|
type: 'submit',
|
package/lib/cron-tool.js
CHANGED
|
@@ -150,7 +150,7 @@ export const cronToolParameters = {
|
|
|
150
150
|
permissionPreset: {
|
|
151
151
|
type: 'string',
|
|
152
152
|
enum: ['default', 'read-only', 'workspace-write', 'full'],
|
|
153
|
-
description: 'Permission preset applied to the task session',
|
|
153
|
+
description: 'Permission preset applied to the task session (only used for agent session tasks: llm, skill, workflow)',
|
|
154
154
|
},
|
|
155
155
|
kanbanMode: {
|
|
156
156
|
type: 'string',
|
package/lib/task-create.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { normalizeTaskType } from './runtimes.js';
|
|
1
|
+
import { normalizeTaskType, EXTERNAL_RUNTIMES } from './runtimes.js';
|
|
2
2
|
import { validateTaskType } from './task-transfer.js';
|
|
3
3
|
import { parseScheduleExpression } from './scheduler.js';
|
|
4
4
|
import { CHANNEL_IDS } from './channels.js';
|
|
@@ -44,7 +44,7 @@ export function executeCreateTask(store, scheduler, args) {
|
|
|
44
44
|
misfirePolicy: ['skip', 'runOnce', 'catchUpAll'].includes(args.misfirePolicy) ? args.misfirePolicy : 'skip',
|
|
45
45
|
maxRetries: Number(args.maxRetries) > 0 ? Number(args.maxRetries) : 0,
|
|
46
46
|
retryBackoffMs: Number(args.retryBackoffMs) > 0 ? Number(args.retryBackoffMs) : 30000,
|
|
47
|
-
permissionPreset: ['default', 'read-only', 'workspace-write', 'full'].includes(args.permissionPreset) ? args.permissionPreset : 'default',
|
|
47
|
+
permissionPreset: !EXTERNAL_RUNTIMES.includes(taskType) && ['default', 'read-only', 'workspace-write', 'full'].includes(args.permissionPreset) ? args.permissionPreset : 'default',
|
|
48
48
|
kanbanMode: args.kanbanMode || 'none',
|
|
49
49
|
channels: Array.isArray(args.channels) ? args.channels.filter((c) => CHANNEL_IDS.includes(c)) : undefined,
|
|
50
50
|
template: args.template ? String(args.template) : '',
|
package/lib/task-patch.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { parseScheduleExpression } from './scheduler.js';
|
|
12
|
-
import { normalizeTaskType, CODE_EXECUTING_TYPES } from './runtimes.js';
|
|
12
|
+
import { normalizeTaskType, CODE_EXECUTING_TYPES, EXTERNAL_RUNTIMES } from './runtimes.js';
|
|
13
13
|
import { PATCHABLE_TASK_FIELDS, validateTaskType } from './task-transfer.js';
|
|
14
14
|
import { pickPatchableFields, restoreTaskSecrets } from './http-utils.js';
|
|
15
15
|
import { unknownChannelIds } from './channels.js';
|
|
@@ -95,6 +95,10 @@ export function buildTaskPatch(current, body) {
|
|
|
95
95
|
if (patch.tokenLimit !== undefined) {
|
|
96
96
|
patch.tokenLimit = patch.tokenLimit === null ? null : (Number(patch.tokenLimit) > 0 ? Number(patch.tokenLimit) : null);
|
|
97
97
|
}
|
|
98
|
+
const effectiveType = patch.type !== undefined ? normalizeTaskType(patch.type) : current.type;
|
|
99
|
+
if (EXTERNAL_RUNTIMES.includes(effectiveType) && patch.permissionPreset !== undefined) {
|
|
100
|
+
patch.permissionPreset = 'default';
|
|
101
|
+
}
|
|
98
102
|
// Issue #310 / GH #5: strip undefined properties from patch
|
|
99
103
|
for (const k of Object.keys(patch)) {
|
|
100
104
|
if (patch[k] === undefined) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-cron",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.50",
|
|
4
4
|
"description": "Background automation runner for DSH: isolated agent runs, script/HTTP/SSH/Docker runtimes, cost guard, notifications, heartbeats.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|