Skip to content

feat: add focus duplication and Windows startup polish#66

Merged
archae0pteryx merged 2 commits into
mainfrom
feat/agents-integration
May 20, 2026
Merged

feat: add focus duplication and Windows startup polish#66
archae0pteryx merged 2 commits into
mainfrom
feat/agents-integration

Conversation

@archae0pteryx

@archae0pteryx archae0pteryx commented May 20, 2026

Copy link
Copy Markdown
Contributor

Summary

  • preserve this agents-integration branch work and add first-launch example focus
  • fix timer dropdown commits on Enter/click-away and add duplicate focus support
  • add cross-platform icon assets from the back-facing pig, including Windows icon.ico, and use a Windows-safe data root

Verification

  • rtk task check
  • rtk cargo test -p adhd-ranch-commands duplicate_focus --all-targets
  • rtk npm run test -- AnimalDetail.test.tsx focusWriter.test.ts
  • rtk npm run test -- TimerDropdown.test.tsx

Notes

  • Windows-target cargo check now gets past the missing icon.ico blocker, but local macOS cross-check is blocked by missing llvm-rc in tauri-winres. Needs a Windows runner or LLVM resource compiler for full Windows validation.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added per-task timers: Set countdowns on individual tasks with preset options
    • Clock/time controls now appear on Focus titles and tasks for quick timer management
    • Focus duplication: Copy existing focuses with all tasks preserved
    • Enhanced animal detail card with consolidated timer controls
    • Example focus automatically created on first launch
  • Bug Fixes

    • Expired timers now display with ghostly transparency instead of red tint
    • Expired animals revive when new tasks are added to the focus
  • Documentation

    • Updated specs documenting task timer persistence and UI interactions

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 20, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR introduces task-level optional timers persisted to per-focus task-timers.json sidecars, replaces the PigDetail popover with a full AnimalDetail card modal, adds a reusable TimerDropdown component for timer control via presets or custom minutes, and extends the backend command/Tauri/TypeScript API stack to support focus duplication and timer lifecycle operations.

Changes

Task Timers and AnimalDetail Implementation

Layer / File(s) Summary
Task timer domain model and persistence schema
crates/domain/src/focus.rs, crates/storage/src/focus_store.rs, crates/commands/src/caps.rs, crates/domain/src/caps.rs, crates/domain/src/parse.rs
Task struct gains optional timer: Option<FocusTimer> field with Serde defaults. FocusStore trait adds clear_timer, update_task_timer, clear_task_timer methods. MarkdownFocusStore implements task-timer persistence via task-timers.json sidecar (array aligned to task order), with index-aware read/write helpers and cleanup on append/delete.
Backend command APIs for timer operations
crates/commands/src/focus.rs
Commands gains duplicate_focus (with slug-based title de-duplication and task cloning), clear_timer, start_task_timer, and clear_task_timer methods. Tests cover focus cloning, timer clearing, and task timer starting on correct indices.
Tauri command wiring and IPC exposure
src-tauri/src/app/mod.rs, src-tauri/src/ui_bridge/mod.rs
Tauri commands registered for duplicate_focus, clear_timer, start_task_timer, clear_task_timer with logging and error forwarding. App initialization calls seed::ensure_example_focus to create example on first run.
TypeScript API bindings and fixtures
src/api/focusWriter.ts, src/api/focusWriter.test.ts, src/api/tauriFocusReader.ts, src/api/tauriFocusReader.test.ts, src/api/fixtureFocusWriter.ts
FocusWriter interface adds new timer/duplicate methods wired to Tauri commands via createTauriFocusWriter. tauriFocusReader maps timer field from Rust payloads. Fixture and test implementations extended to cover new methods and IPC payloads.
TimerDropdown component and timer formatting
src/components/TimerDropdown.tsx, src/components/TimerDropdown.test.tsx
New TimerDropdown React component for timer preset selection with custom-minute input, validation (≥1 min), and auto-start on Enter/outside-click/blur. Exports formatTimer helper for MM:SS display or "Expired" status. Tests cover preset commit, custom input, and focus-within behavior.
AnimalDetail card replacing PigDetail with timer controls
src/components/AnimalDetail.tsx, src/components/AnimalDetail.test.tsx
Replaces PigDetail with AnimalDetail modal using animalX/animalY positioning. Adds focus-level TimerDropdown and duplicate/delete controls; passes task-timer callbacks to per-task TimerDropdown instances. All classnames and test IDs renamed from pig-detail-* to animal-detail-*. Test suite updated for new props/callback surface.
App-level integration with new control flow and state management
src/components/App.tsx, src/components/App.test.tsx, src/hooks/useFocusController.ts, src/hooks/useOpenFocusDetailRequest.ts
Centralizes write-path via new useFocusController hook. Adds useOpenFocusDetailRequest subscription for detail card selection. Implements optimistic task-addition overlay. Swaps detail component from PigDetail to AnimalDetail with updated props and callbacks. Tests extended with fixture updates and task-append assertions.
Expired focus handling in movement and styling
src/hooks/usePigMovement.ts, src/hooks/usePigMovement.test.ts, src/components/PigSprite.tsx, src/components/App.test.tsx
usePigMovement adds isExpiredFocus/restExpiredAnimal helpers to stop velocity and force "back" direction for expired focuses; precomputes expired focus IDs each frame. PigSprite updates expired filter from single hue-rotate to conditional multi-part filter (grayscale/saturation/brightness/drop-shadow) plus opacity: 0.48. Tests cover expired timer transitions.
Path resolution, seeding, and documentation updates
src-tauri/src/app/paths.rs, src-tauri/src/app/seed.rs, src-tauri/src/app/tray.rs, src-tauri/Cargo.toml, CHANGELOG.md, CONTEXT.md, PRD.md, README.md, issues/051-ranch-animal-vocabulary-seam.md, issues/053-task-timer-expiry-workflow.md, issues/README.md, issues/done/030-pig-growth-expired-visual-tray-list.md, issues/done/052-task-timers-and-clock-dropdown-editing.md
data_root() refactored to support ADHD_RANCH_HOME override and platform-specific defaults. ensure_example_focus seeding function with marker-based idempotency. Tray focus partitioning updated to unified list+expired. Dependencies added for log and tempfile. All documentation updated to reflect task-timer features, AnimalDetail surface, and storage layout changes.
CSS updates for animal detail and timer dropdown UI
src/styles.css
Renames pig-detail-* to animal-detail-* across all selectors (backdrop, container, title, actions, delete, tasks). Adds comprehensive timer-dropdown styling (trigger, menu, controls, states) and per-task TimerDropdown layout. Defines animal-detail-task row structure and done-state styling. Updates animal-detail-add-task and animal-detail-timer appearance.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • killallgit/adhd-ranch#61: Builds on this PR's task-timer persistence (task-timers.json, update_task_timer store methods) to implement the background task-timer expiry workflow and task_timer_expired notifications.
  • killallgit/adhd-ranch#59: Overlaps with this PR's expired-Focus visuals and tray behavior by updating PigSprite expired styling and expired focus rendering in the tray menu.
  • killallgit/adhd-ranch#55: Related foundation for timer presets and start-timer wiring; this PR extends those patterns to both focus and per-task timers via the new TimerDropdown component.

Poem

🐰 Hop! The timers bloom on every task,
AnimalDetail's dancing at last,
TimerDropdown counts down with grace,
Pet your pigs in their detail-card space! 🎪

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 32.23% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately summarizes the main changes: focus duplication feature and Windows startup improvements (example focus on first launch). Both are prominent in the changeset and reflect the core commits.

✏️ 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/agents-integration

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 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 `@CHANGELOG.md`:
- Line 9: Update the changelog entry that currently reads "### Added — 052 task
timers and clock dropdown editing (PR `#60`, in flight)" to reference the correct
pull request number `#66`; locate the exact header line text "### Added — 052 task
timers and clock dropdown editing (PR `#60`, in flight)" and replace "PR `#60`" with
"PR `#66`" so it reads "PR `#66`, in flight".

In `@crates/storage/src/focus_store.rs`:
- Around line 232-236: The current delete_task flow mutates focus.md then logs
and continues if remove_task_timer_index(focus_id, index) fails, which can leave
timer indices inconsistent; instead propagate/return the error from
remove_task_timer_index (or perform a compensating rewrite) so the delete_task
operation fails when index cleanup fails. Update the delete_task implementation
to stop treating remove_task_timer_index errors as non-fatal: replace the
log::warn branch with error propagation (e.g., using ? or mapping the error into
delete_task's Error type) or implement an explicit rollback of the focus.md
change before returning the error; ensure references to remove_task_timer_index,
delete_task and focus.md are used to locate the change.

In `@issues/done/052-task-timers-and-clock-dropdown-editing.md`:
- Line 13: The Task type documentation incorrectly documents the timer field as
required; update the description and type notation for Task.timer to indicate
optionality (e.g., change `timer: FocusTimer` to `timer: Option<FocusTimer>` or
the phrase “optional timer field”) so it matches the actual optional behavior;
locate references to Task and FocusTimer in the docs and examples and change
them to the optional form and any explanatory text that assumes the timer is
always present.

In `@src/api/tauriFocusReader.ts`:
- Line 12: The task deserialization in tauriFocusReader drops each task's timer
so task-level FocusTimer objects don't round-trip; update the tasks mapping that
builds Task objects to include the timer property (preserving nullability) by
converting the incoming Rust timer payload into a FocusTimer (or null) and
assigning it to each task.timer; locate the task-deserialization code in
tauriFocusReader (the place that maps/creates tasks from the payload) and wire
the conversion logic (reuse any existing FocusTimer parsing helper or add one)
so timer is not omitted.

In `@src/components/TimerDropdown.tsx`:
- Around line 32-52: The outside-click flow currently calls start() from both
handlePointerDown (capture) and the onBlur handler, causing duplicate commits;
modify the logic so only one path calls start: in handlePointerDown (the capture
listener) set a short-lived flag (e.g., ignoreBlurRef or pointerTriggeredRef)
when you call start(), and in the onBlur handler check that flag and skip
calling start if it's set (clear the flag after a tick or when handling the
blur), or alternatively remove the onBlur start() and rely solely on
handlePointerDown; update references to handlePointerDown, onBlur, start,
rootRef and open accordingly so the outside-click triggers start exactly once.

In `@src/hooks/useFocusController.ts`:
- Around line 30-34: run currently awaits write() without handling rejections so
onWriteFailure(op, outcome) is skipped on error; wrap the write() call in a
try/catch inside run(op: string, write: () => Promise<WriteOutcome>) so that if
write() throws you construct an appropriate failure WriteOutcome (or otherwise
capture the error), call onWriteFailure(op, failureOutcome) and then rethrow the
original error (or return the failure outcome if function callers expect a
resolved WriteOutcome), ensuring onWriteFailure is always invoked for both
resolved-failure and rejected paths.

In `@src/hooks/usePigMovement.ts`:
- Around line 312-314: The Set of expired focus IDs (expiredFocusIds) is being
rebuilt each rAF tick in usePigMovement, causing unnecessary allocations; move
the construction so it runs once whenever focuses changes (e.g., create
expiredFocusIds in an effect or useMemo/useRef updated on focuses) and have the
per-frame tick read that precomputed Set instead of reconstructing it; update
references in the tick callback (the per-frame handler) to use the new
precomputed expiredFocusIds so the hot path avoids iterating/filling the Set
each frame.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1e652c8a-9f98-4b24-b4cf-c15af9f71498

📥 Commits

Reviewing files that changed from the base of the PR and between b8a67c2 and 0cf4201.

⛔ Files ignored due to path filters (7)
  • Cargo.lock is excluded by !**/*.lock
  • src-tauri/icons/128x128.png is excluded by !**/*.png
  • src-tauri/icons/128x128@2x.png is excluded by !**/*.png
  • src-tauri/icons/32x32.png is excluded by !**/*.png
  • src-tauri/icons/icon.ico is excluded by !**/*.ico
  • src-tauri/icons/icon.png is excluded by !**/*.png
  • src/types/generated/Task.ts is excluded by !**/generated/**
📒 Files selected for processing (41)
  • CHANGELOG.md
  • CONTEXT.md
  • PRD.md
  • README.md
  • crates/commands/src/caps.rs
  • crates/commands/src/focus.rs
  • crates/domain/src/caps.rs
  • crates/domain/src/focus.rs
  • crates/domain/src/parse.rs
  • crates/storage/Cargo.toml
  • crates/storage/src/focus_store.rs
  • issues/051-ranch-animal-vocabulary-seam.md
  • issues/053-task-timer-expiry-workflow.md
  • issues/README.md
  • issues/done/030-pig-growth-expired-visual-tray-list.md
  • issues/done/052-task-timers-and-clock-dropdown-editing.md
  • src-tauri/Cargo.toml
  • src-tauri/icons/icon.icns
  • src-tauri/src/app/mod.rs
  • src-tauri/src/app/paths.rs
  • src-tauri/src/app/seed.rs
  • src-tauri/src/app/tray.rs
  • src-tauri/src/ui_bridge/mod.rs
  • src/api/fixtureFocusWriter.ts
  • src/api/focusWriter.test.ts
  • src/api/focusWriter.ts
  • src/api/tauriFocusReader.test.ts
  • src/api/tauriFocusReader.ts
  • src/components/AnimalDetail.test.tsx
  • src/components/AnimalDetail.tsx
  • src/components/App.test.tsx
  • src/components/App.tsx
  • src/components/PigSprite.tsx
  • src/components/TimerDropdown.test.tsx
  • src/components/TimerDropdown.tsx
  • src/hooks/useAppState.test.tsx
  • src/hooks/useFocusController.ts
  • src/hooks/useOpenFocusDetailRequest.ts
  • src/hooks/usePigMovement.test.ts
  • src/hooks/usePigMovement.ts
  • src/styles.css

Comment thread CHANGELOG.md
Comment thread crates/storage/src/focus_store.rs Outdated
Comment thread issues/done/052-task-timers-and-clock-dropdown-editing.md Outdated
Comment thread src/api/tauriFocusReader.ts
Comment thread src/components/TimerDropdown.tsx
Comment thread src/hooks/useFocusController.ts
Comment thread src/hooks/usePigMovement.ts Outdated
@archae0pteryx archae0pteryx force-pushed the feat/agents-integration branch from 0cf4201 to 8d9f230 Compare May 20, 2026 21:05
@archae0pteryx archae0pteryx changed the title feat: agents integration polish feat: add focus duplication and Windows startup polish May 20, 2026
@archae0pteryx archae0pteryx merged commit 9a7552c into main May 20, 2026
4 checks passed
@archae0pteryx archae0pteryx deleted the feat/agents-integration branch May 20, 2026 21:21
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.

1 participant