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/mcp/index.ts","../../src/paths.ts","../../src/version.ts","../../src/schemas/job.ts"],"sourcesContent":["/**\n * crontick MCP server — stdio transport.\n * Thin adapter over the local daemon HTTP API.\n */\nimport { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport { readFileSync, existsSync, appendFileSync, statSync, mkdirSync } from 'node:fs';\nimport { spawn } from 'node:child_process';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, resolve as pathResolve, join as pathJoin } from 'node:path';\nimport { zodToJsonSchema } from 'zod-to-json-schema';\nimport { portFilePath, pidFilePath, logsDir, ensureDirs } from '../paths.js';\nimport { VERSION } from '../version.js';\nimport {\n JobSchema,\n ScheduleSchema,\n ActionSchema,\n} from '../schemas/job.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// ── Daemon URL resolution ─────────────────────────────────────────────────────\n\nfunction getDaemonBaseUrl(): string {\n const envUrl = process.env['CRONTICK_DAEMON_URL'];\n if (envUrl) return envUrl.replace(/\\/$/, '');\n const pf = portFilePath();\n if (!existsSync(pf)) throw new DaemonUnavailableError('Port file not found.');\n const port = parseInt(readFileSync(pf, 'utf-8').trim(), 10);\n if (isNaN(port) || port <= 0) throw new DaemonUnavailableError('Invalid port in port file.');\n return `http://127.0.0.1:${port}`;\n}\n\nclass DaemonUnavailableError extends Error {\n constructor(detail: string) {\n super(\n `Daemon is not running (${detail}) — run: crontick daemon start`,\n );\n this.name = 'DaemonUnavailableError';\n }\n}\n\nfunction daemonScript(): string {\n return pathResolve(__dirname, '../daemon/index.js');\n}\n\nfunction appendAutostartLog(text: string): void {\n try {\n mkdirSync(logsDir(), { recursive: true });\n const logPath = pathJoin(logsDir(), 'daemon.autostart.log');\n let size = 0;\n try { size = statSync(logPath).size; } catch { /* new file */ }\n if (size < 256 * 1024) {\n appendFileSync(logPath, `[${new Date().toISOString()}] ${text}\\n`);\n }\n } catch { /* ignore log errors */ }\n}\n\nfunction waitForPortFile(maxMs = 10_000, getStderr?: () => string): Promise<void> {\n const start = Date.now();\n return new Promise((resolve, reject) => {\n const check = () => {\n if (existsSync(portFilePath())) {\n // Verify it's a valid port\n try {\n const port = parseInt(readFileSync(portFilePath(), 'utf-8').trim(), 10);\n if (!isNaN(port) && port > 0) return resolve();\n } catch { /* retry */ }\n }\n if (Date.now() - start > maxMs) {\n const stderr = getStderr?.() ?? '';\n const hint = stderr ? `\\nAutostart stderr: ${stderr.slice(0, 500)}` : '';\n return reject(new DaemonUnavailableError(`Timed out waiting for daemon to start.${hint}`));\n }\n setTimeout(check, 200);\n };\n check();\n });\n}\n\nasync function ensureDaemon(): Promise<void> {\n // Check if already running\n try {\n const base = getDaemonBaseUrl();\n const res = await fetch(`${base}/health`, {\n signal: AbortSignal.timeout(2000),\n });\n if (res.ok) return;\n } catch { /* not running or not responding */ }\n\n if (process.env['CRONTICK_MCP_NO_AUTOSTART'] === '1') {\n throw new DaemonUnavailableError(\n 'CRONTICK_MCP_NO_AUTOSTART=1 is set — start the daemon manually: crontick daemon start',\n );\n }\n\n // Auto-start\n ensureDirs();\n const script = daemonScript();\n if (!existsSync(script)) {\n throw new DaemonUnavailableError(\n `Daemon script not found. Run: npm run build`,\n );\n }\n const stderrChunks: Buffer[] = [];\n const child = spawn(process.execPath, [script], {\n detached: true,\n stdio: ['ignore', 'ignore', 'pipe'],\n env: process.env,\n });\n if (child.stderr) {\n child.stderr.on('data', (chunk: Buffer) => {\n if (Buffer.concat(stderrChunks).length < 4096) stderrChunks.push(chunk);\n });\n // unref so the MCP process can exit even if the daemon stderr pipe stays open\n (child.stderr as NodeJS.ReadableStream & { unref?(): void }).unref?.();\n }\n child.unref();\n\n const getStderr = (): string => {\n const raw = Buffer.concat(stderrChunks).toString('utf-8');\n return raw.length > 4096 ? raw.slice(0, 4096) + '…' : raw;\n };\n\n try {\n await waitForPortFile(10_000, getStderr);\n } catch (err) {\n const stderr = getStderr();\n if (stderr) appendAutostartLog(`ensureDaemon failed:\\n${stderr}`);\n throw err;\n }\n}\n\n// ── API client ────────────────────────────────────────────────────────────────\n\nasync function callDaemon(method: string, path: string, body?: unknown): Promise<unknown> {\n const base = getDaemonBaseUrl();\n const res = await fetch(`${base}${path}`, {\n method,\n headers: { 'Content-Type': 'application/json' },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n signal: AbortSignal.timeout(30_000),\n });\n const text = await res.text();\n let data: unknown;\n try {\n data = JSON.parse(text);\n } catch {\n throw new Error(`Daemon returned non-JSON: ${text.slice(0, 200)}`);\n }\n if (!res.ok) {\n const err = (data as { error?: { code?: string; message?: string } })?.error;\n throw new Error(`[${err?.code ?? 'API_ERROR'}] ${err?.message ?? `HTTP ${res.status}`}`);\n }\n return data;\n}\n\n// ── Tool result helpers ───────────────────────────────────────────────────────\n\ntype ToolResult = {\n content: Array<{ type: 'text'; text: string }>;\n isError?: boolean;\n};\n\nfunction okResult(data: unknown): ToolResult {\n return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };\n}\n\n/** Redact sensitive details before returning errors to the LLM. Exported for testing. */\nexport function redactForLlm(msg: string): string {\n return msg\n // Loopback address:port\n .replace(/127\\.0\\.0\\.1:\\d+/g, '<daemon-addr>')\n // Windows absolute paths: C:\\foo\\bar (must have at least one separator)\n .replace(/[A-Za-z]:\\\\[^\\s\"']+/g, '<path>')\n // POSIX absolute paths: only when preceded by start-of-string, whitespace,\n // (, [, or a quote — to avoid matching /path inside http://host/path URLs.\n .replace(/(^|[\\s([\"'])\\/(?:[^\\s\"'/]+\\/)+[^\\s\"'/]+/g, '$1<path>');\n}\n\nfunction errResult(err: unknown): ToolResult {\n const msg = err instanceof Error ? err.message : String(err);\n const redacted = redactForLlm(msg);\n return {\n content: [{ type: 'text', text: JSON.stringify({ error: redacted }, null, 2) }],\n isError: true,\n };\n}\n\nasync function toolWrap(fn: () => Promise<unknown>): Promise<ToolResult> {\n try {\n await ensureDaemon();\n const result = await fn();\n return okResult(result);\n } catch (err) {\n return errResult(err);\n }\n}\n\n// ── MCP server setup ──────────────────────────────────────────────────────────\n\nconst kebabCase = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\nexport function createMcpServer(): McpServer {\n const server = new McpServer({\n name: 'crontick',\n version: VERSION,\n });\n\n // ── Jobs ──────────────────────────────────────────────────────────────────\n\n server.registerTool(\n 'crontick_job_create',\n {\n description:\n 'Create and schedule a new cron job. Provide the full job definition including id, schedule (kind: cron|interval|one-shot), and action (kind: script|exec). Validate the schedule first with crontick_schedule_validate.',\n inputSchema: {\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().optional(),\n schedule: ScheduleSchema,\n action: ActionSchema,\n catchup: z.enum(['run-once', 'run-all', 'skip']).optional(),\n overlap: z.enum(['skip', 'queue', 'cancel-previous']).optional(),\n retry: z\n .object({ max: z.number().int().min(0), backoffSec: z.number().positive() })\n .optional(),\n budgets: z\n .object({\n maxRunsPerDay: z.number().int().positive().nullable(),\n maxTokensPerRun: z.number().int().positive().nullable(),\n })\n .optional(),\n },\n },\n async (args) => toolWrap(() => callDaemon('POST', '/api/jobs', args)),\n );\n\n server.registerTool(\n 'crontick_job_list',\n {\n description: 'List all scheduled jobs with their current status and next run time.',\n inputSchema: {},\n },\n async () => toolWrap(() => callDaemon('GET', '/api/jobs')),\n );\n\n server.registerTool(\n 'crontick_job_get',\n {\n description: 'Get the full definition and status of a specific job by ID.',\n inputSchema: { id: z.string() },\n },\n async (args) =>\n toolWrap(() => callDaemon('GET', `/api/jobs/${encodeURIComponent(args.id)}`)),\n );\n\n server.registerTool(\n 'crontick_job_update',\n {\n description:\n 'Update an existing job. Provide the job ID and any fields to change (partial update is merged with existing definition).',\n inputSchema: {\n id: z.string(),\n description: z.string().optional(),\n enabled: z.boolean().optional(),\n schedule: ScheduleSchema.optional(),\n action: ActionSchema.optional(),\n catchup: z.enum(['run-once', 'run-all', 'skip']).optional(),\n overlap: z.enum(['skip', 'queue', 'cancel-previous']).optional(),\n retry: z\n .object({ max: z.number().int().min(0), backoffSec: z.number().positive() })\n .optional(),\n budgets: z\n .object({\n maxRunsPerDay: z.number().int().positive().nullable(),\n maxTokensPerRun: z.number().int().positive().nullable(),\n })\n .optional(),\n },\n },\n async (args) => {\n const { id, ...patch } = args;\n return toolWrap(() =>\n callDaemon('PUT', `/api/jobs/${encodeURIComponent(id)}`, patch),\n );\n },\n );\n\n server.registerTool(\n 'crontick_job_delete',\n {\n description:\n 'Permanently delete a job and all its run history. This cannot be undone — confirm with the user first.',\n inputSchema: { id: z.string() },\n },\n async (args) =>\n toolWrap(() => callDaemon('DELETE', `/api/jobs/${encodeURIComponent(args.id)}`)),\n );\n\n server.registerTool(\n 'crontick_job_enable',\n {\n description: 'Enable a disabled job so it will run on its next scheduled time.',\n inputSchema: { id: z.string() },\n },\n async (args) =>\n toolWrap(() =>\n callDaemon('POST', `/api/jobs/${encodeURIComponent(args.id)}/enable`),\n ),\n );\n\n server.registerTool(\n 'crontick_job_disable',\n {\n description: 'Disable a job so it will not run until re-enabled.',\n inputSchema: { id: z.string() },\n },\n async (args) =>\n toolWrap(() =>\n callDaemon('POST', `/api/jobs/${encodeURIComponent(args.id)}/disable`),\n ),\n );\n\n server.registerTool(\n 'crontick_job_run_now',\n {\n description:\n 'Trigger an immediate run of a job, bypassing its schedule. Returns a runId to track progress with crontick_run_get.',\n inputSchema: { id: z.string() },\n },\n async (args) =>\n toolWrap(() =>\n callDaemon('POST', `/api/jobs/${encodeURIComponent(args.id)}/run`),\n ),\n );\n\n server.registerTool(\n 'crontick_job_cancel_run',\n {\n description: 'Cancel an in-progress run by its run ID.',\n inputSchema: { runId: z.string() },\n },\n async (args) =>\n toolWrap(() =>\n callDaemon('POST', `/api/runs/${encodeURIComponent(args.runId)}/cancel`),\n ),\n );\n\n // ── Runs ───────────────────────────────────────────────────────────────────\n\n server.registerTool(\n 'crontick_run_list',\n {\n description: 'List recent runs, optionally filtered by job ID.',\n inputSchema: {\n jobId: z.string().optional(),\n limit: z.number().int().positive().optional(),\n since: z.number().int().optional(),\n },\n },\n async (args) => {\n const params = new URLSearchParams();\n if (args.jobId) params.set('jobId', args.jobId);\n if (args.limit !== undefined) params.set('limit', String(args.limit));\n if (args.since !== undefined) params.set('since', String(args.since));\n const qs = params.toString();\n return toolWrap(() => callDaemon('GET', `/api/runs${qs ? `?${qs}` : ''}`));\n },\n );\n\n server.registerTool(\n 'crontick_run_get',\n {\n description: 'Get the details and current status of a specific run by run ID.',\n inputSchema: { runId: z.string() },\n },\n async (args) =>\n toolWrap(() =>\n callDaemon('GET', `/api/runs/${encodeURIComponent(args.runId)}`),\n ),\n );\n\n server.registerTool(\n 'crontick_run_logs_tail',\n {\n description:\n 'Get the last N lines of output for a run. Useful for diagnosing failures.',\n inputSchema: {\n runId: z.string(),\n lines: z.number().int().positive().default(50),\n },\n },\n async (args) =>\n toolWrap(async () => {\n const logs = (await callDaemon(\n 'GET',\n `/api/runs/${encodeURIComponent(args.runId)}/logs`,\n )) as Array<{ stream: string; ts: number; data: string }>;\n const all = Array.isArray(logs) ? logs : [];\n const tail = all.slice(-args.lines);\n return { runId: args.runId, lines: tail };\n }),\n );\n\n // ── Schedules ─────────────────────────────────────────────────────────────\n\n server.registerTool(\n 'crontick_schedule_validate',\n {\n description:\n 'Validate a schedule definition. Returns ok:true and human-readable description on success, or an error message on failure. Always call this before creating a job.',\n inputSchema: {\n schedule: ScheduleSchema,\n },\n },\n async (args) =>\n toolWrap(() => callDaemon('POST', '/api/schedules/validate', args.schedule)),\n );\n\n server.registerTool(\n 'crontick_schedule_preview',\n {\n description:\n 'Preview the next N fire times for a schedule. Useful to confirm the schedule is what the user expects before creating the job.',\n inputSchema: {\n schedule: ScheduleSchema,\n n: z.number().int().positive().max(20).default(5),\n tz: z.string().optional(),\n },\n },\n async (args) =>\n toolWrap(() =>\n callDaemon('POST', '/api/schedules/preview', {\n schedule: args.schedule,\n n: args.n,\n tz: args.tz,\n }),\n ),\n );\n\n // ── Stats ──────────────────────────────────────────────────────────────────\n\n server.registerTool(\n 'crontick_stats_summary',\n {\n description:\n 'Get an aggregate summary of all jobs: total count, enabled count, run history, success/failure counts, average duration.',\n inputSchema: {},\n },\n async () => toolWrap(() => callDaemon('GET', '/api/stats/summary')),\n );\n\n server.registerTool(\n 'crontick_stats_job',\n {\n description: 'Get run statistics for a specific job: total runs, success/failure rates, last status.',\n inputSchema: { id: z.string() },\n },\n async (args) =>\n toolWrap(() =>\n callDaemon('GET', `/api/stats/jobs/${encodeURIComponent(args.id)}`),\n ),\n );\n\n // ── Daemon ─────────────────────────────────────────────────────────────────\n\n server.registerTool(\n 'crontick_daemon_status',\n {\n description:\n 'Get the daemon process status: PID, version, uptime, job counts, run stats, Node version, and platform.',\n inputSchema: {},\n },\n async () => toolWrap(() => callDaemon('GET', '/health')),\n );\n\n server.registerTool(\n 'crontick_daemon_reload',\n {\n description:\n 'Reload job definitions from disk without restarting the daemon. Use after manually editing job files.',\n inputSchema: {},\n },\n async () => toolWrap(() => callDaemon('POST', '/api/daemon/reload')),\n );\n\n server.registerTool(\n 'crontick_daemon_restart',\n {\n description:\n 'Restart the crontick daemon (stop + start). Running jobs will be interrupted. Confirm with the user before calling.',\n inputSchema: {},\n },\n async () =>\n toolWrap(async () => {\n // Kill existing daemon\n const pidFile = pidFilePath();\n if (existsSync(pidFile)) {\n try {\n const pid = parseInt(readFileSync(pidFile, 'utf-8').trim(), 10);\n if (!isNaN(pid)) process.kill(pid, 'SIGTERM');\n } catch { /* already dead */ }\n }\n // Wait for port file to disappear (up to 3s)\n await new Promise<void>((res) => {\n const deadline = Date.now() + 3000;\n const poll = setInterval(() => {\n if (!existsSync(portFilePath()) || Date.now() > deadline) {\n clearInterval(poll);\n res();\n }\n }, 100);\n });\n // Start new daemon\n const script = daemonScript();\n const restartChunks: Buffer[] = [];\n const child = spawn(process.execPath, [script], {\n detached: true,\n stdio: ['ignore', 'ignore', 'pipe'],\n env: process.env,\n });\n if (child.stderr) {\n child.stderr.on('data', (chunk: Buffer) => {\n if (Buffer.concat(restartChunks).length < 4096) restartChunks.push(chunk);\n });\n (child.stderr as NodeJS.ReadableStream & { unref?(): void }).unref?.();\n }\n child.unref();\n const getRestartStderr = (): string => {\n const raw = Buffer.concat(restartChunks).toString('utf-8');\n return raw.length > 4096 ? raw.slice(0, 4096) + '…' : raw;\n };\n try {\n await waitForPortFile(10_000, getRestartStderr);\n } catch (err) {\n const stderr = getRestartStderr();\n if (stderr) appendAutostartLog(`daemon restart failed:\\n${stderr}`);\n throw err;\n }\n return { ok: true, message: 'Daemon restarted successfully.' };\n }),\n );\n\n // ── Autostart ─────────────────────────────────────────────────────────────\n\n server.registerTool(\n 'crontick_autostart_status',\n {\n description:\n 'Check whether the crontick daemon is registered to start automatically at login. (v1: Windows uses HKCU Run; other platforms return manual instructions.)',\n inputSchema: {},\n },\n async () => toolWrap(() => callDaemon('GET', '/api/autostart/status')),\n );\n\n server.registerTool(\n 'crontick_autostart_install',\n {\n description:\n 'Register the crontick daemon to start automatically at login. (v1: Windows only via HKCU Run + VBS shim. On other platforms returns manual instructions.) On non-Windows, this returns a 501 with instructions to use manual autostart.',\n inputSchema: {},\n },\n async () => toolWrap(() => callDaemon('POST', '/api/autostart/install', {})),\n );\n\n server.registerTool(\n 'crontick_autostart_remove',\n {\n description: 'Remove the crontick daemon from the automatic startup registry.',\n inputSchema: {},\n },\n async () => toolWrap(() => callDaemon('POST', '/api/autostart/remove', {})),\n );\n\n // ── Admin ──────────────────────────────────────────────────────────────────\n\n server.registerTool(\n 'crontick_export',\n {\n description:\n 'Export all job definitions as a JSON object. Use this to back up or migrate jobs.',\n inputSchema: {},\n },\n async () => toolWrap(() => callDaemon('GET', '/api/export')),\n );\n\n server.registerTool(\n 'crontick_import',\n {\n description:\n 'Import job definitions from a JSON array. Jobs are upserted (existing jobs with the same ID are updated).',\n inputSchema: {\n jobs: z.array(z.unknown()),\n },\n },\n async (args) =>\n toolWrap(() => callDaemon('POST', '/api/import', { jobs: args.jobs })),\n );\n\n server.registerTool(\n 'crontick_dashboard_open',\n {\n description:\n 'Get the URL for the crontick dashboard web UI. Open it in a browser to view jobs and run history visually.',\n inputSchema: {},\n },\n async () =>\n toolWrap(async () => {\n const base = getDaemonBaseUrl();\n return {\n url: `${base}/dashboard`,\n message: `Dashboard available at: ${base}/dashboard — open in your browser.`,\n };\n }),\n );\n\n server.registerTool(\n 'crontick_doctor',\n {\n description:\n 'Run a suite of health checks: Node.js version, SQLite, data directory, daemon connectivity, dashboard reachability, autostart, and MCP server availability.',\n inputSchema: {},\n },\n async () => {\n const checks: Array<{ name: string; ok: boolean; note?: string }> = [];\n let daemonReachable = false;\n\n // Node version\n const major = parseInt(process.versions.node.split('.')[0], 10);\n checks.push({ name: 'Node.js >= 22.5', ok: major >= 22, note: `v${process.versions.node}` });\n\n // SQLite\n try {\n const { DatabaseSync } = await import('node:sqlite');\n new (DatabaseSync as new (path: string) => { close(): void })(':memory:').close();\n checks.push({ name: 'node:sqlite', ok: true });\n } catch (err) {\n checks.push({ name: 'node:sqlite', ok: false, note: String(err) });\n }\n\n // Data dir\n try {\n ensureDirs();\n checks.push({ name: 'data dir writable', ok: true });\n } catch (err) {\n checks.push({ name: 'data dir writable', ok: false, note: String(err) });\n }\n\n // Port file + daemon\n const portFile = portFilePath();\n const portFileExists = existsSync(portFile);\n checks.push({\n name: 'port file readable',\n ok: portFileExists,\n note: portFileExists ? portFile : 'not found',\n });\n\n try {\n const base = getDaemonBaseUrl();\n const res = await fetch(`${base}/health`, { signal: AbortSignal.timeout(2000) });\n if (res.ok) {\n daemonReachable = true;\n checks.push({ name: 'daemon reachable', ok: true });\n } else {\n checks.push({ name: 'daemon reachable', ok: false, note: `HTTP ${res.status}` });\n }\n } catch {\n checks.push({ name: 'daemon reachable', ok: false, note: 'not running' });\n }\n\n // Dashboard reachable\n try {\n const base = getDaemonBaseUrl();\n const dashRes = await fetch(`${base}/dashboard`, { signal: AbortSignal.timeout(2000) });\n const text = await dashRes.text();\n checks.push({\n name: 'dashboard reachable',\n ok: dashRes.status === 200 && text.includes('crontick'),\n note: dashRes.status === 200 ? 'ok' : `HTTP ${dashRes.status}`,\n });\n } catch {\n checks.push({ name: 'dashboard reachable', ok: false, note: 'daemon not running or no dashboard' });\n }\n\n // Autostart status\n if (daemonReachable) {\n try {\n const asResult = await callDaemon('GET', '/api/autostart/status');\n const as = asResult as { installed?: boolean; backend?: string };\n checks.push({\n name: 'autostart',\n ok: true,\n note: `backend=${as.backend ?? '?'}, installed=${String(as.installed ?? false)}`,\n });\n } catch {\n checks.push({ name: 'autostart', ok: false, note: 'could not check (daemon not running)' });\n }\n } else {\n checks.push({ name: 'autostart', ok: false, note: 'could not check (daemon not running)' });\n }\n\n // MCP server binary\n const mcpScript = pathResolve(__dirname, '../mcp/index.js');\n checks.push({\n name: 'MCP server binary',\n ok: existsSync(mcpScript),\n note: mcpScript,\n });\n\n const allOk = checks.every((c) => c.ok);\n return okResult({ ok: allOk, checks });\n },\n );\n\n // ── Resources ─────────────────────────────────────────────────────────────\n\n // crontick://jobs — list of job IDs\n server.resource(\n 'crontick-jobs-list',\n 'crontick://jobs',\n {\n description: 'List of all crontick job IDs',\n mimeType: 'application/json',\n },\n async () => {\n try {\n await ensureDaemon();\n const jobs = (await callDaemon('GET', '/api/jobs')) as Array<{ id: string }>;\n const ids = Array.isArray(jobs) ? jobs.map((j) => j.id) : [];\n return {\n contents: [\n {\n uri: 'crontick://jobs',\n mimeType: 'application/json',\n text: JSON.stringify({ jobIds: ids }, null, 2),\n },\n ],\n };\n } catch (err) {\n return {\n contents: [\n {\n uri: 'crontick://jobs',\n mimeType: 'application/json',\n text: JSON.stringify({ error: String(err) }, null, 2),\n },\n ],\n };\n }\n },\n );\n\n // crontick://jobs/{id} — single job JSON\n const jobTemplate = new ResourceTemplate('crontick://jobs/{id}', {\n list: async () => ({\n resources: [],\n }),\n });\n\n server.resource(\n 'crontick-job',\n jobTemplate,\n { description: 'Full job definition as JSON', mimeType: 'application/json' },\n async (uri, variables) => {\n const id = Array.isArray(variables.id) ? variables.id[0] : variables.id;\n try {\n await ensureDaemon();\n const job = await callDaemon('GET', `/api/jobs/${encodeURIComponent(String(id ?? ''))}`);\n return {\n contents: [\n {\n uri: uri.href,\n mimeType: 'application/json',\n text: JSON.stringify(job, null, 2),\n },\n ],\n };\n } catch (err) {\n return {\n contents: [\n {\n uri: uri.href,\n mimeType: 'application/json',\n text: JSON.stringify({ error: String(err) }, null, 2),\n },\n ],\n };\n }\n },\n );\n\n // crontick://runs/{id} — single run record\n const runTemplate = new ResourceTemplate('crontick://runs/{id}', {\n list: async () => ({ resources: [] }),\n });\n\n server.resource(\n 'crontick-run',\n runTemplate,\n { description: 'Run record as JSON', mimeType: 'application/json' },\n async (uri, variables) => {\n const id = Array.isArray(variables.id) ? variables.id[0] : variables.id;\n try {\n await ensureDaemon();\n const run = await callDaemon('GET', `/api/runs/${encodeURIComponent(String(id ?? ''))}`);\n return {\n contents: [\n {\n uri: uri.href,\n mimeType: 'application/json',\n text: JSON.stringify(run, null, 2),\n },\n ],\n };\n } catch (err) {\n return {\n contents: [\n {\n uri: uri.href,\n mimeType: 'application/json',\n text: JSON.stringify({ error: String(err) }, null, 2),\n },\n ],\n };\n }\n },\n );\n\n // crontick://runs/{id}/log — full log text\n const runLogTemplate = new ResourceTemplate('crontick://runs/{id}/log', {\n list: async () => ({ resources: [] }),\n });\n\n server.resource(\n 'crontick-run-log',\n runLogTemplate,\n { description: 'Full log output for a run as plain text', mimeType: 'text/plain' },\n async (uri, variables) => {\n const id = Array.isArray(variables.id) ? variables.id[0] : variables.id;\n try {\n await ensureDaemon();\n const logs = (await callDaemon(\n 'GET',\n `/api/runs/${encodeURIComponent(String(id ?? ''))}/logs`,\n )) as Array<{ stream: string; data: string; ts: number }>;\n const text = Array.isArray(logs)\n ? logs.map((l) => `[${l.stream}] ${l.data}`).join('')\n : '';\n return {\n contents: [{ uri: uri.href, mimeType: 'text/plain', text }],\n };\n } catch (err) {\n return {\n contents: [{ uri: uri.href, mimeType: 'text/plain', text: `Error: ${String(err)}` }],\n };\n }\n },\n );\n\n // crontick://schemas/job — JSON schema for a job\n server.resource(\n 'crontick-schema-job',\n 'crontick://schemas/job',\n { description: 'JSON Schema for a crontick job definition', mimeType: 'application/json' },\n async () => {\n const schema = zodToJsonSchema(JobSchema as unknown as Parameters<typeof zodToJsonSchema>[0], { name: 'CrontickJob' });\n return {\n contents: [\n {\n uri: 'crontick://schemas/job',\n mimeType: 'application/json',\n text: JSON.stringify(schema, null, 2),\n },\n ],\n };\n },\n );\n\n // ── Prompts ────────────────────────────────────────────────────────────────\n\n server.prompt(\n 'create-scheduled-script',\n 'Guide the LLM through creating a new scheduled script job: understand intent, draft a self-contained shell script, validate/preview the schedule, then create the job.',\n {\n intent: z.string(),\n os: z.enum(['windows', 'unix']).optional(),\n },\n (args) => {\n const shell = args.os === 'windows' ? 'PowerShell' : 'bash';\n const shellHint = args.os === 'windows' ? 'pwsh' : 'bash';\n return {\n description: 'Create a new scheduled script job',\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: `You are helping me schedule an automated task with crontick.\n\nMy intent: ${args.intent}\n\nPlease follow these steps in order:\n\n**Step 1 — Understand the intent**\nClarify what the task does, when it should run, and any side effects or requirements.\n\n**Step 2 — Draft the script**\nWrite a self-contained ${shell} script that accomplishes the task idempotently.\n- The script must not rely on external state set up by other scripts.\n- If it calls an LLM CLI (e.g. \\`copilot\\`, \\`claude\\`), that command goes inside the script.\n- Use error handling: \\`set -euo pipefail\\` for bash, \\`$ErrorActionPreference = 'Stop'\\` for ${shell}.\n\n**Step 3 — Choose a schedule**\nDecide on the cron expression or interval. Then call:\n- \\`crontick_schedule_validate\\` with \\`schedule: { kind: \"cron\", cron: \"<expr>\", tz: \"<tz>\" }\\`\n- \\`crontick_schedule_preview\\` to show the next 5 fire times to the user for confirmation.\n\n**Step 4 — Create the job**\nOnce the user approves the schedule, call \\`crontick_job_create\\` with \\`action.kind: \"script\"\\`:\n\\`\\`\\`json\n{\n \"id\": \"<kebab-case-id>\",\n \"description\": \"<one-line description>\",\n \"schedule\": { \"kind\": \"cron\", \"cron\": \"<expr>\", \"tz\": \"<tz>\" },\n \"action\": {\n \"kind\": \"script\",\n \"script\": \"<full script body>\",\n \"shell\": \"${shellHint}\"\n }\n}\n\\`\\`\\`\n\n**Step 5 — Confirm**\nReport the returned job ID and next run time to the user.\nAlways confirm before calling crontick_job_delete or crontick_job_disable.`,\n },\n },\n ],\n };\n },\n );\n\n server.prompt(\n 'investigate-failed-run',\n 'Load a failed run record and its logs, then help diagnose the failure and propose a fix.',\n {\n runId: z.string(),\n },\n async (args) => {\n let runInfo = 'Run record unavailable.';\n let logInfo = 'Logs unavailable.';\n\n try {\n await ensureDaemon();\n const run = await callDaemon('GET', `/api/runs/${encodeURIComponent(args.runId)}`);\n runInfo = JSON.stringify(run, null, 2);\n } catch (err) {\n runInfo = `Error fetching run: ${String(err)}`;\n }\n\n try {\n const logs = (await callDaemon(\n 'GET',\n `/api/runs/${encodeURIComponent(args.runId)}/logs`,\n )) as Array<{ stream: string; data: string }>;\n const lines = Array.isArray(logs) ? logs.slice(-100) : [];\n logInfo =\n lines.length > 0\n ? lines.map((l) => `[${l.stream}] ${l.data}`).join('')\n : '(no log output)';\n } catch (err) {\n logInfo = `Error fetching logs: ${String(err)}`;\n }\n\n return {\n description: `Investigate failed run ${args.runId}`,\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: `Please investigate why run \\`${args.runId}\\` failed and propose a fix.\n\n## Run Record\n\\`\\`\\`json\n${runInfo}\n\\`\\`\\`\n\n## Last 100 Log Lines\n\\`\\`\\`\n${logInfo}\n\\`\\`\\`\n\n## What to diagnose\n1. What caused the failure? (exit code, timeout, budget exceeded, script error, etc.)\n2. Is this a one-time fluke or likely to recur?\n3. Proposed fix — choose the most appropriate:\n - **Script fix**: edit the script body via \\`crontick_job_update\\` with a corrected \\`action.script\\`\n - **Schedule change**: adjust timing/tz via \\`crontick_job_update\\` with a new \\`schedule\\`\n - **Retry policy**: increase retry max via \\`crontick_job_update\\` with \\`retry.max\\`\n - **Budget cap**: set \\`budgets.maxRunsPerDay\\` if it's running too often\n - **Timeout**: increase \\`action.timeoutSec\\` if the job was killed by timeout\n4. After proposing the fix, ask for user confirmation before applying it.`,\n },\n },\n ],\n };\n },\n );\n\n return server;\n}\n\n// ── Entry point ────────────────────────────────────────────────────────────────\n\nexport async function main(): Promise<void> {\n const server = createMcpServer();\n const transport = new StdioServerTransport();\n await server.connect(transport);\n // Keep alive until transport closes\n}\n\nmain().catch((err) => {\n process.stderr.write(`[crontick-mcp] Fatal: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\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","// 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","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"],"mappings":"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","names":["import_zod","import_node_fs","import_node_path","envPaths","pathResolve","pathJoin","kebabCase"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* crontick MCP server — stdio transport.
|
|
5
|
+
* Thin adapter over the local daemon HTTP API.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** Redact sensitive details before returning errors to the LLM. Exported for testing. */
|
|
9
|
+
declare function redactForLlm(msg: string): string;
|
|
10
|
+
declare function createMcpServer(): McpServer;
|
|
11
|
+
declare function main(): Promise<void>;
|
|
12
|
+
|
|
13
|
+
export { createMcpServer, main, redactForLlm };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* crontick MCP server — stdio transport.
|
|
5
|
+
* Thin adapter over the local daemon HTTP API.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** Redact sensitive details before returning errors to the LLM. Exported for testing. */
|
|
9
|
+
declare function redactForLlm(msg: string): string;
|
|
10
|
+
declare function createMcpServer(): McpServer;
|
|
11
|
+
declare function main(): Promise<void>;
|
|
12
|
+
|
|
13
|
+
export { createMcpServer, main, redactForLlm };
|