refactor(cron): rework scheduled task functionality#1874
Conversation
📝 WalkthroughWalkthroughReplaces the legacy ScheduledTasksService with a full Cron Agent Jobs subsystem: SQLite-backed persistence, a cron trigger/scheduling engine, an Electron utility-process scheduler, run execution with Remote delivery, a ChangesCron Agent Jobs Feature
MCP/Plugin Nonblocking Startup
Dependency and Registry Maintenance
Renderer i18n Type Declarations (Unrelated Additions)
Estimated code review effort: 5 (Critical) | ~150 minutes Sequence Diagram(s)sequenceDiagram
participant SchedulerUtilityHost as "deepchat-scheduler (utility process)"
participant SchedulerProcessManager
participant CronJobsService
participant CronJobRunExecutor
participant AgentSessionPresenter
participant CronJobDeliveryRouter
participant RemoteControlPresenter
SchedulerUtilityHost->>SchedulerUtilityHost: scan due cron jobs
SchedulerUtilityHost->>SchedulerProcessManager: RUN_DUE (jobId, runId)
SchedulerProcessManager->>CronJobsService: onRunDue -> processDueRun
CronJobsService->>CronJobRunExecutor: execute(runId, job)
CronJobRunExecutor->>AgentSessionPresenter: createDetachedSession (metadata: cron_job)
AgentSessionPresenter-->>CronJobRunExecutor: sessionId
CronJobRunExecutor->>AgentSessionPresenter: startSessionRun (task prompt)
AgentSessionPresenter-->>CronJobRunExecutor: session updates (output, status)
CronJobRunExecutor->>CronJobRunExecutor: mark run completed/failed
CronJobRunExecutor->>CronJobDeliveryRouter: deliver(job, run)
CronJobDeliveryRouter->>RemoteControlPresenter: deliverCronJobResult(job, run, target)
RemoteControlPresenter-->>CronJobDeliveryRouter: remoteMessageId
CronJobDeliveryRouter-->>CronJobRunExecutor: delivery receipts recorded
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
zerob13
left a comment
There was a problem hiding this comment.
整体架构评估
✅ 优点
-
清晰的模块化设计
- 完整的SDD文档覆盖(phase-1到phase-6),架构思路清晰
- 代码组织良好:repository、executor、scheduler、delivery router分离职责明确
- 从legacy ScheduledTasks迁移到CronJobs,命名更专业
-
测试覆盖完整
- 新增了完整的单元测试
test/main/presenter/cronJobs.test.ts(1389行) - 涵盖了cron表达式解析、运行执行器、调度器等核心模块
- 使用了条件测试(describeIfSqlite)处理可选依赖
- 新增了完整的单元测试
-
类型安全性强
- 使用Zod schema进行输入验证(cronJobTool.ts)
- 完整的TypeScript类型定义(
@shared/cronJobs.ts) - 状态机模式清晰(CronJobRunStatus、CronJobsSchedulerState等)
🔍 需要关注的问题
1. 安全性问题
高优先级:Agent工具默认启用状态
src/main/presenter/toolPresenter/agentTools/cronJobTool.ts:
- 该工具具有写操作能力(
WRITE_ACTIONS包括create/update/delete/pause/resume/run_now) - 需确认默认禁用策略是否正确实施
- 建议在PR描述中明确说明该工具的权限控制机制
调度器进程管理
src/main/presenter/cronJobs/schedulerProcessManager.ts:
- 使用了UtilityProcess进行进程隔离,设计合理
- 但需要关注:进程异常退出时的资源清理和状态恢复
DEFAULT_MAX_RESTART_ATTEMPTS = 5- 考虑是否需要指数退避策略
2. 并发控制与资源管理
src/main/presenter/cronJobs/runExecutor.ts:86-112:
const activeRuns = this.repository.countActiveRunsByJob(input.job.id, run.id)
if (activeRuns > 0) {
if (input.job.runtime.concurrencyPolicy === 'queue') {
return this.repository.releaseRunQueued(run.id)
}
// ... skip logic
}- 并发检查和策略执行之间存在潜在的竞态条件
- 建议使用数据库级别的锁或原子操作确保并发安全性
3. 数据库迁移
从legacy ScheduledTasks迁移到CronJobs:
- ✅ 新增了4个数据表:cronJobs、cronJobRuns、cronJobDeliveries、deepchatSessionMetadata
- ❓ 缺失数据迁移脚本:没有看到从旧表到新表的数据迁移逻辑
- ❓ 用户升级后旧的scheduled tasks数据会丢失吗?
- 建议添加迁移逻辑或在PR描述中说明数据迁移策略
4. 国际化处理
所有语言文件都已更新(da-DK, de-DE, en-US等),但:
⚠️ 部分翻译可能是机器生成的,建议native speaker review- 新增的key数量较多(~50个),确保覆盖所有UI场景
5. 错误处理与可观测性
src/main/presenter/cronJobs/index.ts:75-91:
- 启动时调用
failStaleRunningRuns()清理陈旧运行状态 - 设计合理 - 但缺少详细的日志记录和监控指标
- 建议添加:
- 运行失败率统计
- 调度延迟监控
- 重试次数追踪
6. 代码质量细节
Magic numbers:
const MODEL_TEXT_PREVIEW_LIMIT = 500 // cronJobTool.ts:22
const DEFAULT_IDLE_SHUTDOWN_MS = 30_000 // schedulerProcessManager.ts:36建议将这些常量移到配置文件或shared constants中
错误消息硬编码:
src/main/presenter/cronJobs/runExecutor.ts:109:
'Another cron job run is already active.'应该使用i18n或至少移到常量定义
📝 文档建议
- API文档:cronJobTool的action类型缺少详细说明
- 架构决策记录:为什么选择UtilityProcess而非Worker threads?
- 性能考量:cron表达式解析的性能影响分析
✅ 推荐操作
在合并前:
⚠️ 必须解决:确认数据迁移策略⚠️ 必须解决:并发控制的竞态条件修复- 🔧 建议修复:添加更详细的错误日志和监控
- 📖 建议补充:用户升级指南文档
总体评价:这是一个高质量的重构PR,架构设计合理,测试覆盖完整。主要关注点在数据迁移和并发安全性上。
zerob13
left a comment
There was a problem hiding this comment.
具体代码Review
src/main/presenter/cronJobs/runExecutor.ts
并发安全问题 (Line 86-112)
const activeRuns = this.repository.countActiveRunsByJob(input.job.id, run.id)
if (activeRuns > 0) {
if (input.job.runtime.concurrencyPolicy === 'queue') {
return this.repository.releaseRunQueued(run.id)
}
// ... skip logic
}问题:在分布式环境或高并发场景下,countActiveRunsByJob和后续的状态更新操作之间存在竞态窗口。两个并发请求可能同时通过检查。
建议:
// 使用数据库级别的原子操作
const claimed = this.repository.claimRunIfNoActive(input.runId, input.job.id, this.claimOwner)
if (!claimed) {
// handle concurrency policy
}src/main/presenter/toolPresenter/agentTools/cronJobTool.ts
输入验证不完整 (Line 44-52)
const createJobSchema = z.strictObject({
name: z.string().trim().min(1).max(200),
description: z.string().trim().optional(),
cronExpr: z.string().trim().min(1).optional(),
timezone: z.string().trim().min(1).optional(),
// ...
})问题:
cronExpr只验证了非空,但没有验证cron表达式的语法有效性timezone只验证了非空,但没有验证是否为有效的IANA时区字符串
建议:
cronExpr: z.string().trim().min(1).refine(
(val) => cronExpressionService.validate(val, 'UTC', Date.now()).valid,
{ message: 'Invalid cron expression' }
),
timezone: z.string().trim().min(1).refine(
(val) => {
try {
Intl.DateTimeFormat(undefined, { timeZone: val })
return true
} catch {
return false
}
},
{ message: 'Invalid timezone' }
)src/main/presenter/cronJobs/schedulerProcessManager.ts
进程重启策略可优化 (Line 36-38)
const DEFAULT_IDLE_SHUTDOWN_MS = 30_000
const DEFAULT_RESTART_DELAY_MS = 1_000
const DEFAULT_MAX_RESTART_ATTEMPTS = 5问题:固定的重启延迟可能导致频繁的失败-重启循环
建议:使用指数退避策略
private getRestartDelay(attempt: number): number {
const baseDelay = 1_000
const maxDelay = 30_000
return Math.min(baseDelay * Math.pow(2, attempt), maxDelay)
}src/main/routes/index.ts
异步操作错误处理 (Line 520-524)
async function reconcileCronJobsAfterAgentChange(
runtime: MainKernelRouteRuntime,
routeName: string
): Promise<void> {
if (!CRON_JOB_AGENT_CHANGE_ROUTES.has(routeName)) {
return
}
try {
await runtime.cronJobs.reconcileScheduler('agent-change')
} catch (error) {
console.warn('[CronJobs] Failed to reconcile jobs after agent change:', error)
}
}问题:只记录警告但不通知用户,可能导致静默失败
建议:
} catch (error) {
console.error('[CronJobs] Failed to reconcile jobs after agent change:', error)
// 考虑返回错误信息给调用方,或者记录到系统通知
throw new Error(`Failed to reconcile cron jobs: ${error.message}`)
}src/renderer/settings/components/CronJobsSettings.vue
UI状态管理 (Line 10)
<Badge v-if="isSaving" variant="outline">{{ t('common.saving') }}</Badge>建议:
- 添加保存失败状态的UI反馈
- 添加防抖以避免频繁的保存操作
- 考虑添加"未保存的更改"提示
<Badge v-if="isSaving" variant="outline">{{ t('common.saving') }}</Badge>
<Badge v-else-if="saveError" variant="destructive">{{ t('common.saveFailed') }}</Badge>
<Badge v-else-if="hasUnsavedChanges" variant="secondary">{{ t('common.unsavedChanges') }}</Badge>src/shared/cronJobs.ts
默认值设计 (Line 7-12)
export const CRON_JOBS_DEFAULT_RUNTIME = {
maxDurationMs: 60 * 60 * 1000, // 1 hour
maxTurns: 20,
concurrencyPolicy: 'skip'
} as const建议:
maxDurationMs: 1小时对某些任务可能太长,考虑是否需要更短的默认值maxTurns: 20的依据是什么?建议添加注释说明- 考虑将这些值设为可配置的
测试覆盖
test/main/presenter/cronJobs.test.ts
✅ 优秀的方面:
- 1389行的测试代码,覆盖面广
- 使用了条件测试处理可选依赖
- 测试了边界情况(misfire、并发、时区等)
- 缺少集成测试:整个workflow从创建job到执行到delivery的端到端测试
- 缺少压力测试:大量并发任务的行为
- 缺少边界测试:时区边界、DST切换、闰秒等
总结
代码质量整体很高,但需要重点关注:
- 🔴 并发安全性问题
- 🟡 输入验证完整性
- 🟡 错误处理和用户反馈
- 🟢 测试覆盖已经很好,建议补充集成测试
zerob13
left a comment
There was a problem hiding this comment.
文档与迁移策略评估
📚 SDD文档质量
优点:
- ✅ 完整的6个phase规格文档(phase-1到phase-6)
- ✅ 每个issue都有对应的spec.md
- ✅ 架构决策有明确记录
docs/features/ 覆盖:
- cron-agent-jobs-phase-1-scheduler (91行)
- cron-agent-jobs-phase-2-cron-trigger-engine (110行)
- cron-agent-jobs-phase-3-agent-binding (102行)
- cron-agent-jobs-phase-4-fresh-session-runs (106行)
- cron-agent-jobs-phase-5-delivery-continuation (79行)
- cron-agent-jobs-phase-6-cronjob-tool (112行)
⚠️ 关键缺失:数据迁移文档
问题分析:
-
删除的文件:
src/main/presenter/scheduledTasks/index.ts(345行)src/main/presenter/scheduledTasks/normalize.ts(223行)src/renderer/api/ScheduledTasksClient.ts(85行)src/renderer/settings/components/ScheduledTasksSettings.vue(958行)
-
新增的表结构:
cronJobs- 替代旧的scheduled_tasks表cronJobRuns- 新增运行历史表cronJobDeliveries- 新增交付记录表deepchatSessionMetadata- 新增会话元数据表
-
数据兼容性问题:
- 旧版本用户升级后,现有的scheduled tasks数据会发生什么?
- 是否有自动迁移脚本?
- 是否需要手动操作?
- 降级路径是什么?
建议添加:
-
迁移指南 (
docs/migrations/scheduled-tasks-to-cron-jobs.md):# Scheduled Tasks to Cron Jobs Migration ## Breaking Changes - Old scheduled_tasks table is deprecated - New cronJobs structure with enhanced features ## Automatic Migration - [ ] Step 1: Detect old scheduled_tasks table - [ ] Step 2: Convert to new cronJobs format - [ ] Step 3: Preserve run history if available - [ ] Step 4: Archive old table ## Manual Steps (if needed) ...
-
数据库迁移脚本:
// src/main/presenter/sqlitePresenter/migrations/scheduled-tasks-to-cron-jobs.ts export async function migrateScheduledTasksToCronJobs(db: Database) { const hasOldTable = db.prepare( "SELECT name FROM sqlite_master WHERE type='table' AND name='scheduled_tasks'" ).get() if (hasOldTable) { // Migration logic } }
-
回滚计划:
- 如果迁移失败,如何回退?
- 数据备份策略是什么?
📖 用户文档建议
需要补充的文档:
-
用户指南 (
docs/user-guide/cron-jobs.md):- Cron表达式语法说明
- 时区选择指南
- Agent绑定步骤
- Remote delivery配置
-
API文档:
- CronJob Agent Tool的完整API参考
- 各个action的参数说明和示例
-
故障排查 (
docs/troubleshooting/cron-jobs.md):- 常见问题和解决方案
- 调度器状态含义
- 日志查看位置
🔍 代码注释质量
需要改进的地方:
-
复杂算法缺少注释:
src/main/presenter/cronJobs/cronExpressionService.ts中的cron解析逻辑需要更详细的注释 -
状态转换缺少说明:
run status的转换路径需要状态图或注释说明:
queued -> running -> completed/failed/cancelled -
并发策略需要详细说明:
skipvsqueue的具体行为和适用场景
建议优先级
-
🔴 P0 - 必须完成:
- 数据迁移策略文档
- 迁移脚本实现
-
🟡 P1 - 强烈建议:
- 用户指南
- API文档
-
🟢 P2 - 可以后续补充:
- 故障排查文档
- 性能调优指南
结论:文档质量整体很好,但缺失了最关键的数据迁移部分。这可能会导致用户升级后数据丢失或功能异常。建议在合并前补充迁移策略文档和实现。
zerob13
left a comment
There was a problem hiding this comment.
性能与资源管理分析
⚡ 性能考虑
1. 调度器进程管理
src/main/presenter/cronJobs/schedulerProcessManager.ts
✅ 优秀设计:
- 使用UtilityProcess进行进程隔离,避免阻塞主进程
- 实现了空闲自动关闭机制(30秒)
- 支持进程重启和错误恢复
// Line 36
const DEFAULT_IDLE_SHUTDOWN_MS = 30_000问题:如果用户有频繁触发的cron任务(例如每分钟一次),调度器可能会频繁启动和关闭,导致性能开销。
建议:
- 考虑根据任务频率动态调整空闲超时
- 或者添加"最小运行时间"防止频繁重启
private calculateIdleTimeout(): number {
const snapshot = this.deps.getSnapshot()
if (snapshot.nextRunAt && snapshot.nextRunAt - Date.now() < 60_000) {
return 60_000 // 如果下次运行在1分钟内,至少保持1分钟
}
return this.idleShutdownMs
}2. 数据库查询优化
src/main/presenter/cronJobs/repository.ts
需要确保以下操作有适当的索引:
// 频繁调用的查询
countActiveRunsByJob(jobId: string, excludeRunId?: string)
listRunsByJob(jobId: string, limit?: number)
getSchedulerSnapshot()建议添加索引:
CREATE INDEX idx_cronJobRuns_jobId_status ON cronJobRuns(jobId, status);
CREATE INDEX idx_cronJobRuns_scheduledAt ON cronJobRuns(scheduledAt);
CREATE INDEX idx_cronJobs_nextRunAt ON cronJobs(nextRunAt) WHERE enabled = 1;3. 内存管理
src/main/presenter/cronJobs/runExecutor.ts:58
private readonly activeSessions = new Map<
string,
{ runId: string; job: CronJob; timeout: ReturnType<typeof setTimeout> | null }
>()问题:如果session异常终止但没有清理,Map会持续增长导致内存泄漏。
建议:
- 添加定期清理机制
- 设置Map大小上限
- 添加监控指标
private readonly MAX_ACTIVE_SESSIONS = 1000
private cleanupStaleSessions(): void {
const now = Date.now()
const staleThreshold = 24 * 60 * 60 * 1000 // 24小时
for (const [sessionId, session] of this.activeSessions.entries()) {
if (now - session.startedAt > staleThreshold) {
console.warn('[CronJobs] Cleaning up stale session:', sessionId)
this.clearActiveSession(sessionId)
}
}
if (this.activeSessions.size > this.MAX_ACTIVE_SESSIONS) {
console.error('[CronJobs] Active sessions limit exceeded')
// 清理最旧的sessions
}
}📊 资源限制与配额
1. 运行时限制
export const CRON_JOBS_DEFAULT_RUNTIME = {
maxDurationMs: 60 * 60 * 1000, // 1小时
maxTurns: 20,
concurrencyPolicy: 'skip'
}问题:
- 1小时的默认超时可能太长,可能导致资源长时间占用
- 没有全局并发限制,用户可能创建数百个同时运行的任务
建议:
- 添加全局并发限制
const MAX_CONCURRENT_RUNS = 10 // 系统级别的限制- 考虑更短的默认超时
maxDurationMs: 15 * 60 * 1000 // 15分钟可能更合理- 添加资源配额系统
interface CronJobQuota {
maxJobs: number
maxConcurrentRuns: number
maxRunsPerDay: number
maxDurationPerRun: number
}2. 存储管理
问题:cronJobRuns表可能会无限增长
建议:实现自动清理策略
interface CronJobRetentionPolicy {
maxRunsPerJob: number // 例如:每个job保留最近100次运行
maxRunAge: number // 例如:保留30天内的运行记录
}
async function cleanupOldRuns(policy: CronJobRetentionPolicy) {
// 清理超过保留期的运行记录
await db.run(, [Date.now() - policy.maxRunAge, jobId, policy.maxRunsPerJob])
}🔄 并发与锁机制
问题:缺少分布式锁
当前的并发控制依赖于:
- 数据库的ACID特性
- 进程内的Map管理
潜在风险:
- 如果将来支持多实例部署,当前的并发控制会失效
建议:
- 短期:在数据库层面添加更强的约束
CREATE UNIQUE INDEX idx_cronJobRuns_one_active_per_job
ON cronJobRuns(jobId)
WHERE status IN ('queued', 'running');- 长期:考虑使用分布式锁(Redis、etcd)或数据库advisory locks
📈 监控与可观测性
当前缺失的指标:
interface CronJobMetrics {
// 调度器指标
schedulerUptime: number
schedulerRestartCount: number
// 任务指标
totalJobs: number
enabledJobs: number
totalRuns: number
failedRuns: number
avgRunDuration: number
// 性能指标
schedulingLatency: number // 预定时间 vs 实际执行时间
queueDepth: number
concurrentRuns: number
// 资源指标
memoryUsage: number
cpuUsage: number
}建议实现:
class CronJobMetricsCollector {
private metrics: CronJobMetrics
recordRunStart(runId: string, scheduledAt: number) {
const latency = Date.now() - scheduledAt
this.metrics.schedulingLatency =
(this.metrics.schedulingLatency * 0.9) + (latency * 0.1) // EMA
}
async getSnapshot(): Promise<CronJobMetrics> {
return { ...this.metrics }
}
}🎯 优化建议优先级
P0 - 立即修复:
- ✅ 无,当前没有阻塞性性能问题
P1 - 合并前完成:
- 添加数据库索引
- 实现activeSessions清理机制
- 添加全局并发限制
P2 - 后续优化:
- 动态调整空闲超时
- 实现运行记录清理
- 添加监控指标收集
- 考虑分布式锁支持
总结:性能设计整体合理,进程隔离和空闲关闭机制是亮点。主要需要关注内存管理、数据库索引和全局资源限制。
zerob13
left a comment
There was a problem hiding this comment.
性能与资源管理分析
⚡ 性能考虑
1. 调度器进程管理
src/main/presenter/cronJobs/schedulerProcessManager.ts
✅ 优秀设计:
- 使用UtilityProcess进行进程隔离,避免阻塞主进程
- 实现了空闲自动关闭机制(30秒)
- 支持进程重启和错误恢复
// Line 36
const DEFAULT_IDLE_SHUTDOWN_MS = 30_000问题:如果用户有频繁触发的cron任务(例如每分钟一次),调度器可能会频繁启动和关闭,导致性能开销。
建议:考虑根据任务频率动态调整空闲超时,或者添加"最小运行时间"防止频繁重启。
2. 数据库查询优化
需要确保频繁调用的查询有适当的索引:
- countActiveRunsByJob
- listRunsByJob
- getSchedulerSnapshot
建议添加索引以提升查询性能
3. 内存管理
src/main/presenter/cronJobs/runExecutor.ts:58
private readonly activeSessions = new Map<string, {...}>()问题:如果session异常终止但没有清理,Map会持续增长导致内存泄漏。
建议:
- 添加定期清理机制
- 设置Map大小上限
- 添加监控指标
📊 资源限制与配额
1. 运行时限制
export const CRON_JOBS_DEFAULT_RUNTIME = {
maxDurationMs: 60 * 60 * 1000, // 1小时
maxTurns: 20,
concurrencyPolicy: 'skip'
}问题:
- 1小时的默认超时可能太长,可能导致资源长时间占用
- 没有全局并发限制,用户可能创建数百个同时运行的任务
建议:
- 添加全局并发限制(例如:MAX_CONCURRENT_RUNS = 10)
- 考虑更短的默认超时(15分钟可能更合理)
- 添加资源配额系统
2. 存储管理
问题:cronJobRuns表可能会无限增长
建议:实现自动清理策略,例如:
- 每个job保留最近100次运行
- 保留30天内的运行记录
🔄 并发与锁机制
问题:缺少分布式锁
当前的并发控制依赖于数据库的ACID特性和进程内的Map管理。
潜在风险:如果将来支持多实例部署,当前的并发控制会失效
建议:
- 短期:在数据库层面添加更强的约束
- 长期:考虑使用分布式锁或数据库advisory locks
📈 监控与可观测性
当前缺失的监控指标:
- 调度器运行时间和重启次数
- 任务成功/失败率
- 平均运行时长
- 调度延迟(预定时间 vs 实际执行时间)
- 并发运行数量
- 资源使用情况
建议:实现指标收集系统,用于故障诊断和性能优化
🎯 优化建议优先级
P0 - 立即修复:
- ✅ 无,当前没有阻塞性性能问题
P1 - 合并前完成:
- 添加数据库索引
- 实现activeSessions清理机制
- 添加全局并发限制
P2 - 后续优化:
- 动态调整空闲超时
- 实现运行记录清理
- 添加监控指标收集
- 考虑分布式锁支持
总结:性能设计整体合理,进程隔离和空闲关闭机制是亮点。主要需要关注内存管理、数据库索引和全局资源限制。
There was a problem hiding this comment.
Actionable comments posted: 19
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
docs/features/cron-jobs-timezone-selector/spec.md (1)
1-18: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winAdd
plan.mdandtasks.mdto this feature folder.docs/features/cron-jobs-timezone-selector/currently has onlyspec.md, but feature docs should ship asspec.md,plan.md, andtasks.md.🤖 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 `@docs/features/cron-jobs-timezone-selector/spec.md` around lines 1 - 18, The feature folder is missing the required planning documents, so add both plan.md and tasks.md alongside the existing spec.md for this Cron Jobs timezone selector feature. Keep the new docs aligned with the feature scope in spec.md and use the same feature folder name, so the set of docs is complete and discoverable.Source: Coding guidelines
src/main/presenter/sqlitePresenter/index.ts (1)
600-626: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick winclear
cron_job_runs.session_idduring reset
clearNewAgentData()deletes the session rows but leaves cron run records pointing at now-missing sessions. Null out those references in the same transaction, or delete the affected run rows too.🤖 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/sqlitePresenter/index.ts` around lines 600 - 626, clearNewAgentData() leaves cron_job_runs.session_id pointing to deleted sessions; update the reset flow to clear those references too. In sqlitePresenter/index.ts, extend the same runTransaction in clearNewAgentData() to either null out cron_job_runs.session_id or delete the affected cron run rows before removing sessions, keeping it consistent with the other DELETE statements and the existing data-clearing order.src/main/presenter/agentSessionPresenter/index.ts (1)
732-791: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
maxProviderRoundsalso needs to be forwarded on thequeuePendingInputpath.
sendMessage()only passes it intoagent.processMessage()today; whenagent.queuePendingInputis used, the option is dropped and queued runs can ignore the turn cap. Pass it through there too.🤖 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/agentSessionPresenter/index.ts` around lines 732 - 791, The sendMessage flow drops maxProviderRounds when agent.queuePendingInput is used, so queued runs can bypass the turn cap. Update the queuePendingInput call in AgentSessionPresenter.sendMessage to forward options?.maxProviderRounds alongside the existing source and projectDir payload, matching the processMessage path so both execution modes honor the same limit.
♻️ Duplicate comments (2)
src/renderer/src/i18n/da-DK/settings.json (1)
1386-1439: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winSame untranslated
cronJobskeys pattern as other locales.
actions.*, mostfields.*,presets.*, and moststatus.*remain in English in this Danish locale file, matching the same gap seen invi-VNandpl-PL.🤖 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/src/i18n/da-DK/settings.json` around lines 1386 - 1439, The cronJobs localization block still contains many English strings in the Danish locale, including actions, fields, presets, and status labels. Update the affected keys in the cronJobs object to proper Danish translations, using the existing structure and the same key names so it stays consistent with the other locale files and the cronJobs UI.src/renderer/src/i18n/pl-PL/settings.json (1)
2767-2820: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winSame untranslated
cronJobskeys pattern as other locales.
actions.*, mostfields.*,presets.*, and moststatus.*remain in English in this Polish locale file, matching the same gap seen invi-VNandda-DK.🤖 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/src/i18n/pl-PL/settings.json` around lines 2767 - 2820, The cronJobs block in the Polish locale still contains many English strings, so translate the remaining untranslated keys to Polish to match the rest of the locale. Update the values under cronJobs, especially actions.*, fields.* (except already translated entries), presets.*, and status.* in settings.json, using the existing key names and the same wording style as other translated sections.
🧹 Nitpick comments (9)
src/main/presenter/cronJobs/schedulerUtilityHost.ts (1)
284-326: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate SQL between the two
queueRunbranches.The
INSERTandINSERT OR IGNOREstatements are identical apart from theOR IGNOREkeyword; consolidate to avoid drift when the column list changes.♻️ Proposed refactor
- const statement = ignoreDuplicate - ? `INSERT OR IGNORE INTO cron_job_runs ( - id, - job_id, - scheduled_at, - queued_at, - started_at, - completed_at, - status, - reason, - error, - created_at, - updated_at - ) - VALUES (?, ?, ?, ?, NULL, NULL, 'queued', ?, NULL, ?, ?)` - : `INSERT INTO cron_job_runs ( - id, - job_id, - scheduled_at, - queued_at, - started_at, - completed_at, - status, - reason, - error, - created_at, - updated_at - ) - VALUES (?, ?, ?, ?, NULL, NULL, 'queued', ?, NULL, ?, ?)` + const statement = `INSERT ${ignoreDuplicate ? 'OR IGNORE ' : ''}INTO cron_job_runs ( + id, + job_id, + scheduled_at, + queued_at, + started_at, + completed_at, + status, + reason, + error, + created_at, + updated_at + ) + VALUES (?, ?, ?, ?, NULL, NULL, 'queued', ?, NULL, ?, ?)`🤖 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/cronJobs/schedulerUtilityHost.ts` around lines 284 - 326, The queueRun method in schedulerUtilityHost duplicates the full cron_job_runs INSERT statement in both branches, differing only by the OR IGNORE keyword. Refactor queueRun to build the common INSERT body once and vary only the conflict clause so the column list and VALUES stay in sync when the schema changes.src/main/presenter/mcpPresenter/index.ts (1)
186-214: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueConsider throttling concurrent background server starts.
Previously sequential
awaitcalls implicitly throttled server startup; now all enabled servers are launched concurrently and unbounded viastartServerInBackground. With many configured MCP servers, this could cause a burst of simultaneous process/network spawns during app init.🤖 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/mcpPresenter/index.ts` around lines 186 - 214, The MCP presenter startup flow now launches all enabled servers in parallel, which can create an unbounded burst of background spawns during initialization. Update the server-start path in mcpPresenter/index.ts around the startingServers and startServerInBackground calls to add throttling or a concurrency limit while preserving the existing custom prompts and enabled-server selection logic. Use the existing identifiers like startServerInBackground, enabledServers, and startingServers to wire the limiter into the startup loop.src/main/presenter/sqlitePresenter/tables/cronJobs.ts (1)
110-117: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRedundant index creation.
getCreateTableSQL()already appendsCRON_JOBS_INDEX_SQL(Line 110), and thecreateTable()override runs it again (Line 116). It's harmless due toIF NOT EXISTS, but you can drop one to avoid confusion—either remove the interpolation at Line 110 or the extraexecin the override.🤖 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/sqlitePresenter/tables/cronJobs.ts` around lines 110 - 117, The cron jobs table setup is creating the same index twice: `CronJobsPresenter.getCreateTableSQL()` already includes `CRON_JOBS_INDEX_SQL`, and `CronJobsPresenter.createTable()` executes it again. Remove one of these paths to avoid redundant index creation—either stop interpolating `CRON_JOBS_INDEX_SQL` in `getCreateTableSQL()` or हटे the extra `this.db.exec(CRON_JOBS_INDEX_SQL)` call in the `createTable()` override.src/main/presenter/lifecyclePresenter/hooks/after-start/cronJobsStartHook.ts (1)
19-22: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUse
loggerinstead ofconsole.warnfor consistency.This file imports the shared
loggerand useslogger.infoon Line 26, but this warning path goes throughconsole.warn. Route it throughlogger.warnso failures to prime the route runtime are captured by the same logging pipeline.♻️ Suggested change
- try { - getMainKernelRouteRuntime() - } catch (error) { - console.warn( - '[cronJobsStartHook] Failed to prime route runtime; cron jobs cannot create sessions until routes initialize:', - error - ) - } + try { + getMainKernelRouteRuntime() + } catch (error) { + logger.warn( + '[cronJobsStartHook] Failed to prime route runtime; cron jobs cannot create sessions until routes initialize:', + error + ) + }🤖 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/lifecyclePresenter/hooks/after-start/cronJobsStartHook.ts` around lines 19 - 22, The warning in cronJobsStartHook is using console.warn instead of the shared logging pipeline. Update the failure path in after-start/cronJobsStartHook.ts to route the message through logger.warn, matching the existing logger.info usage in the same hook and keeping all lifecycle logging consistent.src/main/presenter/cronJobs/index.ts (1)
57-59: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winAttach a
.catchto fire-and-forget scheduler reconciliation.
reconcileScheduler(...)is async and can reject (e.g. scheduler process failure). Both theresumeHandler(Lines 57–59) andstart()(Line 97) discard the promise withvoid, so a rejection surfaces as an unhandled promise rejection rather than a logged warning. Add a.catchto log and swallow.♻️ Suggested change
private readonly resumeHandler = () => { - void this.reconcileScheduler('system-resume') + void this.reconcileScheduler('system-resume').catch((error) => { + console.warn('[CronJobs] Failed to reconcile scheduler on resume:', error) + }) }this.failStaleRunningRuns() void this.attachPowerMonitor() - void this.reconcileScheduler('startup') + void this.reconcileScheduler('startup').catch((error) => { + console.warn('[CronJobs] Failed to reconcile scheduler on startup:', error) + })Also applies to: 90-98
🤖 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/cronJobs/index.ts` around lines 57 - 59, The fire-and-forget calls to reconcileScheduler in resumeHandler and start() currently discard a rejecting promise, which can surface as an unhandled rejection. Update the cronJobs presenter in the resumeHandler and the start() flow so the async reconcileScheduler invocation is followed by a .catch that logs a warning/error with context (for example, system-resume or startup) and then swallows the failure. Use the existing reconcileScheduler method and the surrounding presenter logging to keep the behavior non-fatal while preventing unhandled promise rejections.src/renderer/src/i18n/ja-JP/settings.json (1)
1453-1505: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winSeveral new
cronJobsstrings are left untranslated in ja-JP.Keys like
defaults.name, most ofactions.*, most offields.*(name,cronExpr,timezone,preset,agent,noAgent,taskPrompt,runtimePolicy,followAgent,pinCurrent), all ofpresets.*, and most ofstatus.*are copied verbatim from English instead of translated to Japanese.🤖 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/src/i18n/ja-JP/settings.json` around lines 1453 - 1505, The new cronJobs localization block in settings.json still contains many English strings, so translate the remaining copied keys to Japanese while keeping the existing structure intact. Update cronJobs.defaults.name, actions.*, fields.* entries like name, cronExpr, timezone, preset, agent, noAgent, taskPrompt, runtimePolicy, followAgent, pinCurrent, plus all presets.* and status.* values in the ja-JP locale file, using the surrounding Japanese entries as style guidance.src/renderer/src/i18n/es-ES/settings.json (1)
2767-2819: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winSeveral new
cronJobsstrings are left untranslated in es-ES.Keys like
defaults.name, most ofactions.*, most offields.*(name,cronExpr,timezone,preset,agent,noAgent,taskPrompt,runtimePolicy,followAgent,pinCurrent), all ofpresets.*, and most ofstatus.*are copied verbatim from English instead of translated to Spanish.🤖 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/src/i18n/es-ES/settings.json` around lines 2767 - 2819, The new cronJobs localization block in settings.json still contains many English fallbacks; translate the copied strings in cronJobs.defaults, cronJobs.actions, cronJobs.fields, cronJobs.presets, and cronJobs.status to proper es-ES values. Update the affected entries in the cronJobs object so the Spanish locale is consistent, keeping the existing keys and the rest of the structure unchanged.src/renderer/src/components/WindowSideBarSessionItem.vue (1)
181-192: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueTooltip trigger isn't keyboard-focusable.
The
role="img"span has no interactive semantics/tabindex, so keyboard users can't reveal the tooltip via focus (only hover). Consider making the trigger abutton/focusable element or accept mouse-only as a known limitation for this decorative indicator.🤖 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/src/components/WindowSideBarSessionItem.vue` around lines 181 - 192, The tooltip trigger in WindowSideBarSessionItem.vue is not keyboard-focusable because the current session-source indicator uses a non-interactive span with role="img". Update the TooltipTrigger content so the source indicator can receive focus via keyboard, either by switching the trigger to a focusable element such as a button or by adding appropriate focusability/interaction semantics to the existing trigger around sourceIndicatorLabel and TooltipTrigger. Keep the tooltip behavior intact while ensuring keyboard users can reveal it without relying on hover.src/renderer/api/CronJobsClient.ts (1)
80-168: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueInconsistent response validation: some routes use descriptive error wrappers, others parse raw.
parseJobResponse/parseRunResponse/parseSchedulerStatusResponsethrow route-scoped, descriptive errors onsafeParsefailure, butlist()'sjobsarray,listRuns,listDeliveries,validateSchedule, andpreviewSchedulecall.parse()/route.output.parse()directly, surfacing raw ZodErrors without route context. Consider routing all responses through a shared, descriptive parse helper for consistent failure diagnostics.🤖 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/api/CronJobsClient.ts` around lines 80 - 168, Several CronJobsClient methods are bypassing the route-scoped error handling used by parseJobResponse, parseRunResponse, and parseSchedulerStatusResponse, so validation failures leak raw Zod errors without route context. Update list, listRuns, listDeliveries, validateSchedule, and previewSchedule to use the same descriptive parsing pattern as the existing helpers, ideally via a shared parse wrapper for cronJobsListRoute, cronJobsListRunsRoute, cronJobsListDeliveriesRoute, cronJobsValidateScheduleRoute, and cronJobsPreviewScheduleRoute. Keep the returned shapes unchanged, but ensure all response parsing failures include the route name and consistent diagnostics.
🤖 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/issues/cron-scheduler-utility-start-crash/spec.md`:
- Around line 1-17: The cron scheduler utility startup crash is caused by the
utility host importing the SQLite presenter index, which pulls in Electron
main-process dependencies. Update the scheduler utility host to use a
lightweight database connection helper instead of importing `openSQLiteDatabase`
from `sqlitePresenter/index.ts`, while keeping existing presenter callers on the
index export. Add the missing `plan.md` and `tasks.md` alongside `spec.md` under
the cron-scheduler-utility-start-crash issue docs, and make sure the utility
build path no longer reaches Electron-only dependencies through the SQLite
presenter route.
In `@src/main/presenter/configPresenter/index.ts`:
- Around line 214-219: `ensureBuiltinDeepChatAgent` is leaving persisted builtin
agent configs unchanged, and `withDeepChatAgentDefaults` only copies an existing
`disabledAgentTools` array instead of merging in missing defaults. Update the
builtin config handling in `configPresenter/index.ts` so
`DEFAULT_DISABLED_AGENT_TOOLS` is applied to existing builtin `configJson` as
well, and adjust `withDeepChatAgentDefaults` to merge the default disabled tools
into any stored array while preserving user-defined entries. Use the
`ensureBuiltinDeepChatAgent` and `withDeepChatAgentDefaults` symbols to locate
the fix.
In `@src/main/presenter/cronJobs/runExecutor.ts`:
- Around line 165-181: The catch path in runExecutor’s error handling can still
transition or deliver a run after it has already reached a terminal state. In
the catch block around startSessionRun, add the same running-status guard used
by the other transition helpers before calling repository.markRunFailed and
deliverRun, or make markRunFailed itself no-op for non-running runs, so terminal
runs are not overwritten or delivered twice.
In `@src/main/presenter/cronJobs/schedulerUtilityHost.ts`:
- Around line 100-142: Guard the scheduler command paths so database failures do
not crash the utility process. In `SchedulerUtilityHost.start()`, `reconcile()`,
and `runNow()`, wrap the `openDatabase()`/`requireDatabase()`/`queueRun()` flow
in try/catch and emit the same `type: 'ERROR'` event pattern used by
`scanDueRuns()` and `sendHeartbeat()` when an exception occurs. Also update the
`parentPort.on('message', ...)` command switch to catch synchronous errors from
these methods and route them through the existing error reporting path instead
of letting the message handler throw.
In `@src/main/presenter/remoteControlPresenter/index.ts`:
- Around line 92-99: The remote delivery fallback cap is too high for Discord,
allowing oversized messages to reach DiscordAdapter.sendMessage() and fail in
DiscordClient.sendMessage(). Update the delivery limit logic in
presenter/remoteControlPresenter to apply a Discord-specific cap (or split
Discord payloads before dispatch) while keeping the existing fallback behavior
for other REMOTE_DELIVERY_CHANNELS. Use the REMOTE_DELIVERY_MESSAGE_LIMIT
constant and DiscordAdapter/DiscordClient.sendMessage as the key spots to
adjust.
- Around line 441-463: deliverCronJobResult currently resolves the channel
binding and adapter outside the runtime-operation queue, which can race with
adapter rebuilds and make sendMessage fail after the connected check. Move the
binding lookup, adapter retrieval, connected validation, and sendMessage call
into enqueueRuntimeOperation in remoteControlPresenter/index.ts, following the
same pattern used by the rebuild/unregister flows, so the cron delivery is
serialized with runtime operations.
- Around line 1289-1320: The cron delivery ID logic in getRemoteDeliveryChatId
currently treats qqbot like a valid reply context by building an ID with run.id,
but QQBot passive replies require a real upstream message/event id. Update the
channel handling so qqbot is excluded from cron delivery here, and route it
through a supported send path or fail fast instead of generating a reply-context
ID; keep telegram/feishu, discord, and Weixin iLink handling unchanged.
In `@src/main/presenter/toolPresenter/agentTools/cronJobTool.ts`:
- Around line 108-116: Partial delivery updates are overwriting existing targets
because `toUpdateInput` passes `patch.delivery ?? existing.delivery` directly
into `normalizeDelivery`, so any patch with only fields like `notifyOnFailure`
loses prior `targets`. Update `toUpdateInput` to merge `existing.delivery` with
`patch.delivery` before calling `normalizeDelivery`, matching the
`normalizeRuntime` pattern, and keep `normalizeDelivery` responsible only for
applying defaults when fields are still missing.
In `@src/renderer/settings/components/CronJobsSettings.vue`:
- Around line 281-286: The scheduler-level error is being rendered inside the
per-job loop in CronJobsSettings.vue, causing the same message to repeat for
every job row. Move the schedulerStatus?.lastError block out of the job v-for
and render it once in the scheduler status card area, using the existing
schedulerStatus binding so the error appears only a single time and is clearly
global rather than job-specific.
In `@src/renderer/settings/components/DeepChatAgentsSettings.vue`:
- Line 711: The default `cronjob` disabled tool is only being applied in
`withDeepChatAgentDefaults()`, so agents with an existing empty
`disabledAgentTools` array are skipped. Update the backend
normalization/migration path to seed the same `DEFAULT_DISABLED_AGENT_TOOLS`
when `disabledAgentTools` is empty as well as missing, using the existing
`withDeepChatAgentDefaults()` logic as the reference point.
In `@src/renderer/src/i18n/de-DE/settings.json`:
- Around line 2767-2819: The new cronJobs localization block in the German
settings bundle is only partially translated, leaving many UI labels in English.
Update the remaining keys under cronJobs, especially actions.*, fields.* (name,
cronExpr, timezone, preset, agent, noAgent, taskPrompt, runtimePolicy,
followAgent, pinCurrent), presets.*, status.*, plus none, nextRunAt, and
defaults.name, so the German locale is consistent when rendered by the cron job
settings UI.
In `@src/renderer/src/i18n/fr-FR/settings.json`:
- Around line 1453-1506: The fr-FR cronJobs locale block is partially
untranslated, with several keys still in English. Update the existing cronJobs
entries in settings.json for the affected keys (including none, nextRunAt,
defaults.name, presets.*, and status.* such as stopped, starting, running, idle,
error, and invalidAgent) so they match the French style used by neighboring
strings in the same object.
In `@src/renderer/src/i18n/ko-KR/settings.json`:
- Around line 1453-1506: The new cronJobs localization block is still using
English fallback text in ko-KR and the other touched locale files, so the
cron-job UI remains partially untranslated. Update the cronJobs object in each
locale’s settings.json, especially the actions, fields, presets, status, none,
nextRunAt, and defaults.name keys, to provide proper translations that match the
existing locale. Keep the same key structure and align the translated strings
with the neighboring settings entries in each locale file.
In `@src/renderer/src/i18n/ms-MY/settings.json`:
- Around line 2771-2817: The ms-MY locale entry for cronJobs still contains many
English strings, so localize the remaining keys to Malay throughout this
section. Update the untranslated values in the cronJobs object, including none,
nextRunAt, defaults.name, all actions.*, most fields.*, all presets.*, and most
status.* entries, while keeping the existing Malay translations like delivery
and remoteDelivery consistent with surrounding i18n style.
In `@src/renderer/src/i18n/pt-BR/settings.json`:
- Around line 1453-1505: The pt-BR cronJobs locale block still contains many
English strings, so complete the translation for all remaining keys under
cronJobs. Update the untranslated values in the cronJobs object (including none,
nextRunAt, actions.*, fields.*, presets.*, and status.*) to proper Portuguese
while keeping the already translated delivery and runNowSuccess entries intact.
Use the existing cronJobs JSON structure and preserve the key names so the
renderer can continue resolving these labels correctly.
In `@src/renderer/src/i18n/zh-HK/settings.json`:
- Around line 1453-1506: The zh-HK cronJobs locale block mixes Simplified
Chinese into a Traditional Chinese file, so update the affected entries in the
cronJobs object to use Hong Kong Traditional wording consistently. Fix the
strings under cronJobs, especially defaults, actions, fields, presets, and
status, replacing Simplified forms like 无/运行/任务/对账/名称/表达式/时区/状态/启用/启动/空闲/错误 with
Traditional equivalents while keeping the existing zh-HK style used by fields
like 傳送、頻道、選擇, and ensure the changed keys remain aligned with the cronJobs
translation structure.
In `@src/renderer/src/i18n/zh-TW/settings.json`:
- Around line 1453-1505: The cronJobs translations in the zh-TW locale mix
Simplified Chinese with Traditional Chinese, so update the affected strings to
full Traditional Chinese for consistency. Fix the entries under cronJobs in
settings.json, especially the keys in fields, actions, nextRunAt, none, and
status, and verify the values in the cronJobs object match the surrounding zh-TW
style while keeping already-correct Traditional terms unchanged.
In `@test/main/presenter/lifecyclePresenter/cronJobsStartHook.test.ts`:
- Around line 1-38: The test location does not mirror the source module path for
cronJobsStartHook, so move this Vitest file to match the source structure under
test/main/presenter/lifecyclePresenter/hooks/after-start and keep the existing
cronJobsStartHook import and assertions unchanged. This should align the test
path with the hook’s module path while preserving the current mocks and
execute() coverage.
In `@test/main/presenter/pluginPresenter.test.ts`:
- Around line 1024-1027: The test in presenter.enablePlugin is using a brittle
20ms Promise.race timeout that can fail on slow CI even when the code is
correct. Update the assertion to avoid depending on such a tight fixed budget by
either widening the timeout or, better, validating non-blocking behavior through
a separate check on startServer/await behavior while still using
presenter.enablePlugin and fixture.pluginId.
---
Outside diff comments:
In `@docs/features/cron-jobs-timezone-selector/spec.md`:
- Around line 1-18: The feature folder is missing the required planning
documents, so add both plan.md and tasks.md alongside the existing spec.md for
this Cron Jobs timezone selector feature. Keep the new docs aligned with the
feature scope in spec.md and use the same feature folder name, so the set of
docs is complete and discoverable.
In `@src/main/presenter/agentSessionPresenter/index.ts`:
- Around line 732-791: The sendMessage flow drops maxProviderRounds when
agent.queuePendingInput is used, so queued runs can bypass the turn cap. Update
the queuePendingInput call in AgentSessionPresenter.sendMessage to forward
options?.maxProviderRounds alongside the existing source and projectDir payload,
matching the processMessage path so both execution modes honor the same limit.
In `@src/main/presenter/sqlitePresenter/index.ts`:
- Around line 600-626: clearNewAgentData() leaves cron_job_runs.session_id
pointing to deleted sessions; update the reset flow to clear those references
too. In sqlitePresenter/index.ts, extend the same runTransaction in
clearNewAgentData() to either null out cron_job_runs.session_id or delete the
affected cron run rows before removing sessions, keeping it consistent with the
other DELETE statements and the existing data-clearing order.
---
Duplicate comments:
In `@src/renderer/src/i18n/da-DK/settings.json`:
- Around line 1386-1439: The cronJobs localization block still contains many
English strings in the Danish locale, including actions, fields, presets, and
status labels. Update the affected keys in the cronJobs object to proper Danish
translations, using the existing structure and the same key names so it stays
consistent with the other locale files and the cronJobs UI.
In `@src/renderer/src/i18n/pl-PL/settings.json`:
- Around line 2767-2820: The cronJobs block in the Polish locale still contains
many English strings, so translate the remaining untranslated keys to Polish to
match the rest of the locale. Update the values under cronJobs, especially
actions.*, fields.* (except already translated entries), presets.*, and status.*
in settings.json, using the existing key names and the same wording style as
other translated sections.
---
Nitpick comments:
In `@src/main/presenter/cronJobs/index.ts`:
- Around line 57-59: The fire-and-forget calls to reconcileScheduler in
resumeHandler and start() currently discard a rejecting promise, which can
surface as an unhandled rejection. Update the cronJobs presenter in the
resumeHandler and the start() flow so the async reconcileScheduler invocation is
followed by a .catch that logs a warning/error with context (for example,
system-resume or startup) and then swallows the failure. Use the existing
reconcileScheduler method and the surrounding presenter logging to keep the
behavior non-fatal while preventing unhandled promise rejections.
In `@src/main/presenter/cronJobs/schedulerUtilityHost.ts`:
- Around line 284-326: The queueRun method in schedulerUtilityHost duplicates
the full cron_job_runs INSERT statement in both branches, differing only by the
OR IGNORE keyword. Refactor queueRun to build the common INSERT body once and
vary only the conflict clause so the column list and VALUES stay in sync when
the schema changes.
In
`@src/main/presenter/lifecyclePresenter/hooks/after-start/cronJobsStartHook.ts`:
- Around line 19-22: The warning in cronJobsStartHook is using console.warn
instead of the shared logging pipeline. Update the failure path in
after-start/cronJobsStartHook.ts to route the message through logger.warn,
matching the existing logger.info usage in the same hook and keeping all
lifecycle logging consistent.
In `@src/main/presenter/mcpPresenter/index.ts`:
- Around line 186-214: The MCP presenter startup flow now launches all enabled
servers in parallel, which can create an unbounded burst of background spawns
during initialization. Update the server-start path in mcpPresenter/index.ts
around the startingServers and startServerInBackground calls to add throttling
or a concurrency limit while preserving the existing custom prompts and
enabled-server selection logic. Use the existing identifiers like
startServerInBackground, enabledServers, and startingServers to wire the limiter
into the startup loop.
In `@src/main/presenter/sqlitePresenter/tables/cronJobs.ts`:
- Around line 110-117: The cron jobs table setup is creating the same index
twice: `CronJobsPresenter.getCreateTableSQL()` already includes
`CRON_JOBS_INDEX_SQL`, and `CronJobsPresenter.createTable()` executes it again.
Remove one of these paths to avoid redundant index creation—either stop
interpolating `CRON_JOBS_INDEX_SQL` in `getCreateTableSQL()` or हटे the extra
`this.db.exec(CRON_JOBS_INDEX_SQL)` call in the `createTable()` override.
In `@src/renderer/api/CronJobsClient.ts`:
- Around line 80-168: Several CronJobsClient methods are bypassing the
route-scoped error handling used by parseJobResponse, parseRunResponse, and
parseSchedulerStatusResponse, so validation failures leak raw Zod errors without
route context. Update list, listRuns, listDeliveries, validateSchedule, and
previewSchedule to use the same descriptive parsing pattern as the existing
helpers, ideally via a shared parse wrapper for cronJobsListRoute,
cronJobsListRunsRoute, cronJobsListDeliveriesRoute,
cronJobsValidateScheduleRoute, and cronJobsPreviewScheduleRoute. Keep the
returned shapes unchanged, but ensure all response parsing failures include the
route name and consistent diagnostics.
In `@src/renderer/src/components/WindowSideBarSessionItem.vue`:
- Around line 181-192: The tooltip trigger in WindowSideBarSessionItem.vue is
not keyboard-focusable because the current session-source indicator uses a
non-interactive span with role="img". Update the TooltipTrigger content so the
source indicator can receive focus via keyboard, either by switching the trigger
to a focusable element such as a button or by adding appropriate
focusability/interaction semantics to the existing trigger around
sourceIndicatorLabel and TooltipTrigger. Keep the tooltip behavior intact while
ensuring keyboard users can reveal it without relying on hover.
In `@src/renderer/src/i18n/es-ES/settings.json`:
- Around line 2767-2819: The new cronJobs localization block in settings.json
still contains many English fallbacks; translate the copied strings in
cronJobs.defaults, cronJobs.actions, cronJobs.fields, cronJobs.presets, and
cronJobs.status to proper es-ES values. Update the affected entries in the
cronJobs object so the Spanish locale is consistent, keeping the existing keys
and the rest of the structure unchanged.
In `@src/renderer/src/i18n/ja-JP/settings.json`:
- Around line 1453-1505: The new cronJobs localization block in settings.json
still contains many English strings, so translate the remaining copied keys to
Japanese while keeping the existing structure intact. Update
cronJobs.defaults.name, actions.*, fields.* entries like name, cronExpr,
timezone, preset, agent, noAgent, taskPrompt, runtimePolicy, followAgent,
pinCurrent, plus all presets.* and status.* values in the ja-JP locale file,
using the surrounding Japanese entries as style guidance.
🪄 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: c6de93bd-6ec8-4b3a-89f2-3f0a0f25561d
📒 Files selected for processing (138)
docs/ARCHITECTURE.mddocs/FLOWS.mddocs/features/cron-agent-jobs-phase-1-scheduler/spec.mddocs/features/cron-agent-jobs-phase-2-cron-trigger-engine/spec.mddocs/features/cron-agent-jobs-phase-3-agent-binding/spec.mddocs/features/cron-agent-jobs-phase-4-fresh-session-runs/spec.mddocs/features/cron-agent-jobs-phase-5-delivery-continuation/spec.mddocs/features/cron-agent-jobs-phase-6-cronjob-tool/spec.mddocs/features/cron-jobs-cron-expression-editor/spec.mddocs/features/cron-jobs-timezone-selector/spec.mddocs/issues/cron-agent-jobs-concurrency-skip-delivery/spec.mddocs/issues/cron-agent-jobs-full-remote-delivery/spec.mddocs/issues/cron-agent-jobs-list-sticky-actions/spec.mddocs/issues/cron-agent-jobs-runtime-observability/spec.mddocs/issues/cron-agent-jobs-stale-running-runs/spec.mddocs/issues/cron-agent-jobs-trigger-logging/spec.mddocs/issues/cron-job-run-insert-values/spec.mddocs/issues/cron-run-open-session-button-removal/spec.mddocs/issues/cron-scheduled-runs-not-visible/spec.mddocs/issues/cron-scheduler-heartbeat-status/spec.mddocs/issues/cron-scheduler-stop-exit-error/spec.mddocs/issues/cron-scheduler-utility-start-crash/spec.mddocs/issues/mcp-plugin-startup-nonblocking/plan.mddocs/issues/mcp-plugin-startup-nonblocking/spec.mddocs/issues/mcp-plugin-startup-nonblocking/tasks.mddocs/issues/remove-legacy-scheduled-tasks/spec.mddocs/issues/scheduled-ui-label-layout/spec.mddocs/issues/settings-save-clone-errors/plan.mddocs/issues/settings-save-clone-errors/spec.mddocs/issues/settings-save-clone-errors/tasks.mdelectron.vite.config.tspackage.jsonpnpm-workspace.yamlresources/acp-registry/registry.jsonresources/model-db/providers.jsonsrc/main/presenter/agentRuntimePresenter/dispatch.tssrc/main/presenter/agentRuntimePresenter/index.tssrc/main/presenter/agentRuntimePresenter/internalSessionEvents.tssrc/main/presenter/agentRuntimePresenter/process.tssrc/main/presenter/agentRuntimePresenter/types.tssrc/main/presenter/agentSessionPresenter/index.tssrc/main/presenter/agentSessionPresenter/sessionManager.tssrc/main/presenter/configPresenter/index.tssrc/main/presenter/cronJobs/cronExpressionService.tssrc/main/presenter/cronJobs/deliveryRouter.tssrc/main/presenter/cronJobs/index.tssrc/main/presenter/cronJobs/repository.tssrc/main/presenter/cronJobs/runExecutor.tssrc/main/presenter/cronJobs/runtimeResolver.tssrc/main/presenter/cronJobs/schedulerProcessManager.tssrc/main/presenter/cronJobs/schedulerUtilityHost.tssrc/main/presenter/index.tssrc/main/presenter/lifecyclePresenter/hooks/after-start/cronJobsStartHook.tssrc/main/presenter/lifecyclePresenter/hooks/after-start/scheduledTasksStartHook.tssrc/main/presenter/lifecyclePresenter/hooks/beforeQuit/cronJobsStopHook.tssrc/main/presenter/lifecyclePresenter/hooks/index.tssrc/main/presenter/mcpPresenter/index.tssrc/main/presenter/pluginPresenter/index.tssrc/main/presenter/remoteControlPresenter/index.tssrc/main/presenter/remoteControlPresenter/interface.tssrc/main/presenter/scheduledTasks/index.tssrc/main/presenter/scheduledTasks/normalize.tssrc/main/presenter/sqlitePresenter/databaseConnection.tssrc/main/presenter/sqlitePresenter/index.tssrc/main/presenter/sqlitePresenter/schemaCatalog.tssrc/main/presenter/sqlitePresenter/tables/cronJobDeliveries.tssrc/main/presenter/sqlitePresenter/tables/cronJobRuns.tssrc/main/presenter/sqlitePresenter/tables/cronJobs.tssrc/main/presenter/sqlitePresenter/tables/deepchatSessionMetadata.tssrc/main/presenter/toolPresenter/agentTools/agentToolManager.tssrc/main/presenter/toolPresenter/agentTools/cronJobTool.tssrc/main/presenter/toolPresenter/agentTools/index.tssrc/main/presenter/toolPresenter/index.tssrc/main/presenter/toolPresenter/runtimePorts.tssrc/main/routes/index.tssrc/main/schedulerUtilityHostEntry.tssrc/renderer/api/CronJobsClient.tssrc/renderer/api/ScheduledTasksClient.tssrc/renderer/api/index.tssrc/renderer/settings/components/CronJobsSettings.vuesrc/renderer/settings/components/DeepChatAgentsSettings.vuesrc/renderer/settings/components/ScheduledTasksSettings.vuesrc/renderer/settings/components/control-center/SettingsPageShell.vuesrc/renderer/settings/main.tssrc/renderer/src/components/WindowSideBarSessionItem.vuesrc/renderer/src/i18n/da-DK/settings.jsonsrc/renderer/src/i18n/de-DE/settings.jsonsrc/renderer/src/i18n/en-US/routes.jsonsrc/renderer/src/i18n/en-US/settings.jsonsrc/renderer/src/i18n/es-ES/settings.jsonsrc/renderer/src/i18n/fa-IR/settings.jsonsrc/renderer/src/i18n/fr-FR/settings.jsonsrc/renderer/src/i18n/he-IL/settings.jsonsrc/renderer/src/i18n/id-ID/routes.jsonsrc/renderer/src/i18n/id-ID/settings.jsonsrc/renderer/src/i18n/it-IT/settings.jsonsrc/renderer/src/i18n/ja-JP/routes.jsonsrc/renderer/src/i18n/ja-JP/settings.jsonsrc/renderer/src/i18n/ko-KR/routes.jsonsrc/renderer/src/i18n/ko-KR/settings.jsonsrc/renderer/src/i18n/ms-MY/routes.jsonsrc/renderer/src/i18n/ms-MY/settings.jsonsrc/renderer/src/i18n/pl-PL/settings.jsonsrc/renderer/src/i18n/pt-BR/settings.jsonsrc/renderer/src/i18n/ru-RU/settings.jsonsrc/renderer/src/i18n/tr-TR/routes.jsonsrc/renderer/src/i18n/tr-TR/settings.jsonsrc/renderer/src/i18n/vi-VN/settings.jsonsrc/renderer/src/i18n/zh-CN/settings.jsonsrc/renderer/src/i18n/zh-HK/settings.jsonsrc/renderer/src/i18n/zh-TW/settings.jsonsrc/renderer/src/pages/NewThreadPage.vuesrc/renderer/src/stores/ui/draft.tssrc/renderer/src/stores/ui/session.tssrc/shared/agentTools.tssrc/shared/contracts/common.tssrc/shared/contracts/routes.tssrc/shared/contracts/routes/cronJobs.routes.tssrc/shared/contracts/routes/scheduledTasks.routes.tssrc/shared/cronJobs.tssrc/shared/scheduledTasks.tssrc/shared/settingsNavigation.tssrc/shared/types/agent-interface.d.tssrc/shared/types/presenters/agent-session.presenter.d.tssrc/shared/types/presenters/core.presenter.d.tssrc/types/i18n.d.tstest/main/presenter/agentRuntimePresenter/internalSessionEvents.test.tstest/main/presenter/agentRuntimePresenter/process.test.tstest/main/presenter/agentSessionPresenter/sessionManager.test.tstest/main/presenter/cronJobs.test.tstest/main/presenter/lifecyclePresenter/cronJobsStartHook.test.tstest/main/presenter/mcpPresenter.test.tstest/main/presenter/pluginPresenter.test.tstest/main/presenter/scheduledTasks.test.tstest/main/presenter/sqlitePresenter.migrationSqlSplit.test.tstest/main/presenter/toolPresenter/toolPresenter.test.tstest/main/routes/dispatcher.test.tstest/renderer/api/cronJobsClient.test.ts
💤 Files with no reviewable changes (9)
- src/main/presenter/lifecyclePresenter/hooks/after-start/scheduledTasksStartHook.ts
- src/renderer/api/ScheduledTasksClient.ts
- src/shared/contracts/routes/scheduledTasks.routes.ts
- src/main/presenter/scheduledTasks/index.ts
- src/main/presenter/scheduledTasks/normalize.ts
- src/shared/scheduledTasks.ts
- src/renderer/settings/components/ScheduledTasksSettings.vue
- test/main/presenter/scheduledTasks.test.ts
- src/shared/types/presenters/core.presenter.d.ts
| # Cron Scheduler Utility Start Crash | ||
|
|
||
| ## Problem | ||
|
|
||
| The cron scheduler utility process can exit with code 1 immediately on startup. | ||
|
|
||
| The utility host imports `openSQLiteDatabase` from `sqlitePresenter/index.ts`. That index module owns | ||
| the full main-process SQLite presenter and pulls Electron main-process dependencies into the | ||
| scheduler utility bundle. The utility process only needs a lightweight SQLite connection helper. | ||
|
|
||
| ## Acceptance Criteria | ||
|
|
||
| - The scheduler utility host must open the database without importing the SQLite presenter index. | ||
| - Existing SQLite presenter callers must keep importing `openSQLiteDatabase` from the index module. | ||
| - The scheduler utility build output must not import Electron-only dependencies through the SQLite | ||
| presenter path. | ||
|
|
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
fd -t f . docs/issues/cron-scheduler-utility-start-crashRepository: ThinkInAIXYZ/deepchat
Length of output: 214
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== target folder =="
fd -t f . docs/issues/cron-scheduler-utility-start-crash || true
echo
echo "== target folder tree =="
find docs/issues/cron-scheduler-utility-start-crash -maxdepth 1 -type f | sort
echo
echo "== sibling issue folders =="
find docs/issues -maxdepth 2 -type f \( -name spec.md -o -name plan.md -o -name tasks.md \) | sortRepository: ThinkInAIXYZ/deepchat
Length of output: 5450
Add plan.md and tasks.md here. This bug-fix issue should include the required spec.md/plan.md/tasks.md triad under docs/issues/cron-scheduler-utility-start-crash/.
🤖 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 `@docs/issues/cron-scheduler-utility-start-crash/spec.md` around lines 1 - 17,
The cron scheduler utility startup crash is caused by the utility host importing
the SQLite presenter index, which pulls in Electron main-process dependencies.
Update the scheduler utility host to use a lightweight database connection
helper instead of importing `openSQLiteDatabase` from
`sqlitePresenter/index.ts`, while keeping existing presenter callers on the
index export. Add the missing `plan.md` and `tasks.md` alongside `spec.md` under
the cron-scheduler-utility-start-crash issue docs, and make sure the utility
build path no longer reaches Electron-only dependencies through the SQLite
presenter route.
Source: Coding guidelines
| "cronJobs": { | ||
| "title": "定時任務", | ||
| "description": "在設定的時間觸發系統通知或自動向 Agent 發送訊息。", | ||
| "hint": "App 未執行時錯過的一次性任務會在下次啟動時補發,重複任務只跳到下一個時間點。", | ||
| "newTask": "新建任務", | ||
| "empty": "暫無任務", | ||
| "namePlaceholder": "任務名稱", | ||
| "fireNow": "立即執行", | ||
| "fireNowSuccess": "任務已觸發", | ||
| "description": "管理定時 Agent 任務與排程程序。", | ||
| "empty": "暫無定時任務。", | ||
| "none": "无", | ||
| "nextRunAt": "下次运行", | ||
| "defaults": { | ||
| "name": "新任務", | ||
| "title": "提醒", | ||
| "body": "到點啦" | ||
| }, | ||
| "trigger": { | ||
| "title": "觸發時間", | ||
| "kind": "觸發方式", | ||
| "kindOnce": "一次性", | ||
| "kindDaily": "每天", | ||
| "kindWeekly": "每週", | ||
| "firesAt": "時間點", | ||
| "dayOfWeek": "星期", | ||
| "time": "時間", | ||
| "description": "選擇執行頻率和時間。" | ||
| }, | ||
| "action": { | ||
| "title": "執行動作", | ||
| "kind": "動作類型", | ||
| "kindNotify": "系統通知", | ||
| "kindPrompt": "聊天提示", | ||
| "titleField": "標題", | ||
| "titlePlaceholder": "通知標題", | ||
| "body": "通知內容", | ||
| "message": "訊息內容", | ||
| "agentId": "Agent", | ||
| "agentIdPlaceholder": "預設 deepchat", | ||
| "modelId": "模型", | ||
| "modelIdPlaceholder": "留空使用預設", | ||
| "systemPrompt": "System Prompt", | ||
| "autoSend": "自動發送到所選 Agent", | ||
| "description": "選擇通知或傳送給 Agent 的提示。" | ||
| }, | ||
| "weekday": { | ||
| "sun": "週日", | ||
| "mon": "週一", | ||
| "tue": "週二", | ||
| "wed": "週三", | ||
| "thu": "週四", | ||
| "fri": "週五", | ||
| "sat": "週六" | ||
| }, | ||
| "listTitle": "任務列表", | ||
| "listDescription": "集中管理定時觸發、執行動作和啟用狀態。", | ||
| "summary": { | ||
| "task": "{trigger} · {action}", | ||
| "once": "{time}", | ||
| "daily": "每天 {time}", | ||
| "weekly": "{day} {time}" | ||
| } | ||
| "name": "Morning cron job" | ||
| }, | ||
| "actions": { | ||
| "newJob": "新建任务", | ||
| "runNow": "立即运行", | ||
| "clearNextRun": "清空下次运行", | ||
| "reconcile": "重新对账", | ||
| "restart": "重啟定時器" | ||
| }, | ||
| "fields": { | ||
| "name": "名称", | ||
| "cronExpr": "Cron 表达式", | ||
| "timezone": "时区", | ||
| "preset": "預設", | ||
| "agent": "Agent", | ||
| "noAgent": "未選擇", | ||
| "taskPrompt": "任務內容", | ||
| "runtimePolicy": "執行配置", | ||
| "followAgent": "跟隨 Agent", | ||
| "pinCurrent": "固定目前配置", | ||
| "delivery": "傳送", | ||
| "remoteDelivery": "Remote 傳送", | ||
| "remoteChannel": "Remote 頻道", | ||
| "noRemoteChannels": "請先啟用 Remote,並綁定頻道。", | ||
| "deliverySuccess": "已傳送", | ||
| "deliveryFailed": "傳送失敗" | ||
| }, | ||
| "presets": { | ||
| "custom": "自訂", | ||
| "every5Minutes": "每 5 分鐘", | ||
| "hourly": "每小時", | ||
| "daily": "每天 09:00", | ||
| "weekdays": "工作日 09:00" | ||
| }, | ||
| "status": { | ||
| "state": "状态", | ||
| "enabled": "启用任务", | ||
| "heartbeat": "心跳", | ||
| "stopped": "已停止", | ||
| "starting": "启动中", | ||
| "running": "运行中", | ||
| "idle": "空闲", | ||
| "error": "错误", | ||
| "invalidAgent": "Agent 不存在或已停用,請重新選擇 Agent。" | ||
| }, | ||
| "runNowSuccess": "定時任務已觸發" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Mixed Simplified/Traditional Chinese characters in the zh-TW locale.
Several cronJobs strings use Simplified Chinese characters inside the Traditional-Chinese (zh-TW) file: e.g. "none": "无" (should be 無), "nextRunAt": "下次运行" (運行), actions.newJob: "新建任务" (新增任務), actions.runNow: "立即运行", actions.clearNextRun: "清空下次运行", actions.reconcile: "重新对账", fields.name: "名称" (名稱), fields.cronExpr: "Cron 表达式" (表達式), fields.timezone: "时区" (時區), and the whole status block (状态, 启用任务, 启动中, 运行中, 空闲, 错误). Other keys in the same block (preset, delivery, presets.*, restart, invalidAgent) are already correctly Traditional. This inconsistency will read as broken/typo'd text to Traditional-Chinese users.
🈶 Example fixes for a subset of mixed-script keys
- "none": "无",
- "nextRunAt": "下次运行",
+ "none": "無",
+ "nextRunAt": "下次執行",
"actions": {
- "newJob": "新建任务",
- "runNow": "立即运行",
- "clearNextRun": "清空下次运行",
- "reconcile": "重新对账",
+ "newJob": "新增任務",
+ "runNow": "立即執行",
+ "clearNextRun": "清除下次執行時間",
+ "reconcile": "重新核對",
"restart": "重啟定時器"
},
"fields": {
- "name": "名称",
- "cronExpr": "Cron 表达式",
- "timezone": "时区",
+ "name": "名稱",
+ "cronExpr": "Cron 表達式",
+ "timezone": "時區",
...
"status": {
- "state": "状态",
- "enabled": "启用任务",
+ "state": "狀態",
+ "enabled": "啟用任務",
"heartbeat": "心跳",
"stopped": "已停止",
- "starting": "启动中",
- "running": "运行中",
- "idle": "空闲",
- "error": "错误",
+ "starting": "啟動中",
+ "running": "執行中",
+ "idle": "空閒",
+ "error": "錯誤",🤖 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/src/i18n/zh-TW/settings.json` around lines 1453 - 1505, The
cronJobs translations in the zh-TW locale mix Simplified Chinese with
Traditional Chinese, so update the affected strings to full Traditional Chinese
for consistency. Fix the entries under cronJobs in settings.json, especially the
keys in fields, actions, nextRunAt, none, and status, and verify the values in
the cronJobs object match the surrounding zh-TW style while keeping
already-correct Traditional terms unchanged.
| import { beforeEach, describe, expect, it, vi } from 'vitest' | ||
|
|
||
| const presenterMocks = vi.hoisted(() => ({ | ||
| start: vi.fn(), | ||
| getRuntime: vi.fn() | ||
| })) | ||
|
|
||
| vi.mock('@/presenter', () => ({ | ||
| presenter: { | ||
| cronJobs: { | ||
| start: presenterMocks.start | ||
| } | ||
| }, | ||
| getMainKernelRouteRuntime: presenterMocks.getRuntime | ||
| })) | ||
|
|
||
| const { cronJobsStartHook } = | ||
| await import('@/presenter/lifecyclePresenter/hooks/after-start/cronJobsStartHook') | ||
|
|
||
| describe('cronJobsStartHook', () => { | ||
| beforeEach(() => { | ||
| vi.clearAllMocks() | ||
| }) | ||
|
|
||
| it('primes route runtime before starting cron jobs', async () => { | ||
| const calls: string[] = [] | ||
| presenterMocks.getRuntime.mockImplementation(() => { | ||
| calls.push('runtime') | ||
| }) | ||
| presenterMocks.start.mockImplementation(() => { | ||
| calls.push('start') | ||
| }) | ||
|
|
||
| await cronJobsStartHook.execute({} as never) | ||
|
|
||
| expect(calls).toEqual(['runtime', 'start']) | ||
| }) | ||
| }) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Test file location does not mirror the source module path.
The hook under test lives at src/main/presenter/lifecyclePresenter/hooks/after-start/cronJobsStartHook.ts, but this test is placed at test/main/presenter/lifecyclePresenter/cronJobsStartHook.test.ts, dropping the hooks/after-start segment.
As per coding guidelines, "Place Vitest main-process tests under test/main/ to mirror source structure."
📁 Suggested relocation
-test/main/presenter/lifecyclePresenter/cronJobsStartHook.test.ts
+test/main/presenter/lifecyclePresenter/hooks/after-start/cronJobsStartHook.test.ts🤖 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 `@test/main/presenter/lifecyclePresenter/cronJobsStartHook.test.ts` around
lines 1 - 38, The test location does not mirror the source module path for
cronJobsStartHook, so move this Vitest file to match the source structure under
test/main/presenter/lifecyclePresenter/hooks/after-start and keep the existing
cronJobsStartHook import and assertions unchanged. This should align the test
path with the hook’s module path while preserving the current mocks and
execute() coverage.
Source: Coding guidelines
CronJobs i18n Translation Review Summary总览对PR #1874中所有19种语言的cronJobs功能翻译进行了全面review。 关键发现🚨 所有19种语言都存在翻译问题 主要问题类型:
语言质量评分🟢 Good (1种语言)
🟡 Needs Improvement (18种语言)所有其他语言都需要改进,主要是大量未翻译内容 问题严重程度统计
典型问题示例1. 完全未翻译(最常见)英文原文: "New job" 正确翻译应为:
2. 部分翻译 + 英文混杂法语示例: "Livraison Remote"
西班牙语示例: "Entrega Remote"
3. 机器翻译痕迹日语问题:
通用问题模式未翻译的关键UI元素:
建议的修复方案方案1: 自动批量修复(推荐)创建一个脚本,基于workflow的建议翻译批量更新所有语言文件。 优点:
缺点:
方案2: 逐语言人工审核为每种语言找native speaker进行翻译。 优点:
缺点:
方案3: 混合方案(建议采用)
优先级建议P0 - 立即修复修复所有Critical级别的问题(UI按钮、表单标签):
P1 - 本次PR合并前修复所有Major级别问题(状态文本、预设选项):
P2 - 后续优化
技术实现细节完整的翻译数据已保存
自动修复脚本示例可以创建一个脚本批量应用所有建议翻译: import { readFileSync, writeFileSync } from 'fs'
// 从workflow结果读取
const results = JSON.parse(readFileSync('workflow_results.json', 'utf8'))
for (const langResult of results.results) {
const langCode = getLangCode(langResult.language)
const filePath = `src/renderer/src/i18n/${langCode}/settings.json`
const settings = JSON.parse(readFileSync(filePath, 'utf8'))
// 应用所有建议翻译
for (const issue of langResult.issues) {
if (issue.severity === 'critical' || issue.severity === 'major') {
setNestedValue(settings, issue.key, issue.suggestedTranslation)
}
}
writeFileSync(filePath, JSON.stringify(settings, null, 2))
}建议的下一步操作选项A: 立即自动修复(最快)
预计时间: 1-2小时 选项B: 仅修复Critical问题
预计时间: 30分钟 选项C: 暂不修复,创建独立PR
预计时间: 需要数周 推荐方案采用选项A: 使用workflow的建议翻译立即修复 理由:
|
Fixed 526 translation issues across 19 languages identified by automated native-speaker style review: - Critical: 80 issues (UI buttons, form labels) - Major: 446 issues (status text, presets, field labels) - Minor issues left for future optimization Languages updated: - da-DK, de-DE, es-ES, fa-IR, fr-FR, he-IL, id-ID - it-IT, ja-JP, ko-KR, ms-MY, pl-PL, pt-BR - ru-RU, tr-TR, vi-VN, zh-CN, zh-HK, zh-TW All translations reviewed for: - Natural native speaker phrasing - Consistent technical terminology - Appropriate UI context - Cultural appropriateness See PR comment for detailed review results.
✅ i18n翻译问题已修复刚刚完成了所有cronJobs功能的国际化翻译修复! 修复统计
修复方法
修复内容所有关键UI元素现已翻译完整:
提交
所有更改已推送到此PR分支。i18n问题已解决,PR可以继续review其他方面。🎉 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/renderer/src/i18n/pl-PL/settings.json (1)
2791-2791: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMinor:
runtimePolicytranslated as "environment" rather than "policy"."Środowisko wykonawcze" reads as "runtime environment"; consider "Zasady środowiska wykonawczego" or similar if the field is meant to convey a policy/rule rather than the environment itself.
🤖 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/src/i18n/pl-PL/settings.json` at line 2791, The pl-PL translation for runtimePolicy is using “Środowisko wykonawcze,” which reads as the runtime environment rather than a policy setting. Update the runtimePolicy string in the settings JSON to a Polish phrase that reflects “policy/rules” for the runtime context, such as “Zasady środowiska wykonawczego,” and keep the key aligned with its meaning in the surrounding i18n entries.
🤖 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.
Nitpick comments:
In `@src/renderer/src/i18n/pl-PL/settings.json`:
- Line 2791: The pl-PL translation for runtimePolicy is using “Środowisko
wykonawcze,” which reads as the runtime environment rather than a policy
setting. Update the runtimePolicy string in the settings JSON to a Polish phrase
that reflects “policy/rules” for the runtime context, such as “Zasady środowiska
wykonawczego,” and keep the key aligned with its meaning in the surrounding i18n
entries.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: cf3acceb-e0aa-4bd2-b2da-0e01465fc967
📒 Files selected for processing (19)
src/renderer/src/i18n/da-DK/settings.jsonsrc/renderer/src/i18n/de-DE/settings.jsonsrc/renderer/src/i18n/es-ES/settings.jsonsrc/renderer/src/i18n/fa-IR/settings.jsonsrc/renderer/src/i18n/fr-FR/settings.jsonsrc/renderer/src/i18n/he-IL/settings.jsonsrc/renderer/src/i18n/id-ID/settings.jsonsrc/renderer/src/i18n/it-IT/settings.jsonsrc/renderer/src/i18n/ja-JP/settings.jsonsrc/renderer/src/i18n/ko-KR/settings.jsonsrc/renderer/src/i18n/ms-MY/settings.jsonsrc/renderer/src/i18n/pl-PL/settings.jsonsrc/renderer/src/i18n/pt-BR/settings.jsonsrc/renderer/src/i18n/ru-RU/settings.jsonsrc/renderer/src/i18n/tr-TR/settings.jsonsrc/renderer/src/i18n/vi-VN/settings.jsonsrc/renderer/src/i18n/zh-CN/settings.jsonsrc/renderer/src/i18n/zh-HK/settings.jsonsrc/renderer/src/i18n/zh-TW/settings.json
✅ Files skipped from review due to trivial changes (1)
- src/renderer/src/i18n/tr-TR/settings.json
🚧 Files skipped from review as they are similar to previous changes (16)
- src/renderer/src/i18n/zh-HK/settings.json
- src/renderer/src/i18n/pt-BR/settings.json
- src/renderer/src/i18n/de-DE/settings.json
- src/renderer/src/i18n/fa-IR/settings.json
- src/renderer/src/i18n/it-IT/settings.json
- src/renderer/src/i18n/es-ES/settings.json
- src/renderer/src/i18n/he-IL/settings.json
- src/renderer/src/i18n/ja-JP/settings.json
- src/renderer/src/i18n/ko-KR/settings.json
- src/renderer/src/i18n/da-DK/settings.json
- src/renderer/src/i18n/zh-CN/settings.json
- src/renderer/src/i18n/id-ID/settings.json
- src/renderer/src/i18n/zh-TW/settings.json
- src/renderer/src/i18n/ru-RU/settings.json
- src/renderer/src/i18n/vi-VN/settings.json
- src/renderer/src/i18n/fr-FR/settings.json
There was a problem hiding this comment.
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/remoteControlPresenter/index.ts (1)
1314-1334: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winLocalize cron remote-delivery text.
buildCronJobDeliveryTextcomposes user-facing English strings for scheduled task delivery. Route these through the project i18n key path and add the corresponding keys before sending remote notifications. As per coding guidelines,**/*.{ts,tsx,vue}must “Use vue-i18n keys for all user-facing strings, with keys defined insrc/renderer/src/i18n.”🤖 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/remoteControlPresenter/index.ts` around lines 1314 - 1334, buildCronJobDeliveryText in remoteControlPresenter currently builds user-facing cron delivery text with hardcoded English strings, so route all of those message fragments through vue-i18n keys instead. Add the needed translation keys under src/renderer/src/i18n, then update buildCronJobDeliveryText and any related notification formatting so scheduled task status, body labels, and run metadata use localized strings before remote notifications are sent.Source: Coding 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.
Outside diff comments:
In `@src/main/presenter/remoteControlPresenter/index.ts`:
- Around line 1314-1334: buildCronJobDeliveryText in remoteControlPresenter
currently builds user-facing cron delivery text with hardcoded English strings,
so route all of those message fragments through vue-i18n keys instead. Add the
needed translation keys under src/renderer/src/i18n, then update
buildCronJobDeliveryText and any related notification formatting so scheduled
task status, body labels, and run metadata use localized strings before remote
notifications are sent.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f1b2f77b-30d7-4ecf-9539-5ae50a30bea0
📒 Files selected for processing (12)
src/main/presenter/configPresenter/index.tssrc/main/presenter/cronJobs/runExecutor.tssrc/main/presenter/cronJobs/schedulerUtilityHost.tssrc/main/presenter/remoteControlPresenter/index.tssrc/main/presenter/toolPresenter/agentTools/cronJobTool.tssrc/renderer/settings/components/CronJobsSettings.vuesrc/renderer/src/i18n/pl-PL/settings.jsonsrc/renderer/src/i18n/zh-TW/settings.jsontest/main/presenter/configPresenter/deprecatedProviderCleanup.test.tstest/main/presenter/cronJobs.test.tstest/main/presenter/lifecyclePresenter/hooks/after-start/cronJobsStartHook.test.tstest/main/presenter/pluginPresenter.test.ts
💤 Files with no reviewable changes (1)
- test/main/presenter/lifecyclePresenter/hooks/after-start/cronJobsStartHook.test.ts
🚧 Files skipped from review as they are similar to previous changes (7)
- src/renderer/src/i18n/zh-TW/settings.json
- src/renderer/src/i18n/pl-PL/settings.json
- test/main/presenter/cronJobs.test.ts
- src/main/presenter/cronJobs/runExecutor.ts
- src/main/presenter/cronJobs/schedulerUtilityHost.ts
- src/main/presenter/toolPresenter/agentTools/cronJobTool.ts
- src/renderer/settings/components/CronJobsSettings.vue
Summary
Validation
Summary by CodeRabbit
New Features
UI Updates