Merge remote-tracking branch 'origin/main' into dev

# Conflicts:
#	nix/package.nix
#	packages/app/src/components/icons/opencode-icon.tsx
#	packages/app/src/components/provider-icons.ts
#	packages/app/src/panels/agent-panel.tsx
#	packages/cli/src/commands/provider/ls.ts
#	packages/server/src/server/agent/provider-manifest.ts
#	packages/server/src/server/agent/provider-registry.ts
#	packages/server/src/server/agent/providers/claude-agent.test.ts
#	packages/server/src/server/agent/providers/claude-agent.ts
#	packages/server/src/server/persistence-hooks.ts
#	packages/server/src/server/session.ts
This commit is contained in:
Mohamed Boudra
2026-04-03 10:10:20 +07:00
65 changed files with 4510 additions and 970 deletions
@@ -27,6 +27,7 @@ import { type GestureType } from "react-native-gesture-handler";
import * as Clipboard from "expo-clipboard";
import {
Archive,
CircleAlert,
ChevronDown,
ChevronRight,
Copy,
@@ -73,7 +74,7 @@ import { decideLongPressMove } from "@/utils/sidebar-gesture-arbitration";
import { confirmDialog } from "@/utils/confirm-dialog";
import { projectIconPlaceholderLabelFromDisplayName } from "@/utils/project-display-name";
import { shouldRenderSyncedStatusLoader } from "@/utils/status-loader";
import { getStatusDotColor } from "@/utils/status-dot-color";
import { getStatusDotColor, isEmphasizedStatusDotBucket } from "@/utils/status-dot-color";
import { Button } from "@/components/ui/button";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { Shortcut } from "@/components/ui/shortcut";
@@ -105,6 +106,10 @@ const workspaceKeyExtractor = (workspace: SidebarWorkspaceEntry) => workspace.wo
const projectKeyExtractor = (project: SidebarProjectEntry) => project.projectKey;
const EMPTY_WORKSPACES = new Map();
const WORKSPACE_STATUS_DOT_WIDTH = 14;
const DEFAULT_STATUS_DOT_SIZE = 7;
const EMPHASIZED_STATUS_DOT_SIZE = 9;
const DEFAULT_STATUS_DOT_OFFSET = 0;
const EMPHASIZED_STATUS_DOT_OFFSET = -1;
const GITHUB_PR_STATE_LABELS: Record<PrHint["state"], string> = {
open: "Open",
merged: "Merged",
@@ -243,6 +248,14 @@ function WorkspaceStatusIndicator({
);
}
if (bucket === "needs_input") {
return (
<View style={styles.workspaceStatusDot}>
<CircleAlert size={14} color={theme.colors.palette.amber[500]} />
</View>
);
}
const KindIcon =
workspaceKind === "checkout"
? Monitor
@@ -252,6 +265,13 @@ function WorkspaceStatusIndicator({
if (!KindIcon) return null;
const dotColor = getStatusDotColor({ theme, bucket, showDoneAsInactive: false });
const statusDotSize = isEmphasizedStatusDotBucket(bucket)
? EMPHASIZED_STATUS_DOT_SIZE
: DEFAULT_STATUS_DOT_SIZE;
const statusDotOffset =
statusDotSize === EMPHASIZED_STATUS_DOT_SIZE
? EMPHASIZED_STATUS_DOT_OFFSET
: DEFAULT_STATUS_DOT_OFFSET;
return (
<View style={styles.workspaceStatusDot}>
@@ -263,6 +283,10 @@ function WorkspaceStatusIndicator({
{
backgroundColor: dotColor,
borderColor: theme.colors.surface0,
width: statusDotSize,
height: statusDotSize,
right: statusDotOffset,
bottom: statusDotOffset,
},
]}
/>
@@ -332,11 +356,26 @@ function ProjectLeadingVisual({
);
}
if (activeWorkspace.statusBucket === "needs_input") {
return (
<View style={styles.projectLeadingVisualSlot}>
<CircleAlert size={14} color={theme.colors.palette.amber[500]} />
</View>
);
}
const dotColor = getStatusDotColor({
theme,
bucket: activeWorkspace.statusBucket,
showDoneAsInactive: false,
});
const statusDotSize = isEmphasizedStatusDotBucket(activeWorkspace.statusBucket)
? EMPHASIZED_STATUS_DOT_SIZE
: DEFAULT_STATUS_DOT_SIZE;
const statusDotOffset =
statusDotSize === EMPHASIZED_STATUS_DOT_SIZE
? EMPHASIZED_STATUS_DOT_OFFSET
: DEFAULT_STATUS_DOT_OFFSET;
return (
<View style={styles.projectLeadingVisualSlot}>
@@ -348,6 +387,10 @@ function ProjectLeadingVisual({
{
backgroundColor: dotColor,
borderColor: theme.colors.surface0,
width: statusDotSize,
height: statusDotSize,
right: statusDotOffset,
bottom: statusDotOffset,
},
]}
/>
@@ -2212,10 +2255,10 @@ const styles = StyleSheet.create((theme) => ({
},
statusDotOverlay: {
position: "absolute",
right: 0,
bottom: 0,
width: 7,
height: 7,
right: DEFAULT_STATUS_DOT_OFFSET,
bottom: DEFAULT_STATUS_DOT_OFFSET,
width: DEFAULT_STATUS_DOT_SIZE,
height: DEFAULT_STATUS_DOT_SIZE,
borderRadius: theme.borderRadius.full,
borderWidth: 1,
},