mirror of
https://github.com/hansjone/dsh-ops-cron.git
synced 2026-10-09 03:03:18 +08:00
Fork dsh-cron-tasks as dsh-ops-cron with DSH/IM delivery.
Agent cron_* jobs default to IM when created from a WhatsApp session with a matching delivery target; otherwise DSH sidebar sessions. Fire path soft-calls ctx.dshIm.send for summaries. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
4447404361
commit
2f08136adf
17 changed files with 472 additions and 285 deletions
26
lib/host.js
26
lib/host.js
|
|
@ -8,6 +8,7 @@ import { mkdir } from 'node:fs/promises'
|
|||
import { homedir } from 'node:os'
|
||||
import { basename, join } from 'node:path'
|
||||
import { claimOccurrence, executeClaimedRun, extractAssistantText, interruptActiveRuns, publicJob, settleRun, TITLE_PREFIX } from './fire.js'
|
||||
import { deliverRunToIm } from './delivery.js'
|
||||
import { workspaceVisibleIds } from './isolation.js'
|
||||
import { decideDispatch, nextFire, validateSchedule } from './scheduler.js'
|
||||
import {
|
||||
|
|
@ -23,15 +24,15 @@ import {
|
|||
upsertJob,
|
||||
} from './store.js'
|
||||
|
||||
export const PLUGIN_NAME = 'dsh-cron-tasks'
|
||||
export const API_PREFIX = '/dsh-cron-tasks'
|
||||
export const PLUGIN_NAME = 'dsh-ops-cron'
|
||||
export const API_PREFIX = '/dsh-ops-cron'
|
||||
|
||||
export function dshHome() {
|
||||
return process.env.DSH_HOME || join(homedir(), '.dsh')
|
||||
}
|
||||
|
||||
export function defaultCwd() {
|
||||
return join(dshHome(), 'cron-tasks', 'workspace')
|
||||
return join(dshHome(), 'ops-cron', 'workspace')
|
||||
}
|
||||
|
||||
function json(res, status, body) {
|
||||
|
|
@ -110,6 +111,8 @@ function runView(run) {
|
|||
* @param {() => number} [options.now]
|
||||
* @param {string} [options.filePath]
|
||||
* @param {object} [options.sessionPort] { createAndPrompt, archiveSession, waitForTurn }
|
||||
* @param {() => object|undefined} [options.getDshIm] soft-injected proactive IM API
|
||||
* @param {{ warn?: Function, info?: Function }} [options.logger]
|
||||
* @param {number} [options.tickIntervalMs]
|
||||
*/
|
||||
export function createHostService(options = {}) {
|
||||
|
|
@ -117,6 +120,8 @@ export function createHostService(options = {}) {
|
|||
const filePath = options.filePath || storePath(dshHome())
|
||||
const store = options.store || createStore({ filePath })
|
||||
const sessionPort = options.sessionPort || null
|
||||
const getDshIm = typeof options.getDshIm === 'function' ? options.getDshIm : () => undefined
|
||||
const logger = options.logger || console
|
||||
const tickIntervalMs = Number(options.tickIntervalMs) > 0 ? Number(options.tickIntervalMs) : 15_000
|
||||
let timer = null
|
||||
let ticking = false
|
||||
|
|
@ -129,6 +134,16 @@ export function createHostService(options = {}) {
|
|||
return store.read()
|
||||
}
|
||||
|
||||
async function maybeDeliverIm(job, run) {
|
||||
if (!job || job.delivery?.kind !== 'im') return
|
||||
try {
|
||||
await deliverRunToIm(job, run?.summary, { dshIm: getDshIm() })
|
||||
logger.info?.(`[dsh-ops-cron] im delivery sent for job ${job.id} → ${job.delivery.targetId}`)
|
||||
} catch (error) {
|
||||
logger.warn?.(`[dsh-ops-cron] im delivery failed for job ${job.id}: ${error instanceof Error ? error.message : error}`)
|
||||
}
|
||||
}
|
||||
|
||||
async function createJob(input) {
|
||||
const t = now()
|
||||
let created
|
||||
|
|
@ -159,6 +174,7 @@ export function createHostService(options = {}) {
|
|||
provider: patch.provider !== undefined ? patch.provider : job.provider,
|
||||
model: patch.model !== undefined ? patch.model : job.model,
|
||||
reasoningEffort: patch.reasoningEffort !== undefined ? patch.reasoningEffort : job.reasoningEffort,
|
||||
delivery: patch.delivery !== undefined ? patch.delivery : job.delivery,
|
||||
}
|
||||
const record = createJobRecord(nextInput, current, t)
|
||||
record.createdAt = job.createdAt
|
||||
|
|
@ -228,9 +244,11 @@ export function createHostService(options = {}) {
|
|||
const settled = await store.mutate((current) => settleRun(current, run.id, terminal, now()))
|
||||
run = (settled.runs || []).find((row) => row.id === claimed.run.id)
|
||||
const job = getJob(settled, jobId)
|
||||
await maybeDeliverIm(job, run)
|
||||
return { job: jobView(job), run: runView(run), decision: claimed.decision }
|
||||
}
|
||||
const job = getJob(executed, jobId)
|
||||
await maybeDeliverIm(job, run)
|
||||
return { job: jobView(job), run: runView(run), decision: claimed.decision }
|
||||
}
|
||||
|
||||
|
|
@ -295,7 +313,7 @@ export function createHostService(options = {}) {
|
|||
}
|
||||
|
||||
async function recover() {
|
||||
await mkdir(join(dshHome(), 'cron-tasks'), { recursive: true })
|
||||
await mkdir(join(dshHome(), 'ops-cron'), { recursive: true })
|
||||
const t = now()
|
||||
await withState((current) => {
|
||||
let next = interruptActiveRuns(current, t)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue