PUBLIC MODULE · lib/jobs.js
Jobs
Portable, folder-only project Jobs. ai-jobs enables, ai-jobs-disabled disables. Operations are best effort: there are no locks, daemon identity records, or cross-process coordination. Concurrent scans/mutations may duplicate work, lose updates, or race archives. Atomic single-file replacement remains used.
class Jobs class
Frozen static namespace for folder-only Jobs operations.
taskFilename(value) function
File selectors are leaf Markdown names, not task IDs or paths. IDs remain opaque parser values.
Defined in lib/jobs/operations.js
async validateJobsLayout(root) function
Refuse missing/redirected durable directories; this query never repairs layout.
Defined in lib/jobs/operations.js
async validateJobsOperational(root, options = {…}) function
Operational eligibility is checked at publication and invocation from folder state.
Defined in lib/jobs/operations.js
async readTaskEntries(root) function
Pure filesystem snapshot: no admission, error reporting, state writes, or symlink following.
Defined in lib/jobs/operations.js
async scheduleJobs(root, command, options = {…}) function
Shared task command boundary. Throws actionable JobsError or filesystem errors; never runs tasks. Create refuses existing files; update replaces whole source (last writer wins); remove does not cancel. Calls validate the current folder before operating. Concurrent mutations are best effort: atomic create refuses an existing file and updates may be last-writer-wins.
Defined in lib/jobs/operations.js
async jobsStatus(projectRoot, options = {…}) function
Read-only status projection. It never creates folders, starts daemons, or coordinates processes.
Defined in lib/jobs/status.js
normalizeDays(value, code = "JOBS_TASK_SCHEDULE") function
Normalize aliases or unique lowercase named arrays; omitted input means all days.
Defined in lib/jobs/days.js
class JobsError extends Error class
Coded jobs-domain error shared by validation, scheduling and execution.
Defined in lib/jobs/errors-base.js
constructor(code, message, details = {…}) constructor
Construct a coded domain failure; details are caller diagnostics, not safe-to-log source.
JOBS_DATA_DIRECTORY = "ai-jobs" constant
Active portable Jobs directory name.
Defined in lib/jobs/paths.js
JOBS_DISABLED_DIRECTORY = "ai-jobs-disabled" constant
Disabled portable Jobs directory name.
Defined in lib/jobs/paths.js
JOBS_PATH_NAMES = Object.freeze({ tasks: "tasks", completed: "completed", state: "state… constant
Names inside the portable Jobs directory.
Defined in lib/jobs/paths.js
jobsPaths(projectRoot) function
Return absolute paths derived from the caller's active project root.
Defined in lib/jobs/paths.js
async canonicalProjectRoot(projectRoot, io = {…}) function
Canonical paths are process-local inputs, never Jobs data.
Defined in lib/jobs/project.js
parseTask(filename, source) function
Parse one task without filesystem side effects; declared bad frontmatter rejects the task.
Defined in lib/jobs/tasks.js
parseTasks(tasks) function
Parse independently so duplicate ids and empty prompts remain task-local rejections.
Defined in lib/jobs/tasks.js
taskId(filename) function
Validate and return a nonempty filename-derived default task ID.
Defined in lib/jobs/tasks.js
taskStateKey(id) function
Map opaque IDs to bounded safe ledger filenames; unsafe IDs use a stable hash.
Defined in lib/jobs/tasks.js
async loadTasks(projectRoot, entries, io) function
Parse entries purely, then durably report only all-or-nothing frontmatter fallbacks.
Defined in lib/jobs/errors.js
async reportTaskDiagnostic(projectRoot, diagnostic, io = {…}) function
Atomically record one frontmatter fallback without retaining source text, metadata names, values, or filenames. Repeated reports overwrite one stable hash-named record for the same task and failure class.
Defined in lib/jobs/errors.js
taskDiagnosticKey(diagnostic) function
Stable SHA-256 key for a filename/failure code; contains no source text.
Defined in lib/jobs/errors.js
JOBS_STATE_VERSION = 2 constant
Persisted occurrence schema version; unsupported versions are refused.
Defined in lib/jobs/state.js
createTaskState(task) function
Create the durable, task-local occurrence ledger.
Defined in lib/jobs/state.js
statePath(projectRoot, taskId) function
Resolve a task ledger path through the domain-owned safe ID mapping.
Defined in lib/jobs/state.js
validateTaskState(value, taskId) function
Validate the complete persisted v2 schema before it is used for admission.
Defined in lib/jobs/state.js
validateArchiveReference(value) function
A durable archive location is portable project-local data, never a host path.
Defined in lib/jobs/state.js
resolveArchiveReference(projectRoot, reference) function
Resolve only a previously validated relative reference against this active Jobs root.
Defined in lib/jobs/state.js
async loadTaskState(projectRoot, task, io = fs) function
Read and validate a ledger, or return a fresh state when absent; does not persist.
Defined in lib/jobs/state.js
async saveTaskState(projectRoot, state, io = fs) function
Atomic replace of one task ledger; callers own cross-file reconciliation.
Defined in lib/jobs/state.js
admitOccurrence(state, task, now) function
Admit one execution per scan, coalescing earlier eligible and excluded history.
Defined in lib/jobs/state.js
recordAttempt(state, occurrenceId, attempt) function
Persist a new attempt before any irreversible source move.
Defined in lib/jobs/state.js
reconcileAttempt(state, occurrenceId, attemptId, archivePresent) function
Reconciliation is visible: an interrupted archive is consumed, never due again.
Defined in lib/jobs/state.js
finalizeAttempt(state, occurrenceId, attemptId, outcome, archivePresent, session = null) function
Finalize the current attempt in the same dispatch cycle, without crash reconciliation.
Defined in lib/jobs/state.js
async loadAllTaskStates(projectRoot, io = fs) function
Read all ledgers, including removed one-shots, for crash reconciliation.
Defined in lib/jobs/state.js
newAttemptId(occurrence, sequence = occurrence.attempts.length) function
Derive an occurrence-local attempt ID; callers persist it before archival.
Defined in lib/jobs/state.js
async allocateArchive(projectRoot, localDate, sourceFilename, io = fs) function
Allocate an unused date-local archival name. The integer field has no 999 cap.
Defined in lib/jobs/archive.js
async moveToArchive(source, archive, io = fs) function
Atomically claim destination without overwrite, then remove source hardlink.
Defined in lib/jobs/archive.js
async snapshotAndArchive(source, archive, io = fs) function
Snapshot source bytes before move. Execution must consume snapshot, not disk.
Defined in lib/jobs/archive.js
async archiveExists(path, io = fs) function
Check archive presence; absence returns false, other I/O failures throw JobsError.
Defined in lib/jobs/archive.js
async ensureJobsLayout(projectRoot, io = fs) function
Ensure the standard active layout. Call only from explicit initialization.
Defined in lib/jobs/lifecycle.js
async initializeJobs(projectRoot, settings = {…}, options = {…}) function
Enable folder-only Jobs, restoring a disabled directory without changing bytes.
Defined in lib/jobs/lifecycle.js
async validateJobsActivation(projectRoot, settings = {…}, options = {…}) function
Validate active folder state without writing or coordinating with other processes.
Defined in lib/jobs/lifecycle.js
async disableJobs(projectRoot, options = {…}) function
Disable by renaming the active directory. Concurrent work is best effort.
Defined in lib/jobs/lifecycle.js
cycleRecord(at) function
Create the location-neutral public result record for one Jobs scan.
Defined in lib/jobs/dispatcher.js
async dispatchJobs(projectRoot, options = {…}) function
Best-effort serial scan. Concurrent scans may duplicate execution or lose state updates.
Defined in lib/jobs/dispatcher.js
async runJobAgent(task, options = {…}) function
One fresh, headless Agent run against a SHARED per-wake Env. Cancellation is deliberate (the caller's AbortSignal); any request/tool timeout remains Agent/IO policy, never a Jobs schedule watchdog. The caller owns the Env and its teardown; factories are trusted embedding/test boundaries. Retries, context limits, tool timeouts and transcript writes remain Agent/IO-owned.
Defined in lib/jobs/agent-execution.js
async foregroundJobsDaemon(projectRoot, options = {…}) function
Run a foreground, cwd-bound best-effort daemon. No daemon identity or control record is persisted; multiple foreground daemons may run concurrently.
Defined in lib/jobs/daemon.js