Add container-native scheduled task system with timezone support
All checks were successful
Build App / build-linux (push) Successful in 2m39s
Build App / build-windows (push) Successful in 3m43s
Build Container / build-container (push) Successful in 16s

Introduces a cron-based scheduler that lets Claude set up recurring and
one-time tasks inside containers. Tasks run as separate Claude Code agents
and persist across container recreation via the named volume.

New files:
- container/triple-c-scheduler: CLI for add/remove/enable/disable/list/logs/run/notifications
- container/triple-c-task-runner: cron wrapper with flock, logging, notifications, auto-cleanup

Key changes:
- Dockerfile: add cron package and COPY both scripts
- entrypoint.sh: timezone setup, cron daemon, crontab restore, env saving
- container.rs: init=true for zombie reaping, TZ env, scheduler instructions, timezone recreation check
- image.rs: embed scheduler scripts in build context
- app_settings.rs + types.ts: timezone field
- settings_commands.rs: detect_host_timezone via iana-time-zone crate
- SettingsPanel.tsx: timezone input with auto-detection

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-01 15:57:22 +00:00
parent 06be613e36
commit 2e81b52205
15 changed files with 781 additions and 1 deletions

View File

@@ -6,6 +6,7 @@ import { useSettings } from "../../hooks/useSettings";
import { useUpdates } from "../../hooks/useUpdates";
import ClaudeInstructionsModal from "../projects/ClaudeInstructionsModal";
import EnvVarsModal from "../projects/EnvVarsModal";
import { detectHostTimezone } from "../../lib/tauri-commands";
import type { EnvVar } from "../../lib/types";
export default function SettingsPanel() {
@@ -14,6 +15,7 @@ export default function SettingsPanel() {
const [globalInstructions, setGlobalInstructions] = useState(appSettings?.global_claude_instructions ?? "");
const [globalEnvVars, setGlobalEnvVars] = useState<EnvVar[]>(appSettings?.global_custom_env_vars ?? []);
const [checkingUpdates, setCheckingUpdates] = useState(false);
const [timezone, setTimezone] = useState(appSettings?.timezone ?? "");
const [showInstructionsModal, setShowInstructionsModal] = useState(false);
const [showEnvVarsModal, setShowEnvVarsModal] = useState(false);
@@ -21,7 +23,18 @@ export default function SettingsPanel() {
useEffect(() => {
setGlobalInstructions(appSettings?.global_claude_instructions ?? "");
setGlobalEnvVars(appSettings?.global_custom_env_vars ?? []);
}, [appSettings?.global_claude_instructions, appSettings?.global_custom_env_vars]);
setTimezone(appSettings?.timezone ?? "");
}, [appSettings?.global_claude_instructions, appSettings?.global_custom_env_vars, appSettings?.timezone]);
// Auto-detect timezone on first load if not yet set
useEffect(() => {
if (appSettings && !appSettings.timezone) {
detectHostTimezone().then((tz) => {
setTimezone(tz);
saveSettings({ ...appSettings, timezone: tz });
}).catch(() => {});
}
}, [appSettings?.timezone]);
const handleCheckNow = async () => {
setCheckingUpdates(true);
@@ -46,6 +59,26 @@ export default function SettingsPanel() {
<DockerSettings />
<AwsSettings />
{/* Container Timezone */}
<div>
<label className="block text-sm font-medium mb-1">Container Timezone</label>
<p className="text-xs text-[var(--text-secondary)] mb-1.5">
Timezone for containers affects scheduled task timing (IANA format, e.g. America/New_York)
</p>
<input
type="text"
value={timezone}
onChange={(e) => setTimezone(e.target.value)}
onBlur={async () => {
if (appSettings) {
await saveSettings({ ...appSettings, timezone: timezone || null });
}
}}
placeholder="UTC"
className="w-full px-2 py-1 text-sm bg-[var(--bg-primary)] border border-[var(--border-color)] rounded focus:outline-none focus:border-[var(--accent)]"
/>
</div>
{/* Global Claude Instructions */}
<div>
<label className="block text-sm font-medium mb-1">Claude Instructions</label>

View File

@@ -35,6 +35,8 @@ export const detectAwsConfig = () =>
invoke<string | null>("detect_aws_config");
export const listAwsProfiles = () =>
invoke<string[]>("list_aws_profiles");
export const detectHostTimezone = () =>
invoke<string>("detect_host_timezone");
// Terminal
export const openTerminalSession = (projectId: string, sessionId: string) =>

View File

@@ -98,6 +98,7 @@ export interface AppSettings {
global_custom_env_vars: EnvVar[];
auto_check_updates: boolean;
dismissed_update_version: string | null;
timezone: string | null;
}
export interface UpdateInfo {