import { Hype } from '@because/hype' import { define, stylesToCSS } from '@because/forge' import { baseStyles, initScript, theme } from '@because/toes/tools' import { discoverCronJobs } from './lib/discovery' import { scheduleJob, stopJob } from './lib/scheduler' import { executeJob } from './lib/executor' import { setJobs, getJob, getAllJobs, broadcast } from './lib/state' import { SCHEDULES, type CronJob } from './lib/schedules' import type { Child } from 'hono/jsx' import { join } from 'path' import { mkdir, writeFile } from 'fs/promises' import { existsSync } from 'fs' const APPS_DIR = process.env.APPS_DIR! const app = new Hype({ prettyHTML: false }) // Styles (follow versions tool pattern) const Container = define('Container', { fontFamily: theme('fonts-sans'), padding: '20px', paddingTop: 0, maxWidth: '900px', margin: '0 auto', color: theme('colors-text'), }) const JobList = define('JobList', { listStyle: 'none', padding: 0, margin: '20px 0', border: `1px solid ${theme('colors-border')}`, borderRadius: theme('radius-md'), overflow: 'hidden', }) const JobItem = define('JobItem', { padding: '12px 15px', borderBottom: `1px solid ${theme('colors-border')}`, display: 'flex', alignItems: 'center', gap: '15px', states: { ':last-child': { borderBottom: 'none' }, ':hover': { backgroundColor: theme('colors-bgHover') }, }, }) const StatusDot = define('StatusDot', { width: '10px', height: '10px', borderRadius: '50%', flexShrink: 0, }) const JobName = define('JobName', { fontFamily: theme('fonts-mono'), fontSize: '14px', flex: 1, }) const Schedule = define('Schedule', { fontSize: '13px', color: theme('colors-textMuted'), minWidth: '80px', }) const Time = define('Time', { fontSize: '12px', color: theme('colors-textMuted'), minWidth: '100px', }) const RunButton = define('RunButton', { base: 'button', padding: '4px 10px', fontSize: '12px', backgroundColor: theme('colors-primary'), color: 'white', border: 'none', borderRadius: theme('radius-md'), cursor: 'pointer', states: { ':hover': { opacity: 0.9 }, ':disabled': { opacity: 0.5, cursor: 'not-allowed' }, }, }) const EmptyState = define('EmptyState', { padding: '40px 20px', textAlign: 'center', color: theme('colors-textMuted'), }) const ActionRow = define('ActionRow', { display: 'flex', justifyContent: 'flex-end', marginBottom: '15px', }) const NewButton = define('NewButton', { base: 'a', padding: '8px 16px', fontSize: '14px', backgroundColor: theme('colors-primary'), color: 'white', border: 'none', borderRadius: theme('radius-md'), cursor: 'pointer', textDecoration: 'none', display: 'inline-block', states: { ':hover': { opacity: 0.9 }, }, }) const buttonStyles = { padding: '8px 16px', fontSize: '14px', backgroundColor: theme('colors-primary'), color: 'white', border: 'none', borderRadius: theme('radius-md'), cursor: 'pointer', } const Form = define('Form', { display: 'flex', flexDirection: 'column', gap: '16px', maxWidth: '400px', }) const FormGroup = define('FormGroup', { display: 'flex', flexDirection: 'column', gap: '6px', }) const Label = define('Label', { fontSize: '14px', fontWeight: 500, }) const inputStyles = { padding: '8px 12px', fontSize: '14px', border: `1px solid ${theme('colors-border')}`, borderRadius: theme('radius-md'), backgroundColor: theme('colors-bg'), color: theme('colors-text'), } const ButtonRow = define('ButtonRow', { display: 'flex', gap: '10px', marginTop: '10px', }) const CancelButton = define('CancelButton', { base: 'a', padding: '8px 16px', fontSize: '14px', backgroundColor: 'transparent', color: theme('colors-text'), border: `1px solid ${theme('colors-border')}`, borderRadius: theme('radius-md'), cursor: 'pointer', textDecoration: 'none', states: { ':hover': { backgroundColor: theme('colors-bgHover') }, }, }) // Layout function Layout({ title, children }: { title: string; children: Child }) { return ( {title}