crontick 0.1.0
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/LICENSE +21 -0
- package/README.md +56 -0
- package/dist/chunk-35FFLWP3.js +79 -0
- package/dist/chunk-35FFLWP3.js.map +1 -0
- package/dist/chunk-FMGZ3SSS.js +57 -0
- package/dist/chunk-FMGZ3SSS.js.map +1 -0
- package/dist/chunk-LPAFZNXK.js +214 -0
- package/dist/chunk-LPAFZNXK.js.map +1 -0
- package/dist/chunk-YMAT5MON.js +22 -0
- package/dist/chunk-YMAT5MON.js.map +1 -0
- package/dist/cli/index.cjs +879 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +2 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +554 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/daemon/index.cjs +1655 -0
- package/dist/daemon/index.cjs.map +1 -0
- package/dist/daemon/index.d.cts +2 -0
- package/dist/daemon/index.d.ts +2 -0
- package/dist/daemon/index.js +1306 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/dashboard/.gitkeep +0 -0
- package/dist/dashboard/dashboard.css +192 -0
- package/dist/dashboard/dashboard.js +316 -0
- package/dist/dashboard/index.html +108 -0
- package/dist/index.cjs +180 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +121 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/job-JQGLDEJV.js +26 -0
- package/dist/job-JQGLDEJV.js.map +1 -0
- package/dist/mcp/index.cjs +1000 -0
- package/dist/mcp/index.cjs.map +1 -0
- package/dist/mcp/index.d.cts +13 -0
- package/dist/mcp/index.d.ts +13 -0
- package/dist/mcp/index.js +876 -0
- package/dist/mcp/index.js.map +1 -0
- package/package.json +81 -0
- package/plugin/.gitkeep +0 -0
- package/plugin/README.md +50 -0
- package/plugin/install.mjs +155 -0
- package/plugin/plugin.json +11 -0
- package/plugin/uninstall.mjs +68 -0
- package/src/skill/SKILL.md +227 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/schemas/job.ts","../../src/daemon/index.ts","../../src/paths.ts","../../src/daemon/store.ts","../../src/errors.ts","../../src/daemon/scheduler.ts","../../src/daemon/runner.ts","../../src/daemon/api.ts","../../src/version.ts","../../src/autostart/win32.ts","../../src/autostart/manual.ts","../../src/autostart/darwin.ts","../../src/autostart/linux.ts","../../src/autostart/index.ts"],"sourcesContent":["import { z } from 'zod';\n\n// ── Schedule ──────────────────────────────────────────────────────────────────\n\nexport const CronScheduleSchema = z.object({\n kind: z.literal('cron'),\n cron: z.string().min(1),\n tz: z.string().optional(),\n});\n\nexport const IntervalScheduleSchema = z.object({\n kind: z.literal('interval'),\n everySec: z.number().positive(),\n startAt: z.string().optional(), // ISO-8601\n});\n\nexport const OneShotScheduleSchema = z.object({\n kind: z.literal('one-shot'),\n runAt: z.string().min(1), // ISO-8601\n});\n\nexport const ScheduleSchema = z.discriminatedUnion('kind', [\n CronScheduleSchema,\n IntervalScheduleSchema,\n OneShotScheduleSchema,\n]);\n\n// ── Action ────────────────────────────────────────────────────────────────────\n\nexport const ScriptActionSchema = z.object({\n kind: z.literal('script'),\n script: z.string().min(1),\n shell: z.enum(['auto', 'bash', 'pwsh', 'cmd']).default('auto'),\n cwd: z.string().optional(),\n env: z.record(z.string(), z.string()).optional(),\n envFile: z.string().optional(),\n timeoutSec: z.number().positive().optional(),\n});\n\nexport const ExecActionSchema = z.object({\n kind: z.literal('exec'),\n command: z.string().min(1),\n args: z.array(z.string()).default([]),\n cwd: z.string().optional(),\n env: z.record(z.string(), z.string()).optional(),\n envFile: z.string().optional(),\n timeoutSec: z.number().positive().optional(),\n // shell is intentionally absent: exec always uses shell=false to prevent injection\n});\n\nexport const ActionSchema = z.discriminatedUnion('kind', [ScriptActionSchema, ExecActionSchema]);\n\n// ── Supporting types ──────────────────────────────────────────────────────────\n\nexport const RetrySchema = z.object({\n max: z.number().int().min(0).default(0),\n backoffSec: z.number().positive().default(30),\n});\n\nexport const BudgetsSchema = z.object({\n maxRunsPerDay: z.number().int().positive().nullable().default(null),\n maxTokensPerRun: z.number().int().positive().nullable().default(null),\n});\n\n// ── Job ───────────────────────────────────────────────────────────────────────\n\nconst kebabCase = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\nexport const JobSchema = z.object({\n id: z.string().regex(kebabCase, 'Job ID must be kebab-case (e.g. \"my-job\")'),\n description: z.string().optional(),\n enabled: z.boolean().default(true),\n schedule: ScheduleSchema,\n action: ActionSchema,\n catchup: z.enum(['run-once', 'run-all', 'skip']).default('skip'),\n overlap: z.enum(['skip', 'queue', 'cancel-previous']).default('skip'),\n retry: RetrySchema.default({ max: 0, backoffSec: 30 }),\n budgets: BudgetsSchema.default({ maxRunsPerDay: null, maxTokensPerRun: null }),\n});\n\nexport type Job = z.infer<typeof JobSchema>;\nexport type JobInput = z.input<typeof JobSchema>;\nexport type Schedule = z.infer<typeof ScheduleSchema>;\nexport type Action = z.infer<typeof ActionSchema>;\n","/**\n * crontick daemon entry point.\n * T-NEW-4: Re-exec with --experimental-sqlite on Node < 24 if flag is absent.\n */\nimport { spawn } from 'node:child_process';\nimport { readFileSync, writeFileSync, unlinkSync, existsSync, appendFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport {\n ensureDirs,\n pidFilePath,\n portFilePath,\n logsDir,\n runsDbPath,\n jobsDir,\n} from '../paths.js';\nimport { Store } from './store.js';\nimport { Scheduler } from './scheduler.js';\nimport { Runner } from './runner.js';\nimport { createApiServer } from './api.js';\n\n// ── SQLite shim ───────────────────────────────────────────────────────────────\n\nconst nodeMajor = parseInt(process.versions.node.split('.')[0], 10);\nconst needsSqliteShim = nodeMajor < 24 && !process.execArgv.includes('--experimental-sqlite');\n\nif (needsSqliteShim) {\n const child = spawn(process.execPath, ['--experimental-sqlite', ...process.argv.slice(1)], {\n stdio: 'inherit',\n env: process.env,\n detached: false,\n });\n child.on('exit', (code) => {\n process.exit(code ?? 0);\n });\n} else {\n // ── Logger ──────────────────────────────────────────────────────────────────\n\n let logFile: string | null = null;\n\n function log(level: 'info' | 'warn' | 'error', msg: string, data?: unknown): void {\n const line = JSON.stringify({ ts: new Date().toISOString(), level, msg, ...(data ? { data } : {}) });\n process.stderr.write(line + '\\n');\n if (logFile) {\n try { appendFileSync(logFile, line + '\\n'); } catch { /* ignore */ }\n }\n }\n\n // ── Single-instance guard ───────────────────────────────────────────────────\n\n function checkSingleInstance(): void {\n const pidPath = pidFilePath();\n if (!existsSync(pidPath)) return;\n try {\n const existingPid = parseInt(readFileSync(pidPath, 'utf-8').trim(), 10);\n if (!isNaN(existingPid)) {\n try {\n process.kill(existingPid, 0);\n log('error', 'Daemon already running', { pid: existingPid });\n process.exit(1);\n } catch {\n log('warn', 'Removing stale PID file', { pid: existingPid });\n }\n }\n } catch { /* ignore */ }\n }\n\n function cleanup(): void {\n for (const p of [pidFilePath(), portFilePath()]) {\n try { if (existsSync(p)) unlinkSync(p); } catch { /* ignore */ }\n }\n }\n\n // ── Main ────────────────────────────────────────────────────────────────────\n\n async function main(): Promise<void> {\n ensureDirs();\n const today = new Date().toISOString().slice(0, 10);\n logFile = join(logsDir(), `daemon-${today}.log`);\n log('info', 'Starting crontick daemon', { pid: process.pid, node: process.version });\n\n checkSingleInstance();\n writeFileSync(pidFilePath(), String(process.pid), 'utf-8');\n\n const store = new Store(runsDbPath(), jobsDir());\n store.open();\n const reconciled = store.reconcileOrphanRuns();\n if (reconciled > 0) {\n log('warn', `Reconciled ${reconciled} orphaned run(s) from previous daemon session`);\n }\n store.loadJobsFromDisk();\n const jobs = store.listJobs();\n log('info', `Loaded ${jobs.length} job(s) from disk`);\n\n const scheduler = new Scheduler();\n const runner = new Runner();\n\n for (const job of jobs) {\n if (job.enabled) scheduler.schedule(job, store);\n }\n\n scheduler.on('tick', ({ jobId, plannedAt }) => {\n const job = store.getJob(jobId);\n if (!job || !job.enabled) return;\n const run = store.insertRun(jobId, plannedAt.getTime());\n runner.run(job, run.id, store).catch((err: unknown) => {\n log('error', 'Runner error', { jobId, error: String(err) });\n });\n });\n\n async function reload(): Promise<void> {\n log('info', 'Reloading jobs from disk');\n scheduler.unscheduleAll();\n store.loadJobsFromDisk();\n const reloaded = store.listJobs();\n for (const job of reloaded) {\n if (job.enabled) scheduler.schedule(job, store);\n }\n log('info', `Reloaded ${reloaded.length} job(s)`);\n }\n\n const startedAt = new Date();\n const ctx = { store, scheduler, runner, startedAt, port: 0, reload };\n const server = createApiServer(ctx);\n\n await new Promise<void>((resolve, reject) => {\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address();\n const port = typeof addr === 'object' && addr ? addr.port : 0;\n ctx.port = port;\n writeFileSync(portFilePath(), String(port), 'utf-8');\n log('info', `API listening on 127.0.0.1:${port}`);\n resolve();\n });\n server.on('error', reject);\n });\n\n let shuttingDown = false;\n async function shutdown(signal: string): Promise<void> {\n if (shuttingDown) return;\n shuttingDown = true;\n log('info', `Received ${signal}, shutting down`);\n server.close();\n scheduler.unscheduleAll();\n await new Promise<void>((r) => setTimeout(r, 100));\n store.close();\n cleanup();\n log('info', 'Daemon stopped');\n process.exit(0);\n }\n\n process.on('SIGINT', () => void shutdown('SIGINT'));\n process.on('SIGTERM', () => void shutdown('SIGTERM'));\n log('info', 'Daemon ready');\n }\n\n main().catch((err: unknown) => {\n process.stderr.write(`Fatal daemon error: ${String(err)}\\n`);\n cleanup();\n process.exit(1);\n });\n}\n","import envPaths from 'env-paths';\nimport { mkdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\nfunction root(): string {\n const override = process.env['CRONTICK_HOME'];\n if (override) return override;\n // env-paths v3: data dir on windows = %LOCALAPPDATA%\\crontick\n return envPaths('crontick', { suffix: '' }).data;\n}\n\nexport function dataDir(): string {\n return root();\n}\n\nexport function jobsDir(): string {\n return join(root(), 'jobs');\n}\n\nexport function runsDbPath(): string {\n return join(root(), 'runs.db');\n}\n\nexport function logsDir(): string {\n return join(root(), 'logs');\n}\n\nexport function configPath(): string {\n return join(root(), 'config.json');\n}\n\nexport function pidFilePath(): string {\n return join(root(), 'daemon.pid');\n}\n\nexport function portFilePath(): string {\n return join(root(), 'daemon.port');\n}\n\nexport function autostartDir(): string {\n return join(root(), 'autostart');\n}\n\nexport function ensureDirs(): void {\n for (const dir of [dataDir(), jobsDir(), logsDir()]) {\n mkdirSync(dir, { recursive: true });\n }\n}\n","import { DatabaseSync } from 'node:sqlite';\nimport { randomUUID } from 'node:crypto';\nimport { writeFileSync, readFileSync, unlinkSync, readdirSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { runsDbPath, jobsDir } from '../paths.js';\nimport { JobSchema, type Job } from '../schemas/job.js';\nimport { CrontickError } from '../errors.js';\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type RunStatus = 'queued' | 'running' | 'success' | 'failed' | 'canceled' | 'timeout';\n\nexport interface Run {\n id: string;\n jobId: string;\n startedAt: number; // epoch ms\n endedAt?: number;\n status: RunStatus;\n exitCode?: number;\n error?: string;\n durationMs?: number;\n}\n\nexport interface RunLog {\n runId: string;\n stream: 'stdout' | 'stderr';\n ts: number; // epoch ms\n chunk: Buffer;\n}\n\nexport interface ListRunsOptions {\n jobId?: string;\n limit?: number;\n since?: number; // epoch ms\n}\n\n// ── Migrations ────────────────────────────────────────────────────────────────\n\nconst MIGRATIONS: Array<{ name: string; sql: string }> = [\n {\n name: '001_initial',\n sql: `\n CREATE TABLE IF NOT EXISTS jobs (\n id TEXT PRIMARY KEY,\n json TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n );\n CREATE TABLE IF NOT EXISTS runs (\n id TEXT PRIMARY KEY,\n job_id TEXT NOT NULL,\n started_at INTEGER NOT NULL,\n ended_at INTEGER,\n status TEXT NOT NULL,\n exit_code INTEGER,\n error TEXT,\n duration_ms INTEGER\n );\n CREATE TABLE IF NOT EXISTS run_logs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n run_id TEXT NOT NULL,\n stream TEXT NOT NULL,\n ts INTEGER NOT NULL,\n chunk BLOB NOT NULL\n );\n CREATE INDEX IF NOT EXISTS idx_runs_job_id ON runs(job_id);\n CREATE INDEX IF NOT EXISTS idx_runs_started_at ON runs(started_at);\n CREATE INDEX IF NOT EXISTS idx_run_logs_run_id ON run_logs(run_id);\n `,\n },\n];\n\n// ── Store ─────────────────────────────────────────────────────────────────────\n\nexport class Store {\n private db!: DatabaseSync;\n private dbPath: string;\n private jobsPath: string;\n\n constructor(dbPath?: string, jobsPath?: string) {\n this.dbPath = dbPath ?? runsDbPath();\n this.jobsPath = jobsPath ?? jobsDir();\n }\n\n open(): void {\n this.db = new DatabaseSync(this.dbPath);\n this.db.exec('PRAGMA journal_mode=WAL;');\n this.db.exec('PRAGMA foreign_keys=ON;');\n this.runMigrations();\n }\n\n close(): void {\n try {\n this.db.close();\n } catch {\n // ignore if already closed\n }\n }\n\n private runMigrations(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS migrations (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT NOT NULL UNIQUE,\n applied_at INTEGER NOT NULL\n );\n `);\n\n const applied = this.db\n .prepare('SELECT name FROM migrations')\n .all() as Array<{ name: string }>;\n const appliedSet = new Set(applied.map((r) => r.name));\n\n for (const migration of MIGRATIONS) {\n if (!appliedSet.has(migration.name)) {\n this.db.exec(migration.sql);\n this.db\n .prepare('INSERT INTO migrations (name, applied_at) VALUES (?, ?)')\n .run(migration.name, Date.now());\n }\n }\n }\n\n // ── Job CRUD ────────────────────────────────────────────────────────────────\n\n upsertJob(job: Job): void {\n const json = JSON.stringify(job);\n const now = Date.now();\n this.db\n .prepare(\n 'INSERT INTO jobs (id, json, updated_at) VALUES (?, ?, ?) ON CONFLICT(id) DO UPDATE SET json=excluded.json, updated_at=excluded.updated_at',\n )\n .run(job.id, json, now);\n // File-based persistence: jobs dir is source of truth\n const filePath = join(this.jobsPath, `${job.id}.json`);\n writeFileSync(filePath, json, 'utf-8');\n }\n\n getJob(id: string): Job | undefined {\n const row = this.db.prepare('SELECT json FROM jobs WHERE id = ?').get(id) as\n | { json: string }\n | undefined;\n if (!row) return undefined;\n return JSON.parse(row.json) as Job;\n }\n\n listJobs(): Job[] {\n const rows = this.db.prepare('SELECT json FROM jobs ORDER BY id').all() as Array<{\n json: string;\n }>;\n return rows.map((r) => JSON.parse(r.json) as Job);\n }\n\n deleteJob(id: string): boolean {\n const changes = (this.db.prepare('DELETE FROM jobs WHERE id = ?').run(id) as { changes: number }).changes;\n const filePath = join(this.jobsPath, `${id}.json`);\n if (existsSync(filePath)) {\n try {\n unlinkSync(filePath);\n } catch {\n // ignore\n }\n }\n return changes > 0;\n }\n\n /** Load jobs from the jobs directory (disk is source of truth on daemon start). */\n loadJobsFromDisk(): void {\n if (!existsSync(this.jobsPath)) return;\n const files = readdirSync(this.jobsPath).filter((f) => f.endsWith('.json'));\n for (const file of files) {\n try {\n const raw = readFileSync(join(this.jobsPath, file), 'utf-8');\n const parsed = JobSchema.safeParse(JSON.parse(raw));\n if (parsed.success) {\n const json = JSON.stringify(parsed.data);\n this.db\n .prepare(\n 'INSERT INTO jobs (id, json, updated_at) VALUES (?, ?, ?) ON CONFLICT(id) DO UPDATE SET json=excluded.json, updated_at=excluded.updated_at',\n )\n .run(parsed.data.id, json, Date.now());\n }\n } catch {\n // skip malformed job files\n }\n }\n }\n\n // ── Run CRUD ────────────────────────────────────────────────────────────────\n\n insertRun(jobId: string, startedAt?: number): Run {\n const id = randomUUID();\n const now = startedAt ?? Date.now();\n this.db\n .prepare(\n 'INSERT INTO runs (id, job_id, started_at, status) VALUES (?, ?, ?, ?)',\n )\n .run(id, jobId, now, 'queued');\n return { id, jobId, startedAt: now, status: 'queued' };\n }\n\n updateRun(\n id: string,\n update: Partial<Pick<Run, 'status' | 'exitCode' | 'error' | 'endedAt' | 'durationMs'>>,\n ): void {\n const run = this.getRun(id);\n if (!run) throw new CrontickError('NOT_FOUND', `Run ${id} not found`);\n\n const fields: string[] = [];\n const values: (string | number | null)[] = [];\n\n if (update.status !== undefined) {\n fields.push('status = ?');\n values.push(update.status);\n }\n if (update.exitCode !== undefined) {\n fields.push('exit_code = ?');\n values.push(update.exitCode ?? null);\n }\n if (update.error !== undefined) {\n fields.push('error = ?');\n values.push(update.error ?? null);\n }\n if (update.endedAt !== undefined) {\n fields.push('ended_at = ?');\n values.push(update.endedAt ?? null);\n }\n if (update.durationMs !== undefined) {\n fields.push('duration_ms = ?');\n values.push(update.durationMs ?? null);\n }\n\n if (fields.length === 0) return;\n values.push(id);\n this.db.prepare(`UPDATE runs SET ${fields.join(', ')} WHERE id = ?`).run(...values);\n }\n\n getRun(id: string): Run | undefined {\n const row = this.db\n .prepare('SELECT * FROM runs WHERE id = ?')\n .get(id) as DbRunRow | undefined;\n return row ? rowToRun(row) : undefined;\n }\n\n listRuns(opts: ListRunsOptions = {}): Run[] {\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (opts.jobId) {\n conditions.push('job_id = ?');\n params.push(opts.jobId);\n }\n if (opts.since !== undefined) {\n conditions.push('started_at >= ?');\n params.push(opts.since);\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';\n const limit = opts.limit !== undefined ? `LIMIT ${opts.limit}` : '';\n const rows = this.db.prepare(`SELECT * FROM runs ${where} ORDER BY started_at DESC ${limit}`)\n .all(...params) as unknown as DbRunRow[];\n return rows.map(rowToRun);\n }\n\n /** Get the most recent successful run for a job (for catchup calculation). */\n getLastRun(jobId: string): Run | undefined {\n const row = this.db\n .prepare(\n \"SELECT * FROM runs WHERE job_id = ? AND status IN ('success','failed','timeout') ORDER BY started_at DESC LIMIT 1\",\n )\n .get(jobId) as DbRunRow | undefined;\n return row ? rowToRun(row) : undefined;\n }\n\n /** Count runs for a job started after a given epoch ms. */\n countRunsSince(jobId: string, since: number, excludeId?: string): number {\n if (excludeId) {\n const result = this.db\n .prepare('SELECT COUNT(*) as cnt FROM runs WHERE job_id = ? AND started_at >= ? AND id != ?')\n .get(jobId, since, excludeId) as { cnt: number };\n return result.cnt;\n }\n const result = this.db\n .prepare('SELECT COUNT(*) as cnt FROM runs WHERE job_id = ? AND started_at >= ?')\n .get(jobId, since) as { cnt: number };\n return result.cnt;\n }\n\n // ── Log CRUD ────────────────────────────────────────────────────────────────\n\n appendLog(runId: string, stream: 'stdout' | 'stderr', chunk: Buffer): void {\n this.db\n .prepare('INSERT INTO run_logs (run_id, stream, ts, chunk) VALUES (?, ?, ?, ?)')\n .run(runId, stream, Date.now(), chunk);\n }\n\n getLogs(runId: string): RunLog[] {\n const rows = this.db\n .prepare('SELECT * FROM run_logs WHERE run_id = ? ORDER BY id')\n .all(runId) as unknown as DbLogRow[];\n return rows.map(rowToLog);\n }\n\n tailLogs(runId: string, sinceTs: number): RunLog[] {\n const rows = this.db\n .prepare('SELECT * FROM run_logs WHERE run_id = ? AND ts > ? ORDER BY id')\n .all(runId, sinceTs) as unknown as DbLogRow[];\n return rows.map(rowToLog);\n }\n\n /** On daemon startup, cancel any runs that were left in 'running' or 'queued' state (daemon crashed). */\n reconcileOrphanRuns(): number {\n const result = this.db\n .prepare(\n \"UPDATE runs SET status = 'canceled', error = 'daemon-restart', ended_at = ? WHERE status IN ('running', 'queued')\",\n )\n .run(Date.now()) as { changes: number };\n return result.changes;\n }\n}\n\n// ── Internal row types ────────────────────────────────────────────────────────\n\ninterface DbRunRow {\n id: string;\n job_id: string;\n started_at: number;\n ended_at: number | null;\n status: RunStatus;\n exit_code: number | null;\n error: string | null;\n duration_ms: number | null;\n}\n\ninterface DbLogRow {\n id: number;\n run_id: string;\n stream: 'stdout' | 'stderr';\n ts: number;\n chunk: Buffer;\n}\n\nfunction rowToRun(row: DbRunRow): Run {\n const r: Run = {\n id: row.id,\n jobId: row.job_id,\n startedAt: row.started_at,\n status: row.status,\n };\n if (row.ended_at !== null) r.endedAt = row.ended_at;\n if (row.exit_code !== null) r.exitCode = row.exit_code;\n if (row.error !== null) r.error = row.error;\n if (row.duration_ms !== null) r.durationMs = row.duration_ms;\n return r;\n}\n\nfunction rowToLog(row: DbLogRow): RunLog {\n return {\n runId: row.run_id,\n stream: row.stream,\n ts: row.ts,\n chunk: Buffer.from(row.chunk),\n };\n}\n","export class CrontickError extends Error {\n code: string;\n details?: unknown;\n\n constructor(code: string, message: string, details?: unknown) {\n super(message);\n this.name = 'CrontickError';\n this.code = code;\n this.details = details;\n // Maintain proper prototype chain for instanceof checks\n Object.setPrototypeOf(this, CrontickError.prototype);\n }\n\n toJSON(): { code: string; message: string; details?: unknown } {\n return { code: this.code, message: this.message, details: this.details };\n }\n}\n","import { EventEmitter } from 'node:events';\nimport { Cron, type CronOptions } from 'croner';\nimport type { Job, Schedule } from '../schemas/job.js';\nimport type { Store } from './store.js';\n\n// ── Cron alias expansion ──────────────────────────────────────────────────────\n\nconst CRON_ALIASES: Record<string, string> = {\n '@yearly': '0 0 1 1 *',\n '@annually': '0 0 1 1 *',\n '@monthly': '0 0 1 * *',\n '@weekly': '0 0 * * 0',\n '@daily': '0 0 * * *',\n '@midnight': '0 0 * * *',\n '@noon': '0 12 * * *',\n '@hourly': '0 * * * *',\n '@every_minute': '* * * * *',\n};\n\n/** Expand a cron alias like @daily → '0 0 * * *', or return expr unchanged. */\nexport function expandCronAlias(expr: string): string {\n return CRON_ALIASES[expr.toLowerCase()] ?? expr;\n}\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface TickEvent {\n jobId: string;\n plannedAt: Date;\n}\n\nexport interface PreviewOptions {\n n?: number;\n tz?: string;\n}\n\nexport interface ValidateResult {\n ok: boolean;\n error?: string;\n}\n\n// ── Scheduler ─────────────────────────────────────────────────────────────────\n\nexport class Scheduler extends EventEmitter {\n private entries: Map<string, { stop: () => void }> = new Map();\n\n /**\n * Schedule a job, handling catchup based on the last run time from the store.\n * On daemon start pass `store` so catchup can be resolved; at runtime it's optional.\n */\n schedule(job: Job, store?: Store): void {\n this.unschedule(job.id); // idempotent\n\n if (!job.enabled) return;\n\n const { schedule } = job;\n const lastRun = store?.getLastRun(job.id);\n const lastRunAt = lastRun ? new Date(lastRun.startedAt) : undefined;\n\n if (schedule.kind === 'cron') {\n this.scheduleCron(job, expandCronAlias(schedule.cron), schedule.tz, lastRunAt);\n } else if (schedule.kind === 'interval') {\n this.scheduleInterval(job, schedule.everySec, schedule.startAt, lastRunAt);\n } else if (schedule.kind === 'one-shot') {\n this.scheduleOneShot(job, schedule.runAt);\n }\n }\n\n unschedule(jobId: string): void {\n const entry = this.entries.get(jobId);\n if (entry) {\n entry.stop();\n this.entries.delete(jobId);\n }\n }\n\n unscheduleAll(): void {\n for (const jobId of [...this.entries.keys()]) {\n this.unschedule(jobId);\n }\n }\n\n // ── Preview / Validate ─────────────────────────────────────────────────────\n\n previewNext(schedule: Schedule, opts: PreviewOptions = {}): string[] {\n const n = opts.n ?? 5;\n\n if (schedule.kind === 'cron') {\n return cronNextN(expandCronAlias(schedule.cron), opts.tz ?? schedule.tz, n);\n }\n\n if (schedule.kind === 'interval') {\n const now = Date.now();\n const intervalMs = schedule.everySec * 1000;\n const results: string[] = [];\n for (let i = 1; i <= n; i++) {\n results.push(new Date(now + i * intervalMs).toISOString());\n }\n return results;\n }\n\n if (schedule.kind === 'one-shot') {\n const t = new Date(schedule.runAt);\n if (isNaN(t.getTime())) return [];\n return t > new Date() ? [t.toISOString()] : [];\n }\n\n return [];\n }\n\n validateSchedule(schedule: Schedule): ValidateResult {\n if (schedule.kind === 'cron') {\n try {\n const cron = new Cron(expandCronAlias(schedule.cron), { paused: true });\n cron.stop();\n return { ok: true };\n } catch (err) {\n return { ok: false, error: String(err) };\n }\n }\n\n if (schedule.kind === 'interval') {\n if (schedule.everySec <= 0) {\n return { ok: false, error: 'everySec must be positive' };\n }\n if (schedule.startAt && isNaN(new Date(schedule.startAt).getTime())) {\n return { ok: false, error: 'startAt is not a valid ISO-8601 date' };\n }\n return { ok: true };\n }\n\n if (schedule.kind === 'one-shot') {\n const t = new Date(schedule.runAt);\n if (isNaN(t.getTime())) {\n return { ok: false, error: 'runAt is not a valid ISO-8601 date' };\n }\n return { ok: true };\n }\n\n return { ok: false, error: 'Unknown schedule kind' };\n }\n\n // ── Private helpers ────────────────────────────────────────────────────────\n\n private fireTick(jobId: string, plannedAt: Date): void {\n this.emit('tick', { jobId, plannedAt } satisfies TickEvent);\n }\n\n private scheduleCron(\n job: Job,\n pattern: string,\n tz: string | undefined,\n lastRunAt: Date | undefined,\n ): void {\n // Handle catchup before starting recurring schedule\n this.handleCronCatchup(job, pattern, tz, lastRunAt);\n\n const options: CronOptions = {};\n if (tz) options.timezone = tz;\n\n const cron = new Cron(pattern, options, () => {\n this.fireTick(job.id, new Date());\n });\n\n this.entries.set(job.id, { stop: () => cron.stop() });\n }\n\n private handleCronCatchup(\n job: Job,\n pattern: string,\n tz: string | undefined,\n lastRunAt: Date | undefined,\n ): void {\n if (job.catchup === 'skip' || !lastRunAt) return;\n\n const now = new Date();\n const missed = missedCronFires(pattern, tz, lastRunAt, now);\n if (missed.length === 0) return;\n\n if (job.catchup === 'run-once') {\n setImmediate(() => this.fireTick(job.id, missed[missed.length - 1]));\n } else if (job.catchup === 'run-all') {\n for (const t of missed) {\n const capturedT = t;\n setImmediate(() => this.fireTick(job.id, capturedT));\n }\n }\n }\n\n private scheduleInterval(\n job: Job,\n everySec: number,\n startAt: string | undefined,\n lastRunAt: Date | undefined,\n ): void {\n const intervalMs = everySec * 1000;\n\n // Handle catchup\n if (lastRunAt && job.catchup !== 'skip') {\n const elapsed = Date.now() - lastRunAt.getTime();\n const missedCount = Math.floor(elapsed / intervalMs);\n if (missedCount > 0) {\n if (job.catchup === 'run-once') {\n setImmediate(() => this.fireTick(job.id, new Date()));\n } else if (job.catchup === 'run-all') {\n for (let i = 0; i < missedCount; i++) {\n setImmediate(() => this.fireTick(job.id, new Date()));\n }\n }\n }\n }\n\n // Calculate initial delay\n let delay = intervalMs;\n if (startAt) {\n const startTime = new Date(startAt);\n if (!isNaN(startTime.getTime())) {\n const now = Date.now();\n const startMs = startTime.getTime();\n if (startMs > now) {\n delay = startMs - now;\n } else {\n const elapsed = now - startMs;\n delay = intervalMs - (elapsed % intervalMs);\n }\n }\n }\n\n const timer = safeSetTimeout(() => {\n this.fireTick(job.id, new Date());\n const interval = setInterval(() => this.fireTick(job.id, new Date()), intervalMs);\n this.entries.set(job.id, { stop: () => clearInterval(interval) });\n }, delay);\n\n this.entries.set(job.id, {\n stop: () => timer.clear(),\n });\n }\n\n private scheduleOneShot(job: Job, runAt: string): void {\n const t = new Date(runAt);\n if (isNaN(t.getTime())) return;\n\n const delay = t.getTime() - Date.now();\n if (delay <= 0) {\n if (job.catchup !== 'skip') {\n setImmediate(() => {\n this.fireTick(job.id, t);\n this.entries.delete(job.id);\n });\n }\n return;\n }\n\n const timer = safeSetTimeout(() => {\n this.fireTick(job.id, t);\n this.entries.delete(job.id);\n }, delay);\n\n this.entries.set(job.id, { stop: () => timer.clear() });\n }\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\n/**\n * `setTimeout` clamps delays > 2^31-1 ms (~24.8 days) to 1 ms, causing\n * far-future timers to fire immediately. This helper chains intermediate\n * 2 000 000 000 ms timeouts until the remaining delay is safe.\n */\nconst MAX_SAFE_TIMEOUT_MS = 2_000_000_000;\n\ninterface SafeTimer {\n clear(): void;\n}\n\nfunction safeSetTimeout(cb: () => void, ms: number): SafeTimer {\n if (ms <= MAX_SAFE_TIMEOUT_MS) {\n const t = setTimeout(cb, ms);\n return { clear: () => clearTimeout(t) };\n }\n let inner: SafeTimer | undefined;\n const t = setTimeout(() => {\n inner = safeSetTimeout(cb, ms - MAX_SAFE_TIMEOUT_MS);\n }, MAX_SAFE_TIMEOUT_MS);\n return {\n clear: () => {\n clearTimeout(t);\n inner?.clear();\n },\n };\n}\n\nfunction cronNextN(pattern: string, tz: string | undefined, n: number): string[] {\n try {\n const options: CronOptions = { paused: true };\n if (tz) options.timezone = tz;\n const cron = new Cron(pattern, options);\n const results: string[] = [];\n let ref: Date | undefined;\n for (let i = 0; i < n; i++) {\n const next = cron.nextRun(ref) as Date | null;\n if (!next) break;\n results.push(next.toISOString());\n ref = new Date(next.getTime() + 1);\n }\n cron.stop();\n return results;\n } catch {\n return [];\n }\n}\n\nfunction missedCronFires(\n pattern: string,\n tz: string | undefined,\n from: Date,\n to: Date,\n): Date[] {\n try {\n const options: CronOptions = { paused: true };\n if (tz) options.timezone = tz;\n const cron = new Cron(pattern, options);\n const missed: Date[] = [];\n let ref: Date | undefined = from;\n for (;;) {\n const next = cron.nextRun(ref) as Date | null;\n if (!next || next > to) break;\n missed.push(next);\n ref = new Date(next.getTime() + 1);\n if (missed.length > 1000) break;\n }\n cron.stop();\n return missed;\n } catch {\n return [];\n }\n}\n","import { spawn } from 'node:child_process';\nimport { writeFileSync, unlinkSync, existsSync, mkdirSync, readFileSync } from 'node:fs';\nimport { tmpdir, platform } from 'node:os';\nimport { join, isAbsolute } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport type { Job } from '../schemas/job.js';\nimport type { Store, RunStatus } from './store.js';\nimport { CrontickError } from '../errors.js';\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\ninterface RunResult {\n status: RunStatus;\n exitCode?: number;\n error?: string;\n}\n\ntype QueueEntry = () => Promise<void>;\n\n// ── Secret redaction ──────────────────────────────────────────────────────────\n\nconst SECRET_PATTERNS = [\n /(?:AWS_SECRET_ACCESS_KEY|AWS_SESSION_TOKEN)=[^\\s]*/gi,\n /(?:GITHUB_TOKEN|GH_TOKEN)=[^\\s]*/gi,\n /(?:GCLOUD_SERVICE_KEY|GOOGLE_CREDENTIALS)=[^\\s]*/gi,\n /Bearer\\s+[A-Za-z0-9\\-._~+/]+=*/gi,\n /ghp_[A-Za-z0-9]{36}/g,\n /AKIA[0-9A-Z]{16}/g,\n];\n\nfunction redact(text: string): string {\n let out = text;\n for (const pat of SECRET_PATTERNS) {\n out = out.replace(pat, '[REDACTED]');\n }\n return out;\n}\n\n/**\n * Redact secrets from a chunk only when it is valid UTF-8 text.\n * Binary data (NUL bytes or lossy UTF-8 round-trip) is stored as-is.\n */\nfunction safeRedact(chunk: Buffer): Buffer {\n // NUL byte → likely binary, skip redaction\n if (chunk.includes(0)) return chunk;\n const str = chunk.toString('utf8');\n // Lossy round-trip → binary or non-UTF-8, skip redaction\n if (!Buffer.from(str, 'utf8').equals(chunk)) return chunk;\n const cleaned = redact(str);\n return Buffer.from(cleaned, 'utf8');\n}\n\n// ── Env-file loader ───────────────────────────────────────────────────────────\n\n/**\n * Parse a .env-style file (KEY=VALUE, # comments, quoted values).\n * Returns a record of KEY → VALUE.\n */\nexport function parseEnvFile(contents: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const raw of contents.split(/\\r?\\n/)) {\n const line = raw.trim();\n if (!line || line.startsWith('#')) continue;\n const eq = line.indexOf('=');\n if (eq === -1) continue;\n const key = line.slice(0, eq).trim();\n let value = line.slice(eq + 1).trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"'))\n || (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n if (key) result[key] = value;\n }\n return result;\n}\n\n// ── Runner ────────────────────────────────────────────────────────────────────\n\nexport class Runner {\n /** Per-job queues for overlap=queue policy */\n private queues: Map<string, QueueEntry[]> = new Map();\n /** Abort controllers for currently active runs per job */\n private activeAborts: Map<string, AbortController> = new Map();\n /** Active run IDs per job */\n private activeRunIds: Map<string, string> = new Map();\n /** Whether a job's queue is currently being drained */\n private draining: Set<string> = new Set();\n\n /**\n * Execute a job run, honouring overlap + retry + budget policies.\n * The run record must already exist in the store (status=queued).\n */\n async run(job: Job, runId: string, store: Store): Promise<void> {\n const overlap = job.overlap ?? 'skip';\n\n // Budget: maxRunsPerDay\n if (job.budgets?.maxRunsPerDay != null) {\n const todayStart = new Date();\n todayStart.setUTCHours(0, 0, 0, 0);\n const count = store.countRunsSince(job.id, todayStart.getTime(), runId);\n if (count >= job.budgets.maxRunsPerDay) {\n await this.finalizeRun(store, runId, {\n status: 'canceled',\n error: `budget: maxRunsPerDay (${job.budgets.maxRunsPerDay}) exceeded`,\n });\n return;\n }\n }\n\n const isActive = this.activeRunIds.has(job.id);\n\n if (overlap === 'skip' && isActive) {\n await this.finalizeRun(store, runId, {\n status: 'canceled',\n error: 'overlap=skip: another run is already active',\n });\n return;\n }\n\n if (overlap === 'cancel-previous' && isActive) {\n const ctrl = this.activeAborts.get(job.id);\n if (ctrl) ctrl.abort();\n }\n\n if (overlap === 'queue') {\n await this.enqueue(job, runId, store);\n } else {\n await this.execute(job, runId, store);\n }\n }\n\n private enqueue(job: Job, runId: string, store: Store): Promise<void> {\n return new Promise<void>((resolve) => {\n const queue = this.queues.get(job.id) ?? [];\n queue.push(async () => {\n await this.execute(job, runId, store);\n resolve();\n });\n this.queues.set(job.id, queue);\n if (!this.draining.has(job.id)) {\n this.drainQueue(job.id);\n }\n });\n }\n\n private async drainQueue(jobId: string): Promise<void> {\n this.draining.add(jobId);\n const queue = this.queues.get(jobId);\n if (!queue || queue.length === 0) {\n this.draining.delete(jobId);\n return;\n }\n const next = queue.shift()!;\n try {\n await next();\n } catch {\n // errors handled inside execute\n }\n await this.drainQueue(jobId);\n }\n\n private async execute(job: Job, runId: string, store: Store): Promise<void> {\n const maxRetries = job.retry?.max ?? 0;\n const backoffSec = job.retry?.backoffSec ?? 30;\n let lastResult: RunResult = { status: 'failed', error: 'not started' };\n\n store.updateRun(runId, { status: 'running' });\n\n const ctrl = new AbortController();\n this.activeAborts.set(job.id, ctrl);\n this.activeRunIds.set(job.id, runId);\n\n try {\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n if (attempt > 0) {\n await sleep(backoffSec * 1000);\n }\n if (ctrl.signal.aborted) {\n lastResult = { status: 'canceled', error: 'canceled before retry' };\n break;\n }\n lastResult = await this.spawn(job, runId, store, ctrl.signal);\n if (lastResult.status === 'success') break;\n if (lastResult.status === 'canceled' || lastResult.status === 'timeout') break;\n }\n } finally {\n // Only delete if these maps still point to THIS run's ctrl/runId.\n // A newer run (cancel-previous) may have already overwritten them.\n if (this.activeAborts.get(job.id) === ctrl) this.activeAborts.delete(job.id);\n if (this.activeRunIds.get(job.id) === runId) this.activeRunIds.delete(job.id);\n }\n\n await this.finalizeRun(store, runId, lastResult);\n }\n\n private async spawn(\n job: Job,\n runId: string,\n store: Store,\n signal: AbortSignal,\n ): Promise<RunResult> {\n const { action } = job;\n let tmpFile: string | undefined;\n\n try {\n let cmd: string;\n let args: string[];\n\n if (action.kind === 'script') {\n // Write script to temp file\n const ext = resolveShellExt(action.shell ?? 'auto');\n const tmpDir = join(tmpdir(), 'crontick');\n mkdirSync(tmpDir, { recursive: true });\n tmpFile = join(tmpDir, `${randomUUID()}${ext}`);\n writeFileSync(tmpFile, action.script, { encoding: 'utf-8', mode: 0o700 });\n\n const resolved = resolveShell(action.shell ?? 'auto');\n if (resolved === 'pwsh') {\n cmd = 'pwsh';\n args = ['-NoProfile', '-NonInteractive', '-File', tmpFile];\n } else if (resolved === 'cmd') {\n cmd = 'cmd';\n args = ['/c', tmpFile];\n } else {\n cmd = 'bash';\n args = [tmpFile];\n }\n } else {\n cmd = action.command;\n args = action.args ?? [];\n }\n\n const spawnOpts: Parameters<typeof spawn>[2] = {\n cwd: action.cwd ?? process.cwd(),\n env: { ...process.env, ...(action.env ?? {}) } as NodeJS.ProcessEnv,\n signal,\n shell: false,\n };\n\n // Merge envFile variables (lower priority than action.env).\n // We intentionally do not log environment snapshots, so secret-shaped\n // env-file values are not emitted to logs.\n if (action.envFile) {\n const envFilePath = isAbsolute(action.envFile)\n ? action.envFile\n : join(action.cwd ?? process.cwd(), action.envFile);\n try {\n const fileContents = readFileSync(envFilePath, 'utf-8');\n const envFileVars = parseEnvFile(fileContents);\n spawnOpts.env = {\n ...process.env,\n ...envFileVars,\n ...(action.env ?? {}),\n } as NodeJS.ProcessEnv;\n } catch (err) {\n throw new CrontickError('ENV_FILE_ERROR', `Failed to load envFile: ${String(err)}`);\n }\n }\n\n if (action.timeoutSec) {\n spawnOpts.timeout = action.timeoutSec * 1000;\n }\n\n const result = await new Promise<RunResult>((resolve) => {\n const child = spawn(cmd, args, spawnOpts);\n const startedAt = Date.now();\n\n child.stdout?.on('data', (chunk: Buffer) => {\n store.appendLog(runId, 'stdout', safeRedact(chunk));\n });\n\n child.stderr?.on('data', (chunk: Buffer) => {\n store.appendLog(runId, 'stderr', safeRedact(chunk));\n });\n\n child.on('close', (code, sig) => {\n const durationMs = Date.now() - startedAt;\n if (sig === 'SIGTERM' || sig === 'SIGKILL') {\n resolve({ status: 'canceled', error: `killed by signal ${sig}` });\n } else if (code === null) {\n resolve({ status: 'failed', error: 'process exited without code' });\n } else {\n resolve({\n status: code === 0 ? 'success' : 'failed',\n exitCode: code,\n });\n }\n void durationMs; // consumed below via store\n });\n\n child.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'ABORT_ERR' || signal.aborted) {\n resolve({ status: 'canceled', error: 'aborted' });\n } else if (err.code === 'ETIMEDOUT') {\n resolve({ status: 'timeout', error: 'timed out' });\n } else {\n resolve({ status: 'failed', error: err.message });\n }\n });\n });\n\n return result;\n } finally {\n if (tmpFile && existsSync(tmpFile)) {\n try {\n unlinkSync(tmpFile);\n } catch {\n // ignore cleanup failure\n }\n }\n }\n }\n\n private async finalizeRun(store: Store, runId: string, result: RunResult): Promise<void> {\n const run = store.getRun(runId);\n const now = Date.now();\n store.updateRun(runId, {\n status: result.status,\n exitCode: result.exitCode,\n error: result.error,\n endedAt: now,\n durationMs: run ? now - run.startedAt : undefined,\n });\n }\n\n /** Cancel any active run for a job. */\n cancelJob(jobId: string): boolean {\n const ctrl = this.activeAborts.get(jobId);\n if (ctrl) {\n ctrl.abort();\n return true;\n }\n return false;\n }\n\n /** Cancel an active run by run ID. */\n cancelRun(runId: string): boolean {\n for (const [jobId, rId] of this.activeRunIds.entries()) {\n if (rId === runId) {\n return this.cancelJob(jobId);\n }\n }\n return false;\n }\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction resolveShell(shell: string): 'bash' | 'pwsh' | 'cmd' {\n if (shell === 'auto') {\n return platform() === 'win32' ? 'pwsh' : 'bash';\n }\n if (shell === 'pwsh') return 'pwsh';\n if (shell === 'cmd') return 'cmd';\n return 'bash';\n}\n\nfunction resolveShellExt(shell: string): string {\n const resolved = resolveShell(shell);\n if (resolved === 'pwsh') return '.ps1';\n if (resolved === 'cmd') return '.bat';\n return '.sh';\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport { CrontickError };\n","import http from 'node:http';\nimport { createReadStream, existsSync as fsExistsSync, statSync } from 'node:fs';\nimport {\n extname,\n resolve as pathResolve,\n join as pathJoin,\n normalize,\n sep as pathSep,\n} from 'node:path';\nimport { URL } from 'node:url';\nimport { fileURLToPath } from 'node:url';\nimport type { Store } from './store.js';\nimport type { Scheduler } from './scheduler.js';\nimport type { Runner } from './runner.js';\nimport { JobSchema } from '../schemas/job.js';\nimport { CrontickError } from '../errors.js';\nimport { VERSION } from '../version.js';\nimport { createAutostart, NotImplementedInV1Error } from '../autostart/index.js';\nimport type { AutostartBackend } from '../autostart/index.js';\n\n// ── Constants ─────────────────────────────────────────────────────────────────\n\nconst LOOPBACK = new Set(['127.0.0.1', '::1', '::ffff:127.0.0.1']);\nconst SSE_POLL_MS = 200;\nconst MIME_TYPES: Record<string, string> = {\n '.html': 'text/html; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.png': 'image/png',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n};\n\n// ── Context shared with handlers ──────────────────────────────────────────────\n\nexport interface ApiContext {\n store: Store;\n scheduler: Scheduler;\n runner: Runner;\n startedAt: Date;\n port: number;\n reload: () => Promise<void>;\n}\n\n// ── Server factory ────────────────────────────────────────────────────────────\n\nexport function createApiServer(ctx: ApiContext): http.Server {\n const server = http.createServer((req, res) => {\n // Enforce localhost-only\n const remote = req.socket.remoteAddress ?? '';\n if (!LOOPBACK.has(remote)) {\n return sendError(res, 403, 'FORBIDDEN', 'Only localhost connections are allowed');\n }\n void handleRequest(req, res, ctx);\n });\n return server;\n}\n\n// ── Router ────────────────────────────────────────────────────────────────────\n\nasync function handleRequest(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n ctx: ApiContext,\n): Promise<void> {\n const method = req.method ?? 'GET';\n const rawUrl = req.url ?? '/';\n const baseUrl = `http://127.0.0.1`;\n const url = new URL(rawUrl, baseUrl);\n const path = url.pathname;\n\n try {\n // ── Health ───────────────────────────────────────────────────────────────\n if (method === 'GET' && path === '/health') {\n const jobs = ctx.store.listJobs();\n const since24h = Date.now() - 24 * 60 * 60 * 1000;\n const runs24h = ctx.store.listRuns({ since: since24h });\n return sendJson(res, 200, {\n ok: true,\n version: VERSION,\n uptimeSec: Math.floor((Date.now() - ctx.startedAt.getTime()) / 1000),\n pid: process.pid,\n port: ctx.port,\n jobs: {\n total: jobs.length,\n enabled: jobs.filter((j) => j.enabled).length,\n },\n runs: {\n last24h: runs24h.length,\n failures24h: runs24h.filter((r) => r.status === 'failed').length,\n },\n node: process.versions.node,\n platform: process.platform,\n });\n }\n\n // ── Jobs ─────────────────────────────────────────────────────────────────\n if (method === 'GET' && path === '/api/jobs') {\n return sendJson(res, 200, ctx.store.listJobs());\n }\n\n if (method === 'POST' && path === '/api/jobs') {\n const body = await readBody(req);\n const parsed = JobSchema.safeParse(body);\n if (!parsed.success) {\n return sendError(res, 400, 'VALIDATION_ERROR', 'Invalid job', parsed.error.format());\n }\n ctx.store.upsertJob(parsed.data);\n ctx.scheduler.schedule(parsed.data, ctx.store);\n return sendJson(res, 201, parsed.data);\n }\n\n // /api/jobs/:id/*\n const jobMatch = path.match(/^\\/api\\/jobs\\/([^/]+)(\\/.*)?$/);\n if (jobMatch) {\n const id = decodeURIComponent(jobMatch[1]);\n const sub = jobMatch[2] ?? '';\n\n if (method === 'GET' && sub === '') {\n const job = ctx.store.getJob(id);\n if (!job) return sendError(res, 404, 'NOT_FOUND', `Job ${id} not found`);\n return sendJson(res, 200, job);\n }\n\n if (method === 'PUT' && sub === '') {\n const existing = ctx.store.getJob(id);\n if (!existing) return sendError(res, 404, 'NOT_FOUND', `Job ${id} not found`);\n const body = await readBody(req);\n const parsed = JobSchema.safeParse({ ...existing, ...body, id });\n if (!parsed.success) {\n return sendError(res, 400, 'VALIDATION_ERROR', 'Invalid job', parsed.error.format());\n }\n ctx.store.upsertJob(parsed.data);\n ctx.scheduler.schedule(parsed.data, ctx.store);\n return sendJson(res, 200, parsed.data);\n }\n\n if (method === 'DELETE' && sub === '') {\n const deleted = ctx.store.deleteJob(id);\n if (!deleted) return sendError(res, 404, 'NOT_FOUND', `Job ${id} not found`);\n ctx.scheduler.unschedule(id);\n return sendJson(res, 200, { ok: true });\n }\n\n if (method === 'POST' && sub === '/enable') {\n const job = ctx.store.getJob(id);\n if (!job) return sendError(res, 404, 'NOT_FOUND', `Job ${id} not found`);\n const updated = { ...job, enabled: true };\n ctx.store.upsertJob(updated);\n ctx.scheduler.schedule(updated, ctx.store);\n return sendJson(res, 200, updated);\n }\n\n if (method === 'POST' && sub === '/disable') {\n const job = ctx.store.getJob(id);\n if (!job) return sendError(res, 404, 'NOT_FOUND', `Job ${id} not found`);\n const updated = { ...job, enabled: false };\n ctx.store.upsertJob(updated);\n ctx.scheduler.unschedule(id);\n return sendJson(res, 200, updated);\n }\n\n if (method === 'POST' && sub === '/run') {\n const job = ctx.store.getJob(id);\n if (!job) return sendError(res, 404, 'NOT_FOUND', `Job ${id} not found`);\n const run = ctx.store.insertRun(id);\n // fire async, don't await\n ctx.runner.run(job, run.id, ctx.store).catch(() => {});\n return sendJson(res, 202, { runId: run.id });\n }\n }\n\n // ── Runs ─────────────────────────────────────────────────────────────────\n if (method === 'GET' && path === '/api/runs') {\n const jobId = url.searchParams.get('jobId') ?? undefined;\n const limit = url.searchParams.has('limit')\n ? parseInt(url.searchParams.get('limit')!, 10)\n : undefined;\n const since = url.searchParams.has('since')\n ? parseInt(url.searchParams.get('since')!, 10)\n : undefined;\n return sendJson(res, 200, ctx.store.listRuns({ jobId, limit, since }));\n }\n\n // /api/runs/:id/*\n const runMatch = path.match(/^\\/api\\/runs\\/([^/]+)(\\/.*)?$/);\n if (runMatch) {\n const id = decodeURIComponent(runMatch[1]);\n const sub = runMatch[2] ?? '';\n\n if (method === 'GET' && sub === '') {\n const run = ctx.store.getRun(id);\n if (!run) return sendError(res, 404, 'NOT_FOUND', `Run ${id} not found`);\n return sendJson(res, 200, run);\n }\n\n if (method === 'POST' && sub === '/cancel') {\n const run = ctx.store.getRun(id);\n if (!run) return sendError(res, 404, 'NOT_FOUND', `Run ${id} not found`);\n const canceled = ctx.runner.cancelRun(id);\n return sendJson(res, 200, { ok: true, canceled });\n }\n\n if (method === 'GET' && sub === '/logs') {\n const run = ctx.store.getRun(id);\n if (!run) return sendError(res, 404, 'NOT_FOUND', `Run ${id} not found`);\n const logs = ctx.store.getLogs(id);\n return sendJson(res, 200, logs.map((l) => ({\n runId: l.runId,\n stream: l.stream,\n ts: l.ts,\n data: l.chunk.toString('utf-8'),\n })));\n }\n\n if (method === 'GET' && sub === '/logs/stream') {\n const run = ctx.store.getRun(id);\n if (!run) return sendError(res, 404, 'NOT_FOUND', `Run ${id} not found`);\n return streamLogs(req, res, id, ctx);\n }\n }\n\n // ── Schedules ─────────────────────────────────────────────────────────────\n if (method === 'POST' && path === '/api/schedules/validate') {\n const body = await readBody(req);\n const { ScheduleSchema } = await import('../schemas/job.js');\n const parsed = ScheduleSchema.safeParse(body);\n if (!parsed.success) {\n return sendJson(res, 200, { ok: false, error: JSON.stringify(parsed.error.format()) });\n }\n const result = ctx.scheduler.validateSchedule(parsed.data);\n return sendJson(res, 200, result);\n }\n\n if (method === 'POST' && path === '/api/schedules/preview') {\n const body = await readBody(req);\n const { ScheduleSchema } = await import('../schemas/job.js');\n const scheduleResult = ScheduleSchema.safeParse(body?.schedule ?? body);\n if (!scheduleResult.success) {\n return sendError(res, 400, 'VALIDATION_ERROR', 'Invalid schedule');\n }\n const n = typeof body?.n === 'number' ? body.n : 5;\n const tz = body?.tz as string | undefined;\n const next = ctx.scheduler.previewNext(scheduleResult.data, { n, tz });\n return sendJson(res, 200, { next });\n }\n\n // ── Stats ─────────────────────────────────────────────────────────────────\n if (method === 'GET' && path === '/api/stats/summary') {\n const jobs = ctx.store.listJobs();\n const runs = ctx.store.listRuns({ limit: 1000 });\n const failed = runs.filter((r) => r.status === 'failed').length;\n const succeeded = runs.filter((r) => r.status === 'success').length;\n return sendJson(res, 200, {\n totalJobs: jobs.length,\n enabledJobs: jobs.filter((j) => j.enabled).length,\n totalRuns: runs.length,\n succeeded,\n failed,\n avgDurationMs:\n runs.length > 0\n ? Math.round(runs.reduce((s, r) => s + (r.durationMs ?? 0), 0) / runs.length)\n : null,\n });\n }\n\n const statsJobMatch = path.match(/^\\/api\\/stats\\/jobs\\/([^/]+)$/);\n if (method === 'GET' && statsJobMatch) {\n const id = decodeURIComponent(statsJobMatch[1]);\n const job = ctx.store.getJob(id);\n if (!job) return sendError(res, 404, 'NOT_FOUND', `Job ${id} not found`);\n const runs = ctx.store.listRuns({ jobId: id, limit: 100 });\n return sendJson(res, 200, {\n jobId: id,\n totalRuns: runs.length,\n succeeded: runs.filter((r) => r.status === 'success').length,\n failed: runs.filter((r) => r.status === 'failed').length,\n lastStatus: runs[0]?.status ?? null,\n lastRunAt: runs[0]?.startedAt ?? null,\n });\n }\n\n // ── Daemon ────────────────────────────────────────────────────────────────\n if (method === 'GET' && path === '/api/daemon/status') {\n return sendJson(res, 200, {\n pid: process.pid,\n version: VERSION,\n uptimeSec: Math.floor((Date.now() - ctx.startedAt.getTime()) / 1000),\n jobs: ctx.store.listJobs().length,\n });\n }\n\n if (method === 'POST' && path === '/api/daemon/reload') {\n await ctx.reload();\n return sendJson(res, 200, { ok: true });\n }\n\n // ── Export / Import ───────────────────────────────────────────────────────\n if (method === 'GET' && path === '/api/export') {\n return sendJson(res, 200, { jobs: ctx.store.listJobs() });\n }\n\n if (method === 'POST' && path === '/api/import') {\n const body = await readBody(req);\n const jobs = Array.isArray(body?.jobs) ? body.jobs : [];\n const results: Array<{ id: string; ok: boolean; error?: string }> = [];\n for (const raw of jobs) {\n const parsed = JobSchema.safeParse(raw);\n if (parsed.success) {\n ctx.store.upsertJob(parsed.data);\n ctx.scheduler.schedule(parsed.data, ctx.store);\n results.push({ id: parsed.data.id, ok: true });\n } else {\n results.push({ id: String(raw?.id ?? '?'), ok: false, error: 'validation failed' });\n }\n }\n return sendJson(res, 200, { imported: results.filter((r) => r.ok).length, results });\n }\n\n // ── Autostart ─────────────────────────────────────────────────────────────\n\n if (method === 'GET' && path === '/api/autostart/status') {\n const backend = (url.searchParams.get('backend') ?? undefined) as AutostartBackend | undefined;\n const autostart = createAutostart({ backend });\n const result = await autostart.status();\n return sendJson(res, 200, result);\n }\n\n if (method === 'POST' && path === '/api/autostart/install') {\n const body = await readBody(req);\n const backend = (body?.['backend'] as string | undefined) as AutostartBackend | undefined;\n const autostart = createAutostart({ backend });\n const result = await autostart.install();\n return sendJson(res, 200, result);\n }\n\n if (method === 'POST' && path === '/api/autostart/remove') {\n const body = await readBody(req);\n const backend = (body?.['backend'] as string | undefined) as AutostartBackend | undefined;\n const autostart = createAutostart({ backend });\n const result = await autostart.remove();\n return sendJson(res, 200, result);\n }\n\n // ── Dashboard ─────────────────────────────────────────────────────────────\n if (method === 'GET' && (path === '/' || path === '/dashboard' || path.startsWith('/dashboard/'))) {\n return serveDashboard(res, path);\n }\n\n // ── 404 ───────────────────────────────────────────────────────────────────\n return sendError(res, 404, 'NOT_FOUND', `${method} ${path} not found`);\n } catch (err) {\n if (err instanceof NotImplementedInV1Error) {\n return sendError(res, 501, 'NOT_IMPLEMENTED_V1', err.message);\n }\n if (err instanceof CrontickError) {\n return sendError(res, 400, err.code, err.message, err.details);\n }\n const msg = err instanceof Error ? err.message : String(err);\n return sendError(res, 500, 'INTERNAL_ERROR', msg);\n }\n}\n\n// ── SSE log streaming ─────────────────────────────────────────────────────────\n\nfunction streamLogs(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n runId: string,\n ctx: ApiContext,\n): void {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n });\n\n let lastTs = 0;\n\n // Send existing logs first\n const existing = ctx.store.getLogs(runId);\n for (const log of existing) {\n sseEvent(res, { stream: log.stream, ts: log.ts, data: log.chunk.toString('utf-8') });\n if (log.ts > lastTs) lastTs = log.ts;\n }\n\n // Poll for new logs until run is terminal\n const poll = setInterval(() => {\n const run = ctx.store.getRun(runId);\n const newLogs = ctx.store.tailLogs(runId, lastTs);\n for (const log of newLogs) {\n sseEvent(res, { stream: log.stream, ts: log.ts, data: log.chunk.toString('utf-8') });\n if (log.ts > lastTs) lastTs = log.ts;\n }\n\n const terminal = new Set(['success', 'failed', 'canceled', 'timeout']);\n if (!run || terminal.has(run.status)) {\n sseEvent(res, { done: true, status: run?.status });\n clearInterval(poll);\n res.end();\n }\n }, SSE_POLL_MS);\n\n req.on('close', () => {\n clearInterval(poll);\n });\n}\n\nfunction dashboardDir(): string {\n const moduleDir = pathResolve(fileURLToPath(import.meta.url), '..');\n return pathResolve(moduleDir, '../dashboard');\n}\n\nfunction serveDashboard(\n res: http.ServerResponse,\n reqPath: string,\n): void {\n const dashDir = dashboardDir();\n const indexFile = pathJoin(dashDir, 'index.html');\n\n let filePath: string;\n if (reqPath === '/' || reqPath === '/dashboard' || reqPath === '/dashboard/') {\n filePath = indexFile;\n } else {\n const sub = reqPath.startsWith('/dashboard/') ? reqPath.slice('/dashboard'.length) : reqPath;\n const normalizedSub = normalize(sub).replace(/^[/\\\\]+/, '');\n filePath = pathResolve(dashDir, normalizedSub);\n }\n\n if (filePath !== indexFile && !filePath.startsWith(`${dashDir}${pathSep}`)) {\n res.writeHead(400, { 'Content-Type': 'text/plain' });\n res.end('Bad Request');\n return;\n }\n\n if (!fsExistsSync(filePath)) {\n filePath = indexFile;\n }\n\n if (!fsExistsSync(filePath)) {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not Found');\n return;\n }\n\n const stat = statSync(filePath);\n if (!stat.isFile()) {\n res.writeHead(403, { 'Content-Type': 'text/plain' });\n res.end('Forbidden');\n return;\n }\n\n const ext = extname(filePath).toLowerCase();\n const contentType = MIME_TYPES[ext] ?? 'application/octet-stream';\n res.writeHead(200, {\n 'Content-Type': contentType,\n 'Content-Length': stat.size,\n 'Cache-Control': 'no-cache',\n });\n createReadStream(filePath).pipe(res);\n}\n\nfunction sseEvent(res: http.ServerResponse, data: unknown): void {\n res.write(`data: ${JSON.stringify(data)}\\n\\n`);\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nasync function readBody(req: http.IncomingMessage): Promise<Record<string, unknown>> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on('data', (chunk: Buffer) => chunks.push(chunk));\n req.on('end', () => {\n const raw = Buffer.concat(chunks).toString('utf-8');\n if (!raw) {\n resolve({});\n return;\n }\n try {\n resolve(JSON.parse(raw) as Record<string, unknown>);\n } catch {\n resolve({});\n }\n });\n req.on('error', reject);\n });\n}\n\nfunction sendJson(res: http.ServerResponse, status: number, body: unknown): void {\n const json = JSON.stringify(body);\n res.writeHead(status, { 'Content-Type': 'application/json' });\n res.end(json);\n}\n\nfunction sendError(\n res: http.ServerResponse,\n status: number,\n code: string,\n message: string,\n details?: unknown,\n): void {\n sendJson(res, status, { error: { code, message, details } });\n}\n","// Version constant injected at build time by tsup/esbuild (define: __CRONTICK_VERSION__)\n// and at test time by vitest (define in vitest.config.ts).\ndeclare const __CRONTICK_VERSION__: string;\nexport const VERSION: string = __CRONTICK_VERSION__;\n","/**\n * Windows autostart backend — HKCU Run key + hidden VBS shim.\n *\n * Registry key: HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\n * Value name: crontick-daemon (or CRONTICK_AUTOSTART_TEST_VALUE for tests)\n * Value data: wscript.exe \"<dataDir>\\autostart\\crontick-daemon.vbs\"\n *\n * The VBS shim launches crontick-daemon via `cmd /c` with window style 0 (hidden).\n */\nimport { spawnSync } from 'node:child_process';\nimport {\n writeFileSync,\n existsSync,\n unlinkSync,\n mkdirSync,\n} from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { autostartDir } from '../paths.js';\nimport type { AutostartStatus } from './index.js';\n\nconst RUN_KEY = 'HKCU\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run';\n\nfunction getValueName(): string {\n return process.env['CRONTICK_AUTOSTART_TEST_VALUE'] ?? 'crontick-daemon';\n}\n\nfunction getVbsPath(): string {\n return join(autostartDir(), 'crontick-daemon.vbs');\n}\n\n/**\n * Locate the absolute path to the crontick-daemon binary/cmd wrapper.\n * Prefers `where.exe` detection so PATH changes don't break the shim.\n * CRONTICK_DAEMON_BINARY env var overrides detection (useful in CI/tests).\n */\nfunction findDaemonBinary(): string | null {\n // 0. Test / CI override\n const override = process.env['CRONTICK_DAEMON_BINARY'];\n if (override) return override;\n\n // 1. Try where.exe\n const whereResult = spawnSync('where.exe', ['crontick-daemon'], {\n encoding: 'utf-8',\n timeout: 5_000,\n windowsHide: true,\n });\n if (whereResult.status === 0 && whereResult.stdout.trim()) {\n const first = whereResult.stdout.trim().split(/[\\r\\n]+/)[0]?.trim();\n if (first) return first;\n }\n\n // 2. Fallback: look in the same directory as the Node.js executable\n const nodeDir = dirname(process.execPath);\n for (const candidate of ['crontick-daemon.cmd', 'crontick-daemon']) {\n const p = join(nodeDir, candidate);\n if (existsSync(p)) return p;\n }\n\n return null;\n}\n\nfunction buildVbsContent(daemonPath: string): string {\n // Remove any double-quotes in path (shouldn't exist in valid Win paths)\n const safePath = daemonPath.replace(/\"/g, '');\n return [\n \"' crontick-daemon autostart shim — generated by crontick autostart install\",\n \"' Do not edit manually. Run: crontick autostart install to regenerate.\",\n 'Set WshShell = CreateObject(\"WScript.Shell\")',\n `WshShell.Run \"cmd /c \"\"${safePath}\"\"\", 0, False`,\n '',\n ].join('\\r\\n');\n}\n\nfunction regQuery(valueName: string): string | null {\n const result = spawnSync(\n 'reg',\n ['query', RUN_KEY, '/v', valueName],\n { encoding: 'utf-8', timeout: 5_000, windowsHide: true },\n );\n if (result.status !== 0 || !result.stdout) return null;\n // Output format: \" valueName REG_SZ <data>\"\n const match = result.stdout.match(/REG_SZ\\s+(.+)/i);\n return match?.[1]?.trim() ?? null;\n}\n\nfunction regWrite(valueName: string, data: string): void {\n const result = spawnSync(\n 'reg',\n ['add', RUN_KEY, '/v', valueName, '/t', 'REG_SZ', '/d', data, '/f'],\n { encoding: 'utf-8', timeout: 5_000, windowsHide: true },\n );\n if (result.status !== 0) {\n throw new Error(\n `reg.exe add failed (exit ${result.status ?? '?'}): ${result.stderr?.trim() ?? 'unknown error'}`,\n );\n }\n}\n\nfunction regDelete(valueName: string): void {\n spawnSync(\n 'reg',\n ['delete', RUN_KEY, '/v', valueName, '/f'],\n { encoding: 'utf-8', timeout: 5_000, windowsHide: true },\n );\n // Ignore errors (value may not exist)\n}\n\nexport class Win32Autostart {\n async install(): Promise<{ ok: true }> {\n const daemonPath = findDaemonBinary();\n if (!daemonPath) {\n throw new Error(\n 'crontick-daemon binary not found. Ensure crontick is installed globally: npm i -g crontick',\n );\n }\n\n const vbsPath = getVbsPath();\n const valueName = getValueName();\n\n // Ensure directory and write VBS shim\n mkdirSync(autostartDir(), { recursive: true });\n writeFileSync(vbsPath, buildVbsContent(daemonPath), 'utf-8');\n\n // Idempotent: remove previous value before writing\n regDelete(valueName);\n regWrite(valueName, `wscript.exe \"${vbsPath}\"`);\n\n return { ok: true };\n }\n\n async remove(): Promise<{ ok: true }> {\n const valueName = getValueName();\n regDelete(valueName);\n\n // Remove VBS shim if it exists\n const vbsPath = getVbsPath();\n if (existsSync(vbsPath)) {\n try { unlinkSync(vbsPath); } catch { /* ignore */ }\n }\n\n return { ok: true };\n }\n\n async status(): Promise<AutostartStatus> {\n const valueName = getValueName();\n const data = regQuery(valueName);\n const installed = data !== null;\n return {\n installed,\n backend: 'win32',\n details: installed\n ? { registryValue: valueName, registryData: data, vbsPath: getVbsPath() }\n : { registryValue: valueName },\n };\n }\n}\n","/**\n * Manual autostart backend — prints per-platform instructions.\n * Works on any platform; used as the default on non-Windows in v1.\n */\nimport type { AutostartStatus } from './index.js';\n\nfunction instructions(): string {\n switch (process.platform) {\n case 'win32':\n return (\n 'Windows: add the following command to your startup folder or HKCU Run key:\\n' +\n ' crontick-daemon\\n' +\n 'Or run: crontick autostart install (uses HKCU Run + hidden VBS shim)'\n );\n case 'darwin':\n return (\n 'macOS (post-v1): create a launchd plist at\\n' +\n ' ~/Library/LaunchAgents/com.crontick.daemon.plist\\n' +\n 'with ProgramArguments pointing to the crontick-daemon binary.\\n' +\n 'Then run: launchctl load ~/Library/LaunchAgents/com.crontick.daemon.plist\\n' +\n '\\nFor now, add the following to your shell profile (~/.zprofile or ~/.bash_profile):\\n' +\n ' crontick-daemon &'\n );\n case 'linux':\n return (\n 'Linux (post-v1): create a systemd user unit at\\n' +\n ' ~/.config/systemd/user/crontick.service\\n' +\n 'Then run: systemctl --user enable --now crontick.service\\n' +\n '\\nFor now, add the following to your shell profile (~/.profile or ~/.bashrc):\\n' +\n ' crontick-daemon &\\n' +\n 'Or add a @reboot crontab entry: crontab -e\\n' +\n ' @reboot crontick-daemon'\n );\n default:\n return (\n 'Add `crontick-daemon` to your system startup mechanism.\\n' +\n 'The daemon listens on a random localhost port; the port is written to the data directory.'\n );\n }\n}\n\nexport class ManualAutostart {\n async install(): Promise<{ ok: true }> {\n return { ok: true };\n }\n\n async remove(): Promise<{ ok: true }> {\n return { ok: true };\n }\n\n async status(): Promise<AutostartStatus> {\n return {\n installed: false,\n backend: 'manual',\n details: { instructions: instructions() },\n };\n }\n}\n","/**\n * macOS autostart backend — STUB for post-v1.\n *\n * TODO (darwin implementation, post-v1):\n * - install():\n * 1. Build a launchd plist string for com.crontick.daemon\n * 2. Write to ~/Library/LaunchAgents/com.crontick.daemon.plist\n * 3. Run: launchctl load ~/Library/LaunchAgents/com.crontick.daemon.plist\n * - remove():\n * 1. Run: launchctl unload ~/Library/LaunchAgents/com.crontick.daemon.plist\n * 2. Delete ~/Library/LaunchAgents/com.crontick.daemon.plist\n * - status():\n * Run: launchctl list com.crontick.daemon (exit 0 = loaded)\n *\n * Plist template:\n * <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n * <!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" ...>\n * <plist version=\"1.0\"><dict>\n * <key>Label</key><string>com.crontick.daemon</string>\n * <key>ProgramArguments</key>\n * <array><string>/usr/local/bin/crontick-daemon</string></array>\n * <key>RunAtLoad</key><true/>\n * <key>StandardOutPath</key><string>~/.local/state/crontick/logs/daemon.stdout.log</string>\n * <key>StandardErrorPath</key><string>~/.local/state/crontick/logs/daemon.stderr.log</string>\n * </dict></plist>\n */\nimport { NotImplementedInV1Error } from './index.js';\nimport type { AutostartStatus } from './index.js';\n\nexport class DarwinAutostart {\n async install(): Promise<{ ok: true }> {\n throw new NotImplementedInV1Error(\n 'darwin autostart is planned for post-v1; use manual for now. ' +\n 'See https://github.com/crontick/crontick for updates.',\n );\n }\n\n async remove(): Promise<{ ok: true }> {\n throw new NotImplementedInV1Error(\n 'darwin autostart is planned for post-v1; use manual for now.',\n );\n }\n\n async status(): Promise<AutostartStatus> {\n throw new NotImplementedInV1Error(\n 'darwin autostart is planned for post-v1; use manual for now.',\n );\n }\n}\n","/**\n * Linux autostart backend — STUB for post-v1.\n *\n * TODO (linux implementation, post-v1):\n * - install():\n * 1. Create ~/.config/systemd/user/ if absent\n * 2. Write unit file to ~/.config/systemd/user/crontick.service:\n *\n * [Unit]\n * Description=crontick daemon\n * After=default.target\n *\n * [Service]\n * Type=simple\n * ExecStart=/usr/local/bin/crontick-daemon\n * Restart=on-failure\n * RestartSec=5\n *\n * [Install]\n * WantedBy=default.target\n *\n * 3. Run: systemctl --user daemon-reload\n * 4. Run: systemctl --user enable --now crontick.service\n *\n * - remove():\n * 1. Run: systemctl --user disable --now crontick.service\n * 2. Delete ~/.config/systemd/user/crontick.service\n * 3. Run: systemctl --user daemon-reload\n *\n * - status():\n * Run: systemctl --user is-active crontick.service (exit 0 = active)\n */\nimport { NotImplementedInV1Error } from './index.js';\nimport type { AutostartStatus } from './index.js';\n\nexport class LinuxAutostart {\n async install(): Promise<{ ok: true }> {\n throw new NotImplementedInV1Error(\n 'linux autostart is planned for post-v1; use manual for now. ' +\n 'See https://github.com/crontick/crontick for updates.',\n );\n }\n\n async remove(): Promise<{ ok: true }> {\n throw new NotImplementedInV1Error(\n 'linux autostart is planned for post-v1; use manual for now.',\n );\n }\n\n async status(): Promise<AutostartStatus> {\n throw new NotImplementedInV1Error(\n 'linux autostart is planned for post-v1; use manual for now.',\n );\n }\n}\n","/**\n * Autostart abstraction — factory + types.\n * v1: win32 (HKCU Run + VBS shim) and manual (prints instructions).\n * darwin/linux are stubs that throw NotImplementedInV1Error.\n */\nimport { Win32Autostart } from './win32.js';\nimport { ManualAutostart } from './manual.js';\nimport { DarwinAutostart } from './darwin.js';\nimport { LinuxAutostart } from './linux.js';\n\nexport type AutostartBackend = 'win32' | 'darwin' | 'linux' | 'manual';\n\nexport interface AutostartStatus {\n installed: boolean;\n backend: AutostartBackend;\n details?: unknown;\n}\n\nexport interface Autostart {\n install(): Promise<{ ok: true }>;\n remove(): Promise<{ ok: true }>;\n status(): Promise<AutostartStatus>;\n}\n\n/** Thrown by darwin/linux stubs; serialised as HTTP 501 by the daemon API. */\nexport class NotImplementedInV1Error extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'NotImplementedInV1Error';\n Object.setPrototypeOf(this, NotImplementedInV1Error.prototype);\n }\n}\n\n/**\n * Factory: default = win32 on Windows, manual everywhere else.\n * An explicit `opts.backend` always overrides the default.\n */\nexport function createAutostart(opts?: { backend?: AutostartBackend }): Autostart {\n const backend: AutostartBackend =\n opts?.backend ?? (process.platform === 'win32' ? 'win32' : 'manual');\n switch (backend) {\n case 'win32': return new Win32Autostart();\n case 'darwin': return new DarwinAutostart();\n case 'linux': return new LinuxAutostart();\n case 'manual':\n default: return new ManualAutostart();\n }\n}\n"],"mappings":"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","names":["import_node_child_process","import_node_fs","import_node_path","envPaths","import_node_fs","import_node_path","result","t","import_node_fs","import_node_path","import_node_crypto","import_node_fs","import_node_path","import_node_url","import_node_child_process","import_node_fs","import_node_path","http","ScheduleSchema","pathResolve","pathJoin","pathSep","fsExistsSync","log","checkSingleInstance","cleanup"]}
|