2026-06-27 08:10:40 +05:30
|
|
|
|
/**
|
2026-06-29 11:35:56 +05:30
|
|
|
|
* @fileoverview Cron Jobs type definitions.
|
2026-06-27 08:10:40 +05:30
|
|
|
|
*
|
|
|
|
|
|
* NOTE: This is intentionally distinct from the existing `ScheduledRun` concept
|
|
|
|
|
|
* (see src/web/ports/infra-port.ts), which is a run-now, duration-bounded
|
2026-06-29 11:35:56 +05:30
|
|
|
|
* autonomous loop. A `CronJob` is a SAVED, NAMED job with a recurring
|
2026-06-27 08:10:40 +05:30
|
|
|
|
* schedule (once/interval/daily/weekly), enable/disable, next-run calculation,
|
2026-06-29 11:35:56 +05:30
|
|
|
|
* and a history of `CronJobRun` records. The two do not interact.
|
2026-06-27 08:10:40 +05:30
|
|
|
|
*
|
|
|
|
|
|
* Persisted to `~/.codeman/state.json` via StateStore (see AppState).
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
import type { SessionMode } from './session.js';
|
|
|
|
|
|
|
|
|
|
|
|
/** How a job's fire times are computed. */
|
|
|
|
|
|
export type ScheduleType = 'once' | 'interval' | 'daily' | 'weekly';
|
|
|
|
|
|
|
|
|
|
|
|
/** Where the prompt text comes from. */
|
|
|
|
|
|
export type PromptMode = 'inline_text' | 'prompt_file_path';
|
|
|
|
|
|
|
|
|
|
|
|
/** How the prompt is delivered into the session. */
|
|
|
|
|
|
export type InputMode = 'paste' | 'typed';
|
|
|
|
|
|
|
|
|
|
|
|
/** Lifecycle status of a single job execution. */
|
2026-06-29 11:50:42 +05:30
|
|
|
|
export type CronJobRunStatus = 'created' | 'session_started' | 'prompt_sent' | 'failed' | 'skipped';
|
2026-06-27 08:10:40 +05:30
|
|
|
|
|
|
|
|
|
|
/** What triggered a run. */
|
|
|
|
|
|
export type TriggerType = 'scheduled' | 'manual_run_now';
|
|
|
|
|
|
|
|
|
|
|
|
/** What to do for an AUTOMATIC run when sessions of the same agent already exist. */
|
|
|
|
|
|
export type ConcurrencyPolicy = 'warn_only' | 'skip_if_same_agent_running';
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-06-29 11:35:56 +05:30
|
|
|
|
* A saved, named cron job.
|
2026-06-27 08:10:40 +05:30
|
|
|
|
*/
|
2026-06-29 11:35:56 +05:30
|
|
|
|
export interface CronJob {
|
2026-06-27 08:10:40 +05:30
|
|
|
|
id: string;
|
|
|
|
|
|
name: string;
|
2026-07-20 04:02:46 +02:00
|
|
|
|
/** Owning username in multi-user mode; the job launches as this user. Undefined in single-user. */
|
|
|
|
|
|
owner?: string;
|
2026-06-27 08:10:40 +05:30
|
|
|
|
/** Reuses Codeman's existing session modes; 'shell' covers Terminal/custom. */
|
|
|
|
|
|
agentType: SessionMode;
|
|
|
|
|
|
workingDir: string;
|
|
|
|
|
|
/** Optional custom launch command (only meaningful for 'shell' mode). */
|
|
|
|
|
|
launchCommand?: string;
|
|
|
|
|
|
|
|
|
|
|
|
promptMode: PromptMode;
|
|
|
|
|
|
promptText?: string;
|
|
|
|
|
|
promptFilePath?: string;
|
|
|
|
|
|
inputMode: InputMode;
|
|
|
|
|
|
|
|
|
|
|
|
scheduleType: ScheduleType;
|
|
|
|
|
|
/** once: absolute epoch-ms fire time. */
|
|
|
|
|
|
runAt?: number;
|
|
|
|
|
|
/** interval: minutes between fires. */
|
|
|
|
|
|
intervalMinutes?: number;
|
|
|
|
|
|
/** daily: 'HH:MM' (24h, server-local time). */
|
|
|
|
|
|
dailyTime?: string;
|
|
|
|
|
|
/** weekly: weekdays 0–6 (0=Sunday). */
|
|
|
|
|
|
weeklyDays?: number[];
|
|
|
|
|
|
/** weekly: 'HH:MM' (24h, server-local time). */
|
|
|
|
|
|
weeklyTime?: string;
|
|
|
|
|
|
|
|
|
|
|
|
enabled: boolean;
|
|
|
|
|
|
notes?: string;
|
|
|
|
|
|
/** Applies to automatic (scheduled) runs only. Manual Run Now always warns client-side. */
|
|
|
|
|
|
concurrencyPolicy: ConcurrencyPolicy;
|
2026-07-12 19:25:42 +02:00
|
|
|
|
/**
|
|
|
|
|
|
* Close the still-open session created by this job's previous run before the
|
|
|
|
|
|
* next run launches (via the normal session-cleanup path), so unattended
|
|
|
|
|
|
* recurring jobs don't accumulate tabs until the global session cap.
|
|
|
|
|
|
* Default true. Ignored for 'once' schedules.
|
|
|
|
|
|
*/
|
|
|
|
|
|
autoClosePreviousSession?: boolean;
|
2026-06-27 08:10:40 +05:30
|
|
|
|
|
|
|
|
|
|
// ── Bookkeeping (server-maintained) ─────────────────────────────────────
|
|
|
|
|
|
createdAt: number;
|
|
|
|
|
|
updatedAt: number;
|
|
|
|
|
|
lastRunAt: number | null;
|
|
|
|
|
|
nextRunAt: number | null;
|
2026-06-29 11:35:56 +05:30
|
|
|
|
lastStatus: CronJobRunStatus | null;
|
2026-06-27 08:10:40 +05:30
|
|
|
|
/** Duplicate-launch guard: identifies the most recent due-time consumed. */
|
|
|
|
|
|
lastDueKey: string | null;
|
|
|
|
|
|
/** True once a 'once' job has fired (it is also disabled). */
|
|
|
|
|
|
completedOnce?: boolean;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-06-29 11:35:56 +05:30
|
|
|
|
* A single execution of a cron job (history record).
|
2026-06-27 08:10:40 +05:30
|
|
|
|
*/
|
2026-06-29 11:35:56 +05:30
|
|
|
|
export interface CronJobRun {
|
2026-06-27 08:10:40 +05:30
|
|
|
|
id: string;
|
2026-06-29 11:35:56 +05:30
|
|
|
|
cronJobId: string;
|
2026-06-27 08:10:40 +05:30
|
|
|
|
sessionId: string | null;
|
|
|
|
|
|
sessionName: string | null;
|
|
|
|
|
|
startedAt: number;
|
|
|
|
|
|
finishedAt: number | null;
|
2026-06-29 11:35:56 +05:30
|
|
|
|
status: CronJobRunStatus;
|
2026-06-27 08:10:40 +05:30
|
|
|
|
errorMessage?: string;
|
|
|
|
|
|
triggerType: TriggerType;
|
|
|
|
|
|
/** Best-effort deep link to the created session in the web UI. */
|
|
|
|
|
|
createdSessionUrl: string | null;
|
|
|
|
|
|
}
|