Installing a plugin now activates it without a restart: the CLI boot provides a
dshReloadProfile handle that re-runs the profile composition and applies it to
the running root Include, and the install/uninstall Remotes recompose live when
the handle is present (restartRequired: false). Registry installs try the
ordered INSTALL_REGISTRIES mirrors with the official npm registry as the final
fallback, erroring only when every source is unreachable. The enable/disable
guard splits into a REQUIRED_PLUGINS blacklist and a USER_TOGGLEABLE_PLUGINS
whitelist (default toggleable) generated from the running plugin list, and the
offline optional-bundle catalog is emptied (default bundles are not
installable/uninstallable). The plugin-list tab becomes a registry install form
and shows immediate-activation instead of a restart notice.
Co-Authored-By: Claude <noreply@anthropic.com>
The RemoteNamespaceService reserves `install` as its private registration
method, so a Remote method also named `install` collided at client-api boot
(`pluginInventory/install conflicts with its namespace service`). Rename the
plugin-install Remote to `installPlugin` across host, client, and tests.
Co-Authored-By: Claude <noreply@anthropic.com>
Adds an install surface to the plugin-inventory gateway: availableBundles lists
the curated offline-installable optional bundles (AVAILABLE_BUNDLES); install
composes an offline bundle into the profile's dsh.profile.bundles, or for a
registry spec runs pnpm against the writable profile via the bundled Node and a
vendored pnpm (gated behind the dshAllowPluginInstall context flag, set only by
the desktop boot); uninstall removes a bundle layer. The reconcile logic from
`dsh plugin add` moves into app-boot as shared helpers. The desktop vendored
pnpm into the harness and sets the allow-install env; the plugin-list SPA gains
an installable-bundles section. Tests cover the guard, install helpers, and the
SPA section at 100% host coverage.
Co-Authored-By: Claude <noreply@anthropic.com>
Notes the preview build as unofficial in the conversation hero and describes the
image-recognition plugin as an extension beyond the official DeepSeek surface.
Co-Authored-By: Claude <noreply@anthropic.com>
Registers a new `settings.section` (id `about`) in ui-settings-general that
introduces PineSound, names the product build, shows the current version, and
offers a check-updates control (a client-side placeholder comparing against a
known-latest constant pending a real update channel). Adds a 16px info icon to
ui-primitives and wires the section into the settings nav. Tests cover the
registration and the About component; READMEs and translation-pairing hashes
are updated.
Co-Authored-By: Claude <noreply@anthropic.com>
The plugin-list tab rendered one flat list of every Loader entry — no separate
"system plugins" section — with each card showing its real enabled state and an
enable/disable button (a required plugin shows only a read-only note). The
enable/disable guard flipped from default-protect to default-open: only the
small REQUIRED_PLUGINS core (entry tree, Remote RPC spine, session/agent spines)
is protected from being disabled, so the shipped plugins are actually
toggleable. Tests, host READMEs, and the enable-disable agent note track the new
grouping and guard.
Co-Authored-By: Claude <noreply@anthropic.com>
The plugin-list tab now splits by current state: disabled plugins sit in the
main list with an enable button (so a bundle-default-disabled plugin can be
re-enabled), while enabled plugins sit in the collapsible system section —
a user-added enabled plugin keeps a disable toggle, a required one shows
none. setEnabled refuses to disable a required plugin but allows re-enabling
a disabled one, verifying the fiber activates and reverting a
dependency-missing enable.
Co-Authored-By: Claude <noreply@anthropic.com>
User-added (toggleable) plugins carry an enable/disable button in the main
list; required system plugins sit in a separate collapsible 'system plugins'
section with no controls. The system section starts expanded so the existing
web e2e/snapshot (which targets a system plugin row) still passes.
Co-Authored-By: Claude <noreply@anthropic.com>
Every entry now carries a protected flag. The guard is default-protect:
disabling a plugin another plugin injects breaks the dependent, and enabling
one whose service is unavailable fails the boot (dsh-tool-ralph: pending on
workflowEngine). setEnabled refuses and the UI hides the toggle for every
shipped plugin; only opt-in-bundle plugins (USER_TOGGLEABLE_PLUGINS in
required.ts) are toggleable.
Co-Authored-By: Claude <noreply@anthropic.com>
Each expanded plugin card gains an enable/disable button wired to
pluginInventory.setEnabled; the tab re-lists after toggling. Adds zh/en
copy for the toggle states.
Co-Authored-By: Claude <noreply@anthropic.com>
Unit-render the card after expanding its disclosure header, asserting the
three configurable controls appear (getByLabelText throws when absent).
Co-Authored-By: Claude <noreply@anthropic.com>
The apply test now expects four plugin.item cards (bash, agent-loop,
web-search, image-recognition), a cardCount of 4, and two credential
re-reads (web-search and image-recognition both watch the reference).
Co-Authored-By: Claude <noreply@anthropic.com>
An image-recognition card in the Plugins settings page (endpoint + key),
cloned from the web-search card: baseURL via the settings section, the key
through the credentials domain.
Co-Authored-By: Claude <noreply@anthropic.com>
Every release member now declares publishConfig.access: public, so the scope no
longer mixes levels: the 221 packages/*/* and apps/* manifests join the vendored
framework and the native packages.
check-workspace-constraints drops the per-sequence expectation and holds every
release member to public, which is what stops a member from drifting back.
Access is a property of the package, not of a version: the dsh packages already
published as restricted become world-readable at their next publication.
- Rewrite the 08-04 gutter-reservation note in place: the reservation is Chat's alone and the overlay branch points to the seat-width compensation note; the Testing section now describes the uncompensated control.
- Cross-reference the earlier rejection of the seat inset in the 08-12 note and record the engine-resolved-vs-fixed-8px drift as accepted residual cost instead of asserting Firefox resolves 8px.
- Pair --dsh-scrollbar-width with the mirrored ::-webkit-scrollbar rule and the compensation consumer in the scrollbar-styles gate; document the variable in the ui-theme README.
- Rename the e2e control to compareTabsWithoutCompensation and correct the vacuity-guard comment; rewrap the WorkspaceBrowser doc comment.