Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 39 additions & 10 deletions .agents/skills/migrate-to-sqlite/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,68 @@ description: Migrate a TinyBase table to SQLite. Use when asked to move a data d
Keep up to date as each PR lands. Outer box = fully done across both
phases. Sub-bullets track sub-states where relevant.

Phase 0 is essentially complete — every non-entrypoint consumer of the
main TinyBase store's `UI.*` surface goes through `~/<domain>/hooks*`.
`apps/desktop/src/main.tsx` (the app entry wiring up the
`TinyBaseProvider`) is the only consumer that still touches `UI.*`
directly.

Non-UI imperative helpers (`store/sessions`, `store/save`,
`store/deleteSession`, `store/importer`, `store/settings`, `persister/*`)
are still imported directly from a handful of consumer files. These are
outside phase-0 scope — phase 0 targets reactive UI access only — and
the `hypr/no-raw-tinybase` rule permits them.

- [x] `templates` — already Drizzle, no Phase 0 needed
- [ ] `calendars`
- [x] Phase 0 reads (PR 2: `useCalendar`, `useEnabledCalendars`)
- [ ] Phase 0 writes — `services/calendar/ctx.ts` has a cross-domain
calendars+events transaction; lands with events PR
- [x] Phase 0 — `calendar/hooks.ts`
- [ ] Phase 1 — Rust migration + ops exist
- [ ] `events`
- [ ] Phase 0
- [x] Phase 0 — `calendar/hooks.ts` + `services/calendar/*` (sync via `ctx.store`)
- [ ] Phase 1 — Rust migration + ops exist
- [ ] `sessions`
- [x] Phase 0 — `session/hooks/storage.ts` used by session UI, STT, sidebar, main2/home, editor, services
- [ ] Phase 1
- [ ] `transcripts`
- [x] Phase 0 — `session/hooks/storage.ts` + STT hooks
- [ ] Phase 1
- [ ] `humans`
- [x] Phase 0 — `contacts/hooks.ts`
- [ ] Phase 1
- [ ] `organizations`
- [x] Phase 0 — `contacts/hooks.ts`
- [ ] Phase 1
- [ ] `enhanced_notes`
- [x] Phase 0 reads — `session/hooks/useEnhancedNotes.ts`
- [ ] Phase 0 writes
- [x] Phase 0 — `session/hooks/useEnhancedNotes.ts` + `session/hooks/storage.ts`
- [ ] Phase 1
- [ ] `mapping_session_participant`
- [x] Phase 0 — `session/hooks/storage.ts` (reads + writes)
- [ ] Phase 1
- [ ] `mapping_tag_session`
- [x] Phase 0 — `session/hooks/storage.ts`
- [ ] Phase 1
- [ ] `mapping_mention`
- [ ] `tags`
- [x] Phase 0 — `session/hooks/storage.ts`
- [ ] Phase 1
- [ ] `chat_groups`
- [x] Phase 0 — `chat/hooks/chat-groups.ts`
- [ ] Phase 1
- [ ] `chat_messages`
- [x] Phase 0 writes (partial) — `chat/store/*`
- [ ] Phase 0 reads
- [x] Phase 0 — `chat/hooks/*`
- [ ] Phase 1
- [ ] `chat_shortcuts`
- [x] Phase 0 — `chat_shortcuts/hooks.ts`
- [ ] Phase 1
- [ ] `tasks`
- [x] Phase 0 — `tasks/hooks.tsx`
- [ ] Phase 1
- [ ] `memories`
- [x] Phase 0 writes — `settings/memory/custom-vocabulary.tsx`
- [ ] Phase 0 reads
- [x] Phase 0 — `settings/memory/hooks.ts`
- [ ] Phase 1
- [ ] `daily_notes`
- [x] Phase 0 — `session/hooks/storage.ts` (`useUpdateDailyNoteContent`) + `main2/home/note-editor.tsx` uses it
- [ ] Phase 1

## Strategy

Expand Down
55 changes: 27 additions & 28 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@
{
"files": [
"apps/desktop/src/store/tinybase/**",
"apps/desktop/src/**/hooks/**",
"apps/desktop/src/**/hooks.ts",
"apps/desktop/src/**/hooks.tsx",
"apps/desktop/src/**/*.test.ts",
"apps/desktop/src/**/*.test.tsx",
"apps/desktop/src/**/*.spec.ts",
Expand All @@ -38,35 +35,37 @@
},
{
"files": [
"apps/desktop/src/ai/**",
"apps/desktop/src/auth/**",
"apps/desktop/src/calendar/**",
"apps/desktop/src/chat/**",
Comment thread
cursor[bot] marked this conversation as resolved.
"apps/desktop/src/chat_shortcuts/**",
"apps/desktop/src/composer/**",
"apps/desktop/src/contacts/**",
"apps/desktop/src/edit/**",
"apps/desktop/src/editor/**",
"apps/desktop/src/folders/**",
"apps/desktop/src/main.tsx",
"apps/desktop/src/main/**",
"apps/desktop/src/main2/**",
"apps/desktop/src/onboarding/**",
"apps/desktop/src/search/**",
"apps/desktop/src/services/**",
"apps/desktop/src/session/**",
"apps/desktop/src/settings/**",
"apps/desktop/src/shared/**",
"apps/desktop/src/sidebar/**",
"apps/desktop/src/store/zustand/**",
"apps/desktop/src/stt/**",
"apps/desktop/src/templates/template-body.tsx",
"apps/desktop/src/templates/template-form.tsx",
"apps/desktop/src/templates/utils.ts"
"apps/desktop/src/session/hooks/storage.ts",
"apps/desktop/src/session/hooks/internal.ts",
"apps/desktop/src/session/hooks/queries.ts",
"apps/desktop/src/session/hooks/sessions.ts",
"apps/desktop/src/session/hooks/participants.ts",
"apps/desktop/src/session/hooks/tags.ts",
"apps/desktop/src/session/hooks/search.ts",
"apps/desktop/src/session/hooks/transcripts.ts",
"apps/desktop/src/session/hooks/runtime.ts",
"apps/desktop/src/session/hooks/enhanced-notes.ts",
"apps/desktop/src/session/hooks/useEnhancedNotes.ts",
"apps/desktop/src/calendar/hooks.ts",
"apps/desktop/src/contacts/hooks.ts",
"apps/desktop/src/chat_shortcuts/hooks.ts",
"apps/desktop/src/chat/hooks/useCreateChatMessage.ts",
"apps/desktop/src/chat/hooks/use-chat-actions.ts",
"apps/desktop/src/chat/hooks/persisted-messages.ts",
"apps/desktop/src/chat/hooks/chat-messages.ts",
"apps/desktop/src/chat/hooks/chat-groups.ts",
"apps/desktop/src/settings/memory/hooks.ts",
"apps/desktop/src/tasks/hooks.tsx"
],
"rules": {
"hypr/no-raw-tinybase": "off"
}
},
{
"files": ["apps/desktop/src/main.tsx"],
"rules": {
"hypr/no-raw-tinybase": "off"
}
}
]
}
23 changes: 11 additions & 12 deletions apps/desktop/src/calendar/components/apple/calendar-selection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ import {
type CalendarItem,
CalendarSelection,
} from "~/calendar/components/calendar-selection";
import {
useCalendarsByProvider,
useSetCalendarEnabled,
} from "~/calendar/hooks";
import { useMountEffect } from "~/shared/hooks/useMountEffect";
import * as main from "~/store/tinybase/store/main";

const SUBSCRIBED_SOURCE_NAME = "Subscribed Calendars";

Expand Down Expand Up @@ -43,23 +46,19 @@ export function useAppleCalendarSelection() {
const { cancelDebouncedSync, status, scheduleDebouncedSync, scheduleSync } =
useSync();

const store = main.UI.useStore(main.STORE_ID);
const calendars = main.UI.useTable("calendars", main.STORE_ID);
const calendars = useCalendarsByProvider("apple");
const setCalendarEnabled = useSetCalendarEnabled();

const groups = useMemo((): CalendarGroup[] => {
const appleCalendars = Object.entries(calendars).filter(
([_, cal]) => cal.provider === "apple",
);

const grouped = new Map<string, CalendarItem[]>();
for (const [id, cal] of appleCalendars) {
for (const cal of calendars) {
const source = cal.source || "Apple Calendar";
if (!grouped.has(source)) grouped.set(source, []);
grouped.get(source)!.push({
id,
id: cal.id,
title: cal.name || "Untitled",
color: cal.color ?? "#888",
enabled: cal.enabled ?? false,
enabled: cal.enabled,
});
}

Expand All @@ -77,10 +76,10 @@ export function useAppleCalendarSelection() {

const handleToggle = useCallback(
(calendar: CalendarItem, enabled: boolean) => {
store?.setPartialRow("calendars", calendar.id, { enabled });
setCalendarEnabled(calendar.id, enabled);
scheduleDebouncedSync();
},
[store, scheduleDebouncedSync],
[setCalendarEnabled, scheduleDebouncedSync],
);

const handleRefresh = useCallback(() => {
Expand Down
52 changes: 23 additions & 29 deletions apps/desktop/src/calendar/components/event-chip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ import {
} from "@hypr/ui/components/ui/popover";
import { cn } from "@hypr/utils";

import { toTz, useCalendar, useTimezone } from "~/calendar/hooks";
import {
toTz,
useCalendar,
useEvent,
useTimelineEvent,
useTimezone,
} from "~/calendar/hooks";
import { EventDisplay } from "~/session/components/outer-header/metadata";
import { useEvent } from "~/store/tinybase/hooks";
import * as main from "~/store/tinybase/store/main";
import { getOrCreateSessionForEventId } from "~/store/tinybase/store/sessions";
import { useGetOrCreateSessionForEvent } from "~/session/hooks/runtime";
import { useTabs } from "~/store/zustand/tabs";

function useCalendarColor(calendarId: string | null): string | null {
Expand All @@ -24,24 +28,18 @@ function useCalendarColor(calendarId: string | null): string | null {

export function EventChip({ eventId }: { eventId: string }) {
const tz = useTimezone();
const event = main.UI.useResultRow(
main.QUERIES.timelineEvents,
eventId,
main.STORE_ID,
);
const calendarColor = useCalendarColor(
(event?.calendar_id as string) ?? null,
);
const event = useTimelineEvent(eventId);
const calendarColor = useCalendarColor(event?.calendarId ?? null);

if (!event || !event.title) {
return null;
}

const isAllDay = !!event.is_all_day;
const isAllDay = event.isAllDay;
const color = calendarColor ?? "#888";

const startedAt = event.started_at
? format(toTz(event.started_at as string, tz), "h:mm a")
const startedAt = event.startedAt
? format(toTz(event.startedAt, tz), "h:mm a")
: null;

return (
Expand All @@ -55,7 +53,7 @@ export function EventChip({ eventId }: { eventId: string }) {
])}
style={{ backgroundColor: color }}
>
{event.title as string}
{event.title}
</button>
) : (
<button
Expand All @@ -68,7 +66,7 @@ export function EventChip({ eventId }: { eventId: string }) {
className="w-[2.5px] shrink-0 self-stretch rounded-full"
style={{ backgroundColor: color }}
/>
<span className="truncate">{event.title as string}</span>
<span className="truncate">{event.title}</span>
{startedAt && (
<span className="ml-auto shrink-0 font-mono text-neutral-400">
{startedAt}
Expand All @@ -93,21 +91,17 @@ export function EventChip({ eventId }: { eventId: string }) {

function EventPopoverContent({ eventId }: { eventId: string }) {
const event = useEvent(eventId);
const store = main.UI.useStore(main.STORE_ID);
const openNew = useTabs((state) => state.openNew);

const eventRow = main.UI.useResultRow(
main.QUERIES.timelineEvents,
eventId,
main.STORE_ID,
);
const eventRow = useTimelineEvent(eventId);
const getOrCreateSession = useGetOrCreateSessionForEvent();

const handleOpen = useCallback(() => {
if (!store) return;
const title = (eventRow?.title as string) || "Untitled";
const sessionId = getOrCreateSessionForEventId(store, eventId, title);
openNew({ type: "sessions", id: sessionId });
}, [store, eventId, eventRow?.title, openNew]);
const title = eventRow?.title || "Untitled";
const sessionId = getOrCreateSession(eventId, title);
if (sessionId) {
openNew({ type: "sessions", id: sessionId });
}
}, [eventId, eventRow?.title, openNew, getOrCreateSession]);

if (!event) {
return null;
Expand Down
Loading
Loading