From 3967ca2790225fcc5fb5b706e218bfaa8dc03244 Mon Sep 17 00:00:00 2001 From: Maurice Date: Thu, 22 Oct 2026 12:14:24 +0200 Subject: [PATCH] feat(assistant): a card framework every addon package plugs into --- client/scripts/i18n-keys.mjs | 7 - client/src/api/assistant.ts | 8 + .../Assistant/AssistantChangeCard.test.tsx | 21 +- .../Assistant/AssistantChangeCard.tsx | 303 ++------------- .../Assistant/AssistantChangeFields.tsx | 21 +- .../Assistant/AssistantHost.test.tsx | 40 +- .../components/Assistant/AssistantHost.tsx | 31 +- .../components/Assistant/AssistantMessage.tsx | 9 +- .../Assistant/AssistantPlaceStrip.tsx | 130 +------ .../Assistant/AssistantPowerParts.test.tsx | 1 + .../components/Assistant/AssistantSurface.tsx | 6 +- .../Assistant/AssistantWindow.test.tsx | 54 ++- .../components/Assistant/AssistantWindow.tsx | 38 +- .../Assistant/assistantFollowUpRules.test.ts | 44 +++ .../Assistant/assistantFollowUpRules.ts | 25 +- .../components/Assistant/assistantModel.ts | 49 +-- .../Assistant/assistantParts.test.ts | 105 +++++- .../components/Assistant/assistantParts.ts | 100 ++++- .../components/Assistant/assistantShare.ts | 4 +- .../Assistant/assistantShowOnMap.test.ts | 31 +- .../Assistant/assistantShowOnMap.ts | 30 +- .../Assistant/assistantViewContext.ts | 11 +- .../cards/AssistantCardBlock.test.tsx | 74 ++++ .../Assistant/cards/AssistantCardBlock.tsx | 21 ++ .../Assistant/cards/ChangeCardSlots.test.tsx | 187 +++++++++ .../Assistant/cards/ChangeCardSlots.tsx | 357 ++++++++++++++++++ .../Assistant/cards/EntityActions.test.tsx | 90 +++++ .../Assistant/cards/EntityActions.tsx | 49 +++ .../Assistant/cards/atlas/atlasLook.ts | 20 + .../Assistant/cards/atlas/atlasViews.tsx | 14 + .../Assistant/cards/booking/bookingLook.ts | 23 ++ .../Assistant/cards/booking/bookingViews.tsx | 12 + .../Assistant/cards/budget/budgetLook.ts | 25 ++ .../Assistant/cards/budget/budgetViews.tsx | 15 + .../Assistant/cards/cardLooks.test.ts | 102 +++++ .../components/Assistant/cards/cardLooks.ts | 248 ++++++++++++ .../components/Assistant/cards/cardTypes.ts | 121 ++++++ .../components/Assistant/cards/cardViews.ts | 37 ++ .../Assistant/cards/collab/collabLook.ts | 20 + .../Assistant/cards/collab/collabViews.tsx | 14 + .../cards/collection/collectionLook.ts | 19 + .../cards/collection/collectionViews.tsx | 13 + .../Assistant/cards/journey/journeyLook.ts | 18 + .../Assistant/cards/journey/journeyViews.tsx | 12 + .../Assistant/cards/packing/packingLook.ts | 24 ++ .../Assistant/cards/packing/packingViews.tsx | 13 + .../Assistant/cards/parts/CardBoundary.tsx | 17 + .../Assistant/cards/parts/CardFacts.tsx | 83 ++++ .../Assistant/cards/parts/CardFrame.tsx | 42 +++ .../Assistant/cards/parts/CardHeader.tsx | 43 +++ .../Assistant/cards/parts/CardOpen.tsx | 51 +++ .../Assistant/cards/parts/CardParts.test.tsx | 193 ++++++++++ .../Assistant/cards/parts/CardPeople.tsx | 61 +++ .../Assistant/cards/parts/CardRows.tsx | 89 +++++ .../Assistant/cards/parts/CardStrip.tsx | 74 ++++ .../Assistant/cards/parts/KindTile.tsx | 41 ++ .../cards/parts/RouteSketch.test.tsx | 76 ++++ .../Assistant/cards/parts/RouteSketch.tsx | 122 ++++++ .../Assistant/cards/parts/assistantTones.ts | 31 ++ .../Assistant/cards/parts/cardHooks.test.tsx | 90 +++++ .../Assistant/cards/parts/routeSketchModel.ts | 88 +++++ .../Assistant/cards/parts/useCardFormat.ts | 42 +++ .../Assistant/cards/parts/useCardPoint.ts | 47 +++ .../Assistant/cards/parts/useCardStrip.ts | 54 +++ .../Assistant/cards/parts/useViewerId.ts | 6 + .../Assistant/cards/roadtrip/roadtripLook.ts | 22 ++ .../cards/roadtrip/roadtripViews.tsx | 16 + .../Assistant/cards/tour/tourLook.ts | 23 ++ .../Assistant/cards/tour/tourViews.tsx | 13 + .../Assistant/cards/useChangeExclusions.ts | 35 ++ .../Assistant/cards/vacay/vacayLook.ts | 18 + .../Assistant/cards/vacay/vacayViews.tsx | 12 + .../Assistant/useAssistantPlaceStrip.ts | 22 +- .../Planner/bookings/bookingParts.tsx | 20 +- client/src/components/Planner/planParts.tsx | 2 +- .../trip/assistant/MAssistantScreen.tsx | 60 ++- .../tripPlanner/deepLinks/deepLinkTypes.ts | 15 + .../deepLinks/useBookingDeepLink.ts | 9 + .../deepLinks/useRoadtripDeepLink.ts | 9 + .../tripPlanner/deepLinks/useTourDeepLink.ts | 9 + .../tripPlanner/useAssistantDeepLink.test.ts | 32 +- .../pages/tripPlanner/useAssistantDeepLink.ts | 39 ++ .../useAssistantEntityLinks.test.tsx | 45 +++ .../tripPlanner/useAssistantEntityLinks.ts | 33 ++ .../pages/tripPlanner/useTripPlannerPage.ts | 6 +- .../repo/assistantRepo.foundPlaces.test.ts | 32 +- client/src/repo/assistantRepo.ts | 7 + .../src/store/assistantMessages.cards.test.ts | 48 ++- client/src/store/assistantMessages.ts | 28 ++ client/src/store/assistantStore.cards.test.ts | 102 +++++ client/src/store/assistantStore.ts | 112 +++++- client/src/types/assistantMap.ts | 41 ++ .../mobile/trip/MAssistantScreen.test.tsx | 62 ++- server/src/db/json-columns.ts | 31 +- server/src/nest/airports/airports.module.ts | 2 + server/src/nest/assistant/assistant-agent.ts | 27 +- .../nest/assistant/assistant-cards.helpers.ts | 38 +- .../src/nest/assistant/assistant-context.ts | 23 +- .../assistant-found-places.service.ts | 29 +- .../src/nest/assistant/assistant-history.ts | 2 +- server/src/nest/assistant/assistant-output.ts | 148 ++++++++ server/src/nest/assistant/assistant-redact.ts | 137 +------ .../nest/assistant/assistant-tool-offer.ts | 37 +- .../assistant/assistant-tools.constants.ts | 66 +--- .../nest/assistant/assistant-tools.service.ts | 50 ++- .../nest/assistant/assistant-undo.helpers.ts | 143 +++---- server/src/nest/assistant/assistant.module.ts | 9 +- server/src/nest/assistant/assistant.prompt.ts | 7 +- .../src/nest/assistant/assistant.service.ts | 86 ++--- .../src/nest/assistant/cards/applied-cards.ts | 33 ++ .../src/nest/assistant/cards/atlas/index.ts | 4 + .../src/nest/assistant/cards/booking/index.ts | 4 + .../src/nest/assistant/cards/budget/index.ts | 4 + .../src/nest/assistant/cards/card-context.ts | 182 +++++++++ server/src/nest/assistant/cards/card-types.ts | 144 +++++++ .../src/nest/assistant/cards/card-values.ts | 134 +++++++ .../src/nest/assistant/cards/collab/index.ts | 4 + .../nest/assistant/cards/collection/index.ts | 4 + .../src/nest/assistant/cards/journey/index.ts | 4 + .../src/nest/assistant/cards/packing/index.ts | 4 + .../nest/assistant/cards/preview-format.ts | 115 ++++++ server/src/nest/assistant/cards/registry.ts | 350 +++++++++++++++++ .../nest/assistant/cards/roadtrip/index.ts | 4 + server/src/nest/assistant/cards/tour/index.ts | 25 ++ .../tour/tour-describe.ts} | 15 +- .../nest/assistant/cards/tour/tour-undo.ts | 37 ++ .../src/nest/assistant/cards/undo-snapshot.ts | 66 ++++ .../src/nest/assistant/cards/vacay/index.ts | 4 + .../nest/assistant/preview-rows.helpers.ts | 51 --- .../assistant/tool-call-generic.helpers.ts | 50 ++- .../assistant/tool-call-preview.helpers.ts | 148 +++----- server/src/nest/assistant/ui-stream.writer.ts | 6 + server/tests/e2e/assistant.e2e.test.ts | 64 +++- .../nest/assistant/assistant-agent.test.ts | 73 +++- .../assistant/assistant-cards.helpers.test.ts | 3 +- .../nest/assistant/assistant-context.test.ts | 53 ++- .../assistant-found-places.service.test.ts | 8 +- .../nest/assistant/assistant-redact.test.ts | 12 +- .../assistant/assistant-tools.service.test.ts | 39 +- .../assistant/assistant-undo.helpers.test.ts | 77 +++- .../nest/assistant/cards/card-context.test.ts | 189 ++++++++++ .../nest/assistant/cards/card-values.test.ts | 102 +++++ .../assistant/cards/registry-guards.test.ts | 87 +++++ .../nest/assistant/cards/registry.test.ts | 225 +++++++++++ .../tool-call-preview.helpers.test.ts | 118 +++++- .../nest/assistant/ui-stream.writer.test.ts | 48 ++- .../unit/nest/dawarich-atlas.mcp.test.ts | 2 +- .../unit/nest/journey-tracks.mcp.test.ts | 2 +- server/tests/unit/utils/json-column.test.ts | 48 +++ .../__fixtures__/ui-stream.cards.v1.txt | 44 +++ shared/src/assistant/assistant.schema.spec.ts | 9 +- shared/src/assistant/assistant.schema.ts | 217 ++++++++--- .../src/assistant/cards/atlas-bucket.card.ts | 5 + .../src/assistant/cards/atlas-country.card.ts | 5 + .../assistant/cards/atlas-passport.card.ts | 8 + shared/src/assistant/cards/atlas.contract.ts | 18 + shared/src/assistant/cards/booking.card.ts | 8 + .../src/assistant/cards/booking.contract.ts | 14 + shared/src/assistant/cards/budget.contract.ts | 25 ++ shared/src/assistant/cards/card-parts.ts | 58 +++ shared/src/assistant/cards/charging.card.ts | 8 + .../src/assistant/cards/collab-chat.card.ts | 8 + .../src/assistant/cards/collab-notes.card.ts | 5 + .../src/assistant/cards/collab-polls.card.ts | 8 + shared/src/assistant/cards/collab.contract.ts | 18 + .../assistant/cards/collection-lists.card.ts | 5 + .../assistant/cards/collection-places.card.ts | 5 + .../assistant/cards/collection.contract.ts | 16 + shared/src/assistant/cards/corridor.card.ts | 8 + .../assistant/cards/cost-per-person.card.ts | 5 + shared/src/assistant/cards/day-route.card.ts | 5 + shared/src/assistant/cards/expenses.card.ts | 8 + shared/src/assistant/cards/index.spec.ts | 209 ++++++++++ shared/src/assistant/cards/index.ts | 66 ++++ .../assistant/cards/journey-entries.card.ts | 5 + .../src/assistant/cards/journey.contract.ts | 14 + .../src/assistant/cards/packing-list.card.ts | 8 + .../src/assistant/cards/packing.contract.ts | 16 + shared/src/assistant/cards/payments.card.ts | 5 + shared/src/assistant/cards/roadtrip.card.ts | 8 + .../src/assistant/cards/roadtrip.contract.ts | 28 ++ shared/src/assistant/cards/settlement.card.ts | 5 + shared/src/assistant/cards/todo-list.card.ts | 5 + shared/src/assistant/cards/tour-list.card.ts | 5 + shared/src/assistant/cards/tour-route.card.ts | 8 + shared/src/assistant/cards/tour.contract.ts | 18 + shared/src/assistant/cards/transit.card.ts | 8 + shared/src/assistant/cards/vacay.card.ts | 8 + shared/src/assistant/cards/vacay.contract.ts | 14 + shared/src/i18n/ar/assistantAtlas.ts | 4 + shared/src/i18n/ar/assistantBooking.ts | 4 + shared/src/i18n/ar/assistantBudget.ts | 4 + shared/src/i18n/ar/assistantCard.ts | 19 + shared/src/i18n/ar/assistantCollab.ts | 4 + shared/src/i18n/ar/assistantCollection.ts | 4 + shared/src/i18n/ar/assistantJourney.ts | 4 + shared/src/i18n/ar/assistantPacking.ts | 4 + shared/src/i18n/ar/assistantRoadtrip.ts | 4 + shared/src/i18n/ar/assistantTour.ts | 4 + shared/src/i18n/ar/assistantVacay.ts | 4 + shared/src/i18n/ar/index.ts | 22 ++ shared/src/i18n/az/assistantAtlas.ts | 4 + shared/src/i18n/az/assistantBooking.ts | 4 + shared/src/i18n/az/assistantBudget.ts | 4 + shared/src/i18n/az/assistantCard.ts | 15 + shared/src/i18n/az/assistantCollab.ts | 4 + shared/src/i18n/az/assistantCollection.ts | 4 + shared/src/i18n/az/assistantJourney.ts | 4 + shared/src/i18n/az/assistantPacking.ts | 4 + shared/src/i18n/az/assistantRoadtrip.ts | 4 + shared/src/i18n/az/assistantTour.ts | 4 + shared/src/i18n/az/assistantVacay.ts | 4 + shared/src/i18n/az/index.ts | 22 ++ shared/src/i18n/br/assistantAtlas.ts | 4 + shared/src/i18n/br/assistantBooking.ts | 4 + shared/src/i18n/br/assistantBudget.ts | 4 + shared/src/i18n/br/assistantCard.ts | 15 + shared/src/i18n/br/assistantCollab.ts | 4 + shared/src/i18n/br/assistantCollection.ts | 4 + shared/src/i18n/br/assistantJourney.ts | 4 + shared/src/i18n/br/assistantPacking.ts | 4 + shared/src/i18n/br/assistantRoadtrip.ts | 4 + shared/src/i18n/br/assistantTour.ts | 4 + shared/src/i18n/br/assistantVacay.ts | 4 + shared/src/i18n/br/index.ts | 22 ++ shared/src/i18n/ca/assistantAtlas.ts | 4 + shared/src/i18n/ca/assistantBooking.ts | 4 + shared/src/i18n/ca/assistantBudget.ts | 4 + shared/src/i18n/ca/assistantCard.ts | 15 + shared/src/i18n/ca/assistantCollab.ts | 4 + shared/src/i18n/ca/assistantCollection.ts | 4 + shared/src/i18n/ca/assistantJourney.ts | 4 + shared/src/i18n/ca/assistantPacking.ts | 4 + shared/src/i18n/ca/assistantRoadtrip.ts | 4 + shared/src/i18n/ca/assistantTour.ts | 4 + shared/src/i18n/ca/assistantVacay.ts | 4 + shared/src/i18n/ca/index.ts | 22 ++ shared/src/i18n/cs/assistantAtlas.ts | 4 + shared/src/i18n/cs/assistantBooking.ts | 4 + shared/src/i18n/cs/assistantBudget.ts | 4 + shared/src/i18n/cs/assistantCard.ts | 16 + shared/src/i18n/cs/assistantCollab.ts | 4 + shared/src/i18n/cs/assistantCollection.ts | 4 + shared/src/i18n/cs/assistantJourney.ts | 4 + shared/src/i18n/cs/assistantPacking.ts | 4 + shared/src/i18n/cs/assistantRoadtrip.ts | 4 + shared/src/i18n/cs/assistantTour.ts | 4 + shared/src/i18n/cs/assistantVacay.ts | 4 + shared/src/i18n/cs/index.ts | 22 ++ shared/src/i18n/de/assistantAtlas.ts | 4 + shared/src/i18n/de/assistantBooking.ts | 4 + shared/src/i18n/de/assistantBudget.ts | 4 + shared/src/i18n/de/assistantCard.ts | 15 + shared/src/i18n/de/assistantCollab.ts | 4 + shared/src/i18n/de/assistantCollection.ts | 4 + shared/src/i18n/de/assistantJourney.ts | 4 + shared/src/i18n/de/assistantPacking.ts | 4 + shared/src/i18n/de/assistantRoadtrip.ts | 4 + shared/src/i18n/de/assistantTour.ts | 4 + shared/src/i18n/de/assistantVacay.ts | 4 + shared/src/i18n/de/index.ts | 22 ++ shared/src/i18n/en/assistantAtlas.ts | 4 + shared/src/i18n/en/assistantBooking.ts | 4 + shared/src/i18n/en/assistantBudget.ts | 4 + shared/src/i18n/en/assistantCard.ts | 15 + shared/src/i18n/en/assistantCollab.ts | 4 + shared/src/i18n/en/assistantCollection.ts | 4 + shared/src/i18n/en/assistantJourney.ts | 4 + shared/src/i18n/en/assistantPacking.ts | 4 + shared/src/i18n/en/assistantRoadtrip.ts | 4 + shared/src/i18n/en/assistantTour.ts | 4 + shared/src/i18n/en/assistantVacay.ts | 4 + shared/src/i18n/en/index.ts | 22 ++ shared/src/i18n/es/assistantAtlas.ts | 4 + shared/src/i18n/es/assistantBooking.ts | 4 + shared/src/i18n/es/assistantBudget.ts | 4 + shared/src/i18n/es/assistantCard.ts | 15 + shared/src/i18n/es/assistantCollab.ts | 4 + shared/src/i18n/es/assistantCollection.ts | 4 + shared/src/i18n/es/assistantJourney.ts | 4 + shared/src/i18n/es/assistantPacking.ts | 4 + shared/src/i18n/es/assistantRoadtrip.ts | 4 + shared/src/i18n/es/assistantTour.ts | 4 + shared/src/i18n/es/assistantVacay.ts | 4 + shared/src/i18n/es/index.ts | 22 ++ shared/src/i18n/et/assistantAtlas.ts | 4 + shared/src/i18n/et/assistantBooking.ts | 4 + shared/src/i18n/et/assistantBudget.ts | 4 + shared/src/i18n/et/assistantCard.ts | 15 + shared/src/i18n/et/assistantCollab.ts | 4 + shared/src/i18n/et/assistantCollection.ts | 4 + shared/src/i18n/et/assistantJourney.ts | 4 + shared/src/i18n/et/assistantPacking.ts | 4 + shared/src/i18n/et/assistantRoadtrip.ts | 4 + shared/src/i18n/et/assistantTour.ts | 4 + shared/src/i18n/et/assistantVacay.ts | 4 + shared/src/i18n/et/index.ts | 22 ++ shared/src/i18n/fr/assistantAtlas.ts | 4 + shared/src/i18n/fr/assistantBooking.ts | 4 + shared/src/i18n/fr/assistantBudget.ts | 4 + shared/src/i18n/fr/assistantCard.ts | 15 + shared/src/i18n/fr/assistantCollab.ts | 4 + shared/src/i18n/fr/assistantCollection.ts | 4 + shared/src/i18n/fr/assistantJourney.ts | 4 + shared/src/i18n/fr/assistantPacking.ts | 4 + shared/src/i18n/fr/assistantRoadtrip.ts | 4 + shared/src/i18n/fr/assistantTour.ts | 4 + shared/src/i18n/fr/assistantVacay.ts | 4 + shared/src/i18n/fr/index.ts | 22 ++ shared/src/i18n/gr/assistantAtlas.ts | 4 + shared/src/i18n/gr/assistantBooking.ts | 4 + shared/src/i18n/gr/assistantBudget.ts | 4 + shared/src/i18n/gr/assistantCard.ts | 15 + shared/src/i18n/gr/assistantCollab.ts | 4 + shared/src/i18n/gr/assistantCollection.ts | 4 + shared/src/i18n/gr/assistantJourney.ts | 4 + shared/src/i18n/gr/assistantPacking.ts | 4 + shared/src/i18n/gr/assistantRoadtrip.ts | 4 + shared/src/i18n/gr/assistantTour.ts | 4 + shared/src/i18n/gr/assistantVacay.ts | 4 + shared/src/i18n/gr/index.ts | 22 ++ shared/src/i18n/hu/assistantAtlas.ts | 4 + shared/src/i18n/hu/assistantBooking.ts | 4 + shared/src/i18n/hu/assistantBudget.ts | 4 + shared/src/i18n/hu/assistantCard.ts | 15 + shared/src/i18n/hu/assistantCollab.ts | 4 + shared/src/i18n/hu/assistantCollection.ts | 4 + shared/src/i18n/hu/assistantJourney.ts | 4 + shared/src/i18n/hu/assistantPacking.ts | 4 + shared/src/i18n/hu/assistantRoadtrip.ts | 4 + shared/src/i18n/hu/assistantTour.ts | 4 + shared/src/i18n/hu/assistantVacay.ts | 4 + shared/src/i18n/hu/index.ts | 22 ++ shared/src/i18n/id/assistantAtlas.ts | 4 + shared/src/i18n/id/assistantBooking.ts | 4 + shared/src/i18n/id/assistantBudget.ts | 4 + shared/src/i18n/id/assistantCard.ts | 14 + shared/src/i18n/id/assistantCollab.ts | 4 + shared/src/i18n/id/assistantCollection.ts | 4 + shared/src/i18n/id/assistantJourney.ts | 4 + shared/src/i18n/id/assistantPacking.ts | 4 + shared/src/i18n/id/assistantRoadtrip.ts | 4 + shared/src/i18n/id/assistantTour.ts | 4 + shared/src/i18n/id/assistantVacay.ts | 4 + shared/src/i18n/id/index.ts | 22 ++ shared/src/i18n/it/assistantAtlas.ts | 4 + shared/src/i18n/it/assistantBooking.ts | 4 + shared/src/i18n/it/assistantBudget.ts | 4 + shared/src/i18n/it/assistantCard.ts | 15 + shared/src/i18n/it/assistantCollab.ts | 4 + shared/src/i18n/it/assistantCollection.ts | 4 + shared/src/i18n/it/assistantJourney.ts | 4 + shared/src/i18n/it/assistantPacking.ts | 4 + shared/src/i18n/it/assistantRoadtrip.ts | 4 + shared/src/i18n/it/assistantTour.ts | 4 + shared/src/i18n/it/assistantVacay.ts | 4 + shared/src/i18n/it/index.ts | 22 ++ shared/src/i18n/ja/assistantAtlas.ts | 4 + shared/src/i18n/ja/assistantBooking.ts | 4 + shared/src/i18n/ja/assistantBudget.ts | 4 + shared/src/i18n/ja/assistantCard.ts | 14 + shared/src/i18n/ja/assistantCollab.ts | 4 + shared/src/i18n/ja/assistantCollection.ts | 4 + shared/src/i18n/ja/assistantJourney.ts | 4 + shared/src/i18n/ja/assistantPacking.ts | 4 + shared/src/i18n/ja/assistantRoadtrip.ts | 4 + shared/src/i18n/ja/assistantTour.ts | 4 + shared/src/i18n/ja/assistantVacay.ts | 4 + shared/src/i18n/ja/index.ts | 22 ++ shared/src/i18n/ko/assistantAtlas.ts | 4 + shared/src/i18n/ko/assistantBooking.ts | 4 + shared/src/i18n/ko/assistantBudget.ts | 4 + shared/src/i18n/ko/assistantCard.ts | 14 + shared/src/i18n/ko/assistantCollab.ts | 4 + shared/src/i18n/ko/assistantCollection.ts | 4 + shared/src/i18n/ko/assistantJourney.ts | 4 + shared/src/i18n/ko/assistantPacking.ts | 4 + shared/src/i18n/ko/assistantRoadtrip.ts | 4 + shared/src/i18n/ko/assistantTour.ts | 4 + shared/src/i18n/ko/assistantVacay.ts | 4 + shared/src/i18n/ko/index.ts | 22 ++ shared/src/i18n/nl/assistantAtlas.ts | 4 + shared/src/i18n/nl/assistantBooking.ts | 4 + shared/src/i18n/nl/assistantBudget.ts | 4 + shared/src/i18n/nl/assistantCard.ts | 15 + shared/src/i18n/nl/assistantCollab.ts | 4 + shared/src/i18n/nl/assistantCollection.ts | 4 + shared/src/i18n/nl/assistantJourney.ts | 4 + shared/src/i18n/nl/assistantPacking.ts | 4 + shared/src/i18n/nl/assistantRoadtrip.ts | 4 + shared/src/i18n/nl/assistantTour.ts | 4 + shared/src/i18n/nl/assistantVacay.ts | 4 + shared/src/i18n/nl/index.ts | 22 ++ shared/src/i18n/pl/assistantAtlas.ts | 4 + shared/src/i18n/pl/assistantBooking.ts | 4 + shared/src/i18n/pl/assistantBudget.ts | 4 + shared/src/i18n/pl/assistantCard.ts | 17 + shared/src/i18n/pl/assistantCollab.ts | 4 + shared/src/i18n/pl/assistantCollection.ts | 4 + shared/src/i18n/pl/assistantJourney.ts | 4 + shared/src/i18n/pl/assistantPacking.ts | 4 + shared/src/i18n/pl/assistantRoadtrip.ts | 4 + shared/src/i18n/pl/assistantTour.ts | 4 + shared/src/i18n/pl/assistantVacay.ts | 4 + shared/src/i18n/pl/index.ts | 22 ++ shared/src/i18n/ru/assistantAtlas.ts | 4 + shared/src/i18n/ru/assistantBooking.ts | 4 + shared/src/i18n/ru/assistantBudget.ts | 4 + shared/src/i18n/ru/assistantCard.ts | 17 + shared/src/i18n/ru/assistantCollab.ts | 4 + shared/src/i18n/ru/assistantCollection.ts | 4 + shared/src/i18n/ru/assistantJourney.ts | 4 + shared/src/i18n/ru/assistantPacking.ts | 4 + shared/src/i18n/ru/assistantRoadtrip.ts | 4 + shared/src/i18n/ru/assistantTour.ts | 4 + shared/src/i18n/ru/assistantVacay.ts | 4 + shared/src/i18n/ru/index.ts | 22 ++ shared/src/i18n/sk/assistantAtlas.ts | 4 + shared/src/i18n/sk/assistantBooking.ts | 4 + shared/src/i18n/sk/assistantBudget.ts | 4 + shared/src/i18n/sk/assistantCard.ts | 16 + shared/src/i18n/sk/assistantCollab.ts | 4 + shared/src/i18n/sk/assistantCollection.ts | 4 + shared/src/i18n/sk/assistantJourney.ts | 4 + shared/src/i18n/sk/assistantPacking.ts | 4 + shared/src/i18n/sk/assistantRoadtrip.ts | 4 + shared/src/i18n/sk/assistantTour.ts | 4 + shared/src/i18n/sk/assistantVacay.ts | 4 + shared/src/i18n/sk/index.ts | 22 ++ shared/src/i18n/sv/assistantAtlas.ts | 4 + shared/src/i18n/sv/assistantBooking.ts | 4 + shared/src/i18n/sv/assistantBudget.ts | 4 + shared/src/i18n/sv/assistantCard.ts | 15 + shared/src/i18n/sv/assistantCollab.ts | 4 + shared/src/i18n/sv/assistantCollection.ts | 4 + shared/src/i18n/sv/assistantJourney.ts | 4 + shared/src/i18n/sv/assistantPacking.ts | 4 + shared/src/i18n/sv/assistantRoadtrip.ts | 4 + shared/src/i18n/sv/assistantTour.ts | 4 + shared/src/i18n/sv/assistantVacay.ts | 4 + shared/src/i18n/sv/index.ts | 22 ++ shared/src/i18n/th/assistantAtlas.ts | 4 + shared/src/i18n/th/assistantBooking.ts | 4 + shared/src/i18n/th/assistantBudget.ts | 4 + shared/src/i18n/th/assistantCard.ts | 14 + shared/src/i18n/th/assistantCollab.ts | 4 + shared/src/i18n/th/assistantCollection.ts | 4 + shared/src/i18n/th/assistantJourney.ts | 4 + shared/src/i18n/th/assistantPacking.ts | 4 + shared/src/i18n/th/assistantRoadtrip.ts | 4 + shared/src/i18n/th/assistantTour.ts | 4 + shared/src/i18n/th/assistantVacay.ts | 4 + shared/src/i18n/th/index.ts | 22 ++ shared/src/i18n/tr/assistantAtlas.ts | 4 + shared/src/i18n/tr/assistantBooking.ts | 4 + shared/src/i18n/tr/assistantBudget.ts | 4 + shared/src/i18n/tr/assistantCard.ts | 15 + shared/src/i18n/tr/assistantCollab.ts | 4 + shared/src/i18n/tr/assistantCollection.ts | 4 + shared/src/i18n/tr/assistantJourney.ts | 4 + shared/src/i18n/tr/assistantPacking.ts | 4 + shared/src/i18n/tr/assistantRoadtrip.ts | 4 + shared/src/i18n/tr/assistantTour.ts | 4 + shared/src/i18n/tr/assistantVacay.ts | 4 + shared/src/i18n/tr/index.ts | 22 ++ shared/src/i18n/uk/assistantAtlas.ts | 4 + shared/src/i18n/uk/assistantBooking.ts | 4 + shared/src/i18n/uk/assistantBudget.ts | 4 + shared/src/i18n/uk/assistantCard.ts | 17 + shared/src/i18n/uk/assistantCollab.ts | 4 + shared/src/i18n/uk/assistantCollection.ts | 4 + shared/src/i18n/uk/assistantJourney.ts | 4 + shared/src/i18n/uk/assistantPacking.ts | 4 + shared/src/i18n/uk/assistantRoadtrip.ts | 4 + shared/src/i18n/uk/assistantTour.ts | 4 + shared/src/i18n/uk/assistantVacay.ts | 4 + shared/src/i18n/uk/index.ts | 22 ++ shared/src/i18n/vi/assistantAtlas.ts | 4 + shared/src/i18n/vi/assistantBooking.ts | 4 + shared/src/i18n/vi/assistantBudget.ts | 4 + shared/src/i18n/vi/assistantCard.ts | 14 + shared/src/i18n/vi/assistantCollab.ts | 4 + shared/src/i18n/vi/assistantCollection.ts | 4 + shared/src/i18n/vi/assistantJourney.ts | 4 + shared/src/i18n/vi/assistantPacking.ts | 4 + shared/src/i18n/vi/assistantRoadtrip.ts | 4 + shared/src/i18n/vi/assistantTour.ts | 4 + shared/src/i18n/vi/assistantVacay.ts | 4 + shared/src/i18n/vi/index.ts | 22 ++ shared/src/i18n/zh-TW/assistantAtlas.ts | 4 + shared/src/i18n/zh-TW/assistantBooking.ts | 4 + shared/src/i18n/zh-TW/assistantBudget.ts | 4 + shared/src/i18n/zh-TW/assistantCard.ts | 14 + shared/src/i18n/zh-TW/assistantCollab.ts | 4 + shared/src/i18n/zh-TW/assistantCollection.ts | 4 + shared/src/i18n/zh-TW/assistantJourney.ts | 4 + shared/src/i18n/zh-TW/assistantPacking.ts | 4 + shared/src/i18n/zh-TW/assistantRoadtrip.ts | 4 + shared/src/i18n/zh-TW/assistantTour.ts | 4 + shared/src/i18n/zh-TW/assistantVacay.ts | 4 + shared/src/i18n/zh-TW/index.ts | 22 ++ shared/src/i18n/zh/assistantAtlas.ts | 4 + shared/src/i18n/zh/assistantBooking.ts | 4 + shared/src/i18n/zh/assistantBudget.ts | 4 + shared/src/i18n/zh/assistantCard.ts | 14 + shared/src/i18n/zh/assistantCollab.ts | 4 + shared/src/i18n/zh/assistantCollection.ts | 4 + shared/src/i18n/zh/assistantJourney.ts | 4 + shared/src/i18n/zh/assistantPacking.ts | 4 + shared/src/i18n/zh/assistantRoadtrip.ts | 4 + shared/src/i18n/zh/assistantTour.ts | 4 + shared/src/i18n/zh/assistantVacay.ts | 4 + shared/src/i18n/zh/index.ts | 22 ++ shared/src/index.ts | 23 ++ 514 files changed, 9868 insertions(+), 1274 deletions(-) create mode 100644 client/src/components/Assistant/assistantFollowUpRules.test.ts create mode 100644 client/src/components/Assistant/cards/AssistantCardBlock.test.tsx create mode 100644 client/src/components/Assistant/cards/AssistantCardBlock.tsx create mode 100644 client/src/components/Assistant/cards/ChangeCardSlots.test.tsx create mode 100644 client/src/components/Assistant/cards/ChangeCardSlots.tsx create mode 100644 client/src/components/Assistant/cards/EntityActions.test.tsx create mode 100644 client/src/components/Assistant/cards/EntityActions.tsx create mode 100644 client/src/components/Assistant/cards/atlas/atlasLook.ts create mode 100644 client/src/components/Assistant/cards/atlas/atlasViews.tsx create mode 100644 client/src/components/Assistant/cards/booking/bookingLook.ts create mode 100644 client/src/components/Assistant/cards/booking/bookingViews.tsx create mode 100644 client/src/components/Assistant/cards/budget/budgetLook.ts create mode 100644 client/src/components/Assistant/cards/budget/budgetViews.tsx create mode 100644 client/src/components/Assistant/cards/cardLooks.test.ts create mode 100644 client/src/components/Assistant/cards/cardLooks.ts create mode 100644 client/src/components/Assistant/cards/cardTypes.ts create mode 100644 client/src/components/Assistant/cards/cardViews.ts create mode 100644 client/src/components/Assistant/cards/collab/collabLook.ts create mode 100644 client/src/components/Assistant/cards/collab/collabViews.tsx create mode 100644 client/src/components/Assistant/cards/collection/collectionLook.ts create mode 100644 client/src/components/Assistant/cards/collection/collectionViews.tsx create mode 100644 client/src/components/Assistant/cards/journey/journeyLook.ts create mode 100644 client/src/components/Assistant/cards/journey/journeyViews.tsx create mode 100644 client/src/components/Assistant/cards/packing/packingLook.ts create mode 100644 client/src/components/Assistant/cards/packing/packingViews.tsx create mode 100644 client/src/components/Assistant/cards/parts/CardBoundary.tsx create mode 100644 client/src/components/Assistant/cards/parts/CardFacts.tsx create mode 100644 client/src/components/Assistant/cards/parts/CardFrame.tsx create mode 100644 client/src/components/Assistant/cards/parts/CardHeader.tsx create mode 100644 client/src/components/Assistant/cards/parts/CardOpen.tsx create mode 100644 client/src/components/Assistant/cards/parts/CardParts.test.tsx create mode 100644 client/src/components/Assistant/cards/parts/CardPeople.tsx create mode 100644 client/src/components/Assistant/cards/parts/CardRows.tsx create mode 100644 client/src/components/Assistant/cards/parts/CardStrip.tsx create mode 100644 client/src/components/Assistant/cards/parts/KindTile.tsx create mode 100644 client/src/components/Assistant/cards/parts/RouteSketch.test.tsx create mode 100644 client/src/components/Assistant/cards/parts/RouteSketch.tsx create mode 100644 client/src/components/Assistant/cards/parts/assistantTones.ts create mode 100644 client/src/components/Assistant/cards/parts/cardHooks.test.tsx create mode 100644 client/src/components/Assistant/cards/parts/routeSketchModel.ts create mode 100644 client/src/components/Assistant/cards/parts/useCardFormat.ts create mode 100644 client/src/components/Assistant/cards/parts/useCardPoint.ts create mode 100644 client/src/components/Assistant/cards/parts/useCardStrip.ts create mode 100644 client/src/components/Assistant/cards/parts/useViewerId.ts create mode 100644 client/src/components/Assistant/cards/roadtrip/roadtripLook.ts create mode 100644 client/src/components/Assistant/cards/roadtrip/roadtripViews.tsx create mode 100644 client/src/components/Assistant/cards/tour/tourLook.ts create mode 100644 client/src/components/Assistant/cards/tour/tourViews.tsx create mode 100644 client/src/components/Assistant/cards/useChangeExclusions.ts create mode 100644 client/src/components/Assistant/cards/vacay/vacayLook.ts create mode 100644 client/src/components/Assistant/cards/vacay/vacayViews.tsx create mode 100644 client/src/pages/tripPlanner/deepLinks/deepLinkTypes.ts create mode 100644 client/src/pages/tripPlanner/deepLinks/useBookingDeepLink.ts create mode 100644 client/src/pages/tripPlanner/deepLinks/useRoadtripDeepLink.ts create mode 100644 client/src/pages/tripPlanner/deepLinks/useTourDeepLink.ts create mode 100644 client/src/pages/tripPlanner/useAssistantEntityLinks.test.tsx create mode 100644 client/src/pages/tripPlanner/useAssistantEntityLinks.ts create mode 100644 client/src/store/assistantStore.cards.test.ts create mode 100644 client/src/types/assistantMap.ts create mode 100644 server/src/nest/assistant/assistant-output.ts create mode 100644 server/src/nest/assistant/cards/applied-cards.ts create mode 100644 server/src/nest/assistant/cards/atlas/index.ts create mode 100644 server/src/nest/assistant/cards/booking/index.ts create mode 100644 server/src/nest/assistant/cards/budget/index.ts create mode 100644 server/src/nest/assistant/cards/card-context.ts create mode 100644 server/src/nest/assistant/cards/card-types.ts create mode 100644 server/src/nest/assistant/cards/card-values.ts create mode 100644 server/src/nest/assistant/cards/collab/index.ts create mode 100644 server/src/nest/assistant/cards/collection/index.ts create mode 100644 server/src/nest/assistant/cards/journey/index.ts create mode 100644 server/src/nest/assistant/cards/packing/index.ts create mode 100644 server/src/nest/assistant/cards/preview-format.ts create mode 100644 server/src/nest/assistant/cards/registry.ts create mode 100644 server/src/nest/assistant/cards/roadtrip/index.ts create mode 100644 server/src/nest/assistant/cards/tour/index.ts rename server/src/nest/assistant/{tour-call-preview.helpers.ts => cards/tour/tour-describe.ts} (90%) create mode 100644 server/src/nest/assistant/cards/tour/tour-undo.ts create mode 100644 server/src/nest/assistant/cards/undo-snapshot.ts create mode 100644 server/src/nest/assistant/cards/vacay/index.ts delete mode 100644 server/src/nest/assistant/preview-rows.helpers.ts create mode 100644 server/tests/unit/nest/assistant/cards/card-context.test.ts create mode 100644 server/tests/unit/nest/assistant/cards/card-values.test.ts create mode 100644 server/tests/unit/nest/assistant/cards/registry-guards.test.ts create mode 100644 server/tests/unit/nest/assistant/cards/registry.test.ts create mode 100644 shared/src/assistant/__fixtures__/ui-stream.cards.v1.txt create mode 100644 shared/src/assistant/cards/atlas-bucket.card.ts create mode 100644 shared/src/assistant/cards/atlas-country.card.ts create mode 100644 shared/src/assistant/cards/atlas-passport.card.ts create mode 100644 shared/src/assistant/cards/atlas.contract.ts create mode 100644 shared/src/assistant/cards/booking.card.ts create mode 100644 shared/src/assistant/cards/booking.contract.ts create mode 100644 shared/src/assistant/cards/budget.contract.ts create mode 100644 shared/src/assistant/cards/card-parts.ts create mode 100644 shared/src/assistant/cards/charging.card.ts create mode 100644 shared/src/assistant/cards/collab-chat.card.ts create mode 100644 shared/src/assistant/cards/collab-notes.card.ts create mode 100644 shared/src/assistant/cards/collab-polls.card.ts create mode 100644 shared/src/assistant/cards/collab.contract.ts create mode 100644 shared/src/assistant/cards/collection-lists.card.ts create mode 100644 shared/src/assistant/cards/collection-places.card.ts create mode 100644 shared/src/assistant/cards/collection.contract.ts create mode 100644 shared/src/assistant/cards/corridor.card.ts create mode 100644 shared/src/assistant/cards/cost-per-person.card.ts create mode 100644 shared/src/assistant/cards/day-route.card.ts create mode 100644 shared/src/assistant/cards/expenses.card.ts create mode 100644 shared/src/assistant/cards/index.spec.ts create mode 100644 shared/src/assistant/cards/index.ts create mode 100644 shared/src/assistant/cards/journey-entries.card.ts create mode 100644 shared/src/assistant/cards/journey.contract.ts create mode 100644 shared/src/assistant/cards/packing-list.card.ts create mode 100644 shared/src/assistant/cards/packing.contract.ts create mode 100644 shared/src/assistant/cards/payments.card.ts create mode 100644 shared/src/assistant/cards/roadtrip.card.ts create mode 100644 shared/src/assistant/cards/roadtrip.contract.ts create mode 100644 shared/src/assistant/cards/settlement.card.ts create mode 100644 shared/src/assistant/cards/todo-list.card.ts create mode 100644 shared/src/assistant/cards/tour-list.card.ts create mode 100644 shared/src/assistant/cards/tour-route.card.ts create mode 100644 shared/src/assistant/cards/tour.contract.ts create mode 100644 shared/src/assistant/cards/transit.card.ts create mode 100644 shared/src/assistant/cards/vacay.card.ts create mode 100644 shared/src/assistant/cards/vacay.contract.ts create mode 100644 shared/src/i18n/ar/assistantAtlas.ts create mode 100644 shared/src/i18n/ar/assistantBooking.ts create mode 100644 shared/src/i18n/ar/assistantBudget.ts create mode 100644 shared/src/i18n/ar/assistantCard.ts create mode 100644 shared/src/i18n/ar/assistantCollab.ts create mode 100644 shared/src/i18n/ar/assistantCollection.ts create mode 100644 shared/src/i18n/ar/assistantJourney.ts create mode 100644 shared/src/i18n/ar/assistantPacking.ts create mode 100644 shared/src/i18n/ar/assistantRoadtrip.ts create mode 100644 shared/src/i18n/ar/assistantTour.ts create mode 100644 shared/src/i18n/ar/assistantVacay.ts create mode 100644 shared/src/i18n/az/assistantAtlas.ts create mode 100644 shared/src/i18n/az/assistantBooking.ts create mode 100644 shared/src/i18n/az/assistantBudget.ts create mode 100644 shared/src/i18n/az/assistantCard.ts create mode 100644 shared/src/i18n/az/assistantCollab.ts create mode 100644 shared/src/i18n/az/assistantCollection.ts create mode 100644 shared/src/i18n/az/assistantJourney.ts create mode 100644 shared/src/i18n/az/assistantPacking.ts create mode 100644 shared/src/i18n/az/assistantRoadtrip.ts create mode 100644 shared/src/i18n/az/assistantTour.ts create mode 100644 shared/src/i18n/az/assistantVacay.ts create mode 100644 shared/src/i18n/br/assistantAtlas.ts create mode 100644 shared/src/i18n/br/assistantBooking.ts create mode 100644 shared/src/i18n/br/assistantBudget.ts create mode 100644 shared/src/i18n/br/assistantCard.ts create mode 100644 shared/src/i18n/br/assistantCollab.ts create mode 100644 shared/src/i18n/br/assistantCollection.ts create mode 100644 shared/src/i18n/br/assistantJourney.ts create mode 100644 shared/src/i18n/br/assistantPacking.ts create mode 100644 shared/src/i18n/br/assistantRoadtrip.ts create mode 100644 shared/src/i18n/br/assistantTour.ts create mode 100644 shared/src/i18n/br/assistantVacay.ts create mode 100644 shared/src/i18n/ca/assistantAtlas.ts create mode 100644 shared/src/i18n/ca/assistantBooking.ts create mode 100644 shared/src/i18n/ca/assistantBudget.ts create mode 100644 shared/src/i18n/ca/assistantCard.ts create mode 100644 shared/src/i18n/ca/assistantCollab.ts create mode 100644 shared/src/i18n/ca/assistantCollection.ts create mode 100644 shared/src/i18n/ca/assistantJourney.ts create mode 100644 shared/src/i18n/ca/assistantPacking.ts create mode 100644 shared/src/i18n/ca/assistantRoadtrip.ts create mode 100644 shared/src/i18n/ca/assistantTour.ts create mode 100644 shared/src/i18n/ca/assistantVacay.ts create mode 100644 shared/src/i18n/cs/assistantAtlas.ts create mode 100644 shared/src/i18n/cs/assistantBooking.ts create mode 100644 shared/src/i18n/cs/assistantBudget.ts create mode 100644 shared/src/i18n/cs/assistantCard.ts create mode 100644 shared/src/i18n/cs/assistantCollab.ts create mode 100644 shared/src/i18n/cs/assistantCollection.ts create mode 100644 shared/src/i18n/cs/assistantJourney.ts create mode 100644 shared/src/i18n/cs/assistantPacking.ts create mode 100644 shared/src/i18n/cs/assistantRoadtrip.ts create mode 100644 shared/src/i18n/cs/assistantTour.ts create mode 100644 shared/src/i18n/cs/assistantVacay.ts create mode 100644 shared/src/i18n/de/assistantAtlas.ts create mode 100644 shared/src/i18n/de/assistantBooking.ts create mode 100644 shared/src/i18n/de/assistantBudget.ts create mode 100644 shared/src/i18n/de/assistantCard.ts create mode 100644 shared/src/i18n/de/assistantCollab.ts create mode 100644 shared/src/i18n/de/assistantCollection.ts create mode 100644 shared/src/i18n/de/assistantJourney.ts create mode 100644 shared/src/i18n/de/assistantPacking.ts create mode 100644 shared/src/i18n/de/assistantRoadtrip.ts create mode 100644 shared/src/i18n/de/assistantTour.ts create mode 100644 shared/src/i18n/de/assistantVacay.ts create mode 100644 shared/src/i18n/en/assistantAtlas.ts create mode 100644 shared/src/i18n/en/assistantBooking.ts create mode 100644 shared/src/i18n/en/assistantBudget.ts create mode 100644 shared/src/i18n/en/assistantCard.ts create mode 100644 shared/src/i18n/en/assistantCollab.ts create mode 100644 shared/src/i18n/en/assistantCollection.ts create mode 100644 shared/src/i18n/en/assistantJourney.ts create mode 100644 shared/src/i18n/en/assistantPacking.ts create mode 100644 shared/src/i18n/en/assistantRoadtrip.ts create mode 100644 shared/src/i18n/en/assistantTour.ts create mode 100644 shared/src/i18n/en/assistantVacay.ts create mode 100644 shared/src/i18n/es/assistantAtlas.ts create mode 100644 shared/src/i18n/es/assistantBooking.ts create mode 100644 shared/src/i18n/es/assistantBudget.ts create mode 100644 shared/src/i18n/es/assistantCard.ts create mode 100644 shared/src/i18n/es/assistantCollab.ts create mode 100644 shared/src/i18n/es/assistantCollection.ts create mode 100644 shared/src/i18n/es/assistantJourney.ts create mode 100644 shared/src/i18n/es/assistantPacking.ts create mode 100644 shared/src/i18n/es/assistantRoadtrip.ts create mode 100644 shared/src/i18n/es/assistantTour.ts create mode 100644 shared/src/i18n/es/assistantVacay.ts create mode 100644 shared/src/i18n/et/assistantAtlas.ts create mode 100644 shared/src/i18n/et/assistantBooking.ts create mode 100644 shared/src/i18n/et/assistantBudget.ts create mode 100644 shared/src/i18n/et/assistantCard.ts create mode 100644 shared/src/i18n/et/assistantCollab.ts create mode 100644 shared/src/i18n/et/assistantCollection.ts create mode 100644 shared/src/i18n/et/assistantJourney.ts create mode 100644 shared/src/i18n/et/assistantPacking.ts create mode 100644 shared/src/i18n/et/assistantRoadtrip.ts create mode 100644 shared/src/i18n/et/assistantTour.ts create mode 100644 shared/src/i18n/et/assistantVacay.ts create mode 100644 shared/src/i18n/fr/assistantAtlas.ts create mode 100644 shared/src/i18n/fr/assistantBooking.ts create mode 100644 shared/src/i18n/fr/assistantBudget.ts create mode 100644 shared/src/i18n/fr/assistantCard.ts create mode 100644 shared/src/i18n/fr/assistantCollab.ts create mode 100644 shared/src/i18n/fr/assistantCollection.ts create mode 100644 shared/src/i18n/fr/assistantJourney.ts create mode 100644 shared/src/i18n/fr/assistantPacking.ts create mode 100644 shared/src/i18n/fr/assistantRoadtrip.ts create mode 100644 shared/src/i18n/fr/assistantTour.ts create mode 100644 shared/src/i18n/fr/assistantVacay.ts create mode 100644 shared/src/i18n/gr/assistantAtlas.ts create mode 100644 shared/src/i18n/gr/assistantBooking.ts create mode 100644 shared/src/i18n/gr/assistantBudget.ts create mode 100644 shared/src/i18n/gr/assistantCard.ts create mode 100644 shared/src/i18n/gr/assistantCollab.ts create mode 100644 shared/src/i18n/gr/assistantCollection.ts create mode 100644 shared/src/i18n/gr/assistantJourney.ts create mode 100644 shared/src/i18n/gr/assistantPacking.ts create mode 100644 shared/src/i18n/gr/assistantRoadtrip.ts create mode 100644 shared/src/i18n/gr/assistantTour.ts create mode 100644 shared/src/i18n/gr/assistantVacay.ts create mode 100644 shared/src/i18n/hu/assistantAtlas.ts create mode 100644 shared/src/i18n/hu/assistantBooking.ts create mode 100644 shared/src/i18n/hu/assistantBudget.ts create mode 100644 shared/src/i18n/hu/assistantCard.ts create mode 100644 shared/src/i18n/hu/assistantCollab.ts create mode 100644 shared/src/i18n/hu/assistantCollection.ts create mode 100644 shared/src/i18n/hu/assistantJourney.ts create mode 100644 shared/src/i18n/hu/assistantPacking.ts create mode 100644 shared/src/i18n/hu/assistantRoadtrip.ts create mode 100644 shared/src/i18n/hu/assistantTour.ts create mode 100644 shared/src/i18n/hu/assistantVacay.ts create mode 100644 shared/src/i18n/id/assistantAtlas.ts create mode 100644 shared/src/i18n/id/assistantBooking.ts create mode 100644 shared/src/i18n/id/assistantBudget.ts create mode 100644 shared/src/i18n/id/assistantCard.ts create mode 100644 shared/src/i18n/id/assistantCollab.ts create mode 100644 shared/src/i18n/id/assistantCollection.ts create mode 100644 shared/src/i18n/id/assistantJourney.ts create mode 100644 shared/src/i18n/id/assistantPacking.ts create mode 100644 shared/src/i18n/id/assistantRoadtrip.ts create mode 100644 shared/src/i18n/id/assistantTour.ts create mode 100644 shared/src/i18n/id/assistantVacay.ts create mode 100644 shared/src/i18n/it/assistantAtlas.ts create mode 100644 shared/src/i18n/it/assistantBooking.ts create mode 100644 shared/src/i18n/it/assistantBudget.ts create mode 100644 shared/src/i18n/it/assistantCard.ts create mode 100644 shared/src/i18n/it/assistantCollab.ts create mode 100644 shared/src/i18n/it/assistantCollection.ts create mode 100644 shared/src/i18n/it/assistantJourney.ts create mode 100644 shared/src/i18n/it/assistantPacking.ts create mode 100644 shared/src/i18n/it/assistantRoadtrip.ts create mode 100644 shared/src/i18n/it/assistantTour.ts create mode 100644 shared/src/i18n/it/assistantVacay.ts create mode 100644 shared/src/i18n/ja/assistantAtlas.ts create mode 100644 shared/src/i18n/ja/assistantBooking.ts create mode 100644 shared/src/i18n/ja/assistantBudget.ts create mode 100644 shared/src/i18n/ja/assistantCard.ts create mode 100644 shared/src/i18n/ja/assistantCollab.ts create mode 100644 shared/src/i18n/ja/assistantCollection.ts create mode 100644 shared/src/i18n/ja/assistantJourney.ts create mode 100644 shared/src/i18n/ja/assistantPacking.ts create mode 100644 shared/src/i18n/ja/assistantRoadtrip.ts create mode 100644 shared/src/i18n/ja/assistantTour.ts create mode 100644 shared/src/i18n/ja/assistantVacay.ts create mode 100644 shared/src/i18n/ko/assistantAtlas.ts create mode 100644 shared/src/i18n/ko/assistantBooking.ts create mode 100644 shared/src/i18n/ko/assistantBudget.ts create mode 100644 shared/src/i18n/ko/assistantCard.ts create mode 100644 shared/src/i18n/ko/assistantCollab.ts create mode 100644 shared/src/i18n/ko/assistantCollection.ts create mode 100644 shared/src/i18n/ko/assistantJourney.ts create mode 100644 shared/src/i18n/ko/assistantPacking.ts create mode 100644 shared/src/i18n/ko/assistantRoadtrip.ts create mode 100644 shared/src/i18n/ko/assistantTour.ts create mode 100644 shared/src/i18n/ko/assistantVacay.ts create mode 100644 shared/src/i18n/nl/assistantAtlas.ts create mode 100644 shared/src/i18n/nl/assistantBooking.ts create mode 100644 shared/src/i18n/nl/assistantBudget.ts create mode 100644 shared/src/i18n/nl/assistantCard.ts create mode 100644 shared/src/i18n/nl/assistantCollab.ts create mode 100644 shared/src/i18n/nl/assistantCollection.ts create mode 100644 shared/src/i18n/nl/assistantJourney.ts create mode 100644 shared/src/i18n/nl/assistantPacking.ts create mode 100644 shared/src/i18n/nl/assistantRoadtrip.ts create mode 100644 shared/src/i18n/nl/assistantTour.ts create mode 100644 shared/src/i18n/nl/assistantVacay.ts create mode 100644 shared/src/i18n/pl/assistantAtlas.ts create mode 100644 shared/src/i18n/pl/assistantBooking.ts create mode 100644 shared/src/i18n/pl/assistantBudget.ts create mode 100644 shared/src/i18n/pl/assistantCard.ts create mode 100644 shared/src/i18n/pl/assistantCollab.ts create mode 100644 shared/src/i18n/pl/assistantCollection.ts create mode 100644 shared/src/i18n/pl/assistantJourney.ts create mode 100644 shared/src/i18n/pl/assistantPacking.ts create mode 100644 shared/src/i18n/pl/assistantRoadtrip.ts create mode 100644 shared/src/i18n/pl/assistantTour.ts create mode 100644 shared/src/i18n/pl/assistantVacay.ts create mode 100644 shared/src/i18n/ru/assistantAtlas.ts create mode 100644 shared/src/i18n/ru/assistantBooking.ts create mode 100644 shared/src/i18n/ru/assistantBudget.ts create mode 100644 shared/src/i18n/ru/assistantCard.ts create mode 100644 shared/src/i18n/ru/assistantCollab.ts create mode 100644 shared/src/i18n/ru/assistantCollection.ts create mode 100644 shared/src/i18n/ru/assistantJourney.ts create mode 100644 shared/src/i18n/ru/assistantPacking.ts create mode 100644 shared/src/i18n/ru/assistantRoadtrip.ts create mode 100644 shared/src/i18n/ru/assistantTour.ts create mode 100644 shared/src/i18n/ru/assistantVacay.ts create mode 100644 shared/src/i18n/sk/assistantAtlas.ts create mode 100644 shared/src/i18n/sk/assistantBooking.ts create mode 100644 shared/src/i18n/sk/assistantBudget.ts create mode 100644 shared/src/i18n/sk/assistantCard.ts create mode 100644 shared/src/i18n/sk/assistantCollab.ts create mode 100644 shared/src/i18n/sk/assistantCollection.ts create mode 100644 shared/src/i18n/sk/assistantJourney.ts create mode 100644 shared/src/i18n/sk/assistantPacking.ts create mode 100644 shared/src/i18n/sk/assistantRoadtrip.ts create mode 100644 shared/src/i18n/sk/assistantTour.ts create mode 100644 shared/src/i18n/sk/assistantVacay.ts create mode 100644 shared/src/i18n/sv/assistantAtlas.ts create mode 100644 shared/src/i18n/sv/assistantBooking.ts create mode 100644 shared/src/i18n/sv/assistantBudget.ts create mode 100644 shared/src/i18n/sv/assistantCard.ts create mode 100644 shared/src/i18n/sv/assistantCollab.ts create mode 100644 shared/src/i18n/sv/assistantCollection.ts create mode 100644 shared/src/i18n/sv/assistantJourney.ts create mode 100644 shared/src/i18n/sv/assistantPacking.ts create mode 100644 shared/src/i18n/sv/assistantRoadtrip.ts create mode 100644 shared/src/i18n/sv/assistantTour.ts create mode 100644 shared/src/i18n/sv/assistantVacay.ts create mode 100644 shared/src/i18n/th/assistantAtlas.ts create mode 100644 shared/src/i18n/th/assistantBooking.ts create mode 100644 shared/src/i18n/th/assistantBudget.ts create mode 100644 shared/src/i18n/th/assistantCard.ts create mode 100644 shared/src/i18n/th/assistantCollab.ts create mode 100644 shared/src/i18n/th/assistantCollection.ts create mode 100644 shared/src/i18n/th/assistantJourney.ts create mode 100644 shared/src/i18n/th/assistantPacking.ts create mode 100644 shared/src/i18n/th/assistantRoadtrip.ts create mode 100644 shared/src/i18n/th/assistantTour.ts create mode 100644 shared/src/i18n/th/assistantVacay.ts create mode 100644 shared/src/i18n/tr/assistantAtlas.ts create mode 100644 shared/src/i18n/tr/assistantBooking.ts create mode 100644 shared/src/i18n/tr/assistantBudget.ts create mode 100644 shared/src/i18n/tr/assistantCard.ts create mode 100644 shared/src/i18n/tr/assistantCollab.ts create mode 100644 shared/src/i18n/tr/assistantCollection.ts create mode 100644 shared/src/i18n/tr/assistantJourney.ts create mode 100644 shared/src/i18n/tr/assistantPacking.ts create mode 100644 shared/src/i18n/tr/assistantRoadtrip.ts create mode 100644 shared/src/i18n/tr/assistantTour.ts create mode 100644 shared/src/i18n/tr/assistantVacay.ts create mode 100644 shared/src/i18n/uk/assistantAtlas.ts create mode 100644 shared/src/i18n/uk/assistantBooking.ts create mode 100644 shared/src/i18n/uk/assistantBudget.ts create mode 100644 shared/src/i18n/uk/assistantCard.ts create mode 100644 shared/src/i18n/uk/assistantCollab.ts create mode 100644 shared/src/i18n/uk/assistantCollection.ts create mode 100644 shared/src/i18n/uk/assistantJourney.ts create mode 100644 shared/src/i18n/uk/assistantPacking.ts create mode 100644 shared/src/i18n/uk/assistantRoadtrip.ts create mode 100644 shared/src/i18n/uk/assistantTour.ts create mode 100644 shared/src/i18n/uk/assistantVacay.ts create mode 100644 shared/src/i18n/vi/assistantAtlas.ts create mode 100644 shared/src/i18n/vi/assistantBooking.ts create mode 100644 shared/src/i18n/vi/assistantBudget.ts create mode 100644 shared/src/i18n/vi/assistantCard.ts create mode 100644 shared/src/i18n/vi/assistantCollab.ts create mode 100644 shared/src/i18n/vi/assistantCollection.ts create mode 100644 shared/src/i18n/vi/assistantJourney.ts create mode 100644 shared/src/i18n/vi/assistantPacking.ts create mode 100644 shared/src/i18n/vi/assistantRoadtrip.ts create mode 100644 shared/src/i18n/vi/assistantTour.ts create mode 100644 shared/src/i18n/vi/assistantVacay.ts create mode 100644 shared/src/i18n/zh-TW/assistantAtlas.ts create mode 100644 shared/src/i18n/zh-TW/assistantBooking.ts create mode 100644 shared/src/i18n/zh-TW/assistantBudget.ts create mode 100644 shared/src/i18n/zh-TW/assistantCard.ts create mode 100644 shared/src/i18n/zh-TW/assistantCollab.ts create mode 100644 shared/src/i18n/zh-TW/assistantCollection.ts create mode 100644 shared/src/i18n/zh-TW/assistantJourney.ts create mode 100644 shared/src/i18n/zh-TW/assistantPacking.ts create mode 100644 shared/src/i18n/zh-TW/assistantRoadtrip.ts create mode 100644 shared/src/i18n/zh-TW/assistantTour.ts create mode 100644 shared/src/i18n/zh-TW/assistantVacay.ts create mode 100644 shared/src/i18n/zh/assistantAtlas.ts create mode 100644 shared/src/i18n/zh/assistantBooking.ts create mode 100644 shared/src/i18n/zh/assistantBudget.ts create mode 100644 shared/src/i18n/zh/assistantCard.ts create mode 100644 shared/src/i18n/zh/assistantCollab.ts create mode 100644 shared/src/i18n/zh/assistantCollection.ts create mode 100644 shared/src/i18n/zh/assistantJourney.ts create mode 100644 shared/src/i18n/zh/assistantPacking.ts create mode 100644 shared/src/i18n/zh/assistantRoadtrip.ts create mode 100644 shared/src/i18n/zh/assistantTour.ts create mode 100644 shared/src/i18n/zh/assistantVacay.ts diff --git a/client/scripts/i18n-keys.mjs b/client/scripts/i18n-keys.mjs index 57aab93fe..b991a9c00 100644 --- a/client/scripts/i18n-keys.mjs +++ b/client/scripts/i18n-keys.mjs @@ -139,13 +139,6 @@ export const DYNAMIC_ALLOWED = [ 'memories.* key in en', })) ), - { - file: 'components/Assistant/AssistantChangeCard.tsx', - template: 'assistant.tool.${tool}', - because: - 'tool is the MCP tool a change card is for; verbLabel shows assistant.tool. only where en names ' + - 'that tool, and the generic add, change or remove verb for every other tool', - }, ]; const KEY_RE = /^[a-z][a-zA-Z0-9_]*(?:\.[a-zA-Z0-9_:-]+)+$/; diff --git a/client/src/api/assistant.ts b/client/src/api/assistant.ts index e44534315..57ad95427 100644 --- a/client/src/api/assistant.ts +++ b/client/src/api/assistant.ts @@ -19,6 +19,7 @@ import { type AssistantDecisionsRequest, type AssistantErrorCode, type AssistantShareRequest, + type AssistantTakeProposalRequest, type AssistantThreadListResponse, type AssistantThreadResponse, type AssistantUndoResponse, @@ -122,6 +123,13 @@ export const assistantApi = { body: AssistantAddFoundPlaceRequest ): Promise => apiClient.post(`${tripBase(tripId)}/threads/${threadId}/found-places`, body).then((r) => r.data), + // A proposal an answer showed as a card ("Plan this"): answers like a found place, with the message holding it. + takeProposal: ( + tripId: number, + threadId: number, + body: AssistantTakeProposalRequest + ): Promise => + apiClient.post(`${tripBase(tripId)}/threads/${threadId}/proposals`, body).then((r) => r.data), // An answer posted to the trip chat, marked as shared from the assistant; the client's socket id skips the echo. share: ( tripId: number, diff --git a/client/src/components/Assistant/AssistantChangeCard.test.tsx b/client/src/components/Assistant/AssistantChangeCard.test.tsx index 27db4bcd1..fb262ce4c 100644 --- a/client/src/components/Assistant/AssistantChangeCard.test.tsx +++ b/client/src/components/Assistant/AssistantChangeCard.test.tsx @@ -65,6 +65,7 @@ const pending = (id: string, subject: string): ChangeItem => ({ preview: preview(id, subject), applied: null, state: 'pending', + card: null, }); const onTheMap = (id: string, subject: string, effect = PANTHEON): ChangeItem => ({ @@ -74,7 +75,7 @@ const onTheMap = (id: string, subject: string, effect = PANTHEON): ChangeItem => function receipt(id: string, undoUntil: string | null): ChangeItem { const applied: AssistantApplied = { toolCallId: id, entity: 'place', ids: [9], dayId: 3, undoUntil }; - return { toolCallId: id, preview: preview(id, 'Kinkaku-ji'), applied, state: 'applied' }; + return { toolCallId: id, preview: preview(id, 'Kinkaku-ji'), applied, state: 'applied', card: null }; } function renderCard(items: ChangeItem[], view: Partial = {}) { @@ -173,12 +174,12 @@ describe('AssistantChangeCard: the receipt', () => { it('FE-AI-CARD-005: an applied change shows on the map and can be undone until its window closes', () => { vi.useFakeTimers({ shouldAdvanceTime: true }); vi.setSystemTime(new Date('2026-10-21T08:00:00.000Z')); - const onShowOnMap = vi.fn(); - renderCard([receipt('c1', '2026-10-21T08:15:00.000Z')], { onShowOnMap }); + const onOpen = vi.fn(); + renderCard([receipt('c1', '2026-10-21T08:15:00.000Z')], { onOpen }); expect(screen.getByRole('img', { name: 'Applied' })).toBeInTheDocument(); fireEvent.click(screen.getByRole('button', { name: 'Show on map' })); - expect(onShowOnMap).toHaveBeenCalledWith(expect.objectContaining({ toolCallId: 'c1', dayId: 3 })); + expect(onOpen).toHaveBeenCalledWith({ kind: 'map', placeId: 9, dayId: null }); expect(screen.getByRole('button', { name: 'Undo' })).toBeInTheDocument(); act(() => { @@ -259,12 +260,12 @@ describe('AssistantChangeCard: on the map', () => { it('FE-AI-CARD-011: on the phone the card hops to the map and frames what it would change', () => { plannerHere(); - const onShowOnMap = vi.fn(); - const first = renderCard([onTheMap('c1', 'Pantheon')], { onShowOnMap }); + const onOpen = vi.fn(); + const first = renderCard([onTheMap('c1', 'Pantheon')], { onOpen }); expect(screen.queryByRole('button', { name: 'View on map' })).toBeNull(); first.unmount(); - renderCard([onTheMap('c1', 'Pantheon')], { variant: 'fullscreen', onShowOnMap }); + renderCard([onTheMap('c1', 'Pantheon')], { variant: 'fullscreen', onOpen }); fireEvent.click(screen.getByRole('button', { name: 'View on map' })); expect(requestCamera).toHaveBeenCalledWith( TRIP, @@ -285,14 +286,14 @@ describe('AssistantChangeCard: the applied block', () => { it('FE-AI-CARD-012: before and after are there only for the block this session can compare, beside a map', () => { compare('c1'); - const onShowOnMap = vi.fn(); - const first = renderCard([receipt('c1', null), receipt('c2', null)], { onShowOnMap }); + const onOpen = vi.fn(); + const first = renderCard([receipt('c1', null), receipt('c2', null)], { onOpen }); expect(screen.getByRole('button', { name: 'After' })).toHaveAttribute('aria-pressed', 'true'); fireEvent.click(screen.getByRole('button', { name: 'Before' })); expect(setCompare).toHaveBeenCalledWith(TRIP, 'before'); first.unmount(); - const other = renderCard([receipt('c7', null), receipt('c8', null)], { onShowOnMap }); + const other = renderCard([receipt('c7', null), receipt('c8', null)], { onOpen }); expect(screen.queryByRole('button', { name: 'Before' })).toBeNull(); other.unmount(); diff --git a/client/src/components/Assistant/AssistantChangeCard.tsx b/client/src/components/Assistant/AssistantChangeCard.tsx index 5ed5e28ed..ddc631b81 100644 --- a/client/src/components/Assistant/AssistantChangeCard.tsx +++ b/client/src/components/Assistant/AssistantChangeCard.tsx @@ -1,25 +1,4 @@ -import type { AssistantApplied, AssistantChangePreview, AssistantChangeVerbKey } from '@trek/shared'; -import { - CalendarArrowUp, - CalendarMinus, - CalendarPlus, - Check, - CircleSlash, - ListTodo, - LoaderCircle, - Luggage, - MapPin, - MapPinPlus, - NotebookPen, - PencilLine, - Plus, - StickyNote, - Ticket, - Trash2, - TriangleAlert, - Undo2, - Wallet, -} from 'lucide-react'; +import { Check, LoaderCircle, MapPin, Undo2 } from 'lucide-react'; import { type ReactNode, useEffect, useMemo, useState } from 'react'; import { useTranslation } from '../../i18n'; @@ -28,14 +7,15 @@ import { chatOf, useAssistantStore } from '../../store/assistantStore'; import { useTripStore } from '../../store/tripStore'; import { useToast } from '../shared/Toast'; import { Tooltip } from '../shared/Tooltip'; -import AssistantChangeFields from './AssistantChangeFields'; import AssistantCompareSwitch from './AssistantCompareSwitch'; import AssistantFitCheck from './AssistantFitCheck'; import AssistantWeekOverview from './AssistantWeekOverview'; -import { type ChangeItem, type ChangeState, undoLeftMs } from './assistantParts'; +import { type ChangeItem, undoLeftMs } from './assistantParts'; import { useAssistantView } from './assistantViewContext'; +import { ChangeRows } from './cards/ChangeCardSlots'; +import { ICON_BUTTON } from './cards/parts/assistantTones'; +import { useChangeExclusions } from './cards/useChangeExclusions'; import { changePoints, type DayChange } from './dayAfterModel'; -import { useChangeHover } from './useChangeHover'; import { useWeekDays } from './useWeekDays'; /** @@ -49,7 +29,8 @@ import { useWeekDays } from './useWeekDays'; * Every change wears its kind: a tinted tile with the icon of what it touches * and a badge naming the verb, in the tone of what happens (green adds, blue * changes, amber moves, red takes away). Its fields sit as badges holding a - * label badge, so a row of them reads at a glance. + * label badge, so a row of them reads at a glance. The rows themselves, and a + * change that carries a card of its own, are drawn in cards/ChangeCardSlots. * * While it waits, the card shows the days it touches as they would read * afterwards, and each row lights its pin on the map (and the pin its row). @@ -57,106 +38,6 @@ import { useWeekDays } from './useWeekDays'; * map, and taking the whole block back at once. */ -type Tone = 'success' | 'info' | 'warning' | 'danger'; - -const TILE: Record = { - success: 'bg-success-soft text-success', - info: 'bg-info-soft text-info', - warning: 'bg-warning-soft text-warning', - danger: 'bg-danger-soft text-danger', -}; - -/** What each kind of change looks like. A table, so a new verb fails to compile until it has a look. */ -const VERB_LOOK: Record = { - addPlace: { Icon: MapPinPlus, tone: 'success' }, - addPlaceToDay: { Icon: CalendarPlus, tone: 'success' }, - updatePlace: { Icon: PencilLine, tone: 'info' }, - assignPlace: { Icon: CalendarPlus, tone: 'success' }, - moveAssignment: { Icon: CalendarArrowUp, tone: 'warning' }, - removeFromDay: { Icon: CalendarMinus, tone: 'danger' }, - addDayNote: { Icon: StickyNote, tone: 'success' }, - updateDayNote: { Icon: StickyNote, tone: 'info' }, - addPackingItem: { Icon: Luggage, tone: 'success' }, - updatePackingItem: { Icon: Luggage, tone: 'info' }, - addTodo: { Icon: ListTodo, tone: 'success' }, - addBudgetItem: { Icon: Wallet, tone: 'success' }, - updateBudgetItem: { Icon: Wallet, tone: 'info' }, - addReservation: { Icon: Ticket, tone: 'success' }, - importBooking: { Icon: Ticket, tone: 'success' }, - rememberNote: { Icon: NotebookPen, tone: 'info' }, - addTour: { Icon: MapPinPlus, tone: 'success' }, - updateTour: { Icon: PencilLine, tone: 'info' }, - importTour: { Icon: Plus, tone: 'success' }, - genericCreate: { Icon: Plus, tone: 'success' }, - genericUpdate: { Icon: PencilLine, tone: 'info' }, - genericRemove: { Icon: Trash2, tone: 'danger' }, -}; - -/** How a decided change reads: one quiet mark, its words in the tooltip. */ -const RECEIPT: Record, { labelKey: string; Icon: typeof Check; tone: string }> = { - applying: { labelKey: 'assistant.change.applying', Icon: LoaderCircle, tone: 'text-content-muted' }, - applied: { labelKey: 'assistant.change.applied', Icon: Check, tone: 'text-success' }, - failed: { labelKey: 'assistant.change.failed', Icon: TriangleAlert, tone: 'text-danger' }, - discarded: { labelKey: 'assistant.change.discarded', Icon: CircleSlash, tone: 'text-content-faint' }, - expired: { labelKey: 'assistant.change.expired', Icon: CircleSlash, tone: 'text-content-faint' }, -}; - -const ICON_BUTTON = - 'flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-md text-content-muted transition-colors hover:bg-surface-hover hover:text-content disabled:opacity-50'; - -function KindTile({ - verbKey, - size = 'md', - dimmed = false, -}: { - verbKey: AssistantChangeVerbKey | null; - size?: 'sm' | 'md'; - dimmed?: boolean; -}) { - const box = size === 'sm' ? 'h-7 w-7 rounded-md' : 'h-8 w-8 rounded-lg'; - if (!verbKey) return