- notescraft-lint (rules, safe fixes, learned style) and notescraft-blocks (block model and edits); engine lint.* and block.* commands with CLI and MCP parity - Lint tab, underlines, slash menu with preview in Source and Visual, block grip and menu, Settings > Editor and lint, Vim block keys - Visual view: tables, note embeds, %% comments, wrapping property chips - Vault knowledge (Related tab, assistant sources, Settings) and calendar plugin - Sidebar top padding fixed, dot grid follows PaperCraft spacing, right-card tabs no longer cover the collapse button Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
9.1 KiB
Tasks: Calendar plugin redesign
Rules: each task is independently testable. No task depends on work in an unfinished task. Order = execution order.
Each task is large; /implement splits it into single-file subtasks. Tag [H] = mechanical parts may go to Haiku 5.5 subagents, [M] = main model only. Every task ends with cargo test -p, clippy -D warnings, cargo fmt; every phase end runs cargo xtask ci.
-
1. Scaffold the
notescraft-calendarcrate and decide MCP naming [H] Files:crates/calendar/Cargo.toml,crates/calendar/src/{lib.rs,error.rs,model.rs,time.rs},Cargo.toml(workspace deps),xtask/src/layers.rsDone when:cargo xtask layersaccepts the crate at L3;Event,Reminder,Calendarserde round-trip in a unit test; deny-header present; MCP naming decision (calendar_*aliases inalias.rs) written intoplan.md. -
2. Event file format: parse and write frontmatter [M] Files:
crates/calendar/src/{file.rs,error.rs,lib.rs},crates/calendar/Cargo.toml,crates/calendar/tests/event_file.rsDone when: tests pass for round trip, unknown keys preserved, malformed/out-of-range dates returnErr(no panic), and a hostile-input suite (huge, nested, non-UTF-8 fields) passes. -
3. Recurrence subset: daily, weekly, monthly, yearly, interval, weekdays, until/count, exceptions [M] Files:
crates/calendar/src/recur.rs,crates/calendar/tests/recur.rsDone when: table tests cover month end, leap day, DST and zone shift; property test shows expansion is capped and every occurrence lies in the query window; "this / following / all" split produces correct series. -
4. Query layer: filter, sort, group, saved filters, conflicts, free time, year heat, week review [M] Files:
crates/calendar/src/{query.rs,free.rs,review.rs,item.rs,lib.rs},crates/calendar/tests/query.rsDone when: tests cover every filter field, every sort and group key, overlap detection and free-slot search;#[ignore]bench filters and sorts 10,000 events under 100 ms p99. -
5. Quick-add parser (English) [M] Files:
crates/calendar/src/quickadd.rs,crates/calendar/src/quickadd/clock.rs,crates/calendar/src/recur.rs(addedRule::validate),crates/calendar/tests/quickadd.rsDone when: phrases with title, date or weekday and time parse to the expected event; an unparsable part returns an error naming it; nothing partial is returned. -
6. ICS reader (read-only, in-house) [M] Files:
crates/calendar/src/ics.rs,crates/calendar/src/lib.rs,crates/calendar/src/error.rs,crates/calendar/tests/ics.rsDone when: valid fixtures import; recurrence rules outside the subset import as read-only flagged; oversize, deeply nested and malformed files returnErrwithin caps, no panic. -
7. Engine read commands:
agenda,next,free,conflicts,year,parse,review[H] Files:crates/engine/src/calendar/{mod.rs,load.rs,read.rs,tasks.rs},crates/engine/src/{commands.rs,lib.rs}(registration),crates/engine/src/vault/daily.rs(two helpers madepub(crate)),crates/engine/src/prefs/config.rs(calendar_folder),crates/engine/Cargo.toml,crates/engine/tests/calendar_commands.rs,crates/calendar/src/time.rs(day-then-clock ordering) Done when: each command returns the documented JSON from a fixture vault; the commands are listed byRegistry::list; they run on a read-only session; added to the read allow-lists inassistant_gate.rsandmcp/calls/gate.rs. -
8. Engine write commands:
add,edit,move,delete,note,bulk, saved filters, with scope handling [M] Files:crates/engine/src/calendar/{events.rs,series.rs,store.rs,bulk.rs,filters.rs}(reminders move to task 13),crates/engine/src/ai/assistant_gate.rs,crates/mcp/src/calls/gate.rs,crates/engine/tests/{calendar_write.rs,core_commands.rs}Done when: tests prove file on disk after each command; missingscopeon a repeating event fails namingthis|following|all; read-only session refuses; writes go through the atomic writer;calendar.*commands joinpanic_huntand survive all 22 hostile inputs. -
9. Expose through CLI, MCP and assistant, with parity [H] Files:
crates/mcp/src/calls/{calendar_alias.rs,alias.rs,tools.rs,gate.rs},crates/mcp/src/calls.rs,crates/engine/src/ai/assistant_gate.rs(core-plugin toggle),crates/mcp/tests/{calendar_tools.rs,aliases.rs,via_control.rs},apps/notescraft-cli/tests/calendar.rs(the CLI needed no new code:run <id> <json>reaches every command) Done when: engine,run --jsonand the MCP tool return identical JSON (tests inmcp/tests/calendar_tools.rsandnotescraft-cli/tests/calendar.rs); with thecalendarplugin toggle off no calendar tool is listed or callable; assistant write calls become pending changes (engine/tests/calendar_write.rs). The assistant list carries three calendar tools (calendar_agenda,calendar_add,calendar_edit) to keep its context small; the rest stay callable by name and throughrun_command. -
10. Calendar view shell: month, week, day, agenda, year, remembered view, truncation [M] Files:
crates/ui-egui/src/views/calendar_view/{mod.rs,month.rs,week.rs,day.rs,agenda.rs,year.rs},crates/ui-egui/src/views/center.rs,crates/ui-egui/src/panels/sidebar.rs:318-386Done when:egui_kittestrenders each view from a fixture vault; long titles end in an ellipsis with full text on hover; the chosen view survives a restart; snapshot PNGs match the PaperCraft artboards by eye; 10,000-event month render stays under 16 ms in the#[ignore]bench. -
11. Keyboard model: navigation, selection, move/resize/copy, find,
gn,gR[M] Files:crates/ui-egui/src/views/calendar_view/{keymap.rs,keymap/helpers.rs,keymap_tests.rs,mod.rs,paint.rs},crates/calendar/src/item.rs(repeats),crates/ui-egui/src/shell/app/window/frame.rsDone when: a test drives every key in the spec (t h j k l H L [ ] gd gm gw gD gy ga v V x o O e dd yy p . z / f s c gn gR) and checks the effect; a uniqueness test finds no duplicate binding; editor keys are untouched when the Calendar lacks focus. -
12. Quick add, filter and sort popover, bulk bar, saved filters UI, i18n [H] Files:
crates/ui-egui/src/views/calendar_view/{prompt.rs,filters.rs,review.rs,agenda.rs,mod.rs,paint.rs}(quick add, go to, find, bulk bar, filter popover, saved filters, week review),crates/engine/src/calendar/{mod.rs,filters.rs}(saved_filters),crates/i18n/locales/en.toml,crates/ui-egui/src/views/settings_view/categories.rs(calendar folder row) Done when: kittest flows pass (type phrase, see preview, Escape saves nothing; filter, sort, group, save, reload); bulk bar shows affected count before confirm;cargo xtask i18nreports no hardcoded strings. -
13. Reminders: scheduler, inbox, snooze, quiet hours, missed on start [M] Files:
crates/calendar/src/remind.rs,crates/engine/src/calendar/{reminders.rs,clock.rs},crates/engine/src/prefs/{reminders_config.rs,config.rs},crates/ui-egui/src/views/calendar_view/inbox.rs,crates/ui-egui/src/shell/app.rs(30 s reminder tick), testscrates/calendar/tests/remind.rs,crates/engine/tests/calendar_reminders.rsDone when: tests with an injected clock fire once, snooze, respect quiet hours and list missed reminders on start without re-notifying; the notifier is a trait (no OS crate yet) with a test double. -
14. ICS feeds and cached offline events (sync crate, no network crate yet) [M] Files:
crates/calendar/src/sync.rs(a module of the calendar crate: a separate L3 crate could not be used by the L4 engine and also usecalendar),crates/engine/src/calendar/{feeds.rs,load.rs},crates/ui-egui/src/shell/{feed_sync.rs,app.rs}, testscrates/calendar/tests/sync.rs,crates/engine/tests/calendar_feeds.rsDone when: a local fixture feed refreshes on an injected clock into the cache viawrite_private; offline start shows cached events with an offline flag; the sync log holds no tokens or event bodies (canary test); fetching sits behind a trait so no HTTP crate is needed. -
15. Network, keychain, notifications and Google view-only without new crates, then docs [M] Files:
crates/calendar/src/feed/google.rs(pure),apps/notescraft/src/{net,notify,keychain,google,desktop}.rs(curl,osascript/notify-send,security/secret-tool, loopback sign-in; no new crate, so no approval was needed),crates/ui-egui/src/shell/app/{services.rs,feed_sync.rs},crates/ui-egui/src/views/settings_view/categories/calendar.rs,ROADMAP.md,docs/ARCHITECTURE.md,SPEC.mditem 26 Done when: no crate was added, so nothing needed approval; Google sign-in lists calendars and loads events view-only (tested against scripted HTTP, an in-memory keychain and a pretend browser; not against live Google, which needs a client id); an edit on an imported event is refused; the Google token is only in the keychain and errors, statuses and logs never carry addresses or tokens (canary tests); a system notification fires throughosascript(run once by hand: exit 0); ROADMAP, ARCHITECTURE and SPEC 26 reflect the real command list;cargo xtask ciis green.