mirror of
https://github.com/hansjone/dsh-ops-cron.git
synced 2026-10-16 15:03:21 +08:00
Fix cron_* registration: Host rejects JSON Schema type arrays.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
25454a5c8c
commit
9b8f937a65
4 changed files with 32 additions and 8 deletions
|
|
@ -222,10 +222,10 @@ export function createStore(options = {}) {
|
||||||
error.code = 'STORE_CORRUPT'
|
error.code = 'STORE_CORRUPT'
|
||||||
try {
|
try {
|
||||||
const bak = `${filePath}.corrupt.${Date.now()}.bak`
|
const bak = `${filePath}.corrupt.${Date.now()}.bak`
|
||||||
await writeFile(bak, raw, 'utf8')
|
await rename(filePath, bak)
|
||||||
error.message = `${error.message} (backup: ${bak})`
|
error.message = `${error.message} (backup: ${bak})`
|
||||||
} catch {
|
} catch {
|
||||||
// best-effort backup
|
// best-effort quarantine; persist() below overwrites either way
|
||||||
}
|
}
|
||||||
console.warn(`[dsh-ops-cron] ${error.message}`)
|
console.warn(`[dsh-ops-cron] ${error.message}`)
|
||||||
state = emptyState()
|
state = emptyState()
|
||||||
|
|
|
||||||
12
lib/tools.js
12
lib/tools.js
|
|
@ -41,9 +41,10 @@ const JOB_SCHEMA = {
|
||||||
schedule: { type: 'object', additionalProperties: true },
|
schedule: { type: 'object', additionalProperties: true },
|
||||||
createdAt: { type: 'number' },
|
createdAt: { type: 'number' },
|
||||||
updatedAt: { type: 'number' },
|
updatedAt: { type: 'number' },
|
||||||
lastRunAt: { type: ['number', 'null'] },
|
// Host assertSupportedJsonSchema rejects type arrays — use oneOf for nullables.
|
||||||
lastStatus: { type: ['string', 'null'] },
|
lastRunAt: { oneOf: [{ type: 'number' }, { type: 'null' }] },
|
||||||
nextRunAt: { type: ['number', 'null'] },
|
lastStatus: { oneOf: [{ type: 'string' }, { type: 'null' }] },
|
||||||
|
nextRunAt: { oneOf: [{ type: 'number' }, { type: 'null' }] },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -497,8 +498,9 @@ export function cronGuidanceText(nowMs = Date.now(), timeZone = 'Asia/Shanghai')
|
||||||
'Agent preset: omit agent_preset to inherit (WhatsApp chat/group preset → creating session → Host default). Pass agent_preset to pin a preset for every scheduled run.',
|
'Agent preset: omit agent_preset to inherit (WhatsApp chat/group preset → creating session → Host default). Pass agent_preset to pin a preset for every scheduled run.',
|
||||||
'When the user asks to look at, create, pause, resume, or delete 定时任务 / scheduled tasks / cron jobs:',
|
'When the user asks to look at, create, pause, resume, or delete 定时任务 / scheduled tasks / cron jobs:',
|
||||||
'1. If cron_list / cron_create / cron_pause / cron_resume / cron_delete are in your tool list, call them.',
|
'1. If cron_list / cron_create / cron_pause / cron_resume / cron_delete are in your tool list, call them.',
|
||||||
'2. If they are not listed, search/unlock tools or skills with query "定时任务" or "cron" (skill_search, skill_load, or dev_tool_search) and then call them.',
|
'2. If they are not listed, load skill "scheduled-tasks" via the skill tool (exact name), then retry the cron_* tools. Those tools are registered by the dsh-ops-cron plugin — they are not unlocked by skill_search/dev_tool_search (those names are obsolete).',
|
||||||
'3. Never run crontab, never read /etc/cron*, and never say there are no tasks until cron_list has returned.',
|
'3. If cron_* still return unknown tool after loading the skill, the plugin failed to register (check Host logs for unsupported JSON schema). Tell the user; do not invent crontab workarounds.',
|
||||||
|
'4. Never run crontab, never read /etc/cron*, and never say there are no tasks until cron_list has returned.',
|
||||||
].join('\n')
|
].join('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "dsh-ops-cron",
|
"name": "dsh-ops-cron",
|
||||||
"description": "Scheduled tasks for DeepSeek Harness: Agent cron_* tools + sidebar 定时任务, with DSH or WhatsApp/IM delivery per job.",
|
"description": "Scheduled tasks for DeepSeek Harness: Agent cron_* tools + sidebar 定时任务, with DSH or WhatsApp/IM delivery per job.",
|
||||||
"version": "0.1.12",
|
"version": "0.1.13",
|
||||||
"private": false,
|
"private": false,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -435,3 +435,25 @@ test('registerCronTools registers each definition and disposer unregisters', ()
|
||||||
off()
|
off()
|
||||||
assert.deepEqual(registered, [])
|
assert.deepEqual(registered, [])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('cron tool output schemas never use type arrays (Host rejects them)', () => {
|
||||||
|
const defs = cronToolDefinitions({
|
||||||
|
async createJob() { return {} },
|
||||||
|
async listJobs() { return [] },
|
||||||
|
async pauseJob() { return {} },
|
||||||
|
async resumeJob() { return {} },
|
||||||
|
async deleteJob() { return {} },
|
||||||
|
})
|
||||||
|
const bad = []
|
||||||
|
function walk(node, path) {
|
||||||
|
if (!node || typeof node !== 'object') return
|
||||||
|
if (Array.isArray(node.type)) bad.push(`${path}.type=${JSON.stringify(node.type)}`)
|
||||||
|
if (Array.isArray(node.oneOf)) node.oneOf.forEach((branch, i) => walk(branch, `${path}.oneOf[${i}]`))
|
||||||
|
if (node.properties && typeof node.properties === 'object') {
|
||||||
|
for (const [key, child] of Object.entries(node.properties)) walk(child, `${path}.properties.${key}`)
|
||||||
|
}
|
||||||
|
if (node.items) walk(node.items, `${path}.items`)
|
||||||
|
}
|
||||||
|
for (const def of defs) walk(def.output?.schema, def.name)
|
||||||
|
assert.deepEqual(bad, [])
|
||||||
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue