diff --git a/README.md b/README.md index 92ecb1d..22da611 100644 --- a/README.md +++ b/README.md @@ -65,17 +65,29 @@ a fact: embeddingApiBase: http://10.50.1.2:11434 ``` -Or edit every setting from the UI. The plugin ships **two halves**, and the settings -page draws a card only when it has both: +Or edit every setting from the UI: **Plugins → dsh-recall → Configure**. The +plugin ships **two halves**, and the page appears only when both are present and +the deployment serves the namespace: -- the **host half** (`index.js`) serves a `dsh-recall` settings namespace; -- the **browser half** (`client/client.js`) claims that same namespace with a - collapsible card under **Settings → Plugins → Plugin configuration**. +- the **host half** (`index.js`) exports a `Config` schema whose every field is + `.volatile()`. That schema *is* the settings page's description — the Harness + keys one form per profile entry by that row's `id` (`dsh-recall` in + `cordis.patch.yml`), and it skips an entry with no volatile field entirely, so + a schema without those markers has no settings surface at all rather than an + empty one; +- the **browser half** (`client/client.js`) renders that form into the Plugins + panel's per-row configuration seat, `plugins.row.config`, keyed + `#` — here `dsh-recall#dsh-recall`. Registering it is + what adds the **Configure** control to the plugin's row. -A served namespace with no card renders nothing at all, and a card whose namespace -is not served is never dispatched — so both are required. A restart is needed for a -newly installed browser half to appear, because client bundle bytes are snapshotted -when the profile activates. +A served namespace with no page draws no control, and a page whose namespace is +not served is deliberately not registered — so both are required. A restart is +needed for a newly installed browser half to appear, because client bundle bytes +are snapshotted when the profile activates. + +Editing in the UI writes to the profile's own patch layer through the settings +document, so the value survives a restart and stays visible in +`cordis.patch.yml`. Every value is also checkable from the tool, without touching a file: @@ -83,9 +95,9 @@ Every value is also checkable from the tool, without touching a file: recall action=configure config={"embeddingApiBase":"http://10.50.1.2:11434"} ``` -The API key is declared `role('secret')` on the host, so it is stripped from every -settings response — the card can show that a key is set without ever receiving it, -and leaving it blank on save means "unchanged" rather than "clear". +The API key is declared `role('secret')`, so it is stripped from every settings +response: the page can show that a key is set without ever receiving it, and a +blank draft writes nothing — leaving it alone means "unchanged", never "clear". Pull the model once: @@ -102,7 +114,7 @@ ollama pull unclemusclez/jina-embeddings-v2-base-code | `search` *(default)* | answers `query`, warming a bounded slice of the index first | | `index` | builds or refreshes the whole index; **background job by default** | | `status` | index and endpoint state, touching nothing | -| `configure` | writes settings through the settings namespace | +| `configure` | writes settings through the settings document | Parameters: `query`, `action`, `limit`, `path` (restrict to a subdirectory), `run_in_background`. @@ -363,10 +375,16 @@ exactly that during development. `test/config.test.js` covers the load-time contract. Cordis rejects a `Config` before `apply` ever runs, so a broken schema cannot be reported from inside the plugin — the profile simply refuses to boot. Every other test in the suite calls -`apply` directly and would not notice. +`apply` directly and would not notice. It also pins the second half of that +contract: that every field is `volatile()`, because that marker is what makes +the Harness serve a settings page at all, and its absence is invisible from +inside the process. -`test/client.test.js` runs the browser half in Node by stubbing `window` and -`require('react')`. That is worth more than it sounds: the two failure modes most -likely to reach you silently are structural — a root element that is not an `
  • `, -and a card that does not start collapsed — and both are invisible until someone -opens Settings. It also pins that an untouched API key is never written or unset. +`test/client.test.js` runs the browser half in Node by stubbing `window`, +`require('react')`, and the settings-form primitives. That is worth more than it +sounds: the failure modes most likely to reach you silently are structural — a +page registered into a slot nobody declares (which is what the 0.1.5 seat, +`settings.plugin.item`, became), a right-sidebar body with no tab type behind it, +and a field list that has drifted from the schema — and all three are invisible +until someone opens Plugins. It also pins that an untouched API key is never +written, and that the field list and `Config` name the same settings. diff --git a/client/client.js b/client/client.js index 37c9fee..1675c8d 100644 --- a/client/client.js +++ b/client/client.js @@ -1,24 +1,37 @@ /** - * dsh-recall — browser half: the card in Settings → Plugins → Plugin configuration. + * dsh-recall — browser half. * - * The Host half registers a `dsh-recall` settings namespace. This file registers - * a card under that exact namespace key. Both are required: the tab pairs the - * namespaces the Host serves with the cards the browser claims, so a served - * namespace with no card draws nothing at all, and a card whose namespace is not - * served is never dispatched. + * Three contributions, each into a seat the Harness 0.1.7 composition declares: * - * The chrome follows the framework's `PluginCard`: the root is an `
  • ` (the tab - * renders every card into a `
      `), the header is its own `