Commit Graph

140 Commits

Author SHA1 Message Date
8eedd1f4fd feat(client): wire up API client and react-query (#75)
* feat(client): wire up API client and react-query

Add ApiClient class, auth middleware placeholder, feed query,
and wrap the app in QueryClientProvider.

Co-authored-by: Ona <no-reply@ona.com>

* fix(client): append base url on api client req

Co-authored-by: Ona <no-reply@ona.com>

* fix(client): allow req middlewares to run on empty init

* fix(client): rm unused private route declr

* fix(client): handle empty url in client.request

Co-authored-by: ona-patrol <ona@nym.sh>

---------

Co-authored-by: Ona <no-reply@ona.com>
Co-authored-by: ona-patrol <ona@nym.sh>
2026-03-15 17:10:32 +00:00
4b824c66ce feat(tfl): add FeedItemRenderer for TfL alerts (#73)
* feat(tfl): add FeedItemRenderer for TfL alerts

Implement renderTflAlert using JRX and @aelis/components.
Upgrade @nym.sh/jrx to 0.2.0 for null child support.

Co-authored-by: Ona <no-reply@ona.com>

* fix(tfl): add jsxImportSource pragma for CI

The CI test runner doesn't use per-package tsconfig.json,
so the pragma is needed alongside the tsconfig setting.

Co-authored-by: Ona <no-reply@ona.com>

* fix(ci): run tests per-package via bun run test

Use 'bun run test' (which runs 'bun run --filter * test')
instead of 'bun test' so each package runs tests from its
own directory. Add jsxImportSource pragma to renderer files
since consumers without a JRX tsconfig also import them.

Co-authored-by: Ona <no-reply@ona.com>

* fix(tfl): handle near-1km boundary in formatDistance

Values like 0.9999km rounded to 1000m and displayed as
'1000m away'. Now converts to meters first and switches
to km format when rounded meters >= 1000.

Co-authored-by: Ona <no-reply@ona.com>

---------

Co-authored-by: Ona <no-reply@ona.com>
2026-03-15 00:20:54 +00:00
272fb9b9b3 feat(caldav): add FeedItemRenderer (#74)
Implement renderCalDavFeedItem using JRX JSX to render
CalDAV events as FeedCard components. Bump @nym.sh/jrx
to 0.2.0 for null/undefined child support.

Co-authored-by: Ona <no-reply@ona.com>
2026-03-15 00:19:44 +00:00
5ea24b0a13 feat(core): add sourceId to FeedItem (#72)
Each FeedSource implementation now sets sourceId on items
it produces, allowing consumers to trace items back to
their originating source.

Co-authored-by: Ona <no-reply@ona.com>
2026-03-14 23:51:41 +00:00
bed033652c ci: add docker build workflow for waitlist website (#71)
* ci: add docker build workflow for waitlist website

Builds and pushes to cr.nym.sh on pushes to master
that touch apps/waitlist-website/.

Co-authored-by: Ona <no-reply@ona.com>

* ci: rename image to aelis-waitlist-website

Co-authored-by: Ona <no-reply@ona.com>

---------

Co-authored-by: Ona <no-reply@ona.com>
2026-03-14 23:24:07 +00:00
ec083c3c77 feat(client): add Button.Icon subcomponent (#70)
Introduce Button.Icon to enforce consistent icon styling
(size, theme-aware color) instead of hardcoding Feather
props at each call site. Update showcase and json-render
registry to use it.

Co-authored-by: Ona <no-reply@ona.com>
2026-03-14 00:39:59 +00:00
45fa539d3e feat(core): add FeedItemRenderer type (#69)
Co-authored-by: Ona <no-reply@ona.com>
2026-03-14 00:06:24 +00:00
b4ad910a14 feat: add @aelis/components package with JRX definitions (#68)
JRX component wrappers for the aelis-client UI components,
enabling server-side feed item rendering via json-render.

Co-authored-by: Ona <no-reply@ona.com>
2026-03-13 23:57:54 +00:00
d3452dd452 feat(client): add json-render catalog and registry (#67)
Co-authored-by: Ona <no-reply@ona.com>
2026-03-13 23:56:34 +00:00
c78ad25f0d feat(client): add component library and simplify routing (#66)
* feat(client): add component library and simplify routing

Remove tab layout, explore page, modal, and unused template
components. Replace with single-page layout and a dev component
showcase with per-component detail pages.

- Add Button with label prop, leading/trailing icon support
- Add FeedCard, SerifText, SansSerifText, MonospaceText
- Add colocated *.showcase.tsx files for each component
- Use Stack navigator with themed headers

Co-authored-by: Ona <no-reply@ona.com>

* fix(client): render showcase as JSX component

Co-authored-by: Ona <no-reply@ona.com>

* chore(client): remove dead code chain

Remove ThemedText, useThemeColor, useColorScheme hook,
Colors, and Fonts — none referenced by current screens.

Co-authored-by: Ona <no-reply@ona.com>

---------

Co-authored-by: Ona <no-reply@ona.com>
2026-03-13 00:23:06 +00:00
e07157eba0 feat(backend): add GET /api/context endpoint (#65)
* feat(backend): add GET /api/context endpoint

Query context values by key with exact/prefix match
support. Default mode tries exact first, falls back
to prefix.

Co-authored-by: Ona <no-reply@ona.com>

* fix(backend): validate context key element types

Reject booleans, nulls, and nested arrays in the key
param. Only string, number, and plain objects with
primitive values are accepted.

Co-authored-by: Ona <no-reply@ona.com>

---------

Co-authored-by: Ona <no-reply@ona.com>
2026-03-13 00:17:54 +00:00
3036f4ad3f refactor(backend): rename feed dir to engine (#64)
Co-authored-by: Ona <no-reply@ona.com>
2026-03-12 00:57:32 +00:00
f2c991eebb feat(core): add RenderedFeedItem type with JRX UI support (#63)
Add RenderedFeedItem that extends FeedItem with a ui: JrxNode field
for client-side rendering. Add @nym.sh/jrx and @json-render/core as
peer dependencies on @aelis/core.

Co-authored-by: Ona <no-reply@ona.com>
2026-03-11 23:31:32 +00:00
805e4f2bc6 feat(backend): bypass auth in development (#62)
Use mockAuthSessionMiddleware with a fully populated dev
user when NODE_ENV is not production. Auth handlers are
only registered in production.

Co-authored-by: Ona <no-reply@ona.com>
2026-03-11 00:21:34 +00:00
34ead53e1d feat(caldav): add slot support for feed items (#57)
Adds three LLM-fillable slots to every CalDav feed item:
insight, preparation, and crossSource. Slot prompts are
stored in separate .txt files under src/prompts/ with
few-shot examples to steer the LLM away from restating
event details.

Co-authored-by: Ona <no-reply@ona.com>
2026-03-10 19:36:34 +00:00
863c298bd3 refactor: rename aris to aelis (#59)
Rename all references across the codebase: package names,
imports, source IDs, directory names, docs, and configs.

Co-authored-by: Ona <no-reply@ona.com>
2026-03-10 19:19:23 +00:00
230116d9f7 fix(waitlist): add delay before email to avoid rate limit (#61)
Co-authored-by: Ona <no-reply@ona.com>
2026-03-08 03:35:58 +00:00
0a08706cf9 feat: init waitlist website (#60)
* feat: init waitlist website

Co-authored-by: Ona <no-reply@ona.com>

* feat[waitlist]: tweak copy

Co-authored-by: Ona <no-reply@ona.com>

* fix[waitlist]: reminify lottie json

Co-authored-by: Ona <no-reply@ona.com>

* feat[waitlist]: seo and preview stuff

* chore[waitlist]: clean up

* build[waitlist]: add fly.io config

* feat(waitlist): add time-of-day greeting and duplicate email message

Co-authored-by: Ona <no-reply@ona.com>

* feat(waitlist): handle duplicate emails and send confirmation

Co-authored-by: Ona <no-reply@ona.com>

* chore: remove stray console.log

Co-authored-by: Ona <no-reply@ona.com>

* feat(waitlist): add privacy policy page

Co-authored-by: Ona <no-reply@ona.com>

* feat(waitlist): add footer with bottom progressive blur

Co-authored-by: Ona <no-reply@ona.com>

* feat(waitlist): add trouble message and improve error handling

Co-authored-by: Ona <no-reply@ona.com>

* fix(waitlist): fix timeOfDay logic, typo, and add audienceId

Co-authored-by: Ona <no-reply@ona.com>

* feat(waitlist): add .ico fallback favicon and style error page

Co-authored-by: Ona <no-reply@ona.com>

* chore(waitlist): add robots.txt, sitemap, clean dockerignore

Co-authored-by: Ona <no-reply@ona.com>

* feat(waitlist): add footer to privacy policy page

Co-authored-by: Ona <no-reply@ona.com>

* fix(waitlist): use segments instead of audienceId

Co-authored-by: Ona <no-reply@ona.com>

* fix[waitlist]: remove segmentId from dup check

Co-authored-by: Ona <no-reply@ona.com>

* fix(waitlist): reset logo animation on mouse leave

Co-authored-by: Ona <no-reply@ona.com>

---------

Co-authored-by: Ona <no-reply@ona.com>
2026-03-08 02:54:56 +00:00
badc00c43b feat(backend): add LLM-powered feed enhancement (#58)
* feat(backend): add LLM-powered feed enhancement

Add enhancement harness that fills feed item slots and
generates synthetic items via OpenRouter.

- LLM client with 30s timeout, reusable SDK instance
- Prompt builder with mini calendar and week overview
- arktype schema validation + JSON Schema for structured output
- Pure merge function with clock injection
- Defensive fallback in feed endpoint on enhancement failure
- Skips LLM call when no unfilled slots or no API key

Co-authored-by: Ona <no-reply@ona.com>

* refactor: move feed enhancement into UserSession

Move enhancement logic from HTTP handler into UserSession so the
transport layer has no knowledge of enhancement. UserSession.feed()
handles refresh, enhancement, and caching in one place.

- UserSession subscribes to engine updates and re-enhances eagerly
- Enhancement cache tracks source identity to prevent stale results
- UserSessionManager accepts config object with optional enhancer
- HTTP handler simplified to just call session.feed()

Co-authored-by: Ona <no-reply@ona.com>

* test: add schema sync tests for arktype/JSON Schema drift

Validates reference payloads against both the arktype schema
(parseEnhancementResult) and the OpenRouter JSON Schema structure.
Catches field additions/removals or type changes in either schema.

Co-authored-by: Ona <no-reply@ona.com>

* refactor: rename arktype schemas to match types

Co-authored-by: Ona <no-reply@ona.com>

---------

Co-authored-by: Ona <no-reply@ona.com>
2026-03-05 02:01:30 +00:00
31d5aa8d50 fix(caldav): expand recurring events in range (#55)
The iCal parser returned master VEVENT components with their
original start dates instead of expanding recurrences. Events
from months ago appeared in today's feed.

parseICalEvents now accepts an optional timeRange. When set,
recurring events are expanded via ical.js iterator and only
occurrences overlapping the range are returned. Exception
overrides (RECURRENCE-ID) are applied during expansion.

Co-authored-by: Ona <no-reply@ona.com>
2026-03-04 23:17:14 +00:00
de29e44a08 feat(source-weatherkit): add insight slot (#54)
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>
2026-03-03 00:00:11 +00:00
caf48484bf feat(core): add Slot type and slots field to FeedItem (#53)
Co-authored-by: Ona <no-reply@ona.com>
2026-03-01 23:57:51 +00:00
ac80e0cdac feat: add TimeOfDayEnhancer post-processor (#52)
* 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>
2026-03-01 23:06:16 +00:00
96e22e227c feat: replace flat context with tuple-keyed store (#50)
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>
2026-03-01 22:52:41 +00:00
8ca8a0d1d2 fix: use PascalCase for FeedItemType members (#51)
Rename camelCase members to PascalCase in WeatherFeedItemType
and CalendarFeedItemType to match TflFeedItemType and
CalDavFeedItemType conventions.

Co-authored-by: Ona <no-reply@ona.com>
2026-03-01 22:10:34 +00:00
4c9ac2c61a feat(tfl): export TflFeedItemType const (#47)
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>
2026-03-01 18:43:27 +00:00
be3fc41a00 refactor(google-calendar): remove redundant type aliases (#48)
The *TypeType re-exports are unnecessary since
consumers can use import type to get the type.

Co-authored-by: Ona <no-reply@ona.com>
2026-03-01 18:43:08 +00:00
2e9c600e93 refactor(weatherkit): remove redundant type aliases (#49)
The *TypeType re-exports are unnecessary since
consumers can use import type to get the type.

Co-authored-by: Ona <no-reply@ona.com>
2026-03-01 18:42:58 +00:00
d616fd52d3 feat(caldav): export CalDavFeedItemType const (#46)
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>
2026-03-01 18:42:40 +00:00
2d7544500d feat: add boost directive to FeedEnhancement (#45)
* 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>
2026-03-01 17:26:25 +00:00
9dc0cc3d2f feat: add GPG commit signing skill (#44)
Co-authored-by: Ona <no-reply@ona.com>
2026-03-01 17:21:30 +00:00
fe1d261f56 feat: pass context to feed post-processors (#43)
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>
2026-03-01 17:10:55 +00:00
40ad90aa2d feat: add generic CalDAV calendar data source (#42)
* 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>
2026-02-28 16:09:11 +00:00
82ac2b577d feat: add post-processor pipeline to FeedEngine (#41)
* 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>
2026-02-28 15:57:01 +00:00
ffea38b986 fix: remove apple calendar data source (#40)
The CalDAV-based approach doesn't work as expected for
Apple Calendar integration.

Co-authored-by: Ona <no-reply@ona.com>
2026-02-28 12:30:23 +00:00
28d26b3c87 Replace FeedItem.priority with signals (#39)
* 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>
2026-02-28 12:02:57 +00:00
78b0ed94bd docs: update UI rendering to server-driven twrnc (#38)
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>
2026-02-26 22:55:46 +00:00
ee957ea7b1 docs: agent vision and enhancement architecture (#37)
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>
2026-02-26 22:48:05 +00:00
6ae0ad1d40 Merge pull request #36 from kennethnym/feat/feed-endpoint
feat: add GET /api/feed endpoint
2026-02-24 22:33:49 +00:00
941acb826c feat: add GET /api/feed endpoint
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>
2026-02-24 22:30:13 +00:00
3d492a5d56 Merge pull request #35 from kennethnym/feat/feed-engine-cache
feat: add caching to FeedEngine
2026-02-24 01:21:20 +00:00
08dd437952 feat: add caching to FeedEngine
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>
2026-02-24 01:13:41 +00:00
2fc20759dd Merge pull request #34 from kennethnym/refactor/remove-trpc
refactor: remove tRPC, use plain Hono routes
2026-02-22 21:10:16 +00:00
963bf073d1 fix: handle malformed JSON in location handler
Co-authored-by: Ona <no-reply@ona.com>
2026-02-22 21:03:58 +00:00
c0b3db0e11 Update apps/aris-backend/src/location/http.ts
Co-authored-by: ona-patrol <ona@nym.sh>
2026-02-22 21:02:44 +00:00
ca4a337dcd refactor: remove tRPC, use plain Hono routes
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>
2026-02-22 20:59:19 +00:00
769e2d4eb0 Merge pull request #33 from kennethnym/feat/source-serif-4-font
Add Source Serif 4 font to aris-client
2026-02-22 19:45:19 +00:00
5e9094710d fix(client): match Source Serif 4 family name
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>
2026-02-22 19:44:27 +00:00
5556f3fbf9 fix(client): specify font weight and style
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>
2026-02-22 19:09:55 +00:00
0176979925 feat(client): embed Inter font assets
Copy Inter font files to assets/fonts/ and add them
to the expo-font config plugin alongside Source Serif 4.

Co-authored-by: Ona <no-reply@ona.com>
2026-02-22 19:05:01 +00:00