Skip to content

v0.18 Theme Studio, Native theme library, Theme Bridge and Prompt None - #315

Open
raiseCatError wants to merge 16 commits into
devfrom
feature/v018-theme-bridge
Open

raiseCatError wants to merge 16 commits into
devfrom
feature/v018-theme-bridge

Conversation

@raiseCatError

@raiseCatError raiseCatError commented Oct 4, 2026 •

Copy link
Copy Markdown
Owner

Refs #304

One implementation PR for the v0.18 Theme Studio / Theme Bridge pass, plus the shell-framework, prompt-provider, Keep Awake and Homebrew-provenance work that followed QA. No merge, release, version bump or publish: package metadata intentionally stays at 0.16.0.

Prompt

  • Prompt None: composer only, with no prompt row, modules or right prompt. The configured structural input marker stays live and configurable. Editing, suggestions, syntax colors, history, themes and Theme Bridge keep working. Commands submitted under None store no prompt snapshot (promptless), and history never substitutes another prompt.
  • Historical prompt Full / Compact / Minimal / Off (/transcript, Settings, Setup): presentation only, over the unchanged stored snapshot.
  • Prompt providers: NMSh Native, None, Starship, Powerlevel10k and Oh My Posh (new). NMSh keeps the editor, composer, transcript and history; an external provider supplies only the prompt content. When a provider cannot render, NMSh Native becomes effective and the UI says so. History records the effective provider.
    • Oh My Posh runs oh-my-posh print primary directly. Arguments are argv only (--pwd, --status/--no-status, --terminal-width, --escape=false, --config), with no TTY, bounded output, a timeout that kills the process group, and cancellation. Its ANSI goes through the same span parser as Starship and Powerlevel10k. Config comes from an optional NMSh path, else POSH_CONFIG, else Oh My Posh's built-in default. No shell rc file is changed.

Native theme library and Theme Studio

  • themes (bounded to 64 assets, stable ids) plus nmsh.themeId are canonical. A legacy customTheme migrates to one Custom asset and stays active.
  • /theme: Built-in · Imported · Custom · Import, one editor, and the real Native preview for every theme. Imported themes are ordinary Native themes (edit, rename, duplicate, export, select, pin).
  • Local Preview Chroma (default Off, never saved). Duplicate current → Custom (<name> - Custom).
  • Import formats (bounded data parsing, previewed with mapping and loss disclosure):
    • NMSh Theme JSON, Base16, Base24, Windows Terminal.
    • Oh My Posh JSON/YAML/TOML: static colors only; templates, extends and remote config are never evaluated or fetched.
    • Kitty, Ghostty, iTerm2 .itermcolors, WezTerm TOML (Lua refused).

Theme Bridge

  • Opt-in master On/Off, plus Apply themes: Manual / Follow NMSh / Choose theme.
    • Under Manual, each tool is Independent / Follow NMSh / Choose theme.
    • Under a global policy, per-tool rows are view-only and Manual choices are kept for later.
  • One large inline panel, grouped by capability.
  • Targets:
    • fzf: NMSh launches only.
    • less/man: termcap colors.
    • File listing colors: GNU ls/gls via LS_COLORS (vivid when installed); macOS/BSD ls via CLICOLOR/LSCOLORS.
    • bat: a real .tmTheme, a reviewed bat cache --build verified with bat --list-themes, and BAT_THEME in NMSh shells.
    • tmux, Neovim, Vim, Helix: generated themes. Helix uses a confirmed theme = "nmsh-bridge" activation that never replaces an existing user theme.
    • delta: detected only; git config is never changed.
  • Safe generated artifacts: ownership ledger, resolve → render → stage → validate → atomic replace, and modified/unrecorded files are never overwritten. Includes are exact, shown before applying, and removed exactly.
  • The NMSh-owned shell environment is applied by the zsh/Bash/Fish adapters at the next prompt.
  • One-time activation, then managed automatic updates. /integrations shows health with Review all / Apply all.

Providers and pickers

  • /providers is one inline panel (no nested panels). Picker query orientation follows the composer position. Provider shortcut commands: /picker, /suggestions, /navigation, /welcome, /history-provider.

Tools, tmux, dotfiles

  • Tool Configuration registry: first-party adapters only. Detection never grants write authority.
  • tmux Config Studio (/tmux): general settings, keymaps/prefix with conflicts, Status Studio (status modules never run shell), and import of a supported subset of an existing tmux.conf.
    • Optional new panes/windows start the actual NMSh: a fixed /bin/sh program with the NMSh path passed as quoted argv data. It falls back to the login shell inside an NMSh-started tmux, and default-shell is untouched.
  • Shell frameworks and prompt engines in /tools:
    • Detection is explicit: either an executable on PATH or a registered filesystem detector.
    • Oh My Zsh (Zsh framework, not a command):
      • Guided install that NMSh never runs. NMSh backs up and fingerprints .zshrc, then shows the official source and the documented KEEP_ZSHRC=yes CHSH=no RUNZSH=no settings (REPO/REMOTE/BRANCH pinned). You run it yourself, and NMSh then verifies what changed.
      • An unexpected .zshrc change is reported, never silently restored.
      • .zshrc.pre-oh-my-zsh comparison and reviewed restore: default No, backup first, atomic replace, and no shell-code merge.
    • Powerlevel10k in /tools reuses the existing detector, provider and p10k configure flow (which backs up .p10k.zsh and .zshrc).
    • Oh My Posh: curated homebrew/core install, Use as prompt, and Import appearance into the existing Theme Studio importer.
    • Prezto, Zim, zinit, Antidote: detected from documented layouts only, inspect-only. Antigen is not listed because it has no stable install location.
    • Zsh-only tools stay visible under Bash/Fish (Installed · Zsh framework · used by Zsh only).
  • Dotfiles wizard (/dotfiles): plain, Git, Stow and chezmoi sources; nothing is run. tmux imports supported fields only.
    • Exact copy is a fail-closed registry capability that no tool holds today. Starship, Helix, bat, Oh My Posh, .p10k.zsh, Oh My Zsh themes/plugins and all shell rc files are inspect-only, with a stated reason.

Keep Awake (/caffeinate, also /awake, /zoomies)

  • One controller, state and panel. Modes are Idle / Display / System / All, with optional strict timeouts (45s, 30m, 2h), status and stop.
  • Backends are detected, not assumed:
    • macOS: /usr/bin/caffeinate with fixed flags (-i, -d -i, -s, -d -i -s; System needs AC power).
    • Linux: systemd-inhibit --what=idle|sleep|idle:sleep --mode=block around an NMSh-owned wait helper. No shutdown, lid or key inhibitors. Display is reported unsupported. No systemd means nothing is guessed.
    • Windows: SetThreadExecutionState (CONTINUOUS | SYSTEM_REQUIRED, + DISPLAY_REQUIRED for Display/All) from a fixed hidden PowerShell helper. No away mode, no powercfg, no elevation.
  • The assertion survives closing the NMSh window.
  • Ownership: a random token plus the exact command line. An unverifiable record is cleared and nothing is killed.
  • Mode changes ask first (default No) and start the new assertion before releasing the old one.

Ask

  • Typed, deterministic actions for tmux, Theme Bridge, providers, frameworks (Oh My Zsh installed/guided install/previous zshrc, Oh My Posh prompt/install/import, Powerlevel10k configure/use) and Keep Awake.
  • Mutations go through the existing review and final Yes. Ask never manufactures shell commands or rc edits.

Commands

  • Appearance: /appearance, /motion, /cursor, /activity, /screensaver, /theme, /theme-bridge, /chroma, /chrome, /glyphs, /strip (also /status-strip).
  • Composer & transcript: /prompt, /syntax, /layout (also /composer), /transcript, /keyboard.
  • Providers: /providers, /picker (also /pickers), /suggestions, /navigation, /welcome, /history-provider.
  • Tools & integration: /tools, /configure, /tmux, /integrations, /dotfiles, /caffeinate (also /awake, /zoomies).
  • All appear in help and the palette.

Host semantics

  • OSC 7 cwd and OSC 133 command zones come from NMSh's command lifecycle, on capable hosts and tmux.
  • NMSh-authored OSC 8 links in /help and task rows are kept separate from program links.

Security hardening in this PR

  • Dotfiles exact copy: a fail-closed exactCopy capability. Parseable is not safe: Starship custom commands, bat's pager and Helix :sh keys can all run programs. Adversarial fixtures prove no copy is offered, nothing is written, and nothing runs.
  • tmux pane frontend: the NMSh path is argv data through both the tmux and /bin/sh parsers. 15 hostile directory names (spaces, ; & | ( ) $ $( ) \ ' " \ < > #) were run through real /bin/sh` and real tmux, and no canary file was created.
  • Native prompt literal-data regression (cf. GHSA-x96c-8w82-wf96): hostile Git branch names and context values (zsh % escapes, $()/backticks/${}, quotes, ANSI/OSC/C1) render literally and inertly in live, snapshot and historical prompts, and no canary runs. No renderer change was needed: NMSh never hands repository text to a prompt parser.

Stability fixes found by CI

  • Detached output: prompt metadata (alias/function lists, large under Ubuntu's global compinit) no longer consumes the output retention budget. The cap itself is unchanged.
  • Bash File listing wrapper: ls() failed to parse when ls was already an alias (Ubuntu's default bashrc), so the managed Bash never became ready. It now uses the function ls {…} form. Real-shell regression tests cover zsh, Bash and Fish, including a live managed Bash with an aliased ls.

Homebrew (distribution infrastructure)

  • An NMSh installed by Homebrew is recognized from the Cellar keg and Homebrew's INSTALL_RECEIPT.json. /update, /version, /status and nmsh doctor say so and point to brew upgrade nmsh; NMSh never modifies the Cellar.
  • .github/workflows/homebrew-tap.yml proposes the raiseCatError/homebrew-tap formula update as a PR for stable releases only. It needs a fine-grained HOMEBREW_TAP_TOKEN scoped to the tap.
  • The tap repository itself is prepared but not yet created, and the README does not advertise it yet.

Automated verification

  • Local (macOS arm64, Node 26): npm run verify:fast (63 tests), npm run verify (1677/1677), npm run verify:release (1677/1677, bench typecheck, timing smoke), and git diff --check origin/dev, all passing.
  • Under heavy local load, a few real-terminal timing tests (zsh completion, capture cleanup, a fullscreen flow) failed once each; each passed 3/3 or more alone and in the next full run, and none touches code changed here.
  • Exact-head GitHub Actions for b2075dbda87eb770c5fff8fd2923b9ce7717e973 (CI run 37251498550): Tests macOS 1/2 and 2/2, Tests Ubuntu 1/2 and 2/2, Quality (Node 26), Node 22 compatibility, CI, Verify (22.x) and Verify (26.x) all succeeded. Timing smoke and the Fedora subset are skipped by workflow conditions.

Physical QA still required (nothing below is claimed as physically verified)

Previously physically confirmed: Vim :colorscheme → nmsh-bridge; tmux Theme Bridge colors.

  • Prompt None in both layouts; historical prompt levels.
  • Theme Studio import of real files from each format; Preview Chroma; Duplicate current.
  • Theme Bridge in real fzf, less/man, ls/gls, bat, tmux (include and reload), Neovim, Vim and Helix (activation and removal); zsh/Bash/Fish propagation.
  • /providers inline panel; picker orientation with the composer at top and bottom.
  • tmux Config Studio, Status Studio, and new panes starting NMSh (and falling back inside an NMSh-started tmux).
  • Oh My Posh as the prompt with a real config; failure fallback; import appearance.
  • Oh My Zsh guided install end to end on a machine with an existing .zshrc; previous-zshrc compare and restore; Powerlevel10k Configure from /tools.
  • Keep Awake on macOS (Idle, Display, Stop, survives closing the window), Linux/systemd (systemd-inhibit --list), and Windows (system/display awake, Stop, no power-plan change). Linux and Windows are covered only by mocked tests.
  • OSC 7/133 in Ghostty, Kitty, WezTerm, iTerm2, Terminal.app and tmux; OSC 8 links (Ghostty needed Cmd+Shift+click during QA).

Deferred

  • Terminal title / OSC 0/2 ownership.
  • Terminal emulator or editor base-theme takeover; delta custom themes.
  • Oh My Zsh theme import (themes are executable Zsh code); a Linux display-inhibition adapter.
  • Linuxbrew support; homebrew/core submission.
  • The NMSh Native module ecosystem and upstream module ports #305 module ecosystem.

…d host semantics

- Prompt provider None: composer only (no prompt row, modules, right prompt
  or marker); promptless history snapshots; /prompt and Setup previews.
- Historical prompt presentation Full / Compact / Minimal / Off over the
  unchanged stored snapshot.
- Native theme library: stable-id assets (Custom/Imported by provenance),
  bounded, migrated from the single customTheme (kept as a deterministic
  mirror of the active asset), stable theme references and one pure
  semantic palette resolver.
- Theme Studio with Built-in | Imported | Custom | Import tabs over one
  editor and the real Native preview; import parses and previews first.
- Importers: NMSh JSON, Base16, Base24, Windows Terminal, Oh My Posh
  (JSON/YAML/TOML, static colors only), Kitty, Ghostty (allowlist), iTerm2
  (bounded plist, no entities), WezTerm TOML (Lua rejected). Data-only
  parsers: yaml, smol-toml, fast-xml-parser.
- Theme Bridge: per-target Independent / Follow NMSh / Choose theme with a
  master switch (default Off); fzf launch colors, less/man termcap and
  LS_COLORS through one validated shell-environment sink applied by the
  zsh/Bash/Fish adapters, tmux/Neovim/Vim managed artifacts with an
  ownership ledger, staged validated writes and exact reviewed includes;
  bat/delta reported as unsupported rather than faked.
- /theme-bridge, /appearance destinations, Setup and Settings selection.
- OSC 7 and OSC 133 projected from the OSC 777 lifecycle on capable hosts;
  NMSh-authored OSC 8 links kept distinct from raw PTY links.
… tests; docs

- Tests: library migration/actions/export/deletion, every importer with
  malformed, oversized, unsafe and lossy fixtures, Theme Bridge modes,
  mappers, environment sink in real zsh/Bash/Fish, ownership ledger,
  exact includes, tmux/Vim artifacts loaded by real tmux/Vim, Prompt None
  layouts and history, historical prompt levels, OSC 7/133/8, Theme Studio
  and /theme-bridge UI, Setup rows, and live end-to-end NMSh sessions.
- Fixes found by them: Prompt None framed as the one-line composer in the
  two-line layout, include planning on a symlinked home, Setup/Settings
  action rows keep "Open ›".
- Docs: help, README, CHANGELOG and docs/design/theme-bridge.md.
…irmed activation

Generated nmsh-bridge.toml in Helix's themes directory (syntax, markup,
diff, diagnostic and editor UI scopes over a named palette), ownership
ledger and staged validated writes, one confirmed theme assignment placed
before the first table of config.toml, never replacing a user-selected
theme, exact removal, factual status, tests and docs.
…ng colors, preview Chroma, /motion

- Theme Bridge switch plus Apply themes policy (Manual / Follow NMSh /
  Choose theme with one global theme); per-target settings stay the Manual
  state and come back exactly; capability classes (direct, managed,
  detected); delta shown but never editable or inherited.
- /theme-bridge is one panel: grouped table, inline expansion, Esc collapses
  first, view-only rows under global policies, Remove managed setup vs Set
  Independent, Review all / Apply all with a combined review defaulting No.
- bat: generated data-only .tmTheme in bat's themes directory, reviewed
  bat cache --build with typed argv verified by bat --list-themes, BAT_THEME
  only when ready, automatic rebuilds only after that approval, Duplicate
  source to Custom.
- File listing colors: GNU ls/gls get LS_COLORS and a session-only
  color-auto wrapper (never shadowing user aliases/functions); macOS/BSD ls
  gets CLICOLOR and LSCOLORS.
- Integrations health planner; Helix activation state detection.
- Theme Studio: local Preview Chroma (default Off) and Duplicate current
  theme to Custom; Setup Prompt/Appearance preview switch; Chroma row in
  Setup Prompt.
- /motion opens the existing Motion screen.
…registry, integrations, dotfiles import, command surface cleanup
…against the detached retention cap

- Dotfiles: exact-copy is an explicit, fail-closed registry capability
  (exactCopy validator). Parseable is not safe: Starship, Helix and bat
  configs can run commands, so they are inspect-only with a stated reason.
  Apply re-checks authority, so a forced copy mode writes nothing.
- tmux: the pane frontend is a fixed /bin/sh program; the NMSh path is
  passed as shell-quoted argv data ("$1"), never as program text. Any
  absolute path without control characters works literally; the validator
  accepts only that exact form.
- Detached output: prompt metadata (alias/function lists) no longer
  consumes the output retention budget, which made in-limit output look
  truncated on Ubuntu (global compinit). The output cap is unchanged.
- Shell switch test reports shell state on timeout.
- Remove a stray committed .swp; ignore *.swp.
@raiseCatError
raiseCatError force-pushed the feature/v018-theme-bridge branch from d40e7a8 to df92d51 Compare October 5, 2026 00:24
…t-literal regression tests

Bash alias-expands `ls()` while parsing, so with ls already an alias
(Ubuntu's default bashrc) the generated bootstrap failed to parse and the
managed Bash never became ready. Use the `function ls { ... }` form; zsh
and fish were unaffected.

- Real bash/zsh/fish tests of the listing wrappers: parse with ls/gls
  aliased, --color=auto before user argv, existing alias/function kept,
  missing executables not wrapped, Off removes only NMSh's wrapper.
- Live managed Bash with an aliased ls in ~/.bashrc reaches ready.
- Native prompt: hostile Git branch names, repository names and context
  values (zsh % escapes, $()/backtick/${}, quotes, ANSI/OSC/C1) render
  literally and inertly in live, snapshot and historical prompts; no
  canary runs. No renderer change was needed.
…l provenance

Shell frameworks and prompt engines
- /tools detects tools by an explicit strategy (executable or a registered
  filesystem detector). Oh My Zsh, Powerlevel10k, Prezto, Zim, zinit and
  Antidote are found by documented layouts only; detection grants no
  install, uninstall, configuration or provider authority. Zsh-only tools
  stay visible under Bash/Fish ("used by Zsh only").
- Oh My Zsh: guided install that never runs the installer. NMSh backs up
  and fingerprints .zshrc, shows the official source and the documented
  KEEP_ZSHRC=yes CHSH=no RUNZSH=no (REPO/REMOTE/BRANCH pinned) steps, and
  verifies afterwards; an unexpected .zshrc change is reported, never
  silently restored. .zshrc.pre-oh-my-zsh comparison with a reviewed
  restore (default No, backup first, atomic replace, no merge).
- Powerlevel10k in /tools routes to the existing detector, provider and
  p10k configurator.
- Oh My Posh: new Prompt provider (oh-my-posh print primary, argv only,
  no TTY, bounded, timed out, cancellable, Native fallback) and a curated
  homebrew/core install; Theme Studio import of its config stays static.
- Ask: typed routes for these requests; dotfiles treats .p10k.zsh, Oh My
  Zsh themes/plugins and Oh My Posh configs as inspect-only.

Keep Awake (/caffeinate, /awake, /zoomies)
- One controller over the OS mechanism: /usr/bin/caffeinate,
  systemd-inhibit (idle/sleep only, Display reported unsupported) and
  SetThreadExecutionState from a fixed PowerShell helper (no away mode,
  no powercfg). Detached so it outlives the window; ownership is a token
  plus the exact command line, so unverifiable records are cleared and
  nothing is killed. Strict timeouts, status, idempotent stop, confirmed
  mode changes that start the new assertion first.

Homebrew
- A Homebrew keg is recognized from the Cellar layout and Homebrew's
  INSTALL_RECEIPT; /update, /version, /status and doctor say so and point
  to brew upgrade nmsh instead of touching the Cellar.
- Release workflow proposes the raiseCatError/homebrew-tap formula update
  as a pull request for stable releases only.
…h; Keep Awake ownership check uses absolute PowerShell

- The guided install's file lived at a predictable /tmp name another local
  user could replace between download, inspection and running.
- On Windows the ownership check resolved powershell.exe through PATH; it
  now uses the System32 path like the backend itself.
…ser chrome; /tools selection is a real band

Keep Awake
- /caffeinate, /awake and /zoomies with no argument opened a panel that was
  never drawn (it was missing from the active-panel set), so the composer
  looked frozen, keys went to the hidden panel, Enter quietly started an
  assertion and only Ctrl+C (the panel's close key) gave the prompt back.
  The panel is registered (the Mise panel had the same omission), and a
  start, an accepted mode change or a stop now closes it and records one
  line under the command that opened it. The assertion was always an
  NMSh-owned detached process; nothing ran through the shell, and a typed
  shell caffeinate stays an ordinary foreground command.
- Presentation: while active, "Awake · <mode>" is NMSh composer chrome,
  never prompt or provider output. Placement Composer edge (default) takes
  a plain top divider, else the bottom divider when a header prompt owns
  the top edge, else one row next to the composer; Above composer and
  Input row (only when the edit is single-line with room to spare; the
  editor's wrapping, caret, selection and hit testing use the narrowed
  width) are explicit choices. The decision is made with the screen plan
  each frame and never rewrites the saved setting.
- Both composer edges render through one exact-width edge renderer, also
  used by the Chroma repaint, so an animated divider never erases the
  accessory and transition tints stay off it.
- Status Strip: an active Keep Awake is always in an enabled strip (no
  per-item switch); it narrows (label, Awake, glyph) before anything would
  drop it, and a disabled strip stays disabled.
- Idle reminder (default On, 30 s without NMSh input): adds the time and a
  muted /zoomies stop on the edge when it fits, else one muted row; the
  next input collapses it. Screensaver status (default On, Bottom left, six
  positions) is a small separate element; the saver and Vespyr are
  untouched.
- Display Text / Icon / Icon + text through the semantic icon set (Safe
  mode keeps text). Colors are theme roles: accent while active, muted for
  the reminder. Off renders nothing anywhere.
- The panel gains Duration and Presentation, Screensaver and Status Strip
  sections. Ask answers status questions and plans start, change, timed and
  stop requests through the same controller, deterministically.
- A deterministic-only inert backend (NMSH_DETERMINISTIC=1 with
  NMSH_KEEP_AWAKE_BACKEND=inert) runs the real slash, controller, ownership
  and presentation paths for tests and recorded demos without keeping a
  machine awake.

/tools
- The selected row uses the shared selected band (the active tab's
  treatment): full width, bold label, quiet text lifted onto the band, and
  reverse video without color.

README art
- scripts/demos/vespyr-svg.ts renders a small transparent divider from
  Vespyr's real sprite pixels and blink pose.
…TECTURE.md

Docs
- README rewritten for a first visit: what NMSh is and is not, highlights,
  a short hero clip, a visual tour, source install (no Homebrew command
  until the tap exists), core commands, Keep Awake, shells/frameworks/
  providers, terminals, accessibility, safety and ownership, limitations.
  Stale zsh-only, fixed-bottom, bat/Theme Bridge and badge claims fixed.
- AGENTS.md: current shell model, composer edges and the screen plan,
  safety boundaries, current unreleased surfaces, PR #315, no-attribution
  rule, demo command. SECURITY.md: supported versions and the boundaries
  NMSh keeps. SUPPORT.md: nmsh doctor. CONTRIBUTING, ROADMAP (PR #315 in
  development; OSC 0/2 still deferred), llms.txt and the Theme Bridge doc
  updated; new docs/design/keep-awake.md and docs/demos.md.
- ARCHITECTURE.md is linked as the high-level overview from README,
  CONTRIBUTING, AGENTS and llms.txt.
- Prompt None: help, the prompt picker and Setup said "no marker"; the
  input marker has always stayed, and the wording now says so.

Demos
- npm run demos records every scripts/demos/*.tape with VHS against a
  disposable demo home (fixture repo ~/Projects/demo, neutral identity, no
  network, update checks and npm's notifier off), encodes GIFs and stills
  from VHS frames with ffmpeg, then stops everything still holding files in
  the demo home and fails if anything survives. Keep Awake is recorded with
  the inert backend; sessions detach with SIGHUP as a closing window does.
- Clips: hero, composer and prompts, Theme Studio, Theme Bridge,
  providers and tools, live sessions, screensavers with Vespyr, Keep Awake;
  three stills; a Vespyr divider generated from the real sprite.
- The old asciinema/tmux recorder, which recorded the real home directory,
  is removed; dev/tapes stays for development captures.
- tests/docsAssets.test.ts checks local doc links and images, that every
  published clip has its tape, and that docs, tapes and vector art name no
  real home path or secret.
Clarify that NMSh should not be configured as the system/login shell.

Explain that zsh, Bash or Fish remains the real shell underneath NMSh, while terminal apps such as Ghostty or Zed can be configured to launch NMSh automatically.

This makes the distinction between “default terminal command” and “login shell” explicit and keeps Terminal.app or another host available as a normal-shell fallback.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant