diff --git a/apps/admin/package.json b/apps/admin/package.json
index 8a5e7a5c1d..7f55e37531 100644
--- a/apps/admin/package.json
+++ b/apps/admin/package.json
@@ -1,6 +1,6 @@
{
"name": "packrat-admin-app",
- "version": "2.0.22",
+ "version": "2.0.23",
"private": true,
"scripts": {
"build": "next build",
diff --git a/apps/expo/app.config.ts b/apps/expo/app.config.ts
index 9ed48acde2..ea6c39bc6d 100644
--- a/apps/expo/app.config.ts
+++ b/apps/expo/app.config.ts
@@ -37,7 +37,7 @@ export default (): ExpoConfig =>
{
name: getAppName(),
slug: 'packrat',
- version: '2.0.22',
+ version: '2.0.23',
scheme: 'packrat',
web: {
bundler: 'metro',
diff --git a/apps/expo/features/guides/screens/GuidesListScreen.tsx b/apps/expo/features/guides/screens/GuidesListScreen.tsx
index 0dec568ac1..355c82ff03 100644
--- a/apps/expo/features/guides/screens/GuidesListScreen.tsx
+++ b/apps/expo/features/guides/screens/GuidesListScreen.tsx
@@ -7,7 +7,7 @@ import { useTranslation } from 'expo-app/lib/hooks/useTranslation';
import { asNonNullableRef } from 'expo-app/lib/utils/asNonNullableRef';
import { useRouter } from 'expo-router';
import { useCallback, useRef, useState } from 'react';
-import { ActivityIndicator, FlatList, RefreshControl, ScrollView, View } from 'react-native';
+import { ActivityIndicator, FlatList, RefreshControl, View } from 'react-native';
import { GuideCard } from '../components/GuideCard';
import { useGuideCategories, useGuides, useSearchGuides } from '../hooks';
import type { Guide } from '../types';
@@ -133,29 +133,45 @@ export const GuidesListScreen = () => {
}
return (
-
-
- {guides.length > 0 && (
-
- {guides.length} {guides.length === 1 ? t('guides.result') : t('guides.results')}
-
- )}
-
-
- {guides.map((guide: Guide) => (
-
- handleGuidePress(guide)} />
+ item.id}
+ renderItem={({ item }) => (
+
+ handleGuidePress(item)} />
- ))}
-
- {guides.length === 0 && (
+ )}
+ ListHeaderComponent={
+ guides.length > 0 ? (
+
+
+ {guides.length} {guides.length === 1 ? t('guides.result') : t('guides.results')}
+
+
+ ) : null
+ }
+ ListEmptyComponent={
{t('guides.noGuidesFound', { query: searchQuery })}
- )}
-
+ }
+ ListFooterComponent={
+ isFetchingNextPageSearch ? (
+
+
+
+ ) : null
+ }
+ onEndReached={() => {
+ if (hasNextPageSearch && !isFetchingNextPageSearch) {
+ fetchNextPageSearch();
+ }
+ }}
+ onEndReachedThreshold={0.5}
+ contentContainerStyle={{ paddingBottom: 40, flexGrow: 1 }}
+ />
);
};
diff --git a/apps/expo/features/pack-templates/screens/PackTemplateListScreen.tsx b/apps/expo/features/pack-templates/screens/PackTemplateListScreen.tsx
index c3ab95ba10..0802d0f957 100644
--- a/apps/expo/features/pack-templates/screens/PackTemplateListScreen.tsx
+++ b/apps/expo/features/pack-templates/screens/PackTemplateListScreen.tsx
@@ -229,7 +229,7 @@ export function PackTemplateListScreen() {
)}
- stickyHeaderIndices={[0]}
+ stickyHeaderIndices={listHeader() ? [0] : undefined}
stickyHeaderHiddenOnScroll
ListHeaderComponent={listHeader()}
ListEmptyComponent={
diff --git a/apps/expo/features/trips/components/TripForm.tsx b/apps/expo/features/trips/components/TripForm.tsx
index 152efb9df2..74f59f0595 100644
--- a/apps/expo/features/trips/components/TripForm.tsx
+++ b/apps/expo/features/trips/components/TripForm.tsx
@@ -115,7 +115,7 @@ export const TripForm = ({ trip }: { trip?: Trip }) => {
const submitData = {
...value,
location: location ?? value.location,
- packId: value.packId ?? undefined,
+ packId: value.packId === '' ? undefined : (value.packId ?? undefined),
};
try {
if (isEditingExistingTrip) {
diff --git a/apps/expo/lib/hooks/useKeyboardHideBlur.tsx b/apps/expo/lib/hooks/useKeyboardHideBlur.tsx
index 5744f55e7f..2f0ef2bf00 100644
--- a/apps/expo/lib/hooks/useKeyboardHideBlur.tsx
+++ b/apps/expo/lib/hooks/useKeyboardHideBlur.tsx
@@ -6,9 +6,20 @@ import { Keyboard } from 'react-native';
* Useful for fixing keyboard behavior issues on Android.
*
* @param textInputRef - Ref to the TextInput or SearchInput component
+ * @param options - Optional configuration
+ * @param options.enabled - Whether the hook should be active (default: true)
*/
-export function useKeyboardHideBlur(textInputRef: React.RefObject<{ blur?: () => void }>) {
+export function useKeyboardHideBlur(
+ textInputRef: React.RefObject<{ blur?: () => void } | null>,
+ options?: { enabled?: boolean },
+) {
+ const { enabled = true } = options ?? {};
+
useEffect(() => {
+ if (!enabled) {
+ return;
+ }
+
const keyboardDidHideCallback = () => {
if (textInputRef.current?.blur) {
textInputRef.current.blur();
@@ -23,5 +34,5 @@ export function useKeyboardHideBlur(textInputRef: React.RefObject<{ blur?: () =>
return () => {
keyboardDidHideSubscription?.remove();
};
- }, [textInputRef]);
+ }, [textInputRef, enabled]);
}
diff --git a/apps/expo/package.json b/apps/expo/package.json
index 9c2655ee02..f6cf4023a7 100644
--- a/apps/expo/package.json
+++ b/apps/expo/package.json
@@ -1,6 +1,6 @@
{
"name": "packrat-expo-app",
- "version": "2.0.22",
+ "version": "2.0.23",
"private": true,
"main": "expo-router/entry",
"scripts": {
diff --git a/apps/guides/package.json b/apps/guides/package.json
index 064d02cb51..ff88d1fbb8 100644
--- a/apps/guides/package.json
+++ b/apps/guides/package.json
@@ -1,6 +1,6 @@
{
"name": "packrat-guides-app",
- "version": "2.0.22",
+ "version": "2.0.23",
"private": true,
"scripts": {
"build": "bun run build-content && next build",
diff --git a/apps/landing/package.json b/apps/landing/package.json
index 7819a6e559..a83bb1fc33 100644
--- a/apps/landing/package.json
+++ b/apps/landing/package.json
@@ -1,6 +1,6 @@
{
"name": "packrat-landing-app",
- "version": "2.0.22",
+ "version": "2.0.23",
"private": true,
"scripts": {
"build": "next build",
diff --git a/bun.lock b/bun.lock
index 63be0cdbea..7103e09422 100644
--- a/bun.lock
+++ b/bun.lock
@@ -19,7 +19,7 @@
},
"apps/admin": {
"name": "packrat-admin-app",
- "version": "2.0.22",
+ "version": "2.0.23",
"dependencies": {
"@packrat/web-ui": "workspace:*",
"@radix-ui/react-alert-dialog": "catalog:",
@@ -59,7 +59,7 @@
},
"apps/expo": {
"name": "packrat-expo-app",
- "version": "2.0.22",
+ "version": "2.0.23",
"dependencies": {
"@ai-sdk/react": "^2.0.11",
"@expo/react-native-action-sheet": "^4.1.1",
@@ -182,7 +182,7 @@
},
"apps/guides": {
"name": "packrat-guides-app",
- "version": "2.0.22",
+ "version": "2.0.23",
"dependencies": {
"@ai-sdk/openai": "^2.0.11",
"@hookform/resolvers": "^3.10.0",
@@ -265,7 +265,7 @@
},
"apps/landing": {
"name": "packrat-landing-app",
- "version": "2.0.22",
+ "version": "2.0.23",
"dependencies": {
"@emotion/is-prop-valid": "^1.3.1",
"@hookform/resolvers": "^3.10.0",
@@ -330,7 +330,7 @@
},
"packages/analytics": {
"name": "@packrat/analytics",
- "version": "2.0.22",
+ "version": "2.0.23",
"dependencies": {
"@duckdb/node-api": "1.5.0-r.1",
"@packrat/env": "workspace:*",
@@ -346,7 +346,7 @@
},
"packages/api": {
"name": "@packrat/api",
- "version": "2.0.22",
+ "version": "2.0.23",
"dependencies": {
"@ai-sdk/google": "^2.0.62",
"@ai-sdk/openai": "^2.0.11",
@@ -400,18 +400,18 @@
},
"packages/api-client": {
"name": "@packrat/api-client",
- "version": "2.0.22",
+ "version": "2.0.23",
"devDependencies": {
"typescript": "catalog:",
},
},
"packages/checks": {
"name": "@packrat/checks",
- "version": "2.0.22",
+ "version": "2.0.23",
},
"packages/cli": {
"name": "@packrat/cli",
- "version": "2.0.22",
+ "version": "2.0.23",
"bin": {
"packrat": "./src/index.ts",
},
@@ -431,25 +431,25 @@
},
"packages/config": {
"name": "@packrat/config",
- "version": "2.0.22",
+ "version": "2.0.23",
},
"packages/env": {
"name": "@packrat/env",
- "version": "2.0.22",
+ "version": "2.0.23",
"dependencies": {
"zod": "catalog:",
},
},
"packages/guards": {
"name": "@packrat/guards",
- "version": "2.0.22",
+ "version": "2.0.23",
"dependencies": {
"radash": "catalog:",
},
},
"packages/mcp": {
"name": "@packrat/mcp",
- "version": "2.0.22",
+ "version": "2.0.23",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.11.0",
"@packrat/api-client": "workspace:*",
@@ -467,14 +467,14 @@
},
"packages/ui": {
"name": "@packrat/ui",
- "version": "2.0.22",
+ "version": "2.0.23",
"dependencies": {
"@packrat-ai/nativewindui": "^2.0.2",
},
},
"packages/web-ui": {
"name": "@packrat/web-ui",
- "version": "2.0.22",
+ "version": "2.0.23",
"dependencies": {
"@packrat/guards": "workspace:*",
"@radix-ui/react-accordion": "catalog:",
@@ -4406,11 +4406,11 @@
"@modelcontextprotocol/sdk/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
- "@packrat/analytics/@types/bun": ["@types/bun@1.3.12", "", { "dependencies": { "bun-types": "1.3.12" } }, "sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A=="],
+ "@packrat/analytics/@types/bun": ["@types/bun@1.3.13", "", { "dependencies": { "bun-types": "1.3.13" } }, "sha512-9fqXWk5YIHGGnUau9TEi+qdlTYDAnOj+xLCmSTwXfAIqXr2x4tytJb43E9uCvt09zJURKXwAtkoH4nLQfzeTXw=="],
- "@packrat/api/@types/bun": ["@types/bun@1.3.12", "", { "dependencies": { "bun-types": "1.3.12" } }, "sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A=="],
+ "@packrat/api/@types/bun": ["@types/bun@1.3.13", "", { "dependencies": { "bun-types": "1.3.13" } }, "sha512-9fqXWk5YIHGGnUau9TEi+qdlTYDAnOj+xLCmSTwXfAIqXr2x4tytJb43E9uCvt09zJURKXwAtkoH4nLQfzeTXw=="],
- "@packrat/cli/@types/bun": ["@types/bun@1.3.12", "", { "dependencies": { "bun-types": "1.3.12" } }, "sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A=="],
+ "@packrat/cli/@types/bun": ["@types/bun@1.3.13", "", { "dependencies": { "bun-types": "1.3.13" } }, "sha512-9fqXWk5YIHGGnUau9TEi+qdlTYDAnOj+xLCmSTwXfAIqXr2x4tytJb43E9uCvt09zJURKXwAtkoH4nLQfzeTXw=="],
"@pnpm/network.ca-file/graceful-fs": ["graceful-fs@4.2.10", "", {}, "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="],
@@ -5124,11 +5124,11 @@
"@manypkg/tools/tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
- "@packrat/analytics/@types/bun/bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="],
+ "@packrat/analytics/@types/bun/bun-types": ["bun-types@1.3.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-QXKeHLlOLqQX9LgYaHJfzdBaV21T63HhFJnvuRCcjZiaUDpbs5ED1MgxbMra71CsryN/1dAoXuJJJwIv/2drVA=="],
- "@packrat/api/@types/bun/bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="],
+ "@packrat/api/@types/bun/bun-types": ["bun-types@1.3.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-QXKeHLlOLqQX9LgYaHJfzdBaV21T63HhFJnvuRCcjZiaUDpbs5ED1MgxbMra71CsryN/1dAoXuJJJwIv/2drVA=="],
- "@packrat/cli/@types/bun/bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="],
+ "@packrat/cli/@types/bun/bun-types": ["bun-types@1.3.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-QXKeHLlOLqQX9LgYaHJfzdBaV21T63HhFJnvuRCcjZiaUDpbs5ED1MgxbMra71CsryN/1dAoXuJJJwIv/2drVA=="],
"@react-native/babel-preset/@babel/plugin-transform-classes/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="],
diff --git a/docs/android-keyboard-focus-prevention-strategies.md b/docs/android-keyboard-focus-prevention-strategies.md
index e834feacfd..db114e532f 100644
--- a/docs/android-keyboard-focus-prevention-strategies.md
+++ b/docs/android-keyboard-focus-prevention-strategies.md
@@ -28,13 +28,14 @@ import { TextInput } from 'react-native'; // FORBIDDEN
```typescript
// For any new input-related components, always include the hook
import { useKeyboardHideBlur } from 'expo-app/lib/hooks/useKeyboardHideBlur';
+import { TextInput } from 'react-native';
export const CustomInput = forwardRef((props, ref) => {
- const inputRef = useRef(null);
-
+ const inputRef = useRef(null);
+
// REQUIRED: Apply keyboard hide blur fix
useKeyboardHideBlur(inputRef);
-
+
useImperativeHandle(ref, () => inputRef.current);
return ;
});
@@ -58,7 +59,7 @@ export const WrappedThirdPartyInput = forwardRef((props, ref) => {
#### 2.1 Code Review Checklist
**Mandatory checks for any PR containing input elements:**
-- [ ] Does the component use the enhanced `TextInput`/`SearchInput` from `expo-app/components/?
+- [ ] Does the component use the enhanced `TextInput`/`SearchInput` from `expo-app/components/`?
- [ ] Is there any direct import from `react-native` for TextInput?
- [ ] If creating a new input component, does it use `useKeyboardHideBlur`?
- [ ] Are there any third-party input components that need wrapping?
@@ -70,10 +71,7 @@ Add to ESLint config:
```json
{
"rules": {
- "no-direct-textinput-import": {
- "rule": "error",
- "message": "Use enhanced TextInput component instead of direct react-native import"
- }
+ "no-direct-textinput-import": "error"
}
}
```
@@ -133,12 +131,10 @@ interface EnhancedTextInputProps extends TextInputProps {
export const EnhancedTextInput = forwardRef(
({ autoKeyboardDismiss = true, ...props }, ref) => {
const inputRef = useRef(null);
-
- // Conditional application for rare edge cases
- if (autoKeyboardDismiss) {
- useKeyboardHideBlur(inputRef);
- }
-
+
+ // Always call hook unconditionally, use enabled flag to control behavior
+ useKeyboardHideBlur(inputRef, { enabled: autoKeyboardDismiss });
+
useImperativeHandle(ref, () => inputRef.current!);
return ;
}
diff --git a/docs/android-keyboard-prevention-implementation-summary.md b/docs/android-keyboard-prevention-implementation-summary.md
index 88c012743a..a87d6e8520 100644
--- a/docs/android-keyboard-prevention-implementation-summary.md
+++ b/docs/android-keyboard-prevention-implementation-summary.md
@@ -48,7 +48,7 @@ The lefthook configuration runs Biome linting automatically on commit. No additi
Your codebase already follows good patterns:
- ✅ Enhanced `TextInput` and `SearchInput` components exist
- ✅ `useKeyboardHideBlur` hook is properly implemented
-- ✅ No direct React Native TextInput imports found
+- ✅ Migration complete as of 2026-04-21 - all TextInput imports updated to use enhanced components
- ✅ Consistent component patterns in use
### No Breaking Changes
diff --git a/docs/solutions/ui-bugs/android-textinput-keyboard-focus-loss.md b/docs/solutions/ui-bugs/android-textinput-keyboard-focus-loss.md
index 5f5426fc12..7af27b181c 100644
--- a/docs/solutions/ui-bugs/android-textinput-keyboard-focus-loss.md
+++ b/docs/solutions/ui-bugs/android-textinput-keyboard-focus-loss.md
@@ -70,11 +70,24 @@ import { Keyboard } from 'react-native';
* Useful for fixing keyboard behavior issues on Android.
*
* @param textInputRef - Ref to the TextInput or SearchInput component
+ * @param options - Optional configuration
+ * @param options.enabled - Whether the hook should be active (default: true)
*/
-export function useKeyboardHideBlur(textInputRef: React.RefObject) {
+export function useKeyboardHideBlur(
+ textInputRef: React.RefObject<{ blur?: () => void } | null>,
+ options?: { enabled?: boolean },
+) {
+ const { enabled = true } = options ?? {};
+
useEffect(() => {
+ if (!enabled) {
+ return;
+ }
+
const keyboardDidHideCallback = () => {
- textInputRef.current?.blur();
+ if (textInputRef.current?.blur) {
+ textInputRef.current.blur();
+ }
};
const keyboardDidHideSubscription = Keyboard.addListener(
@@ -85,7 +98,7 @@ export function useKeyboardHideBlur(textInputRef: React.RefObject) {
return () => {
keyboardDidHideSubscription?.remove();
};
- }, [textInputRef]);
+ }, [textInputRef, enabled]);
}
```
@@ -95,9 +108,11 @@ export function useKeyboardHideBlur(textInputRef: React.RefObject) {
```tsx
// apps/expo/components/TextInput.tsx
+import { assertPresent } from '@packrat/guards';
+import { useKeyboardHideBlur } from 'expo-app/lib/hooks/useKeyboardHideBlur';
+import { asNonNullableRef } from 'expo-app/lib/utils/asNonNullableRef';
import { forwardRef, useImperativeHandle, useRef } from 'react';
import { TextInput as RNTextInput, type TextInputProps } from 'react-native';
-import { useKeyboardHideBlur } from 'expo-app/lib/hooks/useKeyboardHideBlur';
/**
* Enhanced TextInput component that automatically handles keyboard hide blur fix.
@@ -105,13 +120,16 @@ import { useKeyboardHideBlur } from 'expo-app/lib/hooks/useKeyboardHideBlur';
*/
export const TextInput = forwardRef((props, ref) => {
const textInputRef = useRef(null);
-
+
// Apply keyboard hide blur fix
- useKeyboardHideBlur(textInputRef);
-
+ useKeyboardHideBlur(asNonNullableRef(textInputRef));
+
// Forward ref methods to the internal ref
- useImperativeHandle(ref, () => textInputRef.current!);
-
+ useImperativeHandle(ref, () => {
+ assertPresent(textInputRef.current);
+ return textInputRef.current;
+ }, []);
+
return ;
});
@@ -122,23 +140,31 @@ TextInput.displayName = 'TextInput';
```tsx
// apps/expo/components/SearchInput.tsx
-import { forwardRef, useImperativeHandle, useRef } from 'react';
+import { assertPresent } from '@packrat/guards';
import { SearchInput as NativeWindUISearchInput } from '@packrat/ui/nativewindui';
import { useKeyboardHideBlur } from 'expo-app/lib/hooks/useKeyboardHideBlur';
+import { asNonNullableRef } from 'expo-app/lib/utils/asNonNullableRef';
+import { forwardRef, useImperativeHandle, useRef } from 'react';
/**
* Enhanced SearchInput component that automatically handles keyboard hide blur fix.
* Drop-in replacement for NativeWindUI's SearchInput with built-in Android keyboard behavior fix.
*/
-export const SearchInput = forwardRef>((props, ref) => {
- const searchInputRef = useRef(null);
-
+export const SearchInput = forwardRef<
+ React.ComponentRef,
+ React.ComponentProps
+>((props, ref) => {
+ const searchInputRef = useRef>(null);
+
// Apply keyboard hide blur fix
- useKeyboardHideBlur(searchInputRef);
-
+ useKeyboardHideBlur(asNonNullableRef(searchInputRef));
+
// Forward ref methods to the internal ref
- useImperativeHandle(ref, () => searchInputRef.current);
-
+ useImperativeHandle(ref, () => {
+ assertPresent(searchInputRef.current);
+ return searchInputRef.current;
+ }, []);
+
return ;
});
diff --git a/package.json b/package.json
index 67ca422219..b7b940626b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "packrat-monorepo",
- "version": "2.0.22",
+ "version": "2.0.23",
"workspaces": [
"apps/*",
"packages/*"
diff --git a/packages/analytics/package.json b/packages/analytics/package.json
index acc2397bd3..deada916c8 100644
--- a/packages/analytics/package.json
+++ b/packages/analytics/package.json
@@ -1,6 +1,6 @@
{
"name": "@packrat/analytics",
- "version": "2.0.22",
+ "version": "2.0.23",
"private": true,
"type": "module",
"scripts": {
diff --git a/packages/api-client/package.json b/packages/api-client/package.json
index f404be3a77..460e3a5584 100644
--- a/packages/api-client/package.json
+++ b/packages/api-client/package.json
@@ -1,6 +1,6 @@
{
"name": "@packrat/api-client",
- "version": "2.0.22",
+ "version": "2.0.23",
"private": true,
"description": "PackRat typed API client — authenticated HTTP client with error handling and MCP result helpers",
"type": "module",
diff --git a/packages/api/container_src/package.json b/packages/api/container_src/package.json
index 01b7d02499..fce743949b 100644
--- a/packages/api/container_src/package.json
+++ b/packages/api/container_src/package.json
@@ -1,6 +1,6 @@
{
"name": "container",
- "version": "2.0.22",
+ "version": "2.0.23",
"type": "module",
"dependencies": {
"@aws-sdk/client-s3": "^3.0.0",
diff --git a/packages/api/package.json b/packages/api/package.json
index 8fc2527c4b..780335248e 100644
--- a/packages/api/package.json
+++ b/packages/api/package.json
@@ -1,6 +1,6 @@
{
"name": "@packrat/api",
- "version": "2.0.22",
+ "version": "2.0.23",
"scripts": {
"check-types": "tsc --noEmit",
"check-types-watch": "tsc --noEmit --watch",
diff --git a/packages/checks/package.json b/packages/checks/package.json
index 3ef42b55dd..901d72f3a3 100644
--- a/packages/checks/package.json
+++ b/packages/checks/package.json
@@ -1,6 +1,6 @@
{
"name": "@packrat/checks",
- "version": "2.0.22",
+ "version": "2.0.23",
"private": true,
"type": "module",
"scripts": {
diff --git a/packages/cli/package.json b/packages/cli/package.json
index cc504e6ed4..2da074fafe 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@packrat/cli",
- "version": "2.0.22",
+ "version": "2.0.23",
"private": true,
"type": "module",
"bin": {
diff --git a/packages/config/package.json b/packages/config/package.json
index 92fa2d1ad1..c61eae76ee 100644
--- a/packages/config/package.json
+++ b/packages/config/package.json
@@ -1,6 +1,6 @@
{
"name": "@packrat/config",
- "version": "2.0.22",
+ "version": "2.0.23",
"private": true,
"type": "module",
"exports": {
diff --git a/packages/env/package.json b/packages/env/package.json
index 89685a0bdb..7b33a175f8 100644
--- a/packages/env/package.json
+++ b/packages/env/package.json
@@ -1,6 +1,6 @@
{
"name": "@packrat/env",
- "version": "2.0.22",
+ "version": "2.0.23",
"private": true,
"type": "module",
"exports": {
diff --git a/packages/guards/package.json b/packages/guards/package.json
index ea7faa6479..7d5140be8d 100644
--- a/packages/guards/package.json
+++ b/packages/guards/package.json
@@ -1,6 +1,6 @@
{
"name": "@packrat/guards",
- "version": "2.0.22",
+ "version": "2.0.23",
"private": true,
"type": "module",
"exports": {
diff --git a/packages/mcp/package.json b/packages/mcp/package.json
index b80681b7f7..24afef7754 100644
--- a/packages/mcp/package.json
+++ b/packages/mcp/package.json
@@ -1,6 +1,6 @@
{
"name": "@packrat/mcp",
- "version": "2.0.22",
+ "version": "2.0.23",
"private": true,
"description": "PackRat MCP Server — outdoor adventure planning via Model Context Protocol",
"scripts": {
diff --git a/packages/ui/package.json b/packages/ui/package.json
index be3b727eac..b9ff4b6041 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -1,6 +1,6 @@
{
"name": "@packrat/ui",
- "version": "2.0.22",
+ "version": "2.0.23",
"private": true,
"dependencies": {
"@packrat-ai/nativewindui": "^2.0.2"
diff --git a/packages/web-ui/package.json b/packages/web-ui/package.json
index 4a607ca5cc..08a2b64450 100644
--- a/packages/web-ui/package.json
+++ b/packages/web-ui/package.json
@@ -1,6 +1,6 @@
{
"name": "@packrat/web-ui",
- "version": "2.0.22",
+ "version": "2.0.23",
"private": true,
"type": "module",
"exports": {