Compare commits

...
33 changed files with 215 additions and 244 deletions
+18
View File
@@ -1,5 +1,23 @@
# Changelog
## 0.11.2 - 2026-10-09
### Fixed
- Fixed intermittent text clipping in iOS chats and Markdown previews ([#6445](https://github.com/getpaseo/paseo/pull/6445))
## 0.11.1 - 2026-10-07
### Added
- Added Claude Haiku 5.5 for Claude Code 2.1.293 and newer ([#6332](https://github.com/getpaseo/paseo/pull/6332))
### Fixed
- Fixed Claude tool calls that run longer than 30 seconds, such as WebFetch or MCP tools, showing up as subagents ([#6308](https://github.com/getpaseo/paseo/pull/6308))
- Fixed subagents that finish while the app is disconnected staying "working" until one is opened ([#6316](https://github.com/getpaseo/paseo/pull/6316))
- Fixed a Claude agent's history showing "No activity to display" after a daemon restart when its transcript is in another project folder, such as after moving the daemon or running Windows Claude Code from WSL ([#6301](https://github.com/getpaseo/paseo/pull/6301))
## 0.11.0 - 2026-10-07
Paseo 0.11 adds support for the [plugin registry](https://paseo.sh/plugins). Browse community plugins there, install one with `paseo plugin add owner/slug`, or [submit your own](https://paseo.sh/docs/plugins/publishing#plugin-registry).
@@ -0,0 +1,8 @@
Added
- Added Claude Haiku 5.5 for Claude Code 2.1.293 and newer
Fixed
- Fixed Claude tool calls that run longer than 30 seconds, such as WebFetch or MCP tools, showing up as subagents
- Fixed subagents that finish while the app is disconnected staying "working" until one is opened
Full notes: https://paseo.sh/changelog
@@ -0,0 +1,8 @@
Added
- Added Claude Haiku 5.5 for Claude Code 2.1.293 and newer
Fixed
- Fixed Claude tool calls that run longer than 30 seconds, such as WebFetch or MCP tools, showing up as subagents
- Fixed subagents that finish while the app is disconnected staying "working" until one is opened
Full notes: https://paseo.sh/changelog
@@ -0,0 +1,8 @@
Added
- Added Claude Haiku 5.5 for Claude Code 2.1.293 and newer
Fixed
- Fixed Claude tool calls that run longer than 30 seconds, such as WebFetch or MCP tools, showing up as subagents
- Fixed subagents that finish while the app is disconnected staying "working" until one is opened
Full notes: https://paseo.sh/changelog
@@ -0,0 +1,8 @@
Added
- Added Claude Haiku 5.5 for Claude Code 2.1.293 and newer
Fixed
- Fixed Claude tool calls that run longer than 30 seconds, such as WebFetch or MCP tools, showing up as subagents
- Fixed subagents that finish while the app is disconnected staying "working" until one is opened
Full notes: https://paseo.sh/changelog
@@ -0,0 +1,4 @@
Fixed
- Fixed intermittent text clipping in iOS chats and Markdown previews
Full notes: https://paseo.sh/changelog
@@ -0,0 +1,4 @@
Fixed
- Fixed intermittent text clipping in iOS chats and Markdown previews
Full notes: https://paseo.sh/changelog
@@ -0,0 +1,4 @@
Fixed
- Fixed intermittent text clipping in iOS chats and Markdown previews
Full notes: https://paseo.sh/changelog
@@ -0,0 +1,4 @@
Fixed
- Fixed intermittent text clipping in iOS chats and Markdown previews
Full notes: https://paseo.sh/changelog
+28 -28
View File
@@ -1,12 +1,12 @@
{
"name": "paseo",
"version": "0.11.0",
"version": "0.11.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "paseo",
"version": "0.11.0",
"version": "0.11.2",
"hasInstallScript": true,
"license": "Apache-2.0",
"workspaces": [
@@ -36413,7 +36413,7 @@
},
"packages/app": {
"name": "@getpaseo/app",
"version": "0.11.0",
"version": "0.11.2",
"dependencies": {
"@codemirror/commands": "6.10.4",
"@codemirror/language": "6.12.4",
@@ -37496,12 +37496,12 @@
},
"packages/cli": {
"name": "@getpaseo/cli",
"version": "0.11.0",
"version": "0.11.2",
"dependencies": {
"@clack/prompts": "^1.0.0",
"@getpaseo/client": "0.11.0",
"@getpaseo/protocol": "0.11.0",
"@getpaseo/server": "0.11.0",
"@getpaseo/client": "0.11.2",
"@getpaseo/protocol": "0.11.2",
"@getpaseo/server": "0.11.2",
"chalk": "^5.3.0",
"commander": "^12.0.0",
"mime-types": "^2.1.35",
@@ -37748,10 +37748,10 @@
},
"packages/client": {
"name": "@getpaseo/client",
"version": "0.11.0",
"version": "0.11.2",
"dependencies": {
"@getpaseo/protocol": "0.11.0",
"@getpaseo/relay": "0.11.0",
"@getpaseo/protocol": "0.11.2",
"@getpaseo/relay": "0.11.2",
"zod": "^4.4.3"
},
"devDependencies": {
@@ -37762,7 +37762,7 @@
},
"packages/desktop": {
"name": "@getpaseo/desktop",
"version": "0.11.0",
"version": "0.11.2",
"license": "Apache-2.0",
"dependencies": {
"@getpaseo/cli": "*",
@@ -38006,7 +38006,7 @@
},
"packages/expo-two-way-audio": {
"name": "@getpaseo/expo-two-way-audio",
"version": "0.11.0",
"version": "0.11.2",
"license": "MIT",
"devDependencies": {
"@types/jest": "^29.5.14",
@@ -38902,7 +38902,7 @@
},
"packages/highlight": {
"name": "@getpaseo/highlight",
"version": "0.11.0",
"version": "0.11.2",
"dependencies": {
"@codemirror/language": "6.12.4",
"@codemirror/legacy-modes": "^6.5.3",
@@ -38931,14 +38931,14 @@
},
"packages/plugin": {
"name": "@getpaseo/plugin",
"version": "0.11.0",
"version": "0.11.2",
"dependencies": {
"@agentclientprotocol/sdk": "^1.4.0",
"use-sync-external-store": "^1.6.0"
},
"devDependencies": {
"@getpaseo/client": "0.11.0",
"@getpaseo/protocol": "0.11.0",
"@getpaseo/client": "0.11.2",
"@getpaseo/protocol": "0.11.2",
"@types/node": "^20.9.0",
"@types/react": "~19.2.0",
"react": "19.1.0",
@@ -38948,8 +38948,8 @@
"zod": "^4.4.3"
},
"peerDependencies": {
"@getpaseo/client": "0.11.0",
"@getpaseo/protocol": "0.11.0",
"@getpaseo/client": "0.11.2",
"@getpaseo/protocol": "0.11.2",
"react": "~19.1.0",
"react-native": ">=0.81.5",
"zod": "^4.4.3"
@@ -38971,7 +38971,7 @@
},
"packages/protocol": {
"name": "@getpaseo/protocol",
"version": "0.11.0",
"version": "0.11.2",
"dependencies": {
"semver": "^7.8.5",
"zod": "^4.4.3"
@@ -38998,7 +38998,7 @@
},
"packages/relay": {
"name": "@getpaseo/relay",
"version": "0.11.0",
"version": "0.11.2",
"dependencies": {
"base64-js": "^1.5.1",
"tweetnacl": "^1.0.3",
@@ -39216,16 +39216,16 @@
},
"packages/server": {
"name": "@getpaseo/server",
"version": "0.11.0",
"version": "0.11.2",
"dependencies": {
"@agentclientprotocol/sdk": "^0.17.1",
"@anthropic-ai/claude-agent-sdk": "0.3.246",
"@anthropic-ai/sdk": "^0.104.2",
"@getpaseo/client": "0.11.0",
"@getpaseo/highlight": "0.11.0",
"@getpaseo/plugin": "0.11.0",
"@getpaseo/protocol": "0.11.0",
"@getpaseo/relay": "0.11.0",
"@getpaseo/client": "0.11.2",
"@getpaseo/highlight": "0.11.2",
"@getpaseo/plugin": "0.11.2",
"@getpaseo/protocol": "0.11.2",
"@getpaseo/relay": "0.11.2",
"@isaacs/ttlcache": "^2.1.4",
"@modelcontextprotocol/sdk": "1.29.0",
"@opencode-ai/sdk": "1.14.46",
@@ -40146,7 +40146,7 @@
},
"packages/website": {
"name": "@getpaseo/website",
"version": "0.11.0",
"version": "0.11.2",
"dependencies": {
"@cloudflare/vite-plugin": "^1.29.1",
"@cloudflare/workers-types": "^4.20260317.1",
@@ -41754,7 +41754,7 @@
},
"plugins": {
"name": "@getpaseo/builtin-plugins",
"version": "0.11.0",
"version": "0.11.2",
"dependencies": {
"@getpaseo/plugin": "*",
"zod": "^4.4.3"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "paseo",
"version": "0.11.0",
"version": "0.11.2",
"private": true,
"description": "Paseo: voice-controlled development environment for local AI coding agents",
"keywords": [
@@ -1,26 +0,0 @@
# Native iOS text geometry regression
Run on the Namespace Mac with a fresh simulator development build. Use the PID
returned by `xcrun simctl launch <your-task-simulator-UDID> sh.paseo.debug`.
Attach only to your task's app, while no device replay is running:
```sh
PASEO_NATIVE_TEXT_REFLOW_PID=12345 \
PASEO_NATIVE_TEXT_REFLOW_LOG=/Volumes/devbox/workspace/native-text-reflow.log \
bash packages/app/e2e/mobile/native-text-reflow/ios.sh
```
The probe constructs the installed `RNUITextView`, fills its real UIKit text view,
and resizes its content container from 500 to 240 and back to 500 points. It
asserts the inner frame follows both widths and the same selection survives.
It uses public UIView/UITextView operations, without mocking React Native.
LLDB detaches after the probe. An assertion failure or evaluation error fails the
shell command; the log distinguishes them.
This covers native container resizing and selection retention. It does not cover
Fabric event delivery, chat row height, reader anchoring, or the on-screen copy
menu. Those require the real chat journey: read an older multiline response,
open/close Explorer, resize/rotate, inspect complete paragraphs and bullets,
retain expanded/collapsed details, and check a stationary reader's position.
Accessibility exposes full text even when glyphs are clipped, so a text wait
alone does not verify that journey.
@@ -1,55 +0,0 @@
import lldb
def __lldb_init_module(debugger, _internal_dict):
debugger.HandleCommand("expression -l objc++ -- @import UIKit")
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
options = lldb.SBExpressionOptions()
options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus)
result = frame.EvaluateExpression(
r'''({
UIView *host = (UIView *)[[NSClassFromString(@"RNUITextView") alloc] init];
auto hostFrame = host.frame;
hostFrame.size.width = 500;
hostFrame.size.height = 200;
host.frame = hostFrame;
UIView *container = (UIView *)[host performSelector:@selector(contentView)];
container.frame = host.bounds;
UITextView *text = nil;
for (UIView *child in host.subviews) {
if ([child isKindOfClass:UITextView.class]) text = (UITextView *)child;
for (UIView *nested in child.subviews) {
if ([nested isKindOfClass:UITextView.class]) text = (UITextView *)nested;
}
}
text.frame = container.bounds;
text.font = [UIFont systemFontOfSize:16];
text.text = @"A realistic multiline paragraph must reflow when Explorer narrows the available chat width, then fill the restored width without replacing the text view or discarding a selection.";
auto range = text.selectedRange;
range.location = 12;
range.length = 9;
text.selectedRange = range;
auto frame = container.frame;
frame.size.width = 240;
container.frame = frame;
[container layoutIfNeeded];
CGFloat narrow = text.frame.size.width;
auto selection = text.selectedRange;
frame.size.width = 500;
container.frame = frame;
[container layoutIfNeeded];
CGFloat wide = text.frame.size.width;
BOOL ok = text != nil && narrow == 240 && wide == 500 &&
selection.location == text.selectedRange.location &&
selection.length == text.selectedRange.length &&
selection.location == 12 && selection.length == 9;
[NSString stringWithFormat:@"NATIVE_REFLOW_%@ narrow=%.0f wide=%.0f selection=%lu:%lu",
ok ? @"PASS" : @"FAIL", narrow, wide,
(unsigned long)text.selectedRange.location,
(unsigned long)text.selectedRange.length];
})''',
options,
)
if result.GetError().Fail():
raise RuntimeError(result.GetError().GetCString())
print(result.GetObjectDescription())
@@ -1,18 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
: "${PASEO_NATIVE_TEXT_REFLOW_PID:?Set the PID of your task-owned Paseo iOS simulator app}"
: "${PASEO_NATIVE_TEXT_REFLOW_LOG:?Set the test output log path}"
if [[ "$(ps -p "$PASEO_NATIVE_TEXT_REFLOW_PID" -o comm=)" != *PaseoDebug.app/PaseoDebug ]]; then
echo "Expected a running PaseoDebug simulator app" >&2
exit 1
fi
probe_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
xcrun lldb --batch -p "$PASEO_NATIVE_TEXT_REFLOW_PID" \
-o "command script import $probe_dir/ios.py" \
-o "process detach" -o quit > "$PASEO_NATIVE_TEXT_REFLOW_LOG" 2>&1
grep '^NATIVE_REFLOW_' "$PASEO_NATIVE_TEXT_REFLOW_LOG"
grep -q '^NATIVE_REFLOW_PASS narrow=240 wide=500 selection=12:9$' "$PASEO_NATIVE_TEXT_REFLOW_LOG"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@getpaseo/app",
"version": "0.11.0",
"version": "0.11.2",
"private": true,
"main": "index.ts",
"scripts": {
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@getpaseo/cli",
"version": "0.11.0",
"version": "0.11.2",
"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.11.0",
"@getpaseo/protocol": "0.11.0",
"@getpaseo/server": "0.11.0",
"@getpaseo/client": "0.11.2",
"@getpaseo/protocol": "0.11.2",
"@getpaseo/server": "0.11.2",
"chalk": "^5.3.0",
"commander": "^12.0.0",
"mime-types": "^2.1.35",
+8 -3
View File
@@ -122,10 +122,15 @@ const EXPECTED_CLAUDE_MODELS = [
model: "Opus 4.6",
descriptionFragment: "Most capable",
},
{
id: "claude-haiku-5-5",
model: "Haiku 5.5",
descriptionFragment: "Fastest",
},
{
id: "claude-haiku-4-5",
model: "Haiku 4.5",
descriptionFragment: "Fastest",
descriptionFragment: "Previous release",
},
] as const;
@@ -435,8 +440,8 @@ try {
"--quiet should print the same ordered model IDs returned by --json",
);
assert(
claudeModelsFromJson.some((m) => m.id === "claude-sonnet-5-5"),
"captured --json output should include the current Claude everyday model id",
claudeModelsFromJson.some((m) => m.id === "claude-haiku-5-5"),
"captured --json output should include the current Claude quick-answer model id",
);
console.log("✓ provider models --quiet outputs model IDs only\n");
}
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@getpaseo/client",
"version": "0.11.0",
"version": "0.11.2",
"description": "Paseo client SDK package",
"files": [
"dist",
@@ -39,8 +39,8 @@
"test": "vitest run"
},
"dependencies": {
"@getpaseo/protocol": "0.11.0",
"@getpaseo/relay": "0.11.0",
"@getpaseo/protocol": "0.11.2",
"@getpaseo/relay": "0.11.2",
"zod": "^4.4.3"
},
"devDependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@getpaseo/desktop",
"version": "0.11.0",
"version": "0.11.2",
"private": true,
"description": "Paseo desktop app (Electron wrapper)",
"homepage": "https://paseo.sh",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@getpaseo/expo-two-way-audio",
"version": "0.11.0",
"version": "0.11.2",
"description": "Native module for two way audio streaming",
"keywords": [
"ExpoTwoWayAudio",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@getpaseo/highlight",
"version": "0.11.0",
"version": "0.11.2",
"files": [
"dist",
"!dist/**/*.map",
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@getpaseo/plugin",
"version": "0.11.0",
"version": "0.11.2",
"description": "Paseo plugin SDK package",
"files": [
"dist",
@@ -70,8 +70,8 @@
"use-sync-external-store": "^1.6.0"
},
"devDependencies": {
"@getpaseo/client": "0.11.0",
"@getpaseo/protocol": "0.11.0",
"@getpaseo/client": "0.11.2",
"@getpaseo/protocol": "0.11.2",
"@types/node": "^20.9.0",
"@types/react": "~19.2.0",
"react": "19.1.0",
@@ -81,8 +81,8 @@
"zod": "^4.4.3"
},
"peerDependencies": {
"@getpaseo/client": "0.11.0",
"@getpaseo/protocol": "0.11.0",
"@getpaseo/client": "0.11.2",
"@getpaseo/protocol": "0.11.2",
"react": "~19.1.0",
"react-native": ">=0.81.5",
"zod": "^4.4.3"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@getpaseo/protocol",
"version": "0.11.0",
"version": "0.11.2",
"description": "Paseo shared protocol schemas and wire types",
"files": [
"dist",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@getpaseo/relay",
"version": "0.11.0",
"version": "0.11.2",
"description": "Paseo relay for bridging daemon and client connections",
"files": [
"dist",
+6 -6
View File
@@ -1,6 +1,6 @@
{
"name": "@getpaseo/server",
"version": "0.11.0",
"version": "0.11.2",
"description": "Paseo backend server",
"files": [
"dist/server",
@@ -107,11 +107,11 @@
"@agentclientprotocol/sdk": "^0.17.1",
"@anthropic-ai/claude-agent-sdk": "0.3.246",
"@anthropic-ai/sdk": "^0.104.2",
"@getpaseo/client": "0.11.0",
"@getpaseo/highlight": "0.11.0",
"@getpaseo/plugin": "0.11.0",
"@getpaseo/protocol": "0.11.0",
"@getpaseo/relay": "0.11.0",
"@getpaseo/client": "0.11.2",
"@getpaseo/highlight": "0.11.2",
"@getpaseo/plugin": "0.11.2",
"@getpaseo/protocol": "0.11.2",
"@getpaseo/relay": "0.11.2",
"@isaacs/ttlcache": "^2.1.4",
"@modelcontextprotocol/sdk": "1.29.0",
"@opencode-ai/sdk": "1.14.46",
@@ -496,7 +496,7 @@ describe("ClaudeAgentClient.fetchCatalog", () => {
const client = new ClaudeAgentClient({
logger,
resolveBinary: async () => "/test/claude/bin",
resolveVersion: async () => "2.1.284",
resolveVersion: async () => "2.1.293",
runtimeSettings: { env: { CLAUDE_CONFIG_DIR: emptyConfigDir } },
});
const { models } = await client.fetchCatalog({
@@ -515,6 +515,15 @@ describe("ClaudeAgentClient.fetchCatalog", () => {
expect(getThinkingIds("claude-opus-4-8")).toContain("ultracode");
expect(getThinkingIds("claude-sonnet-5")).toContain("xhigh");
expect(getThinkingIds("claude-sonnet-5")).toContain("ultracode");
expect(getThinkingIds("claude-haiku-5-5")).toEqual([
"off",
"low",
"medium",
"high",
"xhigh",
"max",
"ultracode",
]);
expect(getThinkingIds("claude-sonnet-5-5")).toContain("xhigh");
expect(getThinkingIds("claude-sonnet-5-5")).not.toContain("off");
expect(getThinkingIds("claude-opus-4-7[1m]")).toContain("ultracode");
@@ -1223,6 +1232,7 @@ describe("ClaudeAgentSession features", () => {
test.each([
["supported model", "claude-opus-4-8", { type: "disabled" }, undefined],
["Haiku 5.5", "claude-haiku-5-5", { type: "disabled" }, undefined],
["unsupported model", "claude-fable-5", { type: "adaptive", display: "summarized" }, "high"],
["custom model", "openrouter/anthropic/claude-opus-4-8", undefined, undefined],
["provider default", null, undefined, undefined],
@@ -170,10 +170,20 @@ export const CLAUDE_MODEL_MANIFEST = [
effortLevels: CLAUDE_EFFORT_LEVELS.standard,
supportsThinkingDisabled: true,
},
{
id: "claude-haiku-5-5",
label: "Haiku 5.5",
description: "Haiku 5.5 · Fastest for quick answers",
minimumClaudeCodeVersion: "2.1.293",
defaultThinkingOptionId: "medium",
contextWindowMaxTokens: 1_000_000,
effortLevels: CLAUDE_EFFORT_LEVELS.xhigh,
supportsThinkingDisabled: true,
},
{
id: "claude-haiku-4-5",
label: "Haiku 4.5",
description: "Haiku 4.5 · Fastest for quick answers",
description: "Haiku 4.5 · Previous release",
contextWindowMaxTokens: 200_000,
},
] as const satisfies readonly ClaudeModelManifestEntry[];
@@ -39,7 +39,7 @@ async function createClaudeConfigDirWithRawSettings(settings: string): Promise<s
return configDir;
}
function createCatalogClient(claudeCodeVersion = "2.1.284"): ClaudeAgentClient {
function createCatalogClient(claudeCodeVersion = "2.1.293"): ClaudeAgentClient {
return new ClaudeAgentClient({
logger: createTestLogger(),
resolveVersion: async () => claudeCodeVersion,
@@ -66,6 +66,7 @@ describe("getClaudeModels", () => {
"claude-opus-4-6",
"claude-sonnet-4-6[1m]",
"claude-sonnet-4-6",
"claude-haiku-5-5",
"claude-haiku-4-5",
]);
});
@@ -100,6 +101,7 @@ describe("getClaudeModels", () => {
["claude-opus-4-6", 200_000],
["claude-sonnet-4-6[1m]", 1_000_000],
["claude-sonnet-4-6", 200_000],
["claude-haiku-5-5", 1_000_000],
["claude-haiku-4-5", 200_000],
]),
);
@@ -123,6 +125,12 @@ describe("getClaudeModels", () => {
expect(getClaudeModels("2.1.284").map((model) => model.id)).toContain("claude-sonnet-5-5");
});
it("gates Haiku 5.5 on Claude Code 2.1.293 without changing the default", () => {
expect(getClaudeModels("2.1.292").map((model) => model.id)).not.toContain("claude-haiku-5-5");
expect(getClaudeModels("2.1.293").map((model) => model.id)).toContain("claude-haiku-5-5");
expect(getClaudeModels("2.1.293").find((model) => model.isDefault)?.id).toBe("claude-opus-5-5");
});
it("derives thinking options from model effort capabilities", () => {
const models = new Map(getClaudeModels().map((model) => [model.id, model]));
@@ -192,6 +200,8 @@ describe("getClaudeModels", () => {
["claude-sonnet-5-20260101", true, "high"],
["claude-fable-5", false, "high"],
["claude-fable-5-1", false, "high"],
["claude-haiku-5-5", true, "medium"],
["claude-haiku-5-5-20261007", true, "medium"],
["claude-haiku-4-5", false, undefined],
["openrouter/anthropic/claude-opus-4-8", false, undefined],
[null, false, undefined],
@@ -653,6 +663,51 @@ describe("Claude Sonnet 5.5 catalog", () => {
});
});
describe("Claude Haiku 5.5 catalog", () => {
it("offers one Haiku 5.5 entry with a 1M context window", () => {
const haiku55Models = getClaudeModels()
.filter((model) => model.id.startsWith("claude-haiku-5-5"))
.map(({ id, label, contextWindowMaxTokens }) => ({ id, label, contextWindowMaxTokens }));
expect(haiku55Models).toEqual([
{ id: "claude-haiku-5-5", label: "Haiku 5.5", contextWindowMaxTokens: 1_000_000 },
]);
});
it("offers Off and every effort level with medium as the default", () => {
const haiku55 = getClaudeModels().find((model) => model.id === "claude-haiku-5-5");
expect(haiku55?.thinkingOptions?.map((option) => option.id)).toEqual([
CLAUDE_DISABLED_THINKING_OPTION_ID,
"low",
"medium",
"high",
"xhigh",
"max",
CLAUDE_ULTRACODE_THINKING_OPTION_ID,
]);
expect(haiku55?.defaultThinkingOptionId).toBe("medium");
expect(
haiku55?.thinkingOptions?.filter((option) => option.isDefault).map((option) => option.id),
).toEqual(["medium"]);
});
it("normalizes provider-prefixed runtime IDs", () => {
expect(normalizeClaudeRuntimeModelId("anthropic/claude-haiku-5-5")).toBe("claude-haiku-5-5");
expect(normalizeClaudeRuntimeModelId("us.anthropic.claude-haiku-5-5-v1:0")).toBe(
"claude-haiku-5-5",
);
expect(claudeManifestModelSupportsFastMode("claude-haiku-5-5")).toBe(false);
});
it("resolves suffixed and dated Haiku 5.5 IDs to the single catalog entry", () => {
expect(findClaudeModel("claude-haiku-5-5[1m]")?.id).toBe("claude-haiku-5-5");
expect(findClaudeModel("claude-haiku-5-5-20261007")?.id).toBe("claude-haiku-5-5");
expect(findClaudeModel("claude-haiku-5-5-20261007[1m]")?.id).toBe("claude-haiku-5-5");
expect(findClaudeModel("claude-haiku-5-5[1m]")?.contextWindowMaxTokens).toBe(1_000_000);
});
});
describe("claudeManifestModelSupportsFastMode", () => {
it("keeps fast mode strict to first-party manifest model IDs", () => {
expect(normalizeClaudeManifestModelId("openrouter/anthropic/claude-opus-4-8")).toBeNull();
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@getpaseo/website",
"version": "0.11.0",
"version": "0.11.2",
"private": true,
"type": "module",
"scripts": {
@@ -12,6 +12,14 @@ export function SiteHeader() {
<span className="text-lg font-medium">Paseo</span>
</a>
<div className="flex flex-wrap items-center justify-center gap-4">
{PLUGINS_LINKED && (
<a
href="/plugins"
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
>
Plugins
</a>
)}
<a
href="/blog"
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
@@ -24,14 +32,6 @@ export function SiteHeader() {
>
Docs
</a>
{PLUGINS_LINKED && (
<a
href="/plugins"
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
>
Plugins
</a>
)}
<a
href="/changelog"
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
@@ -1,72 +0,0 @@
diff --git a/node_modules/react-native-uitextview/ios/RNUITextView.mm b/node_modules/react-native-uitextview/ios/RNUITextView.mm
index d0c31ed..df8a233 100644
--- a/node_modules/react-native-uitextview/ios/RNUITextView.mm
+++ b/node_modules/react-native-uitextview/ios/RNUITextView.mm
@@ -22,6 +22,7 @@ using namespace facebook::react;
RNUITextViewShadowNode::ConcreteState::Shared _state;
UITapGestureRecognizer * _outsideTapRecognizer;
BOOL _suppressSelectionChange;
+ CGRect _lastTextLayoutFrame;
}
+ (ComponentDescriptorProvider)componentDescriptorProvider
@@ -47,7 +48,8 @@ using namespace facebook::react;
_textView.delegate = self;
// Must match RCTTextLayoutManager, which measures with usesFontLeading = NO.
_textView.layoutManager.usesFontLeading = NO;
- [self addSubview:_textView];
+ _textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+ [_view addSubview:_textView];
const auto longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self
action:@selector(handleLongPressIfNecessary:)];
@@ -94,16 +96,15 @@ using namespace facebook::react;
// Reset the frame to zero so that when it properly lays out on the next use
_textView.frame = CGRectZero;
_textView.attributedText = nil;
+ _lastTextLayoutFrame = CGRectZero;
}
- (void)layoutSubviews
{
[super layoutSubviews];
- // _textView's frame is assigned inside drawRect, which only fires when
- // state changes. Trigger a redraw whenever the host frame moves out from
- // under it (rotation, parent relayout) so the text view resizes and
- // onTextLayout re-fires with the new line wrapping.
- if (!CGRectEqualToRect(_textView.frame, _view.frame)) {
+ // Autoresizing updates UIKit immediately; report the new line layout when
+ // the content container's bounds change.
+ if (!CGRectEqualToRect(_lastTextLayoutFrame, _view.bounds)) {
[self setNeedsDisplay];
}
}
@@ -124,8 +125,9 @@ using namespace facebook::react;
// entirely when nothing actually changed so a JS-side state update made in
// response to onSelectionChange doesn't deselect what the user is selecting.
const BOOL textChanged = ![_textView.attributedText isEqualToAttributedString:convertedAttrString];
- const BOOL frameChanged = !CGRectEqualToRect(_textView.frame, _view.frame);
- if (!textChanged && !frameChanged) {
+ const BOOL frameChanged = !CGRectEqualToRect(_textView.frame, _view.bounds);
+ const BOOL layoutChanged = !CGRectEqualToRect(_lastTextLayoutFrame, _view.bounds);
+ if (!textChanged && !frameChanged && !layoutChanged) {
return;
}
if (textChanged) {
@@ -142,7 +144,7 @@ using namespace facebook::react;
_suppressSelectionChange = NO;
}
if (frameChanged) {
- _textView.frame = _view.frame;
+ _textView.frame = _view.bounds;
}
__block std::vector<std::string> lines;
@@ -162,6 +164,7 @@ using namespace facebook::react;
}
}];
+ _lastTextLayoutFrame = _view.bounds;
if (_eventEmitter != nullptr) {
std::dynamic_pointer_cast<const facebook::react::RNUITextViewEventEmitter>(_eventEmitter)
->onTextLayout(facebook::react::RNUITextViewEventEmitter::OnTextLayout{static_cast<int>(self.tag), lines});
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@getpaseo/builtin-plugins",
"version": "0.11.0",
"version": "0.11.2",
"private": true,
"type": "module",
"scripts": {
-4
View File
@@ -12,10 +12,6 @@ const patchedPackages = [
nodeModulesPath: "node_modules/react-native-markdown-display",
patchPrefix: "react-native-markdown-display+",
},
{
nodeModulesPath: "node_modules/react-native-uitextview",
patchPrefix: "react-native-uitextview+",
},
// Remove after react-native-unistyles ships
// https://github.com/jpudysz/react-native-unistyles/pull/1203.
{