Commit Graph
4 Commits
Author SHA1 Message Date
dsh-slopo agent 1b2ab3613f fix!: port the settings page and shell seam to dsh 0.1.7-rc.2
Release / release (push) Successful in 6s
0.1.7-rc.2 moved four things this bundle was built on, and every one of them
failed quietly rather than loudly, so the plugin looked installed and did
nothing:

  * `ctx.settings.installSection(...)` is gone. The call threw into a
    `try/catch` that only logged a warning, so the settings namespace was never
    registered and `configure` had nowhere to persist. An entry's exported
    Config IS the form now; the namespace is the Loader entry id the bundle's
    patch declares, and `ctx.settings.configure({ auto: false })` is what claims
    that entry's own page.

  * `settingsScope` and the `settings.plugin.item` slot are gone. The card
    registered into both, so it never rendered — the tab draws the intersection
    of served namespaces and registered cards, and that intersection was empty.
    It now registers into `plugins.bundle.config` keyed by the bundle's package
    name, over the `configForms` service, and uses the framework's own form
    chrome (`SettingsFormModel` / `SettingsForm` / `SettingsValueField` /
    `SettingsSecretField`) instead of the hand-rolled equivalent. A save is one
    revision-fenced write.

  * `ctx.shell.run(spec)` is gone. Every action that runs a command threw
    `shell.run is not a function`; the seam is now
    `await ctx.shell.execute(ctx.shell.resolve(request)).result()`.

  * A job's `owner` is a session id, not the agent object. The wrong owner
    registered a job no session could collect or cancel, and the producer's
    `done` resolved `output` where the registry reads `result`, so a finished
    job handed back nothing.

Two conformance gaps went with them: a Config field that is not marked
`volatile()` is invisible to every settings UI — the form projection keeps only
volatile fields, and an entry with no form is dropped from `settings.describe`
entirely — and `embeddingApiKey` was a plain field, so the key rode every
settings read back to the browser. It is `role('secret')` now: the browser is
told whether a key is stored and never receives the key.

Also declares the `@deepseek-ai/dsh-*` peerDependencies the compatibility gate
reads, so an incompatible runtime refuses this plugin at startup instead of
half-loading it.

Verified against a real 0.1.7-rc.2 boot: `settings.describe` serves the entry
with `autoGenerate: false`, the key redacted and reported only as `set: true`,
and no startup diagnostics. The host mock in the tests now has no `run` and no
`installSection`, so those seams are contract-tested rather than assumed, and
the browser tests read the installed harness's own slot catalog and package
exports — a rename fails a test instead of quietly emptying a page.
2026-09-26 06:38:16 +01:00
dsh-slopo agent 2d7a7d1e73 Make the settings card behave like the other plugin cards
It rendered as a flat, always-open block with no header. The framework's card
chrome is a disclosure: the tab renders every card into a <ul>, each card's root
is an <li>, its header is its own <button> that discloses the controls in place,
it starts collapsed, the header marks it when it holds unsaved edits, and a save
that lands folds it back up.

Three things were wrong and only one of them was cosmetic:

  * the root was a <div> inside the tab's <ul>, so the list and card styling
    never reached it
  * there was no header button, so no disclosure and no aria-expanded
  * nothing marked unsaved edits, and nothing collapsed after a save

`PluginCard` is not importable — it lives in that package's client bundle, and
the client purity gate forbids cross-plugin value imports — so the behaviour is
reproduced rather than borrowed, with inline styles for the same reason.

The collapse-on-save originally lived in an effect watching a `saving` flag, which
is how the shipped card does it because its form state comes from a controller.
This card awaits its own writes, so it already knows the save landed; collapsing
directly in the success path is simpler and is what the tests can actually reach.
A failed save still keeps the card open with its drafts.

Tests cover the disclosure itself: the root element, collapsed-by-default, the
header's aria-expanded and label, that staged edits survive collapsing, and that
a landed save folds the card up.
2026-09-22 13:26:29 +01:00
dsh-slopo agent e149b6a977 Surface the scope settings on the card
Extra exclude patterns, the default-excludes switch, and the backlog budget, each
with the number that motivates it.
2026-09-22 13:23:49 +01:00
dsh-slopo agent 4bb19af2ac Add the settings card — the browser half
The settings namespace was registered but nothing drew a form for it, because
the Plugin configuration tab renders the INTERSECTION of the namespaces the Host
serves and the cards a browser half claims. A served namespace with no card
renders nothing at all. This is the missing card.

Plain ESM in the module-loader wrapper, no build step, requiring only `react` —
which is in the platform seed table. Anything outside that table would have to be
bundled into this file or declared in `dsh.client.external`, and the tests fail
loudly on any other specifier.

It stages edits and writes them on Save; a cleared field is an `unset` rather
than a write of "", so the value re-inherits the composition layer instead of
becoming empty, and the user layer's presence is what marks a field overridden.
Reset clears every override. A namespace this client cannot reach renders
nothing, so a deployment without the Host half shows no trace.

package.json gains an `exports` map (the loader reads `exports["./client"]`; a
bare `main` would not be enough) and the `dsh.client` declaration.
2026-09-22 07:22:03 +01:00