Marketplace cards now reflect whether an extension is already installed in
the current workspace, and the installed-extension list gains a search box.
Backend (stream install progress):
- _read_httpx_response_limited gains an optional task_context: it publishes
download_total from Content-Length before the first chunk and updates
download_current / download_speed per chunk. The marketplace download path
previously had no progress reporting; it now matches the GitHub path.
- _marketplace_get forwards task_context to that helper.
- install_plugin resets the per-install counters so re-installing the same
plugin cannot inherit stale metadata, and reports human-readable stages:
preparing -> downloading -> inspecting -> storing -> installing
dependencies -> launching -> waiting for plugin to become ready.
Frontend (installed state):
- New marketplace-installed helper normalises the sidebar identities
(plugin: author/name, mcp: author__name, skill: bare name) into one
type:author/name index and resolves a card's installed state from it.
useMarketplaceInstalledIndex memoises on the sidebar lists, so a finished
install (which refreshes the sidebar) re-evaluates the cards automatically.
- PluginMarketCardVO carries installed / hasUpdate. An installed extension
turns its download affordance into a hollow green ring with a green check
in place, instead of adding a separate badge; the count slot switches to
the installed label. Cards with an available update use amber.
- PluginMarketComponent derives the annotated list and shares the index with
RecommendationLists.
Frontend (install task UI):
- mapActionToStage matches the new connector stage strings. The pre-download
stages are checked before the generic "install" match, because
"preparing plugin install" also contains "install".
- Stage progress ranges are non-overlapping; overall progress interpolates on
real byte counts while downloading and drifts monotonically elsewhere,
capped at 99%.
- The progress dialog and task queue expose the launching stage.
Frontend (installed list search):
- The installed list had no search at all. A query box in the page header
filters by label / name / author / description, case-insensitively, applied
before grouping so grouped and flat views both honour it.
- Search misses and an empty list now show distinct empty states, with a
clear action on a search miss.
- AsyncTask entity gains the optional created_at field.
i18n: new marketplace / install / search strings across all 8 locales.
Verified: ruff format + check, tsc --noEmit, prettier --check, eslint
(0 errors), and 89/89 frontend unit tests.
- Safely resolve media_cache via getattr in cleanup_expired_files to prevent AttributeError when storage_mgr is unset in cloud/test fixtures
- Only attach 'media_files' in cleanup return dictionary when media cache is active on singleton, preserving exact return contract for cloud maintenance tests
- Add explanatory comments to exception suppression in MediaCache.touch and cleanup loops to address code-quality review findings
- Add MediaCache using xxHash3-128 (with sha256 fallback) content-addressable storage
- Externalize message chain image payloads before recording monitoring and discarded messages
- Strip base64 payloads to null in SQLite monitoring_messages, dropping row size from megabytes to hundreds of bytes
- Add GET /api/v1/files/media/<filename> route with immutable HTTP cache headers to serve cached media
- Integrate age-based retention (default 30 days) and configurable disk quota with MaintenanceService cleanup loop
- Add defensive sanitizer in MonitoringService.record_message against oversized raw base64 payloads
- Add comprehensive unit tests and end-to-end verification covering CAS deduplication, route serving, and LRU pruning
* feat(packaging): add fnOS FPK packaging and CI workflow
Add packaging/fnos/ shell (manifest, lifecycle cmd scripts, install/
upgrade/uninstall wizards, desktop entry, EULA) plus in-repo build
script. A release now auto-builds langbot-<tag>-fnos.fpk via
.github/workflows/build-fnos-fpk.yaml, uploaded to the release assets.
* ci(fnos): skip release upload on manual dispatch
github.event.release.tag_name is empty when triggered via
workflow_dispatch, causing 'gh release upload' to fail with
'requires at least 2 arg(s)'. Restrict the step to release events.
* ci(fnos): normalize release asset name
Strip a trailing -fnos from the tag-derived version before appending
the suffix, avoiding langbot-<v>-fnos-fnos.fpk when the tag itself
already carries -fnos.
* ci(fnos): use release tag version for auto build, manifest for manual
Auto build (release/tag) reads version from tag like other release
workflows; build.sh strips the v prefix when injecting into manifest.
Manual dispatch falls back to the version maintained in manifest.
* feat(fnos): add post-install deployment notice to install wizard
Last wizard step now informs users that first startup takes about
5-10 minutes for dependency setup before the web UI is ready.
* docs(fnos): add packaging directory README
* refactor(fnos): rename app from ai.langbot to langbot
Rename appname, desktop entry, data share, build artifacts, and all
references from ai.langbot to langbot across packaging files.
---------
Co-authored-by: dadachann <185672915+dadachann@users.noreply.github.com>