Skip to content

feat: timing task#1677

Merged
zerob13 merged 3 commits into
devfrom
feat-timing-task
May 26, 2026
Merged

feat: timing task#1677
zerob13 merged 3 commits into
devfrom
feat-timing-task

Conversation

@zhangmo8
Copy link
Copy Markdown
Collaborator

@zhangmo8 zhangmo8 commented May 26, 2026

closes #1567

Summary by CodeRabbit

  • New Features

    • Scheduled Tasks: create one-time or recurring (daily/weekly) tasks to show notifications or send chat prompts (optional auto-send).
    • Settings UI: full management (create/edit/delete/enable/disable/run-now), agent/model selection, and settings navigation entry.
    • Localization: added UI strings across many languages.
  • Bug Fixes

    • Resolved serialization/cloning error when editing and saving tasks.
  • Documentation & Tests

    • Added specs, implementation plans, checklists, and unit tests for scheduling logic.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

📝 Walkthrough

Walkthrough

Adds a full scheduled-tasks feature: shared types and Zod IPC routes, config persistence with normalization, a timer-backed ScheduledTasksService with start/stop and mutation routes, presenter/runtime/lifecycle wiring, renderer client and settings UI, i18n across locales, and unit tests for core scheduling logic.

Changes

Scheduled Tasks Feature

Layer / File(s) Summary
Shared types and route contracts
src/shared/scheduledTasks.ts, src/shared/contracts/routes/scheduledTasks.routes.ts, src/shared/contracts/routes.ts, src/shared/contracts/routes/system.routes.ts, src/shared/settingsNavigation.ts, src/shared/types/presenters/legacy.presenters.d.ts
Defines discriminated unions for triggers (once/daily/weekly) and actions (notify/prompt), task and settings interfaces, five Zod-based IPC route contracts (list/upsert/delete/toggle/fireNow), and extends navigation and presenter type unions.
Config persistence integration
src/main/presenter/configPresenter/index.ts
Adds getScheduledTasksConfig() and setScheduledTasksConfig() methods that persist scheduled tasks via ElectronStore and normalize on read/write with normalizeScheduledTasksConfig().
Normalization and scheduling utilities
src/main/presenter/scheduledTasks/normalize.ts
Validates and sanitizes task configs, generates missing IDs and defaults, drops malformed tasks, computes next-fire timestamps for once/daily/weekly triggers, and identifies one-shot backfill candidates.
Scheduled tasks service implementation
src/main/presenter/scheduledTasks/index.ts
Core service managing per-task timers, startup backfill, list/upsert/delete/toggle/fireNow mutations with persistence, consistent timer cancellation/rescheduling, and action dispatch (notify or prompt with auto-send via session creation or draft deep-link).
Presenter class and kernel routing
src/main/presenter/index.ts, src/main/routes/index.ts
Initializes ScheduledTasksService in Presenter, exposes a lazy-built kernel route runtime (getMainKernelRouteRuntime), wires scheduled tasks to ChatService/SessionService for auto-send, and registers dispatch handlers for the five scheduled-tasks routes.
Lifecycle hooks
src/main/presenter/lifecyclePresenter/hooks/after-start/scheduledTasksStartHook.ts, src/main/presenter/lifecyclePresenter/hooks/beforeQuit/scheduledTasksStopHook.ts, src/main/presenter/lifecyclePresenter/hooks/index.ts
Primes kernel routes and starts the scheduler after app start; stops the scheduler on app shutdown.
Renderer IPC client
src/renderer/api/ScheduledTasksClient.ts
Typed client wrapping scheduled-tasks routes with Zod-validated response parsing and descriptive errors; exposes list/upsert/remove/toggle/fireNow.
Settings UI and navigation
src/renderer/settings/components/ScheduledTasksSettings.vue, src/renderer/settings/main.ts
Vue SFC implementing scheduled-tasks settings UI (create/edit/toggle/delete/fire-now) with trigger and action editors, model picker popover, per-input buffers, and optimistic persistence; registered lazily in settings router.
Internationalization
src/renderer/src/i18n/*/routes.json, src/renderer/src/i18n/*/settings.json
Adds route labels and a scheduledTasks settings translation block across many locales (en-US, ja-JP, zh-CN, zh-HK, zh-TW, fr-FR, de-DE, es-ES, pt-BR, ru-RU, ko-KR, fa-IR, etc.).
Unit tests
test/main/presenter/scheduledTasks.test.ts
Tests for computeNextFireAt (one-shot and recurring roll-forward), shouldBackfillOneShot eligibility, normalizeScheduledTasksConfig defaults/filtering/dedup, and ScheduledTasksService.fireNow behavior for notify and prompt actions.
Documentation
docs/features/scheduled-tasks/*, docs/issues/scheduled-task-prompt-picker-ux/*, docs/issues/scheduled-tasks-clone-error/*, docs/issues/scheduled-tasks-real-dispatch/*
Feature plan/spec/tasks and related issue artifacts describing UX, clone-error fix, and real dispatch changes.

Sequence Diagram

sequenceDiagram
  Renderer->>Presenter: scheduledTasksList / scheduledTasksUpsert / scheduledTasksFireNow
  Presenter->>ScheduledTasksService: list / upsert / fireNow
  ScheduledTasksService->>ScheduledTasksService: computeNextFireAt & arm timers
  ScheduledTasksService->>SessionCreator: createSessionForTask (autoSend)
  SessionCreator->>ChatService: sendMessage
  ScheduledTasksService->>NotificationPresenter: showNotification
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • zerob13

Poem

🐰 Timers tick and tasks align,
I hop to save each scheduled line,
Settings bloom and toasts appear,
Prompts take flight — the rabbit cheers!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'feat: timing task' is vague and generic; it does not clearly convey the main change (scheduled tasks feature with recurring/one-shot triggers, actions, settings UI, and lifecycle wiring). Use a more descriptive title such as 'feat: add scheduled tasks feature with UI and service integration' to better communicate the scope and primary changes.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR comprehensively implements scheduled tasks feature including service, routes, UI, persistence, lifecycle hooks, i18n, and tests, fully addressing the linked issue #1567 objective to add timed reminders and scheduling functionality.
Out of Scope Changes check ✅ Passed All changes are in scope: new scheduled tasks documentation, service implementation, route contracts, config persistence, lifecycle hooks, UI component, client API, and comprehensive i18n/test coverage directly support the feature objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-timing-task

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🧹 Nitpick comments (2)
src/main/presenter/scheduledTasks/index.ts (1)

271-278: 💤 Low value

Consider adding exhaustive handling for action kinds.

If a new action kind is added to the schema in the future, this function will silently do nothing. Adding an exhaustive check would catch such additions at compile time:

Suggested pattern
     if (action.kind === 'prompt') {
       if (action.autoSend) {
         await this.runPromptAutoSend(taskId, action)
         return
       }
       await this.runPromptDraft(taskId, action)
+      return
     }
+
+    const _exhaustive: never = action
+    log.warn('[ScheduledTasks] Unknown action kind:', (_exhaustive as ScheduledTaskAction).kind)
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/presenter/scheduledTasks/index.ts` around lines 271 - 278, The
current handler for action kinds only handles 'prompt' and silently ignores any
future kinds; update the function containing this snippet (the method that calls
runPromptAutoSend and runPromptDraft) to use an exhaustive check (e.g., convert
the if into a switch on action.kind or add a final default that calls an
assertNever/throws) so unknown action.kind values fail at compile/runtime.
Reference the symbols action.kind, runPromptAutoSend, runPromptDraft and add a
guard (throw or assertNever) for unhandled kinds to ensure the TypeScript
compiler enforces exhaustive handling when new kinds are added.
src/renderer/settings/components/ScheduledTasksSettings.vue (1)

550-558: ⚡ Quick win

Use SCREAMING_SNAKE_CASE for constants.

Rename dayOfWeekOptions to DAY_OF_WEEK_OPTIONS for guideline compliance.

As per coding guidelines, "Constants must use SCREAMING_SNAKE_CASE naming".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/settings/components/ScheduledTasksSettings.vue` around lines 550
- 558, Rename the constant dayOfWeekOptions to DAY_OF_WEEK_OPTIONS and update
all usages to the new name; this includes the declaration (const
DAY_OF_WEEK_OPTIONS: Record<number, string> = { ... }) and any references in the
component script/template where dayOfWeekOptions is accessed (e.g., in computed
properties, methods, or template bindings) so the identifier is consistent with
SCREAMING_SNAKE_CASE guidelines.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/features/scheduled-tasks/plan.md`:
- Around line 60-63: Update the documentation line that mentions the stale test
location: replace the string referencing `test/main/scheduledTasks/` with the
correct test file/path `test/main/presenter/scheduledTasks.test.ts` in the
docs/features/scheduled-tasks/plan.md entry that describes unit tests for
computeNextFireAt and normalizeScheduledTasksConfig so the validation checklist
points to the actual tests.

In `@src/main/presenter/scheduledTasks/normalize.ts`:
- Around line 120-134: Normalization currently allows duplicate task ids from
rawTasks which will break id-keyed operations; in the reduce that builds tasks
(using sanitizeTask and variable tasks) add deduplication by tracking seen ids
(e.g., a Set seenIds) and when a sanitized task's id collides either regenerate
a new unique id (via an existing id generator or by appending a deterministic
suffix/sequence until unique) or skip duplicates, then insert the final unique
id into seenIds before pushing; ensure this logic runs inside the reduce before
acc.push and that the returned object (version: SCHEDULED_TASKS_VERSION, tasks)
contains only tasks with unique ids.

In `@src/main/routes/index.ts`:
- Around line 322-348: The captured mainWindowWebContentsId variable can become
stale; move the webContents id lookup into the scheduled task callback so it is
evaluated at execution time. In the deps.scheduledTasks.setSessionCreator
createSessionForTask implementation, replace uses of the outer
mainWindowWebContentsId with a fresh read like
deps.windowPresenter.mainWindow?.webContents?.id ?? -1 (same fallback) when
constructing the session options, keeping the windowId lookup as-is so both ids
are resolved at runtime.

In `@src/renderer/settings/components/ScheduledTasksSettings.vue`:
- Around line 669-691: persistTask and other commit handlers can be applied
out-of-order and overwrite newer edits; add a "latest-write-wins" guard by
introducing a numeric saveCounter (ref) at component scope, increment it before
each network request, capture its value in the local request (e.g., const reqId
= ++saveCounter.value), then when the response arrives only assign
settings.value (or merge into it) if reqId === saveCounter.value; update the
same pattern in commitTask and the other save handlers referenced (the calls
around lines 693-699, 731-732, 781-782, 807-808, 839-840, 861-862) and prefer
merging response.settings into the current settings.value rather than blindly
replacing it to avoid stomping concurrent local changes.

In `@src/renderer/src/i18n/da-DK/settings.json`:
- Around line 1281-1340: The scheduledTasks block in the da-DK locale is still
in English; translate every string inside the scheduledTasks object (e.g.,
scheduledTasks.title, scheduledTasks.description, scheduledTasks.hint,
scheduledTasks.newTask, defaults.name/title/body, trigger.* like
kindOnce/kindDaily/firesAt/time/description, action.* like
kindNotify/kindPrompt/titlePlaceholder/agentIdPlaceholder/modelIdPlaceholder/systemPrompt/autoSend/description,
weekday.* keys, listTitle/listDescription, and summary.*) into Danish, keeping
all interpolation tokens (e.g., {time}, {day}, {trigger}, {action}) and
placeholder semantics intact. Ensure translations preserve capitalization and UI
context (placeholders remain short), and do not change key names or token
syntax.

In `@src/renderer/src/i18n/fa-IR/settings.json`:
- Around line 1348-1407: The scheduledTasks block in the fa-IR locale is still
English; translate every string under "scheduledTasks" (including nested keys:
defaults, trigger, action, weekday, listTitle, listDescription, summary and
their children like namePlaceholder, fireNow, kindOnce/kindDaily/kindWeekly,
firesAt, dayOfWeek, time, titleField, titlePlaceholder, body, message,
agentIdPlaceholder, modelIdPlaceholder, systemPrompt, autoSend, weekday names,
and summary templates) into Persian; keep the same key names and interpolation
tokens ({time},{day},{trigger},{action}) intact and ensure plural/format
patterns match the originals so the UI reads fully in Persian.

In `@src/renderer/src/i18n/fr-FR/settings.json`:
- Around line 1348-1407: The scheduledTasks section contains English strings
that must be translated to French; update the "scheduledTasks" object and all
nested keys (e.g., defaults, trigger, action, weekday, listTitle,
listDescription, summary) with French translations while preserving keys,
placeholders and interpolation tokens like {time}, {day}, {trigger}, and
{action} exactly as-is and not altering identifiers such as "kindOnce",
"kindDaily", "agentIdPlaceholder" or "modelIdPlaceholder".

In `@src/renderer/src/i18n/he-IL/settings.json`:
- Around line 1348-1406: The scheduledTasks block contains untranslated English
strings; update the he-IL translations for the scheduledTasks object (keys such
as title, description, hint, newTask, empty, namePlaceholder, fireNow,
fireNowSuccess, defaults, trigger.*, action.*, weekday.*, listTitle,
listDescription, summary.*) to Hebrew equivalents so the UI is consistent in the
he-IL locale—edit the scheduledTasks JSON entries to provide proper Hebrew text
for each of those keys (including nested keys like trigger.kindOnce,
action.kindNotify, weekday.sun, summary.daily, etc.).

In `@src/renderer/src/i18n/ja-JP/settings.json`:
- Line 1371: In the ja-JP settings.json under the scheduledTasks block there are
leftover English values (e.g., the "description" value currently "Choose when
this task runs." and several other strings in the same scheduledTasks object).
Replace those English strings with their correct Japanese translations while
preserving the exact JSON keys and structure (escape characters and punctuation
unchanged). Locate the scheduledTasks object and update every untranslated value
in that block so all strings are consistent in Japanese.

In `@src/renderer/src/i18n/ko-KR/settings.json`:
- Line 1371: The scheduledTasks localization block contains English strings
(e.g., the "description" value "Choose when this task runs." plus other entries
around the scheduledTasks block at the same section) that must be translated
into Korean; open the scheduledTasks entries in the ko-KR settings.json (look
for the "scheduledTasks" object and keys like "description" and the strings
around lines ~1371, ~1388, ~1399-1405) and replace each English value with the
appropriate Korean translation, keeping the JSON keys unchanged and preserving
punctuation/formatting and surrounding quotes.

In `@src/renderer/src/i18n/pt-BR/settings.json`:
- Around line 1348-1407: The scheduledTasks block was added with English strings
in the pt-BR locale; translate every value under the "scheduledTasks" object
(keys: title, description, hint, newTask, empty, namePlaceholder, fireNow,
fireNowSuccess, defaults.*, trigger.*, action.*, weekday.*, listTitle,
listDescription, summary.*) into Brazilian Portuguese so the pt-BR file contains
localized text (keep placeholders like {trigger}, {action}, {time}, {day}
intact).

In `@src/renderer/src/i18n/ru-RU/settings.json`:
- Around line 1348-1407: Translate all English values inside the scheduledTasks
JSON object to Russian while preserving the JSON keys and placeholder tokens;
update fields including title, description, hint, newTask, empty,
namePlaceholder, fireNow, fireNowSuccess, defaults (name, title, body), trigger
(title, kind, kindOnce, kindDaily, kindWeekly, firesAt, dayOfWeek, time,
description), action (title, kind, kindNotify, kindPrompt, titleField,
titlePlaceholder, body, message, agentId, agentIdPlaceholder, modelId,
modelIdPlaceholder, systemPrompt, autoSend, description), weekday entries
(sun–sat), listTitle, listDescription, and summary templates; keep placeholder
variables like {trigger}, {action}, {time}, {day} and any colon/format hints
intact and do not change key names or JSON structure.

In `@src/renderer/src/i18n/zh-CN/settings.json`:
- Line 1449: The "systemPrompt" JSON key currently has an English value; update
its value to the Chinese localized string (e.g., replace "System Prompt" with
"系统提示" or the agreed translation) so it matches the surrounding localization;
edit the entry for "systemPrompt" in the settings JSON to the Chinese text.

---

Nitpick comments:
In `@src/main/presenter/scheduledTasks/index.ts`:
- Around line 271-278: The current handler for action kinds only handles
'prompt' and silently ignores any future kinds; update the function containing
this snippet (the method that calls runPromptAutoSend and runPromptDraft) to use
an exhaustive check (e.g., convert the if into a switch on action.kind or add a
final default that calls an assertNever/throws) so unknown action.kind values
fail at compile/runtime. Reference the symbols action.kind, runPromptAutoSend,
runPromptDraft and add a guard (throw or assertNever) for unhandled kinds to
ensure the TypeScript compiler enforces exhaustive handling when new kinds are
added.

In `@src/renderer/settings/components/ScheduledTasksSettings.vue`:
- Around line 550-558: Rename the constant dayOfWeekOptions to
DAY_OF_WEEK_OPTIONS and update all usages to the new name; this includes the
declaration (const DAY_OF_WEEK_OPTIONS: Record<number, string> = { ... }) and
any references in the component script/template where dayOfWeekOptions is
accessed (e.g., in computed properties, methods, or template bindings) so the
identifier is consistent with SCREAMING_SNAKE_CASE guidelines.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3fd72c24-9962-44f2-98a5-8cd382229306

📥 Commits

Reviewing files that changed from the base of the PR and between fcb2898 and f6e3d5c.

📒 Files selected for processing (54)
  • docs/features/scheduled-tasks/plan.md
  • docs/features/scheduled-tasks/spec.md
  • docs/features/scheduled-tasks/tasks.md
  • docs/issues/scheduled-task-prompt-picker-ux/plan.md
  • docs/issues/scheduled-task-prompt-picker-ux/spec.md
  • docs/issues/scheduled-task-prompt-picker-ux/tasks.md
  • docs/issues/scheduled-tasks-clone-error/plan.md
  • docs/issues/scheduled-tasks-clone-error/spec.md
  • docs/issues/scheduled-tasks-clone-error/tasks.md
  • docs/issues/scheduled-tasks-real-dispatch/plan.md
  • docs/issues/scheduled-tasks-real-dispatch/spec.md
  • docs/issues/scheduled-tasks-real-dispatch/tasks.md
  • src/main/presenter/configPresenter/index.ts
  • src/main/presenter/index.ts
  • src/main/presenter/lifecyclePresenter/hooks/after-start/scheduledTasksStartHook.ts
  • src/main/presenter/lifecyclePresenter/hooks/beforeQuit/scheduledTasksStopHook.ts
  • src/main/presenter/lifecyclePresenter/hooks/index.ts
  • src/main/presenter/scheduledTasks/index.ts
  • src/main/presenter/scheduledTasks/normalize.ts
  • src/main/routes/index.ts
  • src/renderer/api/ScheduledTasksClient.ts
  • src/renderer/settings/components/ScheduledTasksSettings.vue
  • src/renderer/settings/main.ts
  • src/renderer/src/i18n/da-DK/routes.json
  • src/renderer/src/i18n/da-DK/settings.json
  • src/renderer/src/i18n/en-US/routes.json
  • src/renderer/src/i18n/en-US/settings.json
  • src/renderer/src/i18n/fa-IR/routes.json
  • src/renderer/src/i18n/fa-IR/settings.json
  • src/renderer/src/i18n/fr-FR/routes.json
  • src/renderer/src/i18n/fr-FR/settings.json
  • src/renderer/src/i18n/he-IL/routes.json
  • src/renderer/src/i18n/he-IL/settings.json
  • src/renderer/src/i18n/ja-JP/routes.json
  • src/renderer/src/i18n/ja-JP/settings.json
  • src/renderer/src/i18n/ko-KR/routes.json
  • src/renderer/src/i18n/ko-KR/settings.json
  • src/renderer/src/i18n/pt-BR/routes.json
  • src/renderer/src/i18n/pt-BR/settings.json
  • src/renderer/src/i18n/ru-RU/routes.json
  • src/renderer/src/i18n/ru-RU/settings.json
  • src/renderer/src/i18n/zh-CN/routes.json
  • src/renderer/src/i18n/zh-CN/settings.json
  • src/renderer/src/i18n/zh-HK/routes.json
  • src/renderer/src/i18n/zh-HK/settings.json
  • src/renderer/src/i18n/zh-TW/routes.json
  • src/renderer/src/i18n/zh-TW/settings.json
  • src/shared/contracts/routes.ts
  • src/shared/contracts/routes/scheduledTasks.routes.ts
  • src/shared/contracts/routes/system.routes.ts
  • src/shared/scheduledTasks.ts
  • src/shared/settingsNavigation.ts
  • src/shared/types/presenters/legacy.presenters.d.ts
  • test/main/presenter/scheduledTasks.test.ts

Comment thread docs/features/scheduled-tasks/plan.md Outdated
Comment thread src/main/presenter/scheduledTasks/normalize.ts
Comment thread src/main/routes/index.ts
Comment thread src/renderer/settings/components/ScheduledTasksSettings.vue
Comment thread src/renderer/src/i18n/da-DK/settings.json
Comment thread src/renderer/src/i18n/ja-JP/settings.json Outdated
Comment thread src/renderer/src/i18n/ko-KR/settings.json Outdated
Comment thread src/renderer/src/i18n/pt-BR/settings.json
Comment thread src/renderer/src/i18n/ru-RU/settings.json
Comment thread src/renderer/src/i18n/zh-CN/settings.json Outdated
zhangmo8 added 2 commits May 26, 2026 10:39
Adds a new settings page (Tools → 定时任务) for creating one-shot,
daily, and weekly scheduled tasks. Each task can either raise a
system notification or send a preset prompt to a chosen agent —
with an opt-in autoSend toggle that bypasses the deeplink draft
path via sessionService.createSession. A small in-process scheduler
arms one setTimeout per task with a 12h chained-timeout cap; missed
one-shot tasks are backfilled on next launch, recurring tasks are
not. Persisted via ConfigPresenter, normalized on read to drop any
malformed records.
@zhangmo8 zhangmo8 force-pushed the feat-timing-task branch from f6e3d5c to ed04a62 Compare May 26, 2026 02:41
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/main/presenter/scheduledTasks/normalize.ts (1)

13-61: ⚡ Quick win

Rename these schema constants to SCREAMING_SNAKE_CASE.

TriggerSchema, ActionSchema, ScheduledTaskSchema, and LooseSchedulerSettingsSchema don't match the repository constant-naming rule. As per coding guidelines, src/**/*.{ts,tsx,js,jsx,vue}: Constants must use SCREAMING_SNAKE_CASE naming.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/presenter/scheduledTasks/normalize.ts` around lines 13 - 61, Rename
the constant schema identifiers to SCREAMING_SNAKE_CASE and update all their
usages: change TriggerSchema -> TRIGGER_SCHEMA, ActionSchema -> ACTION_SCHEMA,
ScheduledTaskSchema -> SCHEDULED_TASK_SCHEMA, and LooseSchedulerSettingsSchema
-> LOOSE_SCHEDULER_SETTINGS_SCHEMA; ensure the z.discriminatedUnion/z.object
definitions remain identical and update any references within this file (or
imports/exports) that use TriggerSchema, ActionSchema, ScheduledTaskSchema, or
LooseSchedulerSettingsSchema so they now reference the new names.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/presenter/configPresenter/index.ts`:
- Around line 3201-3213: getScheduledTasksConfig and setScheduledTasksConfig are
directly using this.store which bypasses the key-aware settings store; change
both to use the key-aware store returned by
getSettingsStoreForKey('scheduledTasks') so reads/writes follow DB-backed
settings after sqlite attach. Specifically, inside getScheduledTasksConfig call
const store = this.getSettingsStoreForKey('scheduledTasks') then read with
store.get, normalize via normalizeScheduledTasksConfig and write back with
store.set if needed; do the same in setScheduledTasksConfig: normalize with
normalizeScheduledTasksConfig, then persist using the key-specific store.set and
return the normalized value.

In `@src/main/presenter/scheduledTasks/index.ts`:
- Around line 240-253: The current fireAndPersist method always calls markFired
in the finally block even if dispatch(task) throws, causing failed dispatches
(especially one-shot tasks) to be marked consumed; change the control flow so
markFired(task) is only called on successful dispatch (i.e., inside the try
after await this.dispatch(task) or in an explicit success branch) and ensure the
existing re-arm logic that uses list().tasks and armTask(refreshed, Date.now())
still runs for recurring tasks only when dispatch succeeded; keep dispatch error
logging (log.error) in the catch block and do not call markFired there.

---

Nitpick comments:
In `@src/main/presenter/scheduledTasks/normalize.ts`:
- Around line 13-61: Rename the constant schema identifiers to
SCREAMING_SNAKE_CASE and update all their usages: change TriggerSchema ->
TRIGGER_SCHEMA, ActionSchema -> ACTION_SCHEMA, ScheduledTaskSchema ->
SCHEDULED_TASK_SCHEMA, and LooseSchedulerSettingsSchema ->
LOOSE_SCHEDULER_SETTINGS_SCHEMA; ensure the z.discriminatedUnion/z.object
definitions remain identical and update any references within this file (or
imports/exports) that use TriggerSchema, ActionSchema, ScheduledTaskSchema, or
LooseSchedulerSettingsSchema so they now reference the new names.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0e1c6a41-9f15-4b0d-8ef5-29d1f9af7bfb

📥 Commits

Reviewing files that changed from the base of the PR and between f6e3d5c and ed04a62.

📒 Files selected for processing (41)
  • docs/features/scheduled-tasks/plan.md
  • docs/features/scheduled-tasks/spec.md
  • docs/features/scheduled-tasks/tasks.md
  • docs/issues/scheduled-task-prompt-picker-ux/plan.md
  • docs/issues/scheduled-task-prompt-picker-ux/spec.md
  • docs/issues/scheduled-task-prompt-picker-ux/tasks.md
  • docs/issues/scheduled-tasks-clone-error/plan.md
  • docs/issues/scheduled-tasks-clone-error/spec.md
  • docs/issues/scheduled-tasks-clone-error/tasks.md
  • docs/issues/scheduled-tasks-real-dispatch/plan.md
  • docs/issues/scheduled-tasks-real-dispatch/spec.md
  • docs/issues/scheduled-tasks-real-dispatch/tasks.md
  • src/main/presenter/configPresenter/index.ts
  • src/main/presenter/index.ts
  • src/main/presenter/lifecyclePresenter/hooks/after-start/scheduledTasksStartHook.ts
  • src/main/presenter/lifecyclePresenter/hooks/beforeQuit/scheduledTasksStopHook.ts
  • src/main/presenter/lifecyclePresenter/hooks/index.ts
  • src/main/presenter/scheduledTasks/index.ts
  • src/main/presenter/scheduledTasks/normalize.ts
  • src/main/routes/index.ts
  • src/renderer/api/ScheduledTasksClient.ts
  • src/renderer/settings/components/ScheduledTasksSettings.vue
  • src/renderer/settings/main.ts
  • src/renderer/src/i18n/da-DK/routes.json
  • src/renderer/src/i18n/da-DK/settings.json
  • src/renderer/src/i18n/en-US/routes.json
  • src/renderer/src/i18n/en-US/settings.json
  • src/renderer/src/i18n/fa-IR/routes.json
  • src/renderer/src/i18n/fa-IR/settings.json
  • src/renderer/src/i18n/fr-FR/routes.json
  • src/renderer/src/i18n/fr-FR/settings.json
  • src/renderer/src/i18n/he-IL/routes.json
  • src/renderer/src/i18n/he-IL/settings.json
  • src/renderer/src/i18n/ja-JP/routes.json
  • src/renderer/src/i18n/ja-JP/settings.json
  • src/renderer/src/i18n/ko-KR/routes.json
  • src/renderer/src/i18n/ko-KR/settings.json
  • src/renderer/src/i18n/pt-BR/routes.json
  • src/renderer/src/i18n/pt-BR/settings.json
  • src/renderer/src/i18n/ru-RU/routes.json
  • src/renderer/src/i18n/ru-RU/settings.json
💤 Files with no reviewable changes (16)
  • src/renderer/src/i18n/he-IL/routes.json
  • src/renderer/src/i18n/ru-RU/routes.json
  • src/renderer/src/i18n/fr-FR/routes.json
  • src/renderer/src/i18n/ja-JP/routes.json
  • src/renderer/src/i18n/pt-BR/routes.json
  • src/renderer/src/i18n/fa-IR/routes.json
  • src/renderer/src/i18n/pt-BR/settings.json
  • src/renderer/src/i18n/ko-KR/routes.json
  • src/renderer/src/i18n/ko-KR/settings.json
  • src/renderer/src/i18n/ru-RU/settings.json
  • src/renderer/src/i18n/en-US/settings.json
  • src/renderer/src/i18n/fa-IR/settings.json
  • src/renderer/src/i18n/en-US/routes.json
  • src/renderer/src/i18n/he-IL/settings.json
  • src/renderer/src/i18n/ja-JP/settings.json
  • src/renderer/src/i18n/fr-FR/settings.json
✅ Files skipped from review due to trivial changes (13)
  • docs/issues/scheduled-tasks-real-dispatch/plan.md
  • docs/features/scheduled-tasks/spec.md
  • src/renderer/settings/main.ts
  • docs/issues/scheduled-tasks-clone-error/spec.md
  • src/renderer/src/i18n/da-DK/routes.json
  • docs/features/scheduled-tasks/tasks.md
  • docs/issues/scheduled-tasks-clone-error/tasks.md
  • docs/issues/scheduled-tasks-clone-error/plan.md
  • docs/issues/scheduled-task-prompt-picker-ux/plan.md
  • docs/issues/scheduled-task-prompt-picker-ux/tasks.md
  • docs/issues/scheduled-tasks-real-dispatch/tasks.md
  • docs/issues/scheduled-tasks-real-dispatch/spec.md
  • docs/features/scheduled-tasks/plan.md

Comment thread src/main/presenter/configPresenter/index.ts
Comment thread src/main/presenter/scheduledTasks/index.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/presenter/scheduledTasks/index.ts (1)

319-337: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Treat sessionId: null as an auto-send failure.

createSessionForTask() can return { sessionId: null } from the route wiring, but this branch is handled as success here. That means the task can be marked fired even though no session was created and no prompt was sent. Fall back to draft mode when no sessionId comes back.

Suggested fix
   try {
-      await this.sessionCreator.createSessionForTask({
+      const { sessionId } = await this.sessionCreator.createSessionForTask({
         agentId: action.agentId ?? SCHEDULED_TASK_DEFAULT_AGENT_ID,
         message: action.message,
         providerId: action.providerId,
         modelId: action.modelId,
         systemPrompt: action.systemPrompt
       })
+
+      if (!sessionId) {
+        log.warn('[ScheduledTasks] Session creation returned no session id; falling back to draft mode')
+        await this.runPromptDraft(taskId, action)
+        return
+      }
 
       await this.notificationPresenter.showNotification({
         id: `scheduled:${taskId}`,
         title: action.title,
         body: action.message.slice(0, 200)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/presenter/scheduledTasks/index.ts` around lines 319 - 337, The
current try block treats any completion of
this.sessionCreator.createSessionForTask(...) as success even when it returns {
sessionId: null }; change the flow to capture the return (e.g. const result =
await this.sessionCreator.createSessionForTask(...)) and if result.sessionId is
null, throw or directly call this.runPromptDraft(taskId, action) and skip the
notificationPresenter.showNotification call so the task isn't considered sent;
keep the existing catch that logs via log.error('[ScheduledTasks] Failed to
create session for task:', error) and falls back to this.runPromptDraft as
before.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/main/presenter/scheduledTasks/index.ts`:
- Around line 319-337: The current try block treats any completion of
this.sessionCreator.createSessionForTask(...) as success even when it returns {
sessionId: null }; change the flow to capture the return (e.g. const result =
await this.sessionCreator.createSessionForTask(...)) and if result.sessionId is
null, throw or directly call this.runPromptDraft(taskId, action) and skip the
notificationPresenter.showNotification call so the task isn't considered sent;
keep the existing catch that logs via log.error('[ScheduledTasks] Failed to
create session for task:', error) and falls back to this.runPromptDraft as
before.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ab7b433e-a807-4ec5-85d6-11aa2501f95a

📥 Commits

Reviewing files that changed from the base of the PR and between ed04a62 and 6a2ad9a.

📒 Files selected for processing (32)
  • docs/features/scheduled-tasks/plan.md
  • docs/features/scheduled-tasks/tasks.md
  • src/main/presenter/scheduledTasks/index.ts
  • src/main/presenter/scheduledTasks/normalize.ts
  • src/main/routes/index.ts
  • src/renderer/settings/components/ScheduledTasksSettings.vue
  • src/renderer/src/i18n/da-DK/settings.json
  • src/renderer/src/i18n/de-DE/routes.json
  • src/renderer/src/i18n/de-DE/settings.json
  • src/renderer/src/i18n/es-ES/routes.json
  • src/renderer/src/i18n/es-ES/settings.json
  • src/renderer/src/i18n/fa-IR/settings.json
  • src/renderer/src/i18n/fr-FR/settings.json
  • src/renderer/src/i18n/he-IL/settings.json
  • src/renderer/src/i18n/id-ID/routes.json
  • src/renderer/src/i18n/id-ID/settings.json
  • src/renderer/src/i18n/it-IT/routes.json
  • src/renderer/src/i18n/it-IT/settings.json
  • src/renderer/src/i18n/ja-JP/settings.json
  • src/renderer/src/i18n/ko-KR/settings.json
  • src/renderer/src/i18n/ms-MY/routes.json
  • src/renderer/src/i18n/ms-MY/settings.json
  • src/renderer/src/i18n/pl-PL/routes.json
  • src/renderer/src/i18n/pl-PL/settings.json
  • src/renderer/src/i18n/pt-BR/settings.json
  • src/renderer/src/i18n/ru-RU/settings.json
  • src/renderer/src/i18n/tr-TR/routes.json
  • src/renderer/src/i18n/tr-TR/settings.json
  • src/renderer/src/i18n/vi-VN/routes.json
  • src/renderer/src/i18n/vi-VN/settings.json
  • src/renderer/src/i18n/zh-CN/settings.json
  • test/main/presenter/scheduledTasks.test.ts
✅ Files skipped from review due to trivial changes (15)
  • src/renderer/src/i18n/de-DE/routes.json
  • src/renderer/src/i18n/vi-VN/routes.json
  • src/renderer/src/i18n/es-ES/routes.json
  • src/renderer/src/i18n/ms-MY/routes.json
  • src/renderer/src/i18n/pl-PL/routes.json
  • src/renderer/src/i18n/it-IT/settings.json
  • src/renderer/src/i18n/da-DK/settings.json
  • docs/features/scheduled-tasks/tasks.md
  • src/renderer/src/i18n/de-DE/settings.json
  • docs/features/scheduled-tasks/plan.md
  • src/renderer/src/i18n/ja-JP/settings.json
  • src/renderer/src/i18n/ko-KR/settings.json
  • src/renderer/src/i18n/zh-CN/settings.json
  • src/renderer/src/i18n/id-ID/settings.json
  • src/renderer/src/i18n/ru-RU/settings.json

@zerob13 zerob13 merged commit aabd048 into dev May 26, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature] timing task

2 participants