1 Commits

Author SHA1 Message Date
Han
e4c9e8e148 feat(timer): add one-shot delayed task system (/timer) (#1012)
* feat(timer): add one-shot delayed task system (/timer)

Introduces a one-shot timer feature parallel to the existing cron
(recurring) system. Users can schedule delayed tasks via chat command
(/timer add 2h check PR status), CLI (cc-connect timer add --delay 2h),
or agent system prompt.

Core changes:
- core/timer.go: TimerJob, TimerStore, TimerScheduler, ParseDelayOrTime
- core/timer_test.go: 13 unit tests covering store, scheduler, parsing
- cmd/cc-connect/timer.go: CLI subcommands (add/list/del/info)
- core/engine.go: ExecuteTimerJob, cmdTimer, renderTimerCard, shell exec
- core/api.go: /timer/add, /timer/list, /timer/info, /timer/del endpoints
- core/i18n.go: 22 MsgTimer* keys with 5-language translations
- core/hooks.go: HookEventTimerTriggered event
- core/interfaces.go: agent system prompt section for timers
- core/management.go: SetTimerScheduler wiring
- cmd/cc-connect/main.go: timer store/scheduler lifecycle

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(timer): add /timer to help card and improve usage docs

- Add /timer to /help card tools section (all 5 languages)
- Add /timer to text-based /help fallback (all 5 languages)
- Improve MsgTimerAddUsage with both relative and absolute time examples

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(timer): use local timezone for absolute time parsing

When a user specifies an absolute time without timezone (e.g. "9:00"),
it should be interpreted as local time, not UTC. Use time.ParseInLocation
with time.Local for layouts that don't include a timezone component.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(timer): clarify local timezone for absolute time

Absolute times without timezone (e.g. "2026-05-16T09:00") use the
system's local timezone, not UTC. This is now documented in:
- Agent system prompt (core/interfaces.go)
- /timer usage message (MsgTimerUsage, all 5 languages)
- /timer add usage message (MsgTimerAddUsage, all 5 languages)
- CLI --help text (cmd/cc-connect/timer.go)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(timer): use time.Until instead of Sub(time.Now()) for lint

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(timer): sync cron fixes for session_key validation and slash prompt expansion

Reference PR #973: reject empty session_key in validateTimerJob so
management API doesn't persist unrunnable timer jobs.

Reference PR #928: resolve /skill slash prompts through skill registry
in ExecuteTimerJob before constructing the agent message.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: lint - errcheck resp.Body.Close, staticcheck WriteString(fmt.Sprintf)

* fix: two more WriteString(fmt.Sprintf) → fmt.Fprintf

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 00:10:12 +08:00