diff --git a/.github/issue-evidence/11752-widget-overlap/after-mobile-home.png b/.github/issue-evidence/11752-widget-overlap/after-mobile-home.png
index 934d9cf37c650..6454f04a199ba 100644
Binary files a/.github/issue-evidence/11752-widget-overlap/after-mobile-home.png and b/.github/issue-evidence/11752-widget-overlap/after-mobile-home.png differ
diff --git a/.github/issue-evidence/11752-widget-overlap/before-mobile-home.png b/.github/issue-evidence/11752-widget-overlap/before-mobile-home.png
index 1f6e9c746ea20..9d089a3f3f962 100644
Binary files a/.github/issue-evidence/11752-widget-overlap/before-mobile-home.png and b/.github/issue-evidence/11752-widget-overlap/before-mobile-home.png differ
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 64182c252c4af..0564a58438b92 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -626,40 +626,6 @@ jobs:
run: |
node packages/scripts/verify-npm-pack-dist.mjs --all-public-dist-packages --build
- # Stage downloadable release binaries so the GitHub Release carries more
- # than just source archives (#11858): headline npm tarballs + standalone
- # `elizaos` CLI executables for every platform + a combined checksum file.
- # Runs while workspace:* refs are still replaced (packed dependency ranges
- # match the registry) and before the "Restore workspace references" step.
- # Gated to real release events β a workflow_dispatch beta (tag_created) or
- # a stable GitHub `release`.
- - name: Stage release binaries (npm tarballs + standalone CLI)
- id: stage_artifacts
- if: steps.tag.outputs.tag_created == 'true' || github.event_name == 'release'
- run: |
- set -euo pipefail
- ARTIFACT_DIR="${GITHUB_WORKSPACE}/release-artifacts"
- rm -rf "${ARTIFACT_DIR}"
- mkdir -p "${ARTIFACT_DIR}"
-
- echo "π¦ Packing headline npm tarballs..."
- node packages/scripts/pack-release-artifacts.mjs --out "${ARTIFACT_DIR}/npm"
-
- echo "π Compiling standalone elizaos CLI binaries (all platforms)..."
- bun packages/elizaos/build-standalone.ts --out "${ARTIFACT_DIR}/cli"
-
- echo "π Writing combined SHA256SUMS.txt..."
- (
- cd "${ARTIFACT_DIR}"
- find . -type f \( -name '*.tgz' -o -name '*.tar.gz' -o -name '*.zip' \) \
- | sed 's|^\./||' | sort \
- | while read -r f; do shasum -a 256 "$f"; done > SHA256SUMS.txt
- )
-
- echo "artifact_dir=${ARTIFACT_DIR}" >> "$GITHUB_OUTPUT"
- echo "=== staged release artifacts ==="
- find "${ARTIFACT_DIR}" -type f | sort
-
# Publish to NPM (only after git operations succeed)
- name: Skip NPM publish on forks
if: github.repository != 'elizaOS/eliza'
@@ -827,17 +793,6 @@ jobs:
with:
tag_name: ${{ steps.tag.outputs.tag_name }}
name: ${{ steps.tag.outputs.tag_name }}
- # Attach the staged downloadable binaries alongside the auto-generated
- # source archives. fail_on_unmatched_files surfaces a broken staging
- # step instead of silently publishing a source-only release again.
- files: |
- release-artifacts/npm/*.tgz
- release-artifacts/npm/SHA256SUMS-npm.txt
- release-artifacts/cli/*.tar.gz
- release-artifacts/cli/*.zip
- release-artifacts/cli/SHA256SUMS-cli.txt
- release-artifacts/SHA256SUMS.txt
- fail_on_unmatched_files: true
body: |
π΅ Beta Release
@@ -856,38 +811,12 @@ jobs:
bun add @elizaos/core@${{ steps.release_type.outputs.dist_tag }}
```
- ### Downloads
-
- Prefer a self-contained binary? Grab a standalone `elizaos` CLI
- (`elizaos-.tar.gz` / `.zip`) below β no npm or Bun required.
- The `*.tgz` files are the exact npm tarballs; verify any download
- against `SHA256SUMS.txt`.
-
---
> **Note:** This is a ${{ steps.release_type.outputs.type }} release. Production releases use the `latest` tag and are triggered by GitHub releases on tags matching `v*.*.*`.
draft: false
prerelease: true
- # Stable production releases already exist (a human created the GitHub
- # release before this workflow fired on the `release` event), so we append
- # the staged binaries to that existing release instead of creating one.
- - name: Attach release binaries to production release
- if: github.event_name == 'release' && steps.stage_artifacts.outputs.artifact_dir != ''
- uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- with:
- tag_name: ${{ github.event.release.tag_name }}
- files: |
- release-artifacts/npm/*.tgz
- release-artifacts/npm/SHA256SUMS-npm.txt
- release-artifacts/cli/*.tar.gz
- release-artifacts/cli/*.zip
- release-artifacts/cli/SHA256SUMS-cli.txt
- release-artifacts/SHA256SUMS.txt
- fail_on_unmatched_files: true
-
- name: Summary
if: always()
run: |
diff --git a/.gitignore b/.gitignore
index 5136ecbebe4cb..8207f3a1d0d4d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1518,8 +1518,3 @@ railway.json
.railwayignore
.dockerignore
packages/ui/src/components/shell/__e2e__/output-fused-wake-integration/
-
-# Standalone CLI build output (packages/elizaos/build-standalone.ts)
-packages/elizaos/dist-standalone/
-# Release artifacts staged by release.yaml (npm tarballs + CLI binaries)
-release-artifacts/
diff --git a/packages/app/test/ui-smoke/all-views-interaction.spec.ts b/packages/app/test/ui-smoke/all-views-interaction.spec.ts
index eaa97d1768395..a184eabfb5f09 100644
--- a/packages/app/test/ui-smoke/all-views-interaction.spec.ts
+++ b/packages/app/test/ui-smoke/all-views-interaction.spec.ts
@@ -11,6 +11,7 @@ import {
openAppPath,
seedAppStorage,
} from "./helpers";
+import { VIEW_ROUTES } from "./view-routes";
/**
* Generic per-view interaction coverage (#8796).
@@ -27,42 +28,6 @@ import {
* Clicks that navigate away are recovered by re-opening the route, so one
* navigation doesn't end coverage of the rest of the page.
*/
-const VIEW_ROUTES: Array<{ id: string; path: string }> = [
- { id: "chat", path: "/chat" },
- { id: "phone", path: "/phone" },
- { id: "messages", path: "/messages" },
- { id: "contacts", path: "/contacts" },
- { id: "camera", path: "/camera" },
- { id: "tasks", path: "/apps/tasks" },
- { id: "browser", path: "/browser" },
- { id: "stream", path: "/stream" },
- { id: "apps", path: "/apps" },
- { id: "views", path: "/views" },
- { id: "character", path: "/character" },
- { id: "character-select", path: "/character/select" },
- { id: "automations", path: "/automations" },
- { id: "inventory", path: "/wallet" },
- { id: "documents", path: "/character/documents" },
- { id: "files", path: "/apps/files" },
- { id: "plugins", path: "/apps/plugins" },
- { id: "skills", path: "/apps/skills" },
- { id: "fine-tuning", path: "/apps/fine-tuning" },
- { id: "trajectories", path: "/apps/trajectories" },
- { id: "transcripts", path: "/apps/transcripts" },
- { id: "relationships", path: "/apps/relationships" },
- { id: "memories", path: "/apps/memories" },
- { id: "rolodex", path: "/rolodex" },
- { id: "voice", path: "/settings/voice" },
- { id: "runtime", path: "/apps/runtime" },
- { id: "database", path: "/apps/database" },
- { id: "desktop", path: "/desktop" },
- { id: "settings", path: "/settings" },
- { id: "tutorial", path: "/tutorial" },
- { id: "help", path: "/help" },
- { id: "logs", path: "/apps/logs" },
- { id: "background", path: "/background" },
-];
-
// Bound per-view work so the suite stays under the playwright timeout while
// still exercising a representative breadth of controls.
const MAX_CLICKS = 24;
diff --git a/packages/app/test/ui-smoke/tap-target-geometry-all-views.spec.ts b/packages/app/test/ui-smoke/tap-target-geometry-all-views.spec.ts
new file mode 100644
index 0000000000000..b4add44c8f4f1
--- /dev/null
+++ b/packages/app/test/ui-smoke/tap-target-geometry-all-views.spec.ts
@@ -0,0 +1,528 @@
+// Reusable rendered-geometry tap-target + role/DOM-coherence gate (#10722).
+//
+// The 44px Apple-HIG touch floor used to be enforced only as a CSS token
+// (`--min-touch-target`) plus lint conventions β nothing measured what the
+// browser actually laid out, so a control could regress below 44px (the
+// ShellBackButton shipped at 36px; the spatial filter chips at ~34px) with the
+// whole gate green. `tap-target-geometry.spec.ts` measures the two known
+// regression surfaces; THIS spec generalizes that to a REUSABLE gate that walks
+// the same canonical built-in view enumeration the interaction-coverage spec
+// uses (`./view-routes`), measures REAL `getBoundingClientRect()` geometry for
+// every standalone interactive control on a coarse-pointer Pixel-7 viewport, and
+// asserts:
+//
+// 1. every STANDALONE interactive control (icon/label button, role=button/
+// tab/switch/menuitem, standalone link) renders a >=44x44 hit target, and
+// 2. role<->DOM-node coherence: an ARIA role must not contradict the node's
+// native semantics, a non-native role=button/link must be keyboard-
+// focusable, and every interactive control must expose an accessible name.
+//
+// Legitimately-sub-44 controls (inline prose links, native checkbox/radio boxes
+// whose
-
+
{t("automationsfeed.createFirst", {
defaultValue: "Create your first automation",
@@ -657,7 +663,7 @@ function FilterChipButton({
aria-current={isActive ? "true" : undefined}
// Borderless text tab (#10710): active reads as accent text on a faint
// wash; the count renders as plain text and hides at zero.
- className={`inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-xs font-medium transition-colors ${
+ className={`inline-flex min-h-11 items-center gap-1.5 rounded-full px-3 py-2 text-xs font-medium transition-colors ${
isActive
? "bg-accent/10 text-accent"
: "text-muted-strong hover:bg-bg-accent/40"
diff --git a/packages/ui/src/components/pages/BrowserWorkspaceView.tsx b/packages/ui/src/components/pages/BrowserWorkspaceView.tsx
index 827d75451fe43..3584b3183de92 100644
--- a/packages/ui/src/components/pages/BrowserWorkspaceView.tsx
+++ b/packages/ui/src/components/pages/BrowserWorkspaceView.tsx
@@ -456,7 +456,9 @@ function BrowserAddressInput({
getValue,
onFill,
});
- return ;
+ return (
+
+ );
}
function BrowserTabRow({
@@ -2359,7 +2361,7 @@ export function BrowserWorkspaceView(): React.JSX.Element {
onActivate={() => setTabsSidebarCollapsed((current) => !current)}
variant="ghost"
size="icon"
- className="h-8 w-8 shrink-0"
+ className="h-11 w-11 shrink-0"
aria-label={
tabsSidebarCollapsed
? t("browserworkspace.ExpandTabs", {
@@ -2393,7 +2395,7 @@ export function BrowserWorkspaceView(): React.JSX.Element {
}
variant="ghost"
size="icon"
- className="h-8 w-8 shrink-0"
+ className="h-11 w-11 shrink-0"
aria-label={newTabLabel}
disabled={busyAction !== null}
onClick={() =>
@@ -2420,7 +2422,7 @@ export function BrowserWorkspaceView(): React.JSX.Element {
}
variant="ghost"
size="icon"
- className="h-8 w-8"
+ className="h-11 w-11"
aria-label={t("common.refresh", { defaultValue: "Refresh" })}
disabled={!selectedTab || busyAction !== null}
onClick={() =>
@@ -2445,7 +2447,7 @@ export function BrowserWorkspaceView(): React.JSX.Element {
}
variant="ghost"
size="icon"
- className="h-8 w-8"
+ className="h-11 w-11"
aria-label={t("browserworkspace.CloseAllTabs", {
defaultValue: "Close all tabs",
})}
@@ -2494,7 +2496,7 @@ export function BrowserWorkspaceView(): React.JSX.Element {
})}
data-testid="browser-workspace-address-input"
disabled={busyAction !== null || selectedTabIsInternal}
- className="h-8 min-w-0 flex-1 rounded-full border-border/40 bg-card/70 px-4 text-sm text-txt"
+ className="h-11 min-w-0 flex-1 rounded-full border-border/40 bg-card/70 px-4 text-sm text-txt"
/>
void installBrowserBridgeExtension()}
- className="sm:col-span-3"
+ className="min-h-11 sm:col-span-3"
>
{t("browserworkspace.InstallBrowserBridge", {
defaultValue: "Install Agent Browser Bridge",
@@ -2676,7 +2678,7 @@ export function BrowserWorkspaceView(): React.JSX.Element {
!browserBridgePackageStatus?.chromeBuildPath
}
onClick={() => void revealBrowserBridgeFolder()}
- className="min-w-0"
+ className="min-h-11 min-w-0"
>
@@ -2690,7 +2692,7 @@ export function BrowserWorkspaceView(): React.JSX.Element {
variant="ghost"
disabled={busyAction !== null}
onClick={() => void openBrowserBridgeChromeExtensions()}
- className="min-w-0"
+ className="min-h-11 min-w-0"
>
{t("browserworkspace.OpenChromeExtensions", {
@@ -2703,7 +2705,7 @@ export function BrowserWorkspaceView(): React.JSX.Element {
variant="ghost"
disabled={browserBridgeLoading || busyAction !== null}
onClick={() => void refreshBrowserBridgeConnection()}
- className="min-w-0"
+ className="min-h-11 min-w-0"
>
diff --git a/packages/ui/src/components/pages/DocumentsView.tsx b/packages/ui/src/components/pages/DocumentsView.tsx
index 2d3fadefa9347..c47a643d4b8aa 100644
--- a/packages/ui/src/components/pages/DocumentsView.tsx
+++ b/packages/ui/src/components/pages/DocumentsView.tsx
@@ -137,7 +137,7 @@ function ScopeFilterChip({
aria-current={active ? "page" : undefined}
onClick={() => onSelect(value)}
// Borderless text tab (#10710): active = accent text on a faint wash.
- className={`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-2xs font-semibold transition-colors ${
+ className={`inline-flex min-h-11 items-center gap-1 rounded-full px-3 py-2 text-2xs font-semibold transition-colors ${
active
? "bg-accent/12 text-accent"
: "text-muted hover:bg-bg-muted/30 hover:text-txt"
@@ -266,7 +266,7 @@ const DocumentListItem = memo(function DocumentListItem({
})}
aria-current={active ? "page" : undefined}
title={doc.filename}
- className="flex min-w-0 flex-1 items-center gap-3 px-3.5 py-3 text-left"
+ className="flex min-h-11 min-w-0 flex-1 items-center gap-3 px-3.5 py-3 text-left"
>
onSelect(id)}
// Borderless selector pill (#10710): selection = accent text on a wash.
- className={`inline-flex max-w-[16rem] shrink-0 items-center gap-2 rounded-full px-3 py-1.5 text-xs font-semibold transition ${
+ className={`inline-flex min-h-11 max-w-[16rem] shrink-0 items-center gap-2 rounded-full px-3 py-2 text-xs font-semibold transition ${
active
? "bg-accent/12 text-accent"
: "text-muted hover:bg-bg-muted/30 hover:text-txt"
@@ -392,7 +392,7 @@ function CompactDocChip({
type="button"
onClick={() => onSelect(doc.id)}
// Borderless selector pill (#10710): selection = accent text on a wash.
- className={`inline-flex max-w-[16rem] shrink-0 items-center gap-2 rounded-full px-3 py-1.5 text-xs font-semibold transition ${
+ className={`inline-flex min-h-11 max-w-[16rem] shrink-0 items-center gap-2 rounded-full px-3 py-2 text-xs font-semibold transition ${
active
? "bg-accent/12 text-accent"
: "text-muted hover:bg-bg-muted/30 hover:text-txt"
diff --git a/packages/ui/src/components/pages/FilesView.tsx b/packages/ui/src/components/pages/FilesView.tsx
index ffae9e9e3a908..f1faef66ca67e 100644
--- a/packages/ui/src/components/pages/FilesView.tsx
+++ b/packages/ui/src/components/pages/FilesView.tsx
@@ -143,7 +143,7 @@ function FileFacetButton({
data-testid={`file-facet-${facet}`}
aria-pressed={active}
onClick={() => onSelect(facet)}
- className={`rounded-full px-3 py-1 text-xs-tight font-semibold transition-colors ${
+ className={`min-h-11 rounded-full px-3 py-2 text-xs-tight font-semibold transition-colors ${
active
? "bg-accent/15 text-accent"
: "text-muted hover:bg-surface hover:text-txt"
diff --git a/packages/ui/src/components/pages/LogsView.tsx b/packages/ui/src/components/pages/LogsView.tsx
index dc3e064b11710..c289a158de131 100644
--- a/packages/ui/src/components/pages/LogsView.tsx
+++ b/packages/ui/src/components/pages/LogsView.tsx
@@ -296,7 +296,7 @@ function LogsViewBody() {
>
@@ -318,7 +318,7 @@ function LogsViewBody() {
>
@@ -342,7 +342,7 @@ function LogsViewBody() {
>
diff --git a/packages/ui/src/components/pages/MemoryViewerView.tsx b/packages/ui/src/components/pages/MemoryViewerView.tsx
index 4a6bcc552b791..b415235ee3ee0 100644
--- a/packages/ui/src/components/pages/MemoryViewerView.tsx
+++ b/packages/ui/src/components/pages/MemoryViewerView.tsx
@@ -869,12 +869,16 @@ export function MemoryViewerView({
{/* View mode toggle + person context */}
-
+
setViewMode(v as ViewMode)}
items={viewModeItems}
- buttonClassName="min-h-8 px-4 py-2"
+ buttonClassName="min-h-11 px-4 py-2"
/>
{selectedPerson ? (
@@ -885,7 +889,7 @@ export function MemoryViewerView({
type="button"
size="sm"
variant="ghost"
- className="h-6 px-2 text-xs-tight"
+ className="min-h-11 px-3 text-xs-tight"
onClick={handleClearPerson}
>
{t("memoryviewer.clear", { defaultValue: "Clear" })}
diff --git a/packages/ui/src/components/pages/PluginCard.tsx b/packages/ui/src/components/pages/PluginCard.tsx
index 4d82214b6e750..49d39f6a5f0e3 100644
--- a/packages/ui/src/components/pages/PluginCard.tsx
+++ b/packages/ui/src/components/pages/PluginCard.tsx
@@ -187,7 +187,7 @@ export const PluginCard = memo(function PluginCard({
variant="outline"
size="sm"
data-plugin-toggle={p.id}
- className={`h-auto shrink-0 rounded-full border px-3 py-[3px] text-2xs font-bold tracking-wider transition-colors duration-150 ${toggleHealthClass} ${
+ className={`min-h-11 shrink-0 rounded-full border px-3 py-2 text-2xs font-bold tracking-wider transition-colors duration-150 ${toggleHealthClass} ${
toggleDisabled ? "cursor-not-allowed opacity-60" : "cursor-pointer"
}`}
title={toggleTitle}
diff --git a/packages/ui/src/components/pages/PluginsView.tsx b/packages/ui/src/components/pages/PluginsView.tsx
index d36131b2c77b6..3c02ce4c86a97 100644
--- a/packages/ui/src/components/pages/PluginsView.tsx
+++ b/packages/ui/src/components/pages/PluginsView.tsx
@@ -361,7 +361,7 @@ function PluginListView({
key={tag.id}
variant={isActive ? "default" : "outline"}
size="sm"
- className={`h-8 gap-1.5 rounded-full px-3 text-xs-tight font-bold tracking-wide transition-all ${
+ className={`min-h-11 gap-1.5 rounded-full px-3 text-xs-tight font-bold tracking-wide transition-all ${
isActive
? "border-accent bg-accent text-accent-fg hover:bg-accent/90"
: "border-border/50 bg-card/50 text-muted hover:border-accent/40 hover:text-txt"
@@ -1327,7 +1327,7 @@ function PluginListView({
ref={resetOrderRef}
variant="outline"
size="sm"
- className="ml-1 h-8 rounded-full px-3 text-2xs font-bold tracking-wide text-muted hover:text-txt"
+ className="ml-1 min-h-11 rounded-full px-3 text-2xs font-bold tracking-wide text-muted hover:text-txt"
onClick={handleResetOrder}
title={t("pluginsview.ResetToDefaultSor")}
{...resetOrderAgentProps}
diff --git a/packages/ui/src/components/pages/WalletSectionNav.tsx b/packages/ui/src/components/pages/WalletSectionNav.tsx
index 57e816a932d4c..8b656094bb9f0 100644
--- a/packages/ui/src/components/pages/WalletSectionNav.tsx
+++ b/packages/ui/src/components/pages/WalletSectionNav.tsx
@@ -86,7 +86,7 @@ export function WalletSectionNav({
if (!isActive) navigate(tab.path);
}}
className={cn(
- "rounded-md px-3 py-1.5 text-sm font-medium transition-colors",
+ "min-h-11 rounded-md px-3 py-2 text-sm font-medium transition-colors",
isActive
? "bg-accent/15 text-accent"
: "text-muted-foreground hover:bg-foreground/5 hover:text-foreground",
diff --git a/packages/ui/src/components/pages/relationships/RelationshipsWorkspaceView.tsx b/packages/ui/src/components/pages/relationships/RelationshipsWorkspaceView.tsx
index ab743c654b060..1c00966adce6e 100644
--- a/packages/ui/src/components/pages/relationships/RelationshipsWorkspaceView.tsx
+++ b/packages/ui/src/components/pages/relationships/RelationshipsWorkspaceView.tsx
@@ -222,7 +222,7 @@ export function RelationshipsWorkspaceView({
aria-label={t("relationships.platformFilter", {
defaultValue: "Platform filter",
})}
- className="h-9 w-full rounded-sm border border-border/35 bg-card/45 pl-9 pr-8 text-sm text-txt outline-none transition "
+ className="h-11 w-full rounded-sm border border-border/35 bg-card/45 pl-9 pr-8 text-sm text-txt outline-none transition "
{...platformAgent.agentProps}
>