github longbridge/nsh v0.5.0
nsh v0.5.0

one hour ago

NSH 0.5.0

NSH 0.5.0 brings a terminal backend, a fuller desktop application model, signed application updates, and tools for shipping to mobile stores. It also expands the component and system APIs, improves browser publishing, and addresses everyday interaction details across macOS, Windows, Linux, iOS, Android, and Web.

A large part of this release is about keeping real applications responsive: long conversations retain their scroll position, off-screen content is created incrementally, large tables avoid repeated text layout, and memory is returned when large view trees disappear. Text selection, input methods, menus, keyboard navigation, and screen-reader support receive substantial improvements alongside the new features.

Breaking Changes

0.5.0 is a minor release because it changes public APIs and some default behavior. No version is recorded in nsh-compat yet, so these changes come before the permanent compatibility contract (see the compatibility guide).

Apps (TSX and nsh.json)

  • Window API replaced. Desktop windows now use WindowRef, the <Window> component and window kinds; the old window API is replaced, not aliased. Port secondary-window code to the new model. (#1137, #1219)
  • Media loading checks capabilities grants. An app that declares capabilities and shows local files needs an fs.read grant for them; new URL("./x.png", import.meta.url) needs a ${pluginDir} grant; relative media paths (including Markdown ![](img/a.png)) load nothing in native apps; malformed asset: paths and grant paths with ./.. are refused. Web view base URLs and parser-ambiguous URLs are checked the same way. Apps without capabilities are unchanged. (#1417, #979)
  • focus-visible: only follows keyboard focus. It no longer applies after a press or tap; use focus: for any focus. (#1519)
  • macos.infoPlist refuses LSUIElement. Set macos.activationPolicy instead. LSMinimumSystemVersion is now accepted. (#1390, #1654)
  • Behavior changes. A list at its start now shows rows inserted above its first row instead of scrolling to keep it (#1132); the Tab order puts a popover's content right after its trigger (#1616); macOS delivers Finder files as path file: URLs and lets drops on a text input reach the surrounding onFileDrop (#1092, #1086); scrollbar={false} also hides horizontal indicators on desktop (#937); going back no longer pops a stack in an unselected tab (#996); invalid animation parameters now settle instead of producing NaN (#1556); unreadable nsh.json settings are warnings, not errors (#1190).

Rust and embedders

  • Renamed or retyped APIs. Theme::from_json_lenient โ†’ Theme::from_json_with_diagnostics (#1571); DataTableColumn::fixed changes from bool to ColumnFixed (Left / Right) (#1395); LayoutCurve::Spring { damping } becomes LayoutCurve::FittedSpring { damping_ratio } plus LayoutCurve::Spring(Spring) (#1305).
  • Non-exhaustive types. iOS SurfaceOptions and ContextMenuEvent are #[non_exhaustive]: start from SurfaceOptions::default() / ContextMenuEvent::new (#1404, #978). Platforms matching Command exhaustively must handle Command::Haptic (#1328).
  • New struct fields. Struct literals that list every field need the new ones or ..Default::default(): Accessibility, AccessibilityState, ViewProps, ResolvedTextStyle, LinkProps, BundleOptions, PerfSnapshot, nsh_platform_macos::AppOptions, Driver/KeyframeAnimation/Spring/Timing. (#1650, #1612, #1616, #1438, #1370, #1381, #1262, #1390, #998)
  • Theme readers. Embedders using Registry::tokens_from / Registry::tokens follow the new setTheme signatures. (#1216)

Tooling

  • Platform runtimes are components. Release archives no longer bundle other platforms' runtimes or the embedding SDKs; nsh installs them on demand, and offline environments run nsh component add android web first. (#1302)
  • Performance monitor. The per-second line moves from target nsh::perf to nsh::fps, and nsh run --fps shows it only with -v. (#1322)
  • macOS test hosts start in the background without activating their windows. (#907)

Desktop windows and application lifecycle

  • Multi-window applications. Desktop windows now have WindowRef identities, a declarative <Window> component, and window kinds. Rust applications can open and manage their own windows as well. This gives secondary windows and their content an explicit application-level model. (#1137, #1219)
  • Tray applications and global shortcuts. Tray icons and global shortcuts are available on macOS, Windows, and Linux, including Rust applications. Tray events report icon bounds; macOS trays can show a title with configurable placement, making it possible to position a companion window beside the menu bar item. (#988, #1562, #1355, #1479, #1582)
  • Background and single-instance apps. Applications can opt into single-instance mode, start their main window hidden, and use the macOS menu-bar activation policy. Hidden main windows no longer prevent the app's other windows from receiving frames. (#1563, #1420, #1390, #1652)
  • Lifecycle and window behavior. Application.quit() and Application.restart() let applications control their lifecycle, while on_app_quit provides Rust cleanup on exit. Window key bindings stay scoped to the correct window; Windows gains transparent windows and taskbar visibility control. (#1025, #1055, #1558, #1354, #1391, #987)

System integration and application services

  • Notifications and badges. Applications can send system notifications and update their badge, with Windows toast/taskbar and Linux integration. Notifications can be silent, and an embedding host can hand notification delivery to the application it contains. (#931, #932, #933, #1140, #986)
  • Deep links, navigation, and file associations. Custom URL schemes can launch applications; UrlScheme.url and setUrl expose the app's address, with history entries and URL-change reasons. Desktop applications can declare the file types they open. (#1034, #982, #1448, #1447, #1565)
  • Files and application metadata. Picker.pickFiles accepts general file types, data_dir() exposes the app's own data directory, and appInfo() reports the app version, build, and development flag. Drag-and-drop events gain file URLs and MIME types so apps can decide how to handle incoming files. (#946, #1550, #1381, #938, #1441)
  • Rust integration. Module functions receiving ModuleCx can spawn tasks, app Rust functions can run on the platform's main thread, and mobile hosts can reuse application-owned Tokio runtimes. Platforms implemented outside the NSH repository can also run applications. (#1372, #1382, #1404, #1393)

Application updates and distribution

  • Full application updates. The new updater supports checking, downloading, installing, and restarting into an updated application. Download validation and the restart path are part of the flow; subsequent fixes retain an already downloaded update and restart into the newly installed app. (#922, #1042, #1269)
  • Signed OTA packages. Packaged applications can receive signed code-and-asset updates without replacing the installed shell when the existing runtime is sufficient. The launcher verifies packages and supports trial launches with fallback. On iOS and Android, an accepted package runs on the next cold start; runtime or native-code changes still require a new application build. (#1189)
  • Installed-shell visibility. shellInfo() distinguishes the installed app and NSH runtime from a running OTA package. The updater avoids offering a redundant full-app update when its release is already running as a package, and the engine warns when an installed OTA package can no longer run. (#1226, #1207, #1671)
  • Mobile store publishing. nsh publish adds TestFlight and Google Play internal-track publishing. Android packaging supports App Bundles and configurable target SDK versions; Apple packages can include additional Info.plist keys and entitlements. (#1052, #1054, #1023)
  • Platform packaging controls. Configure icons separately per platform, declare Apple app languages, and raise a package's minimum system version. macOS packaging accepts --arch; Windows packaging gains Inno Setup installers and support for cross-building the runner off Windows. (#1548, #1585, #1654, #1481, #1348, #1067)

Terminal applications and embedded terminals

  • A ratatui-based TUI backend. NSH applications can run in a terminal. Follow-up work fixes initial layout, editor focus, multiline input scrolling, and startup negotiation so the terminal host behaves more reliably across launch and editing scenarios. (#869, #1006, #1083, #1288, #1340)
  • Embedding and terminal links. An embedding program can provide host options and stop the TUI host, including an exit requested before its run loop starts. Link content can render as OSC 8 hyperlinks in supporting terminals. (#1287, #1307, #1289)
  • The Terminal component. Applications can display program output using each platform's text rendering, including the browser runtime. This is separate from running the entire application with the TUI backend. (#1111, #1152)

Lists, scrolling, and large data sets

  • Chat-style list alignment. Bottom-aligned lists open at the end and retain a stable position while earlier rows are measured, history is prepended, or row heights shrink. Loading history above a reader no longer incorrectly follows the end, and native bounce behavior is preserved. (#983, #990, #1243, #1265, #1477, #1498)
  • Stable row identity and interaction. keyExtractor keys drive list reconciliation, retained rows are reused when their order is unchanged, and rows with keyboard focus or an open overlay remain rendered. These changes protect ongoing interaction while other rows enter and leave the viewport. (#1057, #1407, #1102)
  • Less work outside the viewport. Scroll views create native content near the viewport, distant Each rows render as they approach, and off-screen creation is spread across frames. Fast scrolling binds rows farther ahead, while appending list rows avoids rebuilding every offset. (#1304, #1312, #1600, #1310, #1371)
  • DataTable performance and interaction. Scrolling skips repeated cell text measurement and layout, including web wheel-inertia improvements. Buttons inside cells receive their own presses, columns can be fixed on the right, and edge anchoring reserves the native scroll room it needs. (#1175, #1270, #1395, #1392)
  • Programmatic scrolling and mobile controls. View references can reveal a view through its enclosing scroll containers. Mobile platforms gain native scroll handles for both axes, and iOS refresh behavior improves for lists and scroll views beneath large titles. (#1378, #1401, #1426)

Text, Markdown, and editors

  • Selection APIs and native menus. Selectable views expose plain text, Markdown, and HTML, plus selection location. Selectable text uses the platform edit menu on right-click; macOS localizes that menu, Windows application context menus can act on selected text, and Android exposes installed text actions. (#1045, #1504, #1517, #1579, #1505, #1516)
  • Rich text editing. Rich-editor documents can be imported and exported as HTML from JavaScript. Mobile selection gains touch handles and the system edit menu; local and data-URL images render with natural sizing when no size is supplied. (#1578, #1368, #1577, #1121)
  • Streamed Markdown. Incomplete lines are held while their interpretation is still open, including reference brackets arriving over multiple chunks. CJK emphasis and URL handling are improved, and TeX preprocessing avoids quadratic searches through code spans. (#1632, #1486, #1024, #1027, #1458, #1308)
  • Input methods and native editing. Windows text inputs use the system text box. Linux avoids moving multiline text during CJK composition, macOS leaves composition keys to the input method and commits composition on blur, and the editor keeps uncommitted text out of the document. (#1475, #926, #1387, #1507, #965)
  • Mobile input and paste. Touch-focusing an editor on Web keeps the keyboard open; Android submission ends composition; iOS clips a paste to maxLength instead of rejecting the whole paste. Apps can insert an allowed paste as an undoable user edit. (#1482, #1300, #1647, #1443)
  • Text visibility and layout reuse. macOS text remains visible inside transformed ancestors and when the first line exceeds its height, with the latter also fixed on iOS. Color-only changes and hidden-run changes preserve text layout; hidden spans are omitted from copying and screen-reader output. (#1135, #1421, #1334, #1436, #1619, #1438)

Components, styling, and media

  • EmojiPicker and dynamic themes. EmojiPicker provides searchable emoji selection. setTheme changes application themes at runtime, with validation for malformed themes, and applications can register fonts while running. (#1323, #1216, #1571, #1001)
  • Images, SVG, and audio. Images accept in-memory RGBA pixel buffers; Canvas can draw SVG images, including text in native SVG rasterization. Sound and AudioPlayer add playback, and sounds can be loaded from bytes. Apple video playback can resume after seeking back from the end. (#1561, #1291, #955, #1471, #1377)
  • Glass, corners, and shaders. Progressive blur and squircle rendering expand across platforms, macOS gains configurable materials and glass tint compositing, and iOS backdrop effects use mask views. macOS and iOS shader frames render into IOSurfaces; shader initialization can try another backend when a device is refused. (#930, #1008, #1575, #1332, #1333, #1601)
  • Input-aware styling and events. Tailwind adds pointer-fine:, pointer-coarse:, and terminal: variants. focus-visible: follows keyboard-originated focus, and view events gain onWheel and onMouseUp. Text colors accept opacity modifiers for arbitrary and token values, and arbitrary background gradients accept Tailwind's image hint. (#1539, #1519, #1567, #1446, #1669, #1670)
  • Motion and layout correctness. Layout springs use physics-based timing, retain momentum when retargeted, and keep values finite for unusual parameters. Shrink-to-fit flex rows and columns account for their content, including slot holders. (#1305, #1553, #1556, #927, #1461, #1625)
  • Links and haptics. Links show a pointing-hand cursor by default, text links reveal their URL on hover, and nsh/mobile gains haptic feedback on iOS and Android. (#1311, #1370, #1328)

Menus, popovers, and keyboard navigation

  • Complete keyboard paths. Context menus can open from the keyboard and screen readers. Virtualized menu lists support traversal through every row, Page Up/Page Down, and navigation beginning at the hovered item. Tab reaches virtualized list rows and scrolls the focused row into view. (#978, #1437, #1518, #1620)
  • Predictable popup focus. Popover content follows its trigger in Tab order; onOpen can move focus into the popup; focus returns when a popup starts closing. Escape also closes controlled popups opened by application code. (#1616, #1551, #1618, #1622)
  • Placement and dismissal. Popups flip using their natural size, menus fit the available room beside their triggers and scroll when needed, and anchored overlays align to device pixels. Secondary clicks outside overlays dismiss them, and right-clicking a context-menu trigger again reopens the menu at that location. (#1497, #1534, #1400, #1544, #1610)
  • Touch and grouping behavior. Long-press context menus apply to touch and pen and cancel the trigger's pending press. Tabs, radio buttons, and toolbar items can participate in their group through intervening plain views. (#1555, #1415, #1521)

Accessibility

  • Reading order follows the screen. Scroll-view and list content is exposed in visual order across desktop, Web, and Linux paths. Recycled list cells are removed from the accessible content they no longer represent. (#1108, #1107, #1122, #1124, #1503)
  • Richer semantics. macOS exposes table rows and cells, scroll areas and positions; dialogs announce their role and title; elements can expose descriptions and an invalid state. Accessibility frames account for ancestor transforms, and Linux assistive technologies can activate plain buttons. (#1192, #1509, #1624, #1650, #1612, #1182, #1255)
  • Focus feedback. Tooltips and focus-visible styling distinguish keyboard navigation from pointer interaction. A brief blur between focus changes no longer immediately drops focus-within, improving continuity when focus moves inside a control. (#1653, #1519, #1557)

Web publishing and WebView

  • Published applications as web pages. Web publishing adds document markup, links, and page-head support. Applications can configure whether navigation creates browser history entries, serve assets from a CDN with --asset-url, and resolve files relative to their starting page. (#1130, #1158, #997, #1155)
  • Smaller application-specific runtimes. Web linking includes only used nsh/base core, crypto, and URL functionality, including Rust applications. The bundler prunes statically accessed native namespace imports, reducing unnecessary runtime inclusion. The resulting size depends on the features an application imports. (#1220, #1445, #1522)
  • Browser startup and integration. Import maps are installed before app modules start, including older Safari paths; startup waits for registered fonts. Browser lifecycle handling and delivery of host.post to the page's host improve embedding, while reference accounting does less work during application calls. (#921, #1118, #1046, #975, #1668, #1659)
  • WebView capabilities. evaluate returns awaitable script results, WebViews can serve application-owned URL schemes, and page loads support request headers and an incognito mode. Camera and microphone access are added; applications can detect when the platform cannot show a WebView. (#1432, #1233, #1038, #1028, #1559, #1439)
  • Browser clipboard. Image formats are converted to PNG for clipboard interoperability, while copied GIFs retain their animated representation alongside the PNG. (#1540, #1564)

Runtime performance and platform reliability

  • Memory reclamation. Large commits return excess operation-buffer capacity; disposed view trees return reactive graph slots and empty node-table pages. Completed spawned tasks release cleanup state, and shared styles/text-layout storage reduce duplicate allocations. (#1259, #1260, #1261, #1664, #1250, #1341)
  • Rendering efficiency. Backdrops are recaptured when underlying content changes, Windows reduces canvas and partial-frame paint work, and macOS avoids redundant sibling scans and detaches deleted subtrees at their roots. These are targeted reductions in work rather than a single release-wide speedup claim. (#1315, #1316, #1661, #1339, #1513)
  • macOS and Windows windows. Text-heavy window resizing is improved; macOS display links follow the window's screen rate and trackpad momentum stops on a mouse press. Windows fixes stretched resize frames, black resize edges, opening-content flashes, and frameless maximized state. (#944, #1245, #1511, #1142, #1402, #1364, #1422)
  • Linux and Android reliability. Linux keeps drawing after Wayland video closes and can bring a window forward after a tray click. Android gains API 26 support, avoids newer-API class loading on older systems, and fixes corner, GIF, and animation compatibility. (#904, #1615, #1363, #949, #1047, #1082, #956)
  • Diagnostics. The performance monitor can be enabled with NSH_FPS or application controls and reports JS heap and live-node information. CPU measurement uses a one-second window; packaged macOS and iOS apps write to the unified log. (#1150, #1262, #1313, #1655)

Security and capability enforcement

  • Check resources at the point of use. Media loaders enforce source grants, menu icons and image redirects are checked against capabilities, and native <Image> file loading opens files through their granted fs.read root. This closes gaps between an earlier permission check and the file actually opened. (#1417, #1603, #1605)
  • Network and WebView validation. TLS verification uses the system trust store. WebView base URLs and ambiguous URL forms are checked against grants, and the development server restricts asset and WebSocket serving to its own pages. (#1543, #979, #1117)
  • Packaging and update hardening. Packaging rejects application IDs that are not a single path segment; the updater moves to zip 9 to address dependency advisories. Capability-safe file access also permits absolute symlinks whose targets remain within the granted root. (#943, #1164, #1297)

Developer tooling, tests, and documentation

  • CLI workflow. nsh update installs the latest release or nightly, and platform runtimes are installed as components when needed. nsh run --release builds an optimized development host; concurrent apps choose free development ports, and mixed Rust/TSX changes trigger the required restart. (#1273, #1302, #1317, #972, #1487)
  • Assets and configuration. The bundler imports videos and ?url assets as URLs, resolves subdirectory assets from the application directory, and recognizes dynamic imports using backtick strings. Unknown or unreadable configuration settings are reported as warnings so valid settings can still be used. (#1380, #1592, #1178, #1190)
  • Platform testing. Tests can choose an iOS simulator, access layout boxes and platform text engines, invoke application-menu shortcuts, and substitute native modules. macOS/Android screenshot capture and GPUI covered-window capture receive fixes, and web test browsers close when a test times out. (#1604, #1242, #1375, #1379, #1160, #1151, #1172, #1464)
  • Design and internationalization. App guidance now starts with a shared application UI layer and adds more complete design and API-naming rules. Runtime localization uses rust-i18n; translated documentation uses stable English heading anchors. The gallery and website share more component styling, and the website adds a community library/tool directory. (#974, #1529, #1530, #1234, #1353, #1267, #1369)

Upgrading from 0.4

Review the Breaking Changes above. Rebuild with the 0.5.0 toolchain and refresh generated TypeScript declarations; check desktop code against the WindowRef / <Window> model and the versioned APIs before shipping. Test keyboard, selection, and scrolling flows on the platforms your application supports, particularly if you supplied workarounds for behavior fixed here. (#1137, #1219)

For installed applications, distinguish a code-and-asset OTA update from a shell update: using a new NSH runtime or new native functionality requires shipping a new full application. shellInfo() and the package's minimum-runtime requirement help keep those paths explicit. See the 0.5.0 update documentation.

Version 0.5.0 is not yet a recorded compatibility baseline. The permanent backward-compatibility contract begins with the first release recorded in nsh-compat; the versioned compatibility guide explicitly lists 0.3.0, 0.4.0, and 0.5.0 as unrecorded.

Contributors

Thanks to everyone who contributed to this release:

@0xbentang @ahonn @akongG @antoniel @BeADre @Blackman99 @boyan01 @burdygin @caoxing9 @chaxus @ClarkThan @Cooooooker @cosformula @Cupnfish @daoleno @duo @dXnSix @griffinqiu @hexuria @hmziqrs @honsunrise @hsingjui @huacnlee @ihavecoke @itisvincent @Joy-jinyu @kim0 @kindred-7 @kosumic @Laotree @LeeDashan @Lemenxzy @linyiru @lucianosrp @lurenjia534 @LVtomatoJ @madcodelife @marcromeyn @mengyinghu-sys @mrtolkien @nohzafk @obito-t @RebelBIrd @richerfu @sunfuze @sunli829 @sureshkrishnan-ai @t4t5 @taokeqin @Teages @TexasOct @ttizze @twosugar @Tzyito @Vehicoule @williamjakfar @WillisXue @wuyunyoujiduo-jpg @yangkx1024 @YougLin-dev @yuanzhuang-svg @yuezk @zcg @ZZombiee

What's Changed

What's Changed

New Contributors

New Contributors

Full Changelog:v0.4.0...v0.5.0

๐Ÿค– Noop (release-manager) ยท AI agent acting for @huacnlee

Don't miss a new nsh release

NewReleases is sending notifications on new releases.