Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
11c8d35
docs(status): beta.5 promoted to master + tagged; browser NAT fix, #1…
jaylfc Jun 20, 2026
4b605fd
docs(changelog): backfill beta.4 and beta.4.1 sections from their rel…
jaylfc Jun 20, 2026
f8ceb16
neko(rk3588): base the RK3588 image on the CDP image (separate, arm64…
jaylfc Jun 20, 2026
d3fe28b
neko(rk3588): from-source MPP + gstreamer-rockchip build via CI arm64…
jaylfc Jun 20, 2026
f97ecf8
ci(neko-rk3588): build on PR for compile validation (push only on dev…
jaylfc Jun 20, 2026
58c8c4e
neko(rk3588): switch gstreamer-rockchip to BoxCloud fork + multiarch …
jaylfc Jun 20, 2026
ddb1b2a
Merge pull request #1235 from jaylfc/feat/neko-rk3588-cdp-base
jaylfc Jun 20, 2026
b72aeb9
neko(rk3588): flip resolver to the validated HW-encode image (#624)
jaylfc Jun 20, 2026
be265b4
neko(rk3588): expose CDP url for the rk3588 image too (built from CDP)
jaylfc Jun 20, 2026
db7ecc3
test: add endpoint tests for agent_deploy route helpers
jaylfc Jun 20, 2026
523c07f
Merge pull request #1236 from jaylfc/feat/neko-rk3588-flip-resolver
jaylfc Jun 20, 2026
68a455e
Merge pull request #1237 from jaylfc/exec/tsk-qjubyu
jaylfc Jun 20, 2026
68b4025
Add endpoint tests for routes/taos_agent.py
jaylfc Jun 20, 2026
de33707
neko(rk3588): correct comment -- no resolver-level software fallback …
jaylfc Jun 20, 2026
2261916
docs(status): #125 done + overnight owl queue-fill + dispatcher hold-…
jaylfc Jun 20, 2026
c2bbe9b
feat(cluster): capability map store (foundation, #897)
jaylfc Jun 20, 2026
d0aee3c
Merge pull request #1238 from jaylfc/exec/tsk-cvdniw
jaylfc Jun 21, 2026
5f51ed2
test: add unit tests for agent_registry_store
jaylfc Jun 21, 2026
4c6ea47
test: add unit tests for download_manager
jaylfc Jun 21, 2026
8ab5644
fix(cluster): preserve explicit last_seen=0; clear error on missing n…
jaylfc Jun 21, 2026
46b2ad9
test: add unit tests for FeedbackStore
jaylfc Jun 21, 2026
6c9c983
Add unit tests for installed_apps store
jaylfc Jun 21, 2026
71859af
Add unit tests for office_docs
jaylfc Jun 21, 2026
5808a01
test: add unit tests for torrent_settings module
jaylfc Jun 21, 2026
f522340
Merge pull request #1240 from jaylfc/exec/tsk-iw2l6i
jaylfc Jun 21, 2026
d8cab25
test: add vitest tests for use-installed-optional-apps hook
jaylfc Jun 21, 2026
42da853
test: add vitest tests for use-installed-services hook
jaylfc Jun 21, 2026
4e984a7
test: add vitest tests for use-installed-userspace-apps hook
jaylfc Jun 21, 2026
9424a1e
Merge pull request #1245 from jaylfc/exec/tsk-rf6x63
jaylfc Jun 21, 2026
e4e8c14
Merge pull request #1241 from jaylfc/exec/tsk-gahqhx
jaylfc Jun 21, 2026
98a2d39
Merge pull request #1242 from jaylfc/exec/tsk-57o75a
jaylfc Jun 21, 2026
bdc65a1
Merge pull request #1243 from jaylfc/exec/tsk-cibtwn
jaylfc Jun 21, 2026
0cdab13
Merge pull request #1244 from jaylfc/exec/tsk-6zrpqe
jaylfc Jun 21, 2026
5f9a8ca
test: add vitest tests for use-snap-zones hook
jaylfc Jun 21, 2026
42a4012
test: add vitest tests for dock-store
jaylfc Jun 21, 2026
fb944b9
test: add vitest suite for theme-store actions and state transitions
jaylfc Jun 21, 2026
36e404a
chore(deps): bump dependabot/fetch-metadata from 2 to 3
dependabot[bot] Jun 21, 2026
7662c22
chore(deps): bump actions/checkout from 4 to 7
dependabot[bot] Jun 21, 2026
6ad8de6
chore(deps): update litellm[proxy] requirement in the python-deps group
dependabot[bot] Jun 21, 2026
180ce05
Add unit tests for browser_proxy_origin pure functions
jaylfc Jun 21, 2026
ae6b468
Merge pull request #1250 from jaylfc/exec/tsk-ejtgtf
jaylfc Jun 21, 2026
d7eb83d
Merge pull request #1248 from jaylfc/exec/tsk-okq3z2
jaylfc Jun 21, 2026
cff88dd
Merge pull request #1247 from jaylfc/exec/tsk-lgd2mp
jaylfc Jun 21, 2026
de62eba
Merge pull request #1246 from jaylfc/exec/tsk-l4doto
jaylfc Jun 21, 2026
8974438
Merge pull request #1252 from jaylfc/exec/tsk-wepucu
jaylfc Jun 21, 2026
5ff6a39
Merge pull request #1251 from jaylfc/exec/tsk-h6bapx
jaylfc Jun 21, 2026
50c285e
test: add vitest tests for use-shortcut-registry hook
jaylfc Jun 21, 2026
087a791
feat(notifications): archive on dismiss, add History view
jaylfc Jun 21, 2026
fd25ae6
Merge pull request #1256 from jaylfc/exec/tsk-wghbue
jaylfc Jun 21, 2026
5fdfdde
test: add vitest coverage for ServiceIcon component
jaylfc Jun 21, 2026
5e8793e
test: add vitest tests for StatusIndicators component
jaylfc Jun 21, 2026
6b247c9
test: add vitest coverage for SetupChecklist component
jaylfc Jun 21, 2026
2446926
test: add vitest coverage for UpdateAvailableToast
jaylfc Jun 21, 2026
c31119f
test: add Vitest tests for WallpaperPicker component
jaylfc Jun 21, 2026
2be1560
test: add vitest tests for AppErrorBoundary component
jaylfc Jun 21, 2026
d1cd1e6
Merge pull request #1261 from jaylfc/exec/tsk-zj4fyv
jaylfc Jun 21, 2026
063a402
Merge pull request #1260 from jaylfc/exec/tsk-hx34oe
jaylfc Jun 21, 2026
6d160af
Merge pull request #1259 from jaylfc/exec/tsk-7unskw
jaylfc Jun 21, 2026
05ee077
Merge pull request #1257 from jaylfc/exec/tsk-kpuczf
jaylfc Jun 21, 2026
c42b6e9
test(ContextMenu): add vitest tests for component branches
jaylfc Jun 21, 2026
e0c9ab3
test: add vitest coverage for EmojiPickerField component
jaylfc Jun 21, 2026
8eeed76
test: add vitest suite for LoginScreen component
jaylfc Jun 21, 2026
06c29b0
test: add vitest coverage for Launchpad component
jaylfc Jun 21, 2026
39e360c
Merge pull request #1266 from jaylfc/exec/tsk-e7pror
jaylfc Jun 21, 2026
dfde76a
Merge pull request #1265 from jaylfc/exec/tsk-7ervkb
jaylfc Jun 21, 2026
3af5abf
Merge pull request #1264 from jaylfc/exec/tsk-oj6mbc
jaylfc Jun 21, 2026
4fbe60e
Merge pull request #1263 from jaylfc/exec/tsk-vbzuwy
jaylfc Jun 21, 2026
693c11d
Merge pull request #1262 from jaylfc/exec/tsk-wowqhv
jaylfc Jun 21, 2026
8421746
test: add vitest coverage for TaosAssistantSettings component
jaylfc Jun 21, 2026
c43731f
test: add vitest tests for Dock component
jaylfc Jun 21, 2026
4aebeb7
Merge pull request #1272 from jaylfc/exec/tsk-uypkw3
jaylfc Jun 21, 2026
b0f7da5
Merge pull request #1270 from jaylfc/exec/tsk-hsfn42
jaylfc Jun 21, 2026
3c21b8f
Merge pull request #1268 from jaylfc/exec/tsk-tf7j3x
jaylfc Jun 21, 2026
e4d0c85
Merge pull request #1267 from jaylfc/exec/tsk-is3sq6
jaylfc Jun 21, 2026
301134d
test: add vitest tests for CalendarApp
jaylfc Jun 21, 2026
71fd809
Merge pull request #1273 from jaylfc/exec/tsk-gv6mnx
jaylfc Jun 21, 2026
4ba6ac9
feat(audit): append-only board audit log (#105)
jaylfc Jun 21, 2026
501e5d6
feat(coding): workspace-jailed fs tool primitives for the agent (#86)
jaylfc Jun 21, 2026
ca225e3
perf(audit): index board_audit on task_id and ts (gitar #1274; append…
jaylfc Jun 21, 2026
0ebecb2
Merge pull request #1239 from jaylfc/feat/cluster-capability-map
jaylfc Jun 21, 2026
f6323fd
Merge pull request #1274 from jaylfc/feat/board-audit-log
jaylfc Jun 21, 2026
39db9e3
Merge pull request #1275 from jaylfc/feat/coding-fs-tools
jaylfc Jun 21, 2026
2047a78
Merge pull request #1253 from jaylfc/dependabot/github_actions/dev/de…
jaylfc Jun 21, 2026
49c19c7
Merge pull request #1254 from jaylfc/dependabot/github_actions/dev/ac…
jaylfc Jun 21, 2026
6d85d13
Merge pull request #1255 from jaylfc/dependabot/uv/dev/python-deps-f0…
jaylfc Jun 21, 2026
ae019b7
fix(notifications): auto-expiring toasts no longer archive into History
jaylfc Jun 21, 2026
2b55727
feat(cluster): capability-map heartbeat + admin endpoints (#897)
jaylfc Jun 21, 2026
d94b189
feat(audit): record board task transitions + task audit endpoint (#105)
jaylfc Jun 21, 2026
d65e632
feat(coding): agent tool-calling dispatch over workspace fs-tools (#86)
jaylfc Jun 21, 2026
2fdb936
docs(status): morning epic-build pass + cleared overnight queue
jaylfc Jun 21, 2026
3006bc1
Merge pull request #1258 from jaylfc/exec/tsk-dafnla
jaylfc Jun 21, 2026
877524f
fix(cluster): heartbeat preserves admin-set draining status (coderabb…
jaylfc Jun 21, 2026
e121085
fix(audit): derive close from_status race-free, drop TOCTOU pre-read …
jaylfc Jun 21, 2026
efd5e83
fix(coding): dispatch never raises on binary/oversized reads (coderab…
jaylfc Jun 21, 2026
5796695
Merge pull request #1276 from jaylfc/feat/cluster-capability-endpoints
jaylfc Jun 21, 2026
996a0dc
Merge pull request #1277 from jaylfc/feat/board-audit-wiring
jaylfc Jun 21, 2026
ceac6b7
Merge pull request #1278 from jaylfc/feat/coding-tool-loop
jaylfc Jun 21, 2026
b8fed82
feat(cluster): populate capability map from worker registration (#897)
jaylfc Jun 21, 2026
12501e6
feat(coding): model-agnostic tool-calling loop engine (#86)
jaylfc Jun 21, 2026
bd72465
feat(audit): project-scoped activity feed + project_id/detail columns…
jaylfc Jun 21, 2026
8c07e6e
feat(cluster): stale-node offline sweep (non-destructive) (#897)
jaylfc Jun 21, 2026
faf6076
feat(coding): litellm-backed model_step for the tool-calling loop (#86)
jaylfc Jun 21, 2026
e8154a4
fix(cluster): re-registration without hardware keeps stored fields (g…
jaylfc Jun 21, 2026
cb03a22
fix(coding): loop tolerates non-dict step + malformed tool calls (git…
jaylfc Jun 21, 2026
f3c9572
Merge pull request #1281 from jaylfc/feat/board-audit-project-feed
jaylfc Jun 21, 2026
70c20d0
Merge pull request #1282 from jaylfc/feat/cluster-stale-offline
jaylfc Jun 21, 2026
611c304
Merge pull request #1280 from jaylfc/feat/coding-tool-loop-engine
jaylfc Jun 21, 2026
78b1337
Merge origin/dev into capability-from-registration (resolve test-file…
jaylfc Jun 21, 2026
db84272
fix(coding): parse_completion tolerates empty/missing choices (gitar …
jaylfc Jun 21, 2026
b7d7bd3
fix(coding): use .get for dict choices/message so missing keys do not…
jaylfc Jun 21, 2026
981c3a0
Merge pull request #1279 from jaylfc/feat/cluster-capability-from-reg…
jaylfc Jun 21, 2026
32f1f00
Merge pull request #1283 from jaylfc/feat/coding-model-step
jaylfc Jun 21, 2026
d93811a
docs(status): epic slices round 2+3 all merged (cluster/coding/audit)
jaylfc Jun 21, 2026
0ff6aea
feat(store): de-seed X/Reddit/YouTube/GitHub from the default store (…
jaylfc Jun 21, 2026
9b200e6
Merge pull request #1284 from jaylfc/feat/deseed-social-apps
jaylfc Jun 21, 2026
8138c1d
fix(browser): one Browser app + host-capable Pi serves streamed sessions
jaylfc Jun 21, 2026
00f2c46
feat(update): taos rollback -- restore previous branch + version, rec…
jaylfc Jun 21, 2026
474aa02
fix(browser): resolve worker before creating session row (coderabbit …
jaylfc Jun 21, 2026
73c95e5
Merge pull request #1287 from jaylfc/feat/taos-rollback
jaylfc Jun 21, 2026
be4cff2
Merge pull request #1285 from jaylfc/feat/unify-browser-remove-stream…
jaylfc Jun 21, 2026
21bec7a
release: 1.0.0-beta.6
jaylfc Jun 21, 2026
d2ae670
fix(rollback): survive dirty trees, remote-only refs, and never kill …
jaylfc Jun 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/workflows/build-neko-rk3588-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Build Neko RK3588 image

# Builds the RK3588 VPU-encode neko image (MPP + gstreamer-rockchip compiled
# from source against trixie GStreamer 1.26) on a GitHub arm64 runner, so the
# Pi is never used for the build. The Pi only does the final validation run.
# On a PR the image is built but NOT pushed (compile validation only); on
# dev/master it is built and pushed to GHCR.
on:
push:
branches: [master, dev]
paths:
- 'app-catalog/streaming/neko-browser/Dockerfile.rk3588'
- '.github/workflows/build-neko-rk3588-image.yml'
pull_request:
paths:
- 'app-catalog/streaming/neko-browser/Dockerfile.rk3588'
- '.github/workflows/build-neko-rk3588-image.yml'
workflow_dispatch:

permissions:
contents: read
packages: write

jobs:
build:
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v7
- uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build (push only on dev/master)
uses: docker/build-push-action@v6
with:
context: app-catalog/streaming/neko-browser
file: app-catalog/streaming/neko-browser/Dockerfile.rk3588
platforms: linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: |
ghcr.io/jaylfc/taos-neko-rk3588:latest
ghcr.io/jaylfc/taos-neko-rk3588:${{ github.sha }}
cache-from: type=gha,scope=neko-rk3588
cache-to: type=gha,mode=max,scope=neko-rk3588
2 changes: 1 addition & 1 deletion .github/workflows/dependabot-automerge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
steps:
- name: Fetch Dependabot metadata
id: meta
uses: dependabot/fetch-metadata@v2
uses: dependabot/fetch-metadata@v3
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,6 @@ docs/audit/
.understand-anything/
docs/agent-jobs/
.design/

# Update rollback target (written by the updater, never tracked)
.taos-rollback
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,23 @@ Versions follow semver beta: `1.0.0-beta.N`, bumped on each dev->master promotio

## [Unreleased]

## [1.0.0-beta.6] - 2026-06-21

### Added
- Coding Studio gains a model-agnostic tool-calling loop: agents read, edit, and verify files inside a workspace-jailed sandbox using filesystem tool primitives, driven by a LiteLLM-backed model step.
- Cluster capability map: worker registration and heartbeats populate a per-node capability and hardware map with admin endpoints, plus a non-destructive stale-node offline sweep.
- Append-only board audit log: every task transition is recorded, with a project-scoped activity feed and a task audit endpoint, indexed for unbounded growth.
- `taos rollback`: a CLI recovery path that restores the previous branch and version, so a broken update can be recovered even when the dashboard is unreachable.

### Changed
- One Browser app: the separate streamed-browser app is gone. The Browser app attaches a Neko streamed session through a toggle, and a RAM-capable Pi host can serve the session itself instead of reporting that it is not capable.
- The default store no longer seeds the X, Reddit, YouTube, and GitHub apps; they are optional installs.

### Fixed
- Browser sessions resolve the target worker before creating the session row, so a failed placement no longer leaves an orphaned session.
- Auto-expiring notification toasts no longer archive themselves into the History view.
- Dependabot majors updated: actions/checkout v7, dependabot/fetch-metadata v3, and the dev Python dependency group.

## [1.0.0-beta.5] - 2026-06-20

### Added
Expand All @@ -24,6 +41,25 @@ Versions follow semver beta: `1.0.0-beta.N`, bumped on each dev->master promotio
- Security: dompurify updated to 3.4.11; cryptography and pydantic-settings advisories cleared.
- Install: the core install no longer aborts when optional components fail, and drops to the service user without assuming sudo (WSL robustness).

## [1.0.0-beta.4.1] - 2026-06-20

### Changed
- Installs and in-app updates verify the prebuilt bundle's SHA256 before extracting; a corrupted or tampered bundle is rejected and falls back to a local build.
- Re-installs update the existing install in place instead of forking a second copy.

### Fixed
- Symlink-safe staging (no fixed /tmp paths as root), atomic-rename swap, and a fix so the bundle is no longer treated as perpetually stale.
- README corrected (installs download a prebuilt bundle, no local build) and links rebranded to jaylfc/taOS.

## [1.0.0-beta.4] - 2026-06-20

### Added
- "Reduce effects" toggle (Settings, Accessibility) for low-end devices: disables background blur, heavy shadows, and continuous animations for a smoother UI on older hardware.

### Changed
- The installer and in-app update download a prebuilt UI bundle instead of building it locally, so installs and upgrades are faster and no longer fail or silently stay on the old version on low-memory machines including WSL. A local build, when still needed, now fails with a clear message instead of half-updating.
- CI runs on self-hosted runners and gates the desktop test suite.

## [1.0.0-beta.3] - 2026-06-16

### Added
Expand Down
63 changes: 44 additions & 19 deletions app-catalog/streaming/neko-browser/Dockerfile.rk3588
Original file line number Diff line number Diff line change
@@ -1,22 +1,47 @@
# taOS Neko Chromium for RK3588 (Orange Pi 5 Plus) — HW decode + WebRTC encode via VPU.
# Device nodes (/dev/mpp_service, /dev/dri, /dev/rga) are passed at `docker run`
# by the host-tier resolver, not baked in. Software encode is the fallback when
# this image/devices aren't available (see resolve_neko_image).
# Multi-arch base (has a linux/arm64 variant — verified on the Pi). The old
# `arm-chromium` tag does not exist.
FROM ghcr.io/m1k1o/neko/chromium:latest
# taOS Neko Chromium for RK3588 — VPU H.264 encode via MPP + gstreamer-rockchip.
# Multi-stage: stage 1 compiles Rockchip MPP, RGA and the gstreamer-rockchip
# plugin against GStreamer 1.26 (trixie, matching the neko-cdp runtime, so the
# plugin ABI lines up). Stage 2 layers the built libs onto the CDP image.
#
# Built for the Rockchip VENDOR kernel (6.1.x-vendor-rk35xx) which exposes the
# VPU via /dev/mpp_service (no V4L2). Shared publicly for the community (#624).

# Rockchip MPP + RGA + Mali userspace for GStreamer rkmpp HW encode/decode.
# ---- stage 1: build the rockchip multimedia userspace --------------------
FROM debian:trixie AS rkbuild
ENV GIT_TERMINAL_PROMPT=0 LIBDIR=lib/aarch64-linux-gnu
RUN apt-get update && apt-get install -y --no-install-recommends \
gstreamer1.0-rockchip \
librockchip-mpp1 \
librga2 \
&& rm -rf /var/lib/apt/lists/* || true
git ca-certificates build-essential cmake meson ninja-build pkg-config \
libdrm-dev \
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /src
# MPP (Media Process Platform) — nyanmisaka's maintained fork builds cleanly.
RUN git clone --depth=1 -b jellyfin-mpp https://github.com/nyanmisaka/mpp.git mpp \
&& cmake -S mpp -B mpp/build -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=$LIBDIR \
-DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DBUILD_TEST=OFF \
&& cmake --build mpp/build -j"$(nproc)" && cmake --install mpp/build
# RGA (2D raster graphics accel).
RUN git clone --depth=1 -b jellyfin-rga https://github.com/nyanmisaka/rk-mirrors.git rga \
&& meson setup rga rga/build --prefix=/usr --libdir=$LIBDIR -Dlibdrm=false -Dlibrga_demo=false --buildtype=release \
&& meson install -C rga/build
# gstreamer-rockchip plugin (mpph264enc) — BoxCloud streaming fork, against 1.26.
RUN git clone --depth=1 https://github.com/BoxCloudIRL/gstreamer-rockchip.git gst \
&& meson setup gst gst/build --prefix=/usr --libdir=$LIBDIR --buildtype=release \
&& meson install -C gst/build
# Collect outputs into a staging dir (tolerant of exact naming); logged for debug.
RUN mkdir -p /stage/gst \
&& cp -a /usr/lib/aarch64-linux-gnu/librockchip_mpp.so* /stage/ 2>/dev/null || true \
&& cp -a /usr/lib/aarch64-linux-gnu/librockchip_vpu.so* /stage/ 2>/dev/null || true \
&& cp -a /usr/lib/aarch64-linux-gnu/librga.so* /stage/ 2>/dev/null || true \
&& cp -a /usr/lib/aarch64-linux-gnu/gstreamer-1.0/libgstrockchip*.so* /stage/gst/ 2>/dev/null || true \
&& echo "=== staged libs ===" && ls -la /stage /stage/gst

LABEL taos.app.id="neko-browser" \
taos.streaming.encode="rkmpp" \
taos.hardware.soc="rk3588"

# Prefer the VPU encoder; Neko reads its pipeline from env / its own config.
ENV NEKO_VIDEO_CODEC=h264 \
GST_PLUGIN_FEATURE_RANK="mpph264enc:512"
# ---- stage 2: layer onto the CDP image -----------------------------------
FROM ghcr.io/jaylfc/taos-neko-cdp:latest
COPY --from=rkbuild /stage/ /tmp/rkstage/
RUN cp -a /tmp/rkstage/*.so* /usr/lib/aarch64-linux-gnu/ 2>/dev/null || true \
&& cp -a /tmp/rkstage/gst/*.so* /usr/lib/aarch64-linux-gnu/gstreamer-1.0/ 2>/dev/null || true \
&& rm -rf /tmp/rkstage && ldconfig
LABEL taos.app.id="neko-browser-rk3588" taos.streaming.encode="rkmpp" \
taos.hardware.soc="rk3588" taos.base="taos-neko-cdp"
ENV NEKO_VIDEO_CODEC=h264 GST_PLUGIN_FEATURE_RANK="mpph264enc:512"
4 changes: 2 additions & 2 deletions desktop/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "tinyagentos-desktop",
"private": true,
"version": "1.0.0-beta.5",
"version": "1.0.0-beta.6",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
103 changes: 103 additions & 0 deletions desktop/src/apps/CalendarApp.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { render, screen, fireEvent } from "@testing-library/react";
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { CalendarApp } from "./CalendarApp";

const FIXED_DATE = new Date(2025, 5, 15); // June 15, 2025

function mockToday() {
vi.useFakeTimers();
vi.setSystemTime(FIXED_DATE);
}

describe("CalendarApp", () => {
beforeEach(() => {
mockToday();
});

afterEach(() => {
vi.useRealTimers();
});

it("renders the current month and year in the header", () => {
render(<CalendarApp windowId="w1" />);
expect(screen.getByText("June 2025")).toBeTruthy();
});

it("renders all seven day-of-week column headers", () => {
render(<CalendarApp windowId="w1" />);
expect(screen.getByText("Mon")).toBeTruthy();
expect(screen.getByText("Tue")).toBeTruthy();
expect(screen.getByText("Wed")).toBeTruthy();
expect(screen.getByText("Thu")).toBeTruthy();
expect(screen.getByText("Fri")).toBeTruthy();
expect(screen.getByText("Sat")).toBeTruthy();
expect(screen.getByText("Sun")).toBeTruthy();
});

it("renders the correct number of days for the current month", () => {
render(<CalendarApp windowId="w1" />);
// June 2025 has 30 days; day "1" appears as both a trailing prev-month day
// and the first day of June, so use getAllByText for that one.
const days1 = screen.getAllByText("1");
expect(days1.length).toBeGreaterThanOrEqual(1);
const day30 = screen.getAllByText("30");
expect(day30.length).toBeGreaterThanOrEqual(1);
// There are 30 current-month cells plus leading/trailing fill cells
const currentMonthCells = document.querySelectorAll(
".text-shell-text.hover\\:bg-shell-surface",
);
expect(currentMonthCells.length).toBe(30);
});

it("navigates to the next month when the right arrow is clicked", () => {
render(<CalendarApp windowId="w1" />);
const nextBtn = screen.getByRole("button", { name: /next month/i });
fireEvent.click(nextBtn);
expect(screen.getByText("July 2025")).toBeTruthy();
});

it("navigates to the previous month when the left arrow is clicked", () => {
render(<CalendarApp windowId="w1" />);
const prevBtn = screen.getByRole("button", { name: /previous month/i });
fireEvent.click(prevBtn);
expect(screen.getByText("May 2025")).toBeTruthy();
});

it("wraps from January to December of the previous year when going prev", () => {
// Set "today" to January 2025
vi.setSystemTime(new Date(2025, 0, 10));
render(<CalendarApp windowId="w1" />);
expect(screen.getByText("January 2025")).toBeTruthy();
const prevBtn = screen.getByRole("button", { name: /previous month/i });
fireEvent.click(prevBtn);
expect(screen.getByText("December 2024")).toBeTruthy();
});

it("wraps from December to January of the next year when going next", () => {
// Set "today" to December 2025
vi.setSystemTime(new Date(2025, 11, 10));
render(<CalendarApp windowId="w1" />);
expect(screen.getByText("December 2025")).toBeTruthy();
const nextBtn = screen.getByRole("button", { name: /next month/i });
fireEvent.click(nextBtn);
expect(screen.getByText("January 2026")).toBeTruthy();
});

it("highlights today's date with the accent class", () => {
render(<CalendarApp windowId="w1" />);
// June 15 is "today" per our fixed clock; the cell should have the accent bg
const todayCell = screen.getByText("15")?.closest("span");
expect(todayCell?.className).toContain("bg-accent");
});

it("returns to the current month when Today is clicked after navigating", () => {
render(<CalendarApp windowId="w1" />);
const nextBtn = screen.getByRole("button", { name: /next month/i });
fireEvent.click(nextBtn);
fireEvent.click(nextBtn);
expect(screen.getByText("August 2025")).toBeTruthy();
const todayBtn = screen.getByRole("button", { name: /today/i });
fireEvent.click(todayBtn);
expect(screen.getByText("June 2025")).toBeTruthy();
});
});
Loading
Loading