Add LLM-fillable insight slot to weather-current feed items.
Prompt lives in a separate .txt file for easy iteration.
Also adds interactive CLI script (scripts/query.ts) for
querying WeatherKit with credential caching and JSON output.
Co-authored-by: Ona <no-reply@ona.com>
* feat: add TimeOfDayEnhancer post-processor
Rule-based feed post-processor that reranks items
by time period, day type, and calendar proximity.
New package: @aris/feed-enhancers
Co-authored-by: Ona <no-reply@ona.com>
* fix: clamp boost values to [-1, 1]
Additive layers can exceed the documented range.
Co-authored-by: Ona <no-reply@ona.com>
* fix: use TimeRelevance consts instead of strings
Co-authored-by: Ona <no-reply@ona.com>
---------
Co-authored-by: Ona <no-reply@ona.com>
Context keys are now tuples instead of strings, inspired by
React Query's query keys. This prevents context collisions
when multiple instances of the same source type are registered.
Sources write to structured keys like
["aris.google-calendar", "nextEvent", { account: "work" }]
and consumers can query by prefix via context.find().
Co-authored-by: Ona <no-reply@ona.com>
Rename camelCase members to PascalCase in WeatherFeedItemType
and CalendarFeedItemType to match TflFeedItemType and
CalDavFeedItemType conventions.
Co-authored-by: Ona <no-reply@ona.com>
Replace hardcoded "tfl-alert" string with a
TflFeedItemType const object, matching the pattern
used by google-calendar and weatherkit packages.
Co-authored-by: Ona <no-reply@ona.com>
Replace hardcoded "caldav-event" string with a
CalDavFeedItemType const object, matching the pattern
used by google-calendar and weatherkit packages.
Co-authored-by: Ona <no-reply@ona.com>
* feat: add boost directive to FeedEnhancement
Post-processors can now return a boost map (item ID -> score)
to promote or demote items in the feed ordering. Scores from
multiple processors are summed and clamped to [-1, 1].
Co-authored-by: Ona <no-reply@ona.com>
* fix: correct misleading sort order comments
Co-authored-by: Ona <no-reply@ona.com>
---------
Co-authored-by: Ona <no-reply@ona.com>
Post-processors now receive Context as their 2nd parameter,
allowing them to use contextual data (time, location, etc.)
when producing enhancements.
Co-authored-by: Ona <no-reply@ona.com>
* feat: add generic CalDAV calendar data source
Add @aris/source-caldav package that fetches calendar events from any
CalDAV server via tsdav + ical.js.
- Supports Basic auth and OAuth via explicit authMethod discriminant
- serverUrl provided at construction time, not hardcoded
- Optional timeZone for correct local day boundaries
- Credentials cleared from memory after client login
- Failed calendar fetches logged, not silently dropped
- Login promise cached with retry on failure
Co-authored-by: Ona <no-reply@ona.com>
* fix: deduplicate concurrent fetchEvents calls
Co-authored-by: Ona <no-reply@ona.com>
* fix: timezone-aware signals, low-priority cancelled events
- computeSignals uses startOfDay(timeZone) for 'later today' boundary
- Cancelled events get urgency 0.1, excluded from context inProgress/nextEvent
Co-authored-by: Ona <no-reply@ona.com>
---------
Co-authored-by: Ona <no-reply@ona.com>
* feat: add post-processor pipeline to FeedEngine
Add FeedPostProcessor type and FeedEnhancement interface.
Post-processors run after item collection on all update
paths (refresh, reactive context, reactive items).
Pipeline is chained — each processor sees items as modified
by the previous one. Enhancement merging handles additional
items, suppression, and grouped items. Throwing processors
are caught and recorded in FeedResult.errors.
Co-authored-by: Ona <no-reply@ona.com>
* docs: document intentional TItems cast in post-processor merge
Co-authored-by: Ona <no-reply@ona.com>
* fix: filter stale item IDs from groups after pipeline
Groups accumulated during the pipeline can reference items
that a later processor suppressed. The engine now strips
stale IDs and drops empty groups before returning.
Co-authored-by: Ona <no-reply@ona.com>
* refactor: use reduce for stale group filtering
Co-authored-by: Ona <no-reply@ona.com>
---------
Co-authored-by: Ona <no-reply@ona.com>
* feat: replace FeedItem.priority with signals
Remove priority field from FeedItem and engine-level sorting.
Add FeedItemSignals with urgency and timeRelevance fields.
Update all source packages to emit signals instead of priority.
Ranking is now the post-processing layer's responsibility.
Urgency values are unchanged from the old priority values.
Co-authored-by: Ona <no-reply@ona.com>
* fix: use TimeRelevance enum in all tests
Co-authored-by: Ona <no-reply@ona.com>
---------
Co-authored-by: Ona <no-reply@ona.com>
Replace outdated UI Registry model with server-driven
json-render + twrnc approach. Update architecture diagram,
terminology (DataSource→FeedSource, Reconciler→FeedEngine),
and design principles to match current codebase.
Add ui, slots fields to FeedItem in actions spec. Add
Spotify example with twrnc className-based ui tree.
Co-authored-by: Ona <no-reply@ona.com>
Rewrite ai-agent-ideas.md with focus on proactive,
personable assistant behaviors. Add slot-based LLM
enhancement system to architecture-draft.md.
Co-authored-by: Ona <no-reply@ona.com>
Expose the user's current feed via GET /api/feed. Returns
cached feed from engine.lastFeed(), falling back to
engine.refresh() when no cache exists.
Auth middleware is injected as a dependency to allow test
substitution via mockAuthSessionMiddleware.
Co-authored-by: Ona <no-reply@ona.com>
Add lastFeed() method that returns cached FeedResult within
a configurable TTL (default 5 min). refresh() always fetches
fresh data and updates the cache. Periodic auto-refresh via
recursive setTimeout when engine is started. Reactive updates
reset the timer to avoid redundant fetches.
Co-authored-by: Ona <no-reply@ona.com>
Replace tRPC location.update mutation with POST /api/location
using Hono route + requireSession middleware. Extract auth
types (AuthUser, AuthToken) into auth/session.ts. Inject
sessionManager via Hono context local to location handlers.
Co-authored-by: Ona <no-reply@ona.com>
Use 'Source Serif 4' (with spaces) as the Android fontFamily
to match the iOS font metadata, avoiding Platform.select.
Co-authored-by: Ona <no-reply@ona.com>
Use the object syntax with fontFamily, weight, and style
for Android. iOS uses flat paths and reads metadata from
the font files directly.
Co-authored-by: Ona <no-reply@ona.com>
Bun symlinks in node_modules don't resolve on EAS builds.
Copy font files to assets/fonts/ and reference them directly.
Co-authored-by: Ona <no-reply@ona.com>
- Expo SDK 54 / React Native 0.81 with expo-router
- Tailscale devcontainer feature for direct device connectivity
- Dev proxy for React Native DevTools access over Tailscale
- EAS build configuration for development/preview/production
- Ona automation for Expo dev server
Co-authored-by: Ona <no-reply@ona.com>
Replace per-source services (LocationService, WeatherService,
TflService, FeedEngineService) with a single UserSessionManager
that owns all per-user state. Source creation is delegated to
thin FeedSourceProvider implementations per source type.
Co-authored-by: Ona <no-reply@ona.com>
Add listActions() and executeAction() to FeedSource for write
operations back to external services. Actions use arktype schemas
for input validation via StandardSchemaV1.
- ActionDefinition type with optional input schema
- FeedEngine routes actions with existence and ID validation
- Source IDs use reverse-domain format (aris.location, aris.tfl)
- LocationSource: update-location action with schema validation
- TflSource: set-lines-of-interest action with lineId validation
- No-op implementations for sources without actions
Co-authored-by: Ona <no-reply@ona.com>
Sources that cannot provide context now return null
instead of omitting the method. The engine checks the
return value rather than method existence.
Co-authored-by: Ona <no-reply@ona.com>