mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-16 14:22:42 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f517493591 | ||
|
|
fb74f766c8 | ||
|
|
e268d1a894 | ||
|
|
b5f5832214 |
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 0.5.1 - 2026-08-23
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed multiline composers stopping resizing after workspace and agent transitions on iOS and Android ([#3740](https://github.com/getpaseo/paseo/pull/3740))
|
||||
|
||||
## 0.5.0 - 2026-08-23
|
||||
|
||||
### Added
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
sha256-umufh5lfrLUsnvRLzOzw+BYaE/DgH/7x6uGnDwdM4Gk=
|
||||
sha256-mF8N1sBkSt2/ZgtB511lqv1knlQ0lmicZxsoucbWZfE=
|
||||
|
||||
Generated
+25
-25
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "paseo",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "paseo",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"hasInstallScript": true,
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"workspaces": [
|
||||
@@ -36140,7 +36140,7 @@
|
||||
},
|
||||
"packages/app": {
|
||||
"name": "@getpaseo/app",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"dependencies": {
|
||||
"@codemirror/commands": "6.10.4",
|
||||
"@codemirror/language": "6.12.4",
|
||||
@@ -37192,12 +37192,12 @@
|
||||
},
|
||||
"packages/cli": {
|
||||
"name": "@getpaseo/cli",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"dependencies": {
|
||||
"@clack/prompts": "^1.0.0",
|
||||
"@getpaseo/client": "0.5.0",
|
||||
"@getpaseo/protocol": "0.5.0",
|
||||
"@getpaseo/server": "0.5.0",
|
||||
"@getpaseo/client": "0.5.1",
|
||||
"@getpaseo/protocol": "0.5.1",
|
||||
"@getpaseo/server": "0.5.1",
|
||||
"chalk": "^5.3.0",
|
||||
"commander": "^12.0.0",
|
||||
"mime-types": "^2.1.35",
|
||||
@@ -37444,10 +37444,10 @@
|
||||
},
|
||||
"packages/client": {
|
||||
"name": "@getpaseo/client",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"dependencies": {
|
||||
"@getpaseo/protocol": "0.5.0",
|
||||
"@getpaseo/relay": "0.5.0",
|
||||
"@getpaseo/protocol": "0.5.1",
|
||||
"@getpaseo/relay": "0.5.1",
|
||||
"zod": "^4.4.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -37458,7 +37458,7 @@
|
||||
},
|
||||
"packages/desktop": {
|
||||
"name": "@getpaseo/desktop",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@getpaseo/cli": "*",
|
||||
@@ -37701,7 +37701,7 @@
|
||||
},
|
||||
"packages/expo-two-way-audio": {
|
||||
"name": "@getpaseo/expo-two-way-audio",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.14",
|
||||
@@ -38597,7 +38597,7 @@
|
||||
},
|
||||
"packages/highlight": {
|
||||
"name": "@getpaseo/highlight",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"dependencies": {
|
||||
"@codemirror/language": "6.12.4",
|
||||
"@codemirror/legacy-modes": "^6.5.3",
|
||||
@@ -38626,12 +38626,12 @@
|
||||
},
|
||||
"packages/plugin": {
|
||||
"name": "@getpaseo/plugin",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"dependencies": {
|
||||
"use-sync-external-store": "^1.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@getpaseo/client": "0.5.0",
|
||||
"@getpaseo/client": "0.5.1",
|
||||
"@types/node": "^20.9.0",
|
||||
"@types/react": "~19.2.0",
|
||||
"react": "19.1.0",
|
||||
@@ -38640,14 +38640,14 @@
|
||||
"zod": "^4.4.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@getpaseo/client": "0.5.0",
|
||||
"@getpaseo/client": "0.5.1",
|
||||
"react": "19.1.0",
|
||||
"zod": "^4.4.3"
|
||||
}
|
||||
},
|
||||
"packages/protocol": {
|
||||
"name": "@getpaseo/protocol",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"dependencies": {
|
||||
"zod": "^4.4.3"
|
||||
},
|
||||
@@ -38660,7 +38660,7 @@
|
||||
},
|
||||
"packages/relay": {
|
||||
"name": "@getpaseo/relay",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.5.1",
|
||||
"tweetnacl": "^1.0.3",
|
||||
@@ -38878,17 +38878,17 @@
|
||||
},
|
||||
"packages/server": {
|
||||
"name": "@getpaseo/server",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"dependencies": {
|
||||
"@agentclientprotocol/sdk": "^0.17.1",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.3.220",
|
||||
"@anthropic-ai/sdk": "^0.104.2",
|
||||
"@babel/parser": "^7.29.8",
|
||||
"@getpaseo/client": "0.5.0",
|
||||
"@getpaseo/highlight": "0.5.0",
|
||||
"@getpaseo/plugin": "0.5.0",
|
||||
"@getpaseo/protocol": "0.5.0",
|
||||
"@getpaseo/relay": "0.5.0",
|
||||
"@getpaseo/client": "0.5.1",
|
||||
"@getpaseo/highlight": "0.5.1",
|
||||
"@getpaseo/plugin": "0.5.1",
|
||||
"@getpaseo/protocol": "0.5.1",
|
||||
"@getpaseo/relay": "0.5.1",
|
||||
"@isaacs/ttlcache": "^2.1.4",
|
||||
"@modelcontextprotocol/sdk": "1.29.0",
|
||||
"@opencode-ai/sdk": "1.14.46",
|
||||
@@ -39940,7 +39940,7 @@
|
||||
},
|
||||
"packages/website": {
|
||||
"name": "@getpaseo/website",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"dependencies": {
|
||||
"@cloudflare/vite-plugin": "^1.29.1",
|
||||
"@cloudflare/workers-types": "^4.20260317.1",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "paseo",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"private": true,
|
||||
"description": "Paseo: voice-controlled development environment for local AI coding agents",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/app",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"private": true,
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { reduceNativeComposerHeight } from "./height-state";
|
||||
|
||||
const bounds = { minHeight: 30, maxHeight: 240 };
|
||||
|
||||
describe("native composer height", () => {
|
||||
it("grows a fresh composer from the content size exposed during caret scrolling", () => {
|
||||
expect(
|
||||
reduceNativeComposerHeight(30, bounds, {
|
||||
type: "content-measured",
|
||||
height: 131,
|
||||
}),
|
||||
).toBe(131);
|
||||
});
|
||||
|
||||
it("remeasures a restored multiline draft before applying its intrinsic height", () => {
|
||||
const invalidatedHeight = reduceNativeComposerHeight(30, bounds, { type: "remeasure" });
|
||||
|
||||
expect(invalidatedHeight).toBeGreaterThan(30);
|
||||
expect(
|
||||
reduceNativeComposerHeight(invalidatedHeight, bounds, {
|
||||
type: "content-measured",
|
||||
height: 173,
|
||||
}),
|
||||
).toBe(173);
|
||||
});
|
||||
|
||||
it("shrinks a grown composer after deletion and the resulting native measurement", () => {
|
||||
const invalidatedHeight = reduceNativeComposerHeight(240, bounds, {
|
||||
type: "text-changed",
|
||||
previousText: "one\ntwo\nthree",
|
||||
nextText: "one",
|
||||
});
|
||||
|
||||
expect(invalidatedHeight).toBeLessThan(240);
|
||||
expect(
|
||||
reduceNativeComposerHeight(invalidatedHeight, bounds, {
|
||||
type: "content-measured",
|
||||
height: 50,
|
||||
}),
|
||||
).toBe(50);
|
||||
});
|
||||
|
||||
it("does not disturb height while text grows", () => {
|
||||
expect(
|
||||
reduceNativeComposerHeight(120, bounds, {
|
||||
type: "text-changed",
|
||||
previousText: "one",
|
||||
nextText: "one two",
|
||||
}),
|
||||
).toBe(120);
|
||||
});
|
||||
|
||||
it("clamps measurements and resets to the current bounds", () => {
|
||||
expect(
|
||||
reduceNativeComposerHeight(30, bounds, {
|
||||
type: "content-measured",
|
||||
height: 999,
|
||||
}),
|
||||
).toBe(240);
|
||||
expect(reduceNativeComposerHeight(180, bounds, { type: "reset" })).toBe(30);
|
||||
});
|
||||
});
|
||||
@@ -1,41 +0,0 @@
|
||||
export interface ComposerHeightBounds {
|
||||
minHeight: number;
|
||||
maxHeight: number;
|
||||
}
|
||||
|
||||
export type NativeComposerHeightEvent =
|
||||
| { type: "content-measured"; height: number }
|
||||
| { type: "text-changed"; previousText: string; nextText: string }
|
||||
| { type: "remeasure" }
|
||||
| { type: "reset" };
|
||||
|
||||
export function clampComposerHeight(height: number, bounds: ComposerHeightBounds): number {
|
||||
return Math.max(bounds.minHeight, Math.min(bounds.maxHeight, height));
|
||||
}
|
||||
|
||||
export function reduceNativeComposerHeight(
|
||||
currentHeight: number,
|
||||
bounds: ComposerHeightBounds,
|
||||
event: NativeComposerHeightEvent,
|
||||
): number {
|
||||
if (event.type === "reset") return bounds.minHeight;
|
||||
|
||||
if (event.type === "content-measured") {
|
||||
if (!Number.isFinite(event.height) || event.height <= 0) return currentHeight;
|
||||
return clampComposerHeight(event.height, bounds);
|
||||
}
|
||||
|
||||
if (event.type === "remeasure") {
|
||||
const direction = currentHeight <= bounds.minHeight ? 1 : -1;
|
||||
return clampComposerHeight(currentHeight + direction, bounds);
|
||||
}
|
||||
|
||||
if (event.nextText.length >= event.previousText.length || currentHeight <= bounds.minHeight) {
|
||||
return currentHeight;
|
||||
}
|
||||
|
||||
// Fabric can retain the old UITextView content size after deletion while the text still fits
|
||||
// inside its frame. Changing that frame invalidates layout; the following content-size event
|
||||
// supplies the real smaller height.
|
||||
return reduceNativeComposerHeight(currentHeight, bounds, { type: "remeasure" });
|
||||
}
|
||||
@@ -1,100 +1,18 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useMemo } from "react";
|
||||
import type { RefObject } from "react";
|
||||
import type {
|
||||
NativeSyntheticEvent,
|
||||
TextInputContentSizeChangeEventData,
|
||||
TextInputScrollEventData,
|
||||
TextStyle,
|
||||
} from "react-native";
|
||||
import { reduceNativeComposerHeight, type NativeComposerHeightEvent } from "./height-state";
|
||||
import type { ComposerHeightResult } from "./height.types";
|
||||
|
||||
interface ComposerHeightArgs {
|
||||
value: string;
|
||||
textareaRef: RefObject<unknown>;
|
||||
minHeight: number;
|
||||
maxHeight: number;
|
||||
onHeightChange?: (height: number) => void;
|
||||
}
|
||||
|
||||
interface ComposerHeightResult {
|
||||
style: TextStyle;
|
||||
scrollEnabled: boolean;
|
||||
onTextChange: (previousText: string, nextText: string) => void;
|
||||
onContentSizeChange: (event: NativeSyntheticEvent<TextInputContentSizeChangeEventData>) => void;
|
||||
onScroll: (event: NativeSyntheticEvent<TextInputScrollEventData>) => void;
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
export function useComposerHeight({
|
||||
value,
|
||||
minHeight,
|
||||
maxHeight,
|
||||
onHeightChange,
|
||||
}: ComposerHeightArgs): ComposerHeightResult {
|
||||
const [height, setHeight] = useState(minHeight);
|
||||
const heightRef = useRef(minHeight);
|
||||
const didRemeasureInitialValueRef = useRef(false);
|
||||
const onHeightChangeRef = useRef(onHeightChange);
|
||||
onHeightChangeRef.current = onHeightChange;
|
||||
|
||||
const apply = useCallback(
|
||||
(event: NativeComposerHeightEvent) => {
|
||||
const nextHeight = reduceNativeComposerHeight(
|
||||
heightRef.current,
|
||||
{ minHeight, maxHeight },
|
||||
event,
|
||||
);
|
||||
if (Math.abs(nextHeight - heightRef.current) < 1) return;
|
||||
heightRef.current = nextHeight;
|
||||
setHeight(nextHeight);
|
||||
onHeightChangeRef.current?.(nextHeight);
|
||||
},
|
||||
[maxHeight, minHeight],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
apply({ type: "content-measured", height: heightRef.current });
|
||||
}, [apply]);
|
||||
|
||||
useEffect(() => {
|
||||
if (didRemeasureInitialValueRef.current || value.length === 0) return;
|
||||
didRemeasureInitialValueRef.current = true;
|
||||
apply({ type: "remeasure" });
|
||||
}, [apply, value]);
|
||||
|
||||
const onTextChange = useCallback(
|
||||
(previousText: string, nextText: string) => {
|
||||
apply({ type: "text-changed", previousText, nextText });
|
||||
},
|
||||
[apply],
|
||||
);
|
||||
|
||||
const onContentSizeChange = useCallback(
|
||||
(event: NativeSyntheticEvent<TextInputContentSizeChangeEventData>) => {
|
||||
apply({ type: "content-measured", height: event.nativeEvent.contentSize.height });
|
||||
},
|
||||
[apply],
|
||||
);
|
||||
|
||||
const onScroll = useCallback(
|
||||
(event: NativeSyntheticEvent<TextInputScrollEventData>) => {
|
||||
// iOS Fabric can omit the first content-size callback when a fixed-height input overflows.
|
||||
// The caret-scroll event still carries the actual size and bootstraps the same state.
|
||||
const nativeEvent = event.nativeEvent as TextInputScrollEventData & {
|
||||
contentSize?: { width: number; height: number };
|
||||
};
|
||||
const contentHeight = nativeEvent.contentSize?.height;
|
||||
if (contentHeight !== undefined) {
|
||||
apply({ type: "content-measured", height: contentHeight });
|
||||
}
|
||||
},
|
||||
[apply],
|
||||
);
|
||||
|
||||
const reset = useCallback(() => apply({ type: "reset" }), [apply]);
|
||||
const style = useMemo(() => ({ height, minHeight, maxHeight }), [height, maxHeight, minHeight]);
|
||||
|
||||
// A non-scrolling UITextView reports its frame as contentSize. Scrolling stays enabled so
|
||||
// caret overflow can expose the intrinsic size through onScroll.
|
||||
return { style, scrollEnabled: true, onTextChange, onContentSizeChange, onScroll, reset };
|
||||
const style = useMemo(() => ({ minHeight, maxHeight }), [maxHeight, minHeight]);
|
||||
return { mode: "intrinsic", style, scrollEnabled: true };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import type { TextStyle } from "react-native";
|
||||
|
||||
export type ComposerHeightResult =
|
||||
| {
|
||||
mode: "intrinsic";
|
||||
style: TextStyle;
|
||||
scrollEnabled: true;
|
||||
}
|
||||
| {
|
||||
mode: "measured";
|
||||
style: TextStyle;
|
||||
scrollEnabled: boolean;
|
||||
onTextChange: (previousText: string, nextText: string) => void;
|
||||
reset: () => void;
|
||||
};
|
||||
@@ -1,28 +1,12 @@
|
||||
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
||||
import type { RefObject } from "react";
|
||||
import type {
|
||||
NativeSyntheticEvent,
|
||||
TextInputContentSizeChangeEventData,
|
||||
TextInputScrollEventData,
|
||||
TextStyle,
|
||||
} from "react-native";
|
||||
import { clampComposerHeight } from "./height-state";
|
||||
import type { ComposerHeightResult } from "./height.types";
|
||||
|
||||
interface ComposerHeightArgs {
|
||||
value: string;
|
||||
textareaRef: RefObject<HTMLElement | null>;
|
||||
minHeight: number;
|
||||
maxHeight: number;
|
||||
onHeightChange?: (height: number) => void;
|
||||
}
|
||||
|
||||
interface ComposerHeightResult {
|
||||
style: TextStyle;
|
||||
scrollEnabled: boolean;
|
||||
onTextChange: (previousText: string, nextText: string) => void;
|
||||
onContentSizeChange: (event: NativeSyntheticEvent<TextInputContentSizeChangeEventData>) => void;
|
||||
onScroll: (event: NativeSyntheticEvent<TextInputScrollEventData>) => void;
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
const COPIED_STYLES = [
|
||||
@@ -52,28 +36,19 @@ export function useComposerHeight({
|
||||
textareaRef,
|
||||
minHeight,
|
||||
maxHeight,
|
||||
onHeightChange,
|
||||
}: ComposerHeightArgs): ComposerHeightResult {
|
||||
const [height, setHeight] = useState(minHeight);
|
||||
const heightRef = useRef(minHeight);
|
||||
const paramsRef = useRef({ value, minHeight, maxHeight, onHeightChange });
|
||||
paramsRef.current = { value, minHeight, maxHeight, onHeightChange };
|
||||
const paramsRef = useRef({ value, minHeight, maxHeight });
|
||||
paramsRef.current = { value, minHeight, maxHeight };
|
||||
const mirrorRef = useRef<HTMLTextAreaElement | null>(null);
|
||||
|
||||
const setBoundedHeight = useCallback((nextHeight: number) => {
|
||||
const {
|
||||
minHeight: currentMin,
|
||||
maxHeight: currentMax,
|
||||
onHeightChange: onChange,
|
||||
} = paramsRef.current;
|
||||
const bounded = clampComposerHeight(nextHeight, {
|
||||
minHeight: currentMin,
|
||||
maxHeight: currentMax,
|
||||
});
|
||||
const { minHeight: currentMin, maxHeight: currentMax } = paramsRef.current;
|
||||
const bounded = Math.max(currentMin, Math.min(currentMax, nextHeight));
|
||||
if (Math.abs(heightRef.current - bounded) < 1) return;
|
||||
heightRef.current = bounded;
|
||||
setHeight(bounded);
|
||||
onChange?.(bounded);
|
||||
}, []);
|
||||
|
||||
const measure = useCallback(
|
||||
@@ -145,22 +120,13 @@ export function useComposerHeight({
|
||||
[measure],
|
||||
);
|
||||
const reset = useCallback(() => setBoundedHeight(minHeight), [minHeight, setBoundedHeight]);
|
||||
const onContentSizeChange = useCallback(
|
||||
(_event: NativeSyntheticEvent<TextInputContentSizeChangeEventData>) => undefined,
|
||||
[],
|
||||
);
|
||||
const onScroll = useCallback(
|
||||
(_event: NativeSyntheticEvent<TextInputScrollEventData>) => undefined,
|
||||
[],
|
||||
);
|
||||
const style = useMemo(() => ({ height, minHeight, maxHeight }), [height, maxHeight, minHeight]);
|
||||
|
||||
return {
|
||||
mode: "measured",
|
||||
style,
|
||||
scrollEnabled: height >= maxHeight,
|
||||
onTextChange,
|
||||
onContentSizeChange,
|
||||
onScroll,
|
||||
reset,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,10 +4,9 @@ import {
|
||||
Text,
|
||||
useWindowDimensions,
|
||||
NativeSyntheticEvent,
|
||||
TextInputContentSizeChangeEventData,
|
||||
TextInputKeyPressEventData,
|
||||
TextInputScrollEventData,
|
||||
TextInputSelectionChangeEventData,
|
||||
type LayoutChangeEvent,
|
||||
} from "react-native";
|
||||
import {
|
||||
useState,
|
||||
@@ -640,8 +639,6 @@ interface ComposerTextSurfaceProps {
|
||||
editable: boolean;
|
||||
scrollEnabled: boolean;
|
||||
autoFocus: boolean;
|
||||
onContentSizeChange: (event: NativeSyntheticEvent<TextInputContentSizeChangeEventData>) => void;
|
||||
onScroll: (event: NativeSyntheticEvent<TextInputScrollEventData>) => void;
|
||||
onKeyPress: ((event: WebTextInputKeyPressEvent) => void) | undefined;
|
||||
onSelectionChange: (event: NativeSyntheticEvent<TextInputSelectionChangeEventData>) => void;
|
||||
onPasteImages: ((files: readonly NativePastedFile[]) => void) | undefined;
|
||||
@@ -680,8 +677,6 @@ function ComposerTextSurface(props: ComposerTextSurfaceProps): React.ReactElemen
|
||||
style={props.textInputStyle}
|
||||
multiline
|
||||
scrollEnabled={props.scrollEnabled}
|
||||
onContentSizeChange={props.onContentSizeChange}
|
||||
onScroll={props.onScroll}
|
||||
editable={props.editable}
|
||||
onKeyPress={props.onKeyPress}
|
||||
onSelectionChange={props.onSelectionChange}
|
||||
@@ -1216,20 +1211,21 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(
|
||||
const selectionRef = useRef({ start: value.length, end: value.length });
|
||||
const appliedTextReplacementKeyRef = useRef(textReplacementKey);
|
||||
const webTextareaRef = useRef<HTMLElement | null>(null);
|
||||
const {
|
||||
style: composerHeightStyle,
|
||||
scrollEnabled: isComposerScrollEnabled,
|
||||
onTextChange: updateComposerHeightForText,
|
||||
onContentSizeChange: handleComposerContentSizeChange,
|
||||
onScroll: handleComposerScroll,
|
||||
reset: resetComposerHeight,
|
||||
} = useComposerHeight({
|
||||
const composerHeight = useComposerHeight({
|
||||
value,
|
||||
textareaRef: webTextareaRef,
|
||||
minHeight: MIN_INPUT_HEIGHT,
|
||||
maxHeight: maxInputHeight,
|
||||
onHeightChange,
|
||||
});
|
||||
const { style: composerHeightStyle, scrollEnabled: isComposerScrollEnabled } = composerHeight;
|
||||
const measuredComposerHeight = composerHeight.mode === "measured" ? composerHeight : undefined;
|
||||
const updateComposerHeightForText = measuredComposerHeight?.onTextChange;
|
||||
const resetComposerHeight = measuredComposerHeight?.reset;
|
||||
|
||||
const handleComposerLayout = useCallback(
|
||||
(event: LayoutChangeEvent) => onHeightChange?.(event.nativeEvent.layout.height),
|
||||
[onHeightChange],
|
||||
);
|
||||
|
||||
const updateLiveTextPresence = useCallback((text: string) => {
|
||||
const nextHasLiveText = text.trim().length > 0;
|
||||
@@ -1240,7 +1236,7 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(
|
||||
|
||||
const replaceText = useCallback(
|
||||
(nextText: string, selection?: { start: number; end: number }) => {
|
||||
updateComposerHeightForText(valueRef.current, nextText);
|
||||
updateComposerHeightForText?.(valueRef.current, nextText);
|
||||
valueRef.current = nextText;
|
||||
updateLiveTextPresence(nextText);
|
||||
selectionRef.current = selection ?? { start: nextText.length, end: nextText.length };
|
||||
@@ -1293,7 +1289,7 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(
|
||||
useEffect(() => {
|
||||
if (appliedTextReplacementKeyRef.current === textReplacementKey) return;
|
||||
appliedTextReplacementKeyRef.current = textReplacementKey;
|
||||
updateComposerHeightForText(valueRef.current, value);
|
||||
updateComposerHeightForText?.(valueRef.current, value);
|
||||
valueRef.current = value;
|
||||
updateLiveTextPresence(value);
|
||||
textInputRef.current?.replaceText(value);
|
||||
@@ -1494,7 +1490,7 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(
|
||||
]);
|
||||
|
||||
const minimizeInputHeight = useCallback(() => {
|
||||
resetComposerHeight();
|
||||
resetComposerHeight?.();
|
||||
}, [resetComposerHeight]);
|
||||
|
||||
const handleSendMessage = useCallback(() => {
|
||||
@@ -1664,7 +1660,7 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(
|
||||
|
||||
const handleInputChange = useCallback(
|
||||
(nextValue: string) => {
|
||||
updateComposerHeightForText(valueRef.current, nextValue);
|
||||
updateComposerHeightForText?.(valueRef.current, nextValue);
|
||||
valueRef.current = nextValue;
|
||||
updateLiveTextPresence(nextValue);
|
||||
onChangeText(nextValue);
|
||||
@@ -1776,7 +1772,12 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(
|
||||
);
|
||||
|
||||
return (
|
||||
<View ref={rootRef} style={styles.container} testID="message-input-root">
|
||||
<View
|
||||
ref={rootRef}
|
||||
style={styles.container}
|
||||
testID="message-input-root"
|
||||
onLayout={handleComposerLayout}
|
||||
>
|
||||
<MessageInputAutoFocus
|
||||
enabled={autoFocus}
|
||||
autoFocusKey={autoFocusKey}
|
||||
@@ -1805,8 +1806,6 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(
|
||||
editable={!isDictating && !isRealtimeVoiceForCurrentAgent && !disabled}
|
||||
scrollEnabled={isComposerScrollEnabled}
|
||||
autoFocus={false}
|
||||
onContentSizeChange={handleComposerContentSizeChange}
|
||||
onScroll={handleComposerScroll}
|
||||
onKeyPress={shouldHandleWebKeyPress ? handleDesktopKeyPress : undefined}
|
||||
onSelectionChange={handleSelectionChange}
|
||||
onPasteImages={onPasteImages}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/cli",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"description": "Paseo CLI - control your AI coding agents from the command line",
|
||||
"bin": {
|
||||
"paseo": "bin/paseo"
|
||||
@@ -28,9 +28,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@clack/prompts": "^1.0.0",
|
||||
"@getpaseo/client": "0.5.0",
|
||||
"@getpaseo/protocol": "0.5.0",
|
||||
"@getpaseo/server": "0.5.0",
|
||||
"@getpaseo/client": "0.5.1",
|
||||
"@getpaseo/protocol": "0.5.1",
|
||||
"@getpaseo/server": "0.5.1",
|
||||
"chalk": "^5.3.0",
|
||||
"commander": "^12.0.0",
|
||||
"mime-types": "^2.1.35",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/client",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"description": "Paseo client SDK package",
|
||||
"files": [
|
||||
"dist",
|
||||
@@ -39,8 +39,8 @@
|
||||
"test": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@getpaseo/protocol": "0.5.0",
|
||||
"@getpaseo/relay": "0.5.0",
|
||||
"@getpaseo/protocol": "0.5.1",
|
||||
"@getpaseo/relay": "0.5.1",
|
||||
"zod": "^4.4.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/desktop",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"private": true,
|
||||
"description": "Paseo desktop app (Electron wrapper)",
|
||||
"homepage": "https://paseo.sh",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/expo-two-way-audio",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"description": "Native module for two way audio streaming",
|
||||
"keywords": [
|
||||
"ExpoTwoWayAudio",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/highlight",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"files": [
|
||||
"dist",
|
||||
"!dist/**/*.map"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/plugin",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"description": "Paseo plugin SDK package",
|
||||
"files": [
|
||||
"dist",
|
||||
@@ -39,7 +39,7 @@
|
||||
"use-sync-external-store": "^1.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@getpaseo/client": "0.5.0",
|
||||
"@getpaseo/client": "0.5.1",
|
||||
"@types/node": "^20.9.0",
|
||||
"@types/react": "~19.2.0",
|
||||
"react": "19.1.0",
|
||||
@@ -48,7 +48,7 @@
|
||||
"zod": "^4.4.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@getpaseo/client": "0.5.0",
|
||||
"@getpaseo/client": "0.5.1",
|
||||
"react": "19.1.0",
|
||||
"zod": "^4.4.3"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/protocol",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"description": "Paseo shared protocol schemas and wire types",
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/relay",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"description": "Paseo relay for bridging daemon and client connections",
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/server",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"description": "Paseo backend server",
|
||||
"files": [
|
||||
"dist/server",
|
||||
@@ -72,11 +72,11 @@
|
||||
"@anthropic-ai/claude-agent-sdk": "0.3.220",
|
||||
"@anthropic-ai/sdk": "^0.104.2",
|
||||
"@babel/parser": "^7.29.8",
|
||||
"@getpaseo/client": "0.5.0",
|
||||
"@getpaseo/highlight": "0.5.0",
|
||||
"@getpaseo/plugin": "0.5.0",
|
||||
"@getpaseo/protocol": "0.5.0",
|
||||
"@getpaseo/relay": "0.5.0",
|
||||
"@getpaseo/client": "0.5.1",
|
||||
"@getpaseo/highlight": "0.5.1",
|
||||
"@getpaseo/plugin": "0.5.1",
|
||||
"@getpaseo/protocol": "0.5.1",
|
||||
"@getpaseo/relay": "0.5.1",
|
||||
"@isaacs/ttlcache": "^2.1.4",
|
||||
"@modelcontextprotocol/sdk": "1.29.0",
|
||||
"@opencode-ai/sdk": "1.14.46",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/website",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
Reference in New Issue
Block a user