feat(intentions): Phase 7 — if-then rules for task / time / triage triggers
Small if-then automation layer. Rules persist in SQLite; the runner lives on the frontend and binds to the Phase 6 event bus so the rule pipeline reuses the same delivery primitives (timer events, TTS, Tasks navigation). Storage: - Migration v12 adds implementation_rules (id, enabled, trigger_kind, trigger_value, actions_json, last_fired_key, created_at, updated_at) with enabled+trigger_kind index for the runner's hot path. - CRUD helpers: insert / list / get / set-enabled / mark-fired / delete, plus a round-trip test. Commands (all main-window-guarded via ensure_main_window): - list_implementation_rules - create_implementation_rule — validates HH:MM, checks the target task exists at save time for surface-task actions, caps speak-line at 240 chars, pins v1 timers to 5 minutes. - set_implementation_rule_enabled - mark_implementation_rule_fired — main-thread idempotency shim so the runner can atomically claim a fire. - delete_implementation_rule Runner (implementationIntentions.svelte.ts): - Subscribes to kon:task-completed and kon:morning-triage-finished (MorningTriageModal now emits on all three exit paths — empty, skipped, picked — so skip counts as finishing). - 30 s poll for time-of-day rules, plus an immediate check on startup so a rule whose time has already passed today catches up once. - Idempotency via last_fired_key composed as YYYY-MM-DD@HH:MM for time rules; new time rules whose HH:MM has already passed today are pre-seeded so they don't fire retroactively on save. - Rules are paused when Nudges "Mute for now" is on — a hard mute stops all rule delivery in addition to OS notifications. - Stale-task safety: if a surface-task action's target has been deleted, the runner opens Tasks and warns clearly rather than pretending to surface something that's gone. Editor (ImplementationRulesEditor.svelte): - Lives in Settings under a new "If-then rules" accordion section. - `If` picker: time of day (with time input), a task completes, morning triage finishes. - `Then` composer: optional surface (inbox / today / all tasks / specific task), optional 5-min timer, optional speak-aloud line. - Saved rules list with enable toggle + delete. Rules table integration for Phase 10b rename sweep: add implementation_rules to the kon.db → corbie.db migration shim when that phase lands. Gates: fmt, clippy -D warnings, cargo test 265/0, svelte-check 0/0, npm build green. Pre-existing Vite chunk warning on sounds.ts is unrelated to Phase 7.
This commit is contained in:
@@ -16,6 +16,11 @@ export type LlmPromptPreset = "default" | "email" | "notes" | "code";
|
||||
export type AiGpuConcurrency = "parallel" | "sequential";
|
||||
export type TaskBucket = "inbox" | "today" | "soon" | "later";
|
||||
export type ToastSeverity = "info" | "success" | "warn" | "error";
|
||||
export type ImplementationRuleTriggerKind =
|
||||
| "time_of_day"
|
||||
| "task_completed"
|
||||
| "morning_triage_finished";
|
||||
export type ImplementationRuleSurfaceTarget = "inbox" | "today" | "tasks" | "task";
|
||||
|
||||
export interface PageState {
|
||||
current: string;
|
||||
@@ -249,6 +254,43 @@ export interface TaskEntry {
|
||||
energy: EnergyLevel | null;
|
||||
}
|
||||
|
||||
export type ImplementationRuleAction =
|
||||
| {
|
||||
kind: "surface";
|
||||
target: ImplementationRuleSurfaceTarget;
|
||||
taskId?: string | null;
|
||||
label?: string | null;
|
||||
}
|
||||
| {
|
||||
kind: "start_timer";
|
||||
seconds: number;
|
||||
taskId?: string | null;
|
||||
label?: string | null;
|
||||
}
|
||||
| {
|
||||
kind: "speak_line";
|
||||
text: string;
|
||||
};
|
||||
|
||||
export interface ImplementationRule {
|
||||
id: string;
|
||||
enabled: boolean;
|
||||
triggerKind: ImplementationRuleTriggerKind;
|
||||
triggerValue: string;
|
||||
actions: ImplementationRuleAction[];
|
||||
lastFiredKey: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface ImplementationRuleDraft {
|
||||
enabled?: boolean;
|
||||
triggerKind: ImplementationRuleTriggerKind;
|
||||
triggerValue: string;
|
||||
actions: ImplementationRuleAction[];
|
||||
lastFiredKey?: string | null;
|
||||
}
|
||||
|
||||
export interface TaskDraft {
|
||||
text: string;
|
||||
bucket?: TaskBucket;
|
||||
|
||||
Reference in New Issue
Block a user