Skip to content

Promote dev to master: messages polish epic, deep-nav API, CI parallelization, activity + SoC fixes#845

Merged
jaylfc merged 34 commits into
masterfrom
dev
Jun 13, 2026
Merged

Promote dev to master: messages polish epic, deep-nav API, CI parallelization, activity + SoC fixes#845
jaylfc merged 34 commits into
masterfrom
dev

Conversation

@jaylfc

@jaylfc jaylfc commented Jun 13, 2026

Copy link
Copy Markdown
Owner

Integration promotion of dev to the stable channel. Every change below already landed on dev through its own reviewed PR with green CI.

Highlights

  • Messages app polish epic (feat(messages): full markdown rendering in chat #826-feat(messages): empty states #838): full markdown rendering, emoji picker, threads view + live replies, per-channel drafts, unread divider, date separators, search UI, channel switcher (Cmd+K), collapsible sidebar, timestamps, @mention autocomplete, attachment retry, browser notifications, render tests.
  • Deep-navigation API: open apps by ?app= URL param or taos:open-app event, via a tested useDeepNavigation hook.
  • CI: parallelized the test suite with pytest-xdist -n auto (ci: parallelize tests with pytest-xdist (-n auto) #839), ~22m -> ~13m.
  • Activity app: dedupe the local node in the scheduler + detect the ARM SoC (RK3588) for the CPU label (#c55f929).
  • Settings: toggle for the anonymous update ping (job 17).
  • Theme engine: token inventory groundwork (docs(themes): token inventory #837).
  • Status/handoff doc housekeeping.

CI is green on the dev tip (bf37698). No new release tag is cut here.

jaylfc added 30 commits June 12, 2026 16:41
…eme engine plan, messages epic, key-scope fix
It was committed before being added to .gitignore, so it stayed tracked.
The file holds local-only coordination notes; keep it out of the repo.
* feat(messages): render full markdown in message content

* fix(messages): address review on full markdown PR

- Disallow markdown images in chat messages (privacy/SSRF leak).
- Map GFM table/thead/tbody/th/td to a chat-safe, overflow-x wrapper
  with compact cell styling consistent with HelpPanel.
- Collapse h5 and h6 to the same compact paragraph style as h1-h4.

* fix(messages): wrap markdown pre blocks in an overflow-x container

The renderContent fence-splitter handles properly closed triple-backtick
fences, but an unclosed or otherwise malformed fence can still produce
a default <pre> through react-markdown. Add a pre component mapping
with overflow-x-auto and a constrained max width so the chat bubble
never grows past the message width.
* feat(messages): persist composer drafts per channel

* fix(messages): save drafts on every channel transition

- Move the saveDraft(prevChannelRef.current, input) call out of the
  WebSocket-ready guard so drafts persist on channel switches while
  offline/reconnecting.
- Handle the selectedChannel -> null case explicitly: save the draft
  for the channel we are leaving, clear prevChannelRef, then return,
  so handleDeleteArchivedChannel and similar paths no longer drop
  unsaved input.
- Add a brief comment on the draft helpers documenting that drafts
  are kept in localStorage unencrypted (same approach as the job
  spec) and are best-effort.
* feat(messages): expose the all-threads view

* fix(messages): correct threads panel a11y and overlay conflicts

- Use aria-expanded + aria-controls on the all-threads toggle (the
  button now controls a panel, not a pressed state). Label flips
  between 'Show all threads' and 'Hide all threads'. Add id
  'all-threads-panel' to AllThreadsList's <aside> so the link resolves.
- Reset showAllThreads in the shared handleOpenThreadFor path so the
  list does not reappear when a thread closes.
- Exclude showSettings from the AllThreadsList render gate so the
  fixed panel cannot cover ChannelSettingsPanel.

* fix(messages): clear showAllThreads when opening channel settings

handleOpenSettings cleared the open thread but left showAllThreads
true, so the All Threads panel could reappear on the next open of a
thread after settings closed. Reset it here too, mirroring the
handleOpenThreadFor path.
Fix from review: render the separator above the first message too
(showDaySeparator = !prev || prevDay !== currDay), so a same-day
channel shows a single 'Today' divider at the top.
Fix from review: complete the one-right-panel mutex. Opening search now
closes settings/threads (and vice versa) in both the header buttons and
the panel render guards, and handleOpenSettings/handleOpenThreadFor clear
setShowSearch. The onJump 50-message-window limitation comment is present.
- SearchPanel: abort in-flight fetch on query-clear and on unmount so a
  late response cannot repopulate stale results
- onJump: replace the fixed 200ms scroll delay with a bounded rAF retry
  so a slow channel switch/render still lands on the target message
…U label

Duplicate entries: the controller self-registers as a worker named 'local'
(loopback url), so its NPU/CPU appeared both as controller scheduler
resources and as worker cards. The scheduler view now hides the local
worker's cards for tiers the controller already lists, keeping only its
unique devices (e.g. the integrated GPU).

Missing CPU model: _detect_cpu read the SoC only from /proc/device-tree/model,
which holds the board name ('Orange Pi 5 Plus') not the SoC. It now also
reads /proc/device-tree/compatible ('rockchip,rk3588'), so the CPU card
shows RK3588 instead of a bare ARM64. Adds _soc_from_devicetree + tests.
Adds resolveApp(token) (id, alias, or case-insensitive name) and wires the
Desktop to a deep-navigation API:
- URL: /desktop?app=<token>[,<token>] opens apps on load, with optional
  ?appProps=<json> to deep-link into an app (e.g. a Messages channel).
- Runtime: a taos:open-app CustomEvent ({app, props}) opens an app while the
  desktop is live, so the taOS agent can drive the UI for the user.
Tokens accept friendly names ('activity' -> dashboard). Singleton apps focus
and re-receive props rather than duplicate. Useful for tests/screenshots and
agent-driven navigation. Adds resolveApp tests.
…ation hook

Moves the ?app= / taos:open-app logic out of Desktop into a hook with full
coverage: URL single/multi/props/malformed-props parsing, the runtime event,
alias resolution, unknown-token no-op, and listener cleanup on unmount.
Adds an 'Anonymous install ping' switch to the Updates panel, bound to the
existing auto-update/update_ping_enabled preference (default on), saved
through the same PUT path as the neighboring auto-check toggle.
Covers exact multi-line rendering, the copy button accessible name,
clipboard.writeText receiving the exact code, the copied->revert label
flip with fake timers, long-line overflow container, and empty input.
Cmd/Ctrl+K opens a centered switcher over the Messages app: typed substring
filters active channels (max 8), Up/Down move the highlight, Enter or click
selects, Escape or backdrop closes. New ChannelSwitcher component + a window
keydown listener in MessagesApp that suppresses the browser default.
The test job was not hanging, it was slow: the serial suite (4845 tests,
two Python versions, -v) took ~22 minutes, so 'merge on green' was
impractical. Add pytest-xdist and run with -n auto to use all runner
cores; drop -v so worker output stays readable. Per-test timeout (120s)
already guards against a genuinely stuck test.
jaylfc added 4 commits June 13, 2026 13:48
…r collapse, pin-jump, timestamps, mention autocomplete, live threads, attachment retry, notifications, render tests (#838)

Jobs 24, 21, 22, 23, 26, 19, 18, 13, 9, 10 from the agent-jobs pack. Merged on CI-green + Kilo + author review (CodeRabbit free tier exhausted).
Adds 5 answer templates (add a machine to the cluster, models for your
hardware, backup, report a bug, offline operation) to the compiled agent
manual. Source + regenerated compiled file committed together; the
test_agent_manual_compiled CI guard passes.
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@jaylfc, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 26 minutes and 13 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b1342ea5-487c-4fdc-9cba-b6e46463c094

📥 Commits

Reviewing files that changed from the base of the PR and between 99cf786 and bf37698.

📒 Files selected for processing (26)
  • .github/workflows/ci.yml
  • .gitignore
  • desktop/src/apps/ActivityApp.tsx
  • desktop/src/apps/MessagesApp.tsx
  • desktop/src/apps/SettingsApp/UpdatesPanel.tsx
  • desktop/src/apps/chat/AllThreadsList.tsx
  • desktop/src/apps/chat/AttachmentsBar.tsx
  • desktop/src/apps/chat/ChannelSwitcher.tsx
  • desktop/src/apps/chat/SearchPanel.tsx
  • desktop/src/apps/chat/ThreadPanel.tsx
  • desktop/src/apps/chat/__tests__/render-helpers.test.tsx
  • desktop/src/apps/chat/useChatNotifications.ts
  • desktop/src/components/Desktop.tsx
  • desktop/src/components/__tests__/CodeBlock.test.tsx
  • desktop/src/hooks/use-deep-navigation.test.ts
  • desktop/src/hooks/use-deep-navigation.ts
  • desktop/src/registry/app-registry.test.ts
  • desktop/src/registry/app-registry.ts
  • docs/AGENT_HANDOFF.md
  • docs/STATUS.md
  • docs/agent-manual/08-answer-templates.md
  • docs/design/theme-token-inventory.md
  • docs/taos-agent-manual.md
  • pyproject.toml
  • tests/test_hardware.py
  • tinyagentos/hardware.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-code-review

qodo-code-review Bot commented Jun 13, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0)

Grey Divider


Remediation recommended

1. Sync draft save jank 🐞 Bug ➹ Performance
Description
MessagesApp.handleInputChange writes drafts to localStorage on every keystroke via saveDraft(),
which performs synchronous setItem/removeItem on the main thread. This can degrade typing
responsiveness (and increase GC pressure) as draft size grows or storage becomes slow/unavailable.
Code

desktop/src/apps/MessagesApp.tsx[R1141-1144]

  const handleInputChange = (val: string) => {
    setInput(val);
+    if (selectedChannel) saveDraft(selectedChannel, val);
+    // @mention detection: is the cursor inside an @token (no whitespace, the
Evidence
The composer calls saveDraft() on every input change, and saveDraft() synchronously writes to
localStorage, which is a main-thread blocking API.

desktop/src/apps/MessagesApp.tsx[1141-1149]
desktop/src/apps/MessagesApp.tsx[310-318]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`MessagesApp` persists per-channel drafts to `localStorage` on every `onChange` keystroke. `localStorage` operations are synchronous and can block the main thread, causing typing lag/jank in the composer.

### Issue Context
Draft persistence is valuable, but it should be buffered in memory and flushed to storage on a timer (debounce), and/or on key lifecycle events (blur, channel switch, send, unmount).

### Fix Focus Areas
- desktop/src/apps/MessagesApp.tsx[1140-1160]
- desktop/src/apps/MessagesApp.tsx[305-319]

### Suggested implementation sketch
- Add a `draftFlushTimerRef` (and optionally a `pendingDraftRef`) to batch writes.
- In `handleInputChange`, update React state as today, but schedule a debounced `saveDraft(selectedChannel, val)` (e.g. 250-500ms after last input).
- Flush immediately on:
 - channel switch (already saves on leave, keep it)
 - send success/failure paths where you clear input
 - textarea blur / component unmount
- Ensure timer cleanup on unmount and when `selectedChannel` changes.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@github-actions

Copy link
Copy Markdown

👋 Thanks for the PR! This one targets master, which is our
stable branch (it's what live installs track). Please retarget it to
dev — click Edit next to the PR title and change the base
branch dropdown from master to dev. Your commits and any review
carry over, nothing is lost.

See CONTRIBUTING.md for the branch model.

@jaylfc jaylfc merged commit 6394a3e into master Jun 13, 2026
13 of 14 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in TinyAgentOS Roadmap Jun 13, 2026
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Promote dev to master: Messages polish, deep-nav API, xdist CI speedup
✨ Enhancement 🐞 Bug fix 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

Walkthroughs

Description
• Polish Messages with threads, search, emoji picker portal, drafts, and improved unread UX.
• Add deep-navigation to open apps via ?app= and taos:open-app (tested resolver + hook).
• Speed up CI by parallelizing pytest with xdist; add targeted frontend and hardware tests.
Diagram
graph TD
  CI["GitHub Actions CI"] --> PY["pytest (xdist)"]
  DESK["Desktop"] --> DN["useDeepNavigation"] --> REG["resolveApp"]
  DN --> EVT["taos:open-app event"]
  DN --> URL["?app= params"]
  MSG["MessagesApp"] --> CHATAPI["/api/chat/*"]
  MSG --> UI["Thread/Search/Switcher"]
  MSG --> BROW["Browser APIs"]
  MSG --> LS["localStorage drafts/collapse"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Split CI across job matrix instead of xdist
  • ➕ Avoids xdist flakiness on tests not parallel-safe
  • ➕ Can shard by file/marker and run on separate runners for predictable wall time
  • ➖ More YAML and ongoing sharding maintenance
  • ➖ Requires careful balancing to avoid slow shard dominating
2. Centralize Messages UI state into a reducer/store
  • ➕ Reduces ref/ref-sync patterns and effect coupling
  • ➕ Makes feature additions (threads/search/unread) easier to reason about
  • ➖ Higher refactor risk in a promotion PR
  • ➖ More up-front work; current approach is already landed and tested
3. Use a router-driven deep-link scheme rather than `?app=` + CustomEvent
  • ➕ More extensible navigation semantics over time
  • ➕ Easier to document/share canonical deep links
  • ➖ Requires routing infrastructure and migration
  • ➖ CustomEvent is simpler for agent-driven opens and avoids routing complexity

Recommendation: The current approach is appropriate for a dev→master promotion: xdist delivers immediate CI wins with minimal workflow change, deep-navigation is cleanly encapsulated in a hook + token resolver, and Messages features are mostly additive with targeted tests. If CI parallelism reveals non-parallel-safe tests, consider migrating to a job-matrix sharding strategy incrementally.

Grey Divider

File Changes

Enhancement (11)
MessagesApp.tsx Messages polish: markdown, drafts, threads/search/switcher, notifications, unread UX +623/-71

Messages polish: markdown, drafts, threads/search/switcher, notifications, unread UX

• Major Messages UI expansion: full markdown rendering via react-markdown (GFM, safe element mappings, no images), per-channel draft persistence, day separators + "New" divider, scroll-to-latest badge, emoji picker rendered via portal with outside-click/Esc handling, @mention autocomplete, attachment retry, and browser notifications for background channels. Adds All Threads panel, Search panel, and Cmd/Ctrl+K channel switcher, plus live thread replies fed from the main WS stream.

desktop/src/apps/MessagesApp.tsx


UpdatesPanel.tsx Add toggle for anonymous update/install ping +16/-0

Add toggle for anonymous update/install ping

• Extends update preferences with 'update_ping_enabled' and renders a new switch explaining what is sent. Persists the preference via existing savePrefs flow.

desktop/src/apps/SettingsApp/UpdatesPanel.tsx


AllThreadsList.tsx Add stable panel id for accessibility wiring +1/-0

Add stable panel id for accessibility wiring

• Adds 'id="all-threads-panel"' so the Messages toolbar button can reference it via 'aria-controls'. Improves a11y and UI-to-panel association.

desktop/src/apps/chat/AllThreadsList.tsx


AttachmentsBar.tsx Track original File and retry count for upload retries +7/-1

Track original File and retry count for upload retries

• Extends 'PendingAttachment' to optionally retain the original 'File' and a retry counter. Updates the UI to show retry only when possible and otherwise mark the attachment as failed.

desktop/src/apps/chat/AttachmentsBar.tsx


ChannelSwitcher.tsx Add Slack-style quick channel switcher modal (Cmd/Ctrl+K) +112/-0

Add Slack-style quick channel switcher modal (Cmd/Ctrl+K)

• Introduces a modal dialog that filters channels by query, supports keyboard navigation, and selects a channel on Enter/click. Closes on Escape or backdrop click.

desktop/src/apps/chat/ChannelSwitcher.tsx


SearchPanel.tsx Add message search side panel with debounced API calls +186/-0

Add message search side panel with debounced API calls

• Implements a right-side search panel that queries '/api/chat/search' with debounce + AbortController cancellation. Groups hits by channel and supports jumping to the message in the main list.

desktop/src/apps/chat/SearchPanel.tsx


ThreadPanel.tsx Merge live WS replies into thread view and auto-scroll on new replies +27/-4

Merge live WS replies into thread view and auto-scroll on new replies

• Extends thread message timestamps to accept string/number and adds 'liveReplies' input. De-duplicates fetched replies with live ones by id and scrolls the panel to bottom when new live replies arrive.

desktop/src/apps/chat/ThreadPanel.tsx


useChatNotifications.ts Add hook for background-channel browser notifications +30/-0

Add hook for background-channel browser notifications

• Adds a hook that lazily requests Notification permission and suppresses notifications while the window is focused. Provides a 'notify' helper with click-to-focus behavior and defensive try/catch.

desktop/src/apps/chat/useChatNotifications.ts


Desktop.tsx Wire deep-navigation hook into Desktop app opening +5/-0

Wire deep-navigation hook into Desktop app opening

• Installs 'useDeepNavigation(openWindow)' so apps can be opened via URL params on load or by runtime 'taos:open-app' events. Documents intended usage for agent-driven desktop control.

desktop/src/components/Desktop.tsx


use-deep-navigation.ts Introduce useDeepNavigation hook for ?app= and taos:open-app +56/-0

Introduce useDeepNavigation hook for ?app= and taos:open-app

• Adds a Desktop hook that opens apps based on URL query tokens and listens for a 'taos:open-app' CustomEvent to open apps at runtime. Supports optional JSON props and delegates token resolution to 'resolveApp'.

desktop/src/hooks/use-deep-navigation.ts


app-registry.ts Add resolveApp with friendly aliases for deep-navigation tokens +31/-0

Add resolveApp with friendly aliases for deep-navigation tokens

• Introduces an alias map (e.g., activity/monitor/chat/assistant) and a 'resolveApp(token)' helper that matches by id, alias, then case-insensitive display name. Enables user/agent-friendly deep links without requiring canonical ids.

desktop/src/registry/app-registry.ts


Bug fix (2)
ActivityApp.tsx Hide duplicated self-node hardware cards in Activity scheduler view +15/-1

Hide duplicated self-node hardware cards in Activity scheduler view

• Detects when a worker entry represents the controller's local node and filters hardware cards whose tiers are already shown in controller scheduler resources. Prevents duplicate GPU/NPU/CPU entries for the same physical machine.

desktop/src/apps/ActivityApp.tsx


hardware.py Improve ARM SoC detection using device-tree model + compatible +27/-12

Improve ARM SoC detection using device-tree model + compatible

• Extracts SoC parsing into '_soc_from_devicetree' and updates CPU detection to concatenate both '/proc/device-tree/model' and '/proc/device-tree/compatible'. Fixes boards whose model string omits the SoC (e.g., Orange Pi 5 Plus) by relying on compatible entries.

tinyagentos/hardware.py


Tests (5)
render-helpers.test.tsx Add tests for markdown rendering helpers and day labels +76/-0

Add tests for markdown rendering helpers and day labels

• Adds Vitest/RTL coverage for 'renderContent' (markdown + fenced blocks + key warnings) and 'dayLabel' behavior using fake timers. Validates rendering and date labeling semantics.

desktop/src/apps/chat/tests/render-helpers.test.tsx


CodeBlock.test.tsx Add CodeBlock rendering/copy behavior tests +72/-0

Add CodeBlock rendering/copy behavior tests

• Adds RTL tests for CodeBlock newline preservation, accessible copy button labeling, clipboard writes, timeout-driven "copied" state, and long/empty code rendering safety.

desktop/src/components/tests/CodeBlock.test.tsx


use-deep-navigation.test.ts Add tests for deep-navigation URL and event behavior +76/-0

Add tests for deep-navigation URL and event behavior

• Covers '?app=' parsing (single and comma-separated), alias resolution, appProps JSON parsing (including malformed props), runtime event handling, and event listener cleanup on unmount.

desktop/src/hooks/use-deep-navigation.test.ts


app-registry.test.ts Add resolveApp unit tests for token/alias/name resolution +28/-1

Add resolveApp unit tests for token/alias/name resolution

• Adds a focused test suite validating resolve-by-id, case-insensitive name matching, friendly aliases, trimming/normalization, and unknown-token handling.

desktop/src/registry/app-registry.test.ts


test_hardware.py Add unit tests for SoC detection via device-tree strings +19/-0

Add unit tests for SoC detection via device-tree strings

• Adds a dedicated test class for '_soc_from_devicetree', validating RK3588 detection from compatible strings, Raspberry Pi family detection, and unknown fallbacks.

tests/test_hardware.py


Documentation (4)
STATUS.md Refresh status snapshot and remove tracked handoff playbook references +32/-72

Refresh status snapshot and remove tracked handoff playbook references

• Rewrites the header and updates the status snapshot for 2026-06-13, including CI xdist note, messages train progress, and process guidance. Removes references that assumed 'docs/AGENT_HANDOFF.md' is tracked and adds updated operational notes.

docs/STATUS.md


08-answer-templates.md Expand agent answer templates (cluster, models, backups, bugs, offline) +10/-0

Expand agent answer templates (cluster, models, backups, bugs, offline)

• Adds additional canned support answers covering cluster machine add flow, model sizing guidance, backup instructions, bug reporting guidance, and offline usage expectations.

docs/agent-manual/08-answer-templates.md


theme-token-inventory.md Add theme token inventory groundwork for future theme engine +278/-0

Add theme token inventory groundwork for future theme engine

• Adds a comprehensive inventory of hardcoded UI color/shadow/radius usage across desktop surfaces, proposing token names and highlighting high-impact migration targets. Serves as design groundwork for theme tokenization.

docs/design/theme-token-inventory.md


taos-agent-manual.md Mirror new agent answer templates into consolidated manual +10/-0

Mirror new agent answer templates into consolidated manual

• Appends the same new FAQ-style answer templates added to the agent-manual section into the consolidated taos-agent manual.

docs/taos-agent-manual.md


Other (2)
ci.yml Parallelize pytest in CI with xdist +4/-1

Parallelize pytest in CI with xdist

• Switches CI test invocation to 'pytest -n auto' and documents the motivation (significant runtime reduction). Drops verbose output to keep xdist worker logs readable.

.github/workflows/ci.yml


pyproject.toml Add pytest-xdist dev dependency +1/-0

Add pytest-xdist dev dependency

• Adds 'pytest-xdist' to the dev dependency set to support 'pytest -n auto' in CI and local runs.

pyproject.toml


Grey Divider

Qodo Logo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

1 participant