Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a350178434 | ||
|
|
7f1dfddb83 | ||
|
|
233215e6c9 | ||
|
|
df2fa0f54b | ||
|
|
1f42d2a821 | ||
|
|
269360a4ea |
No files matched your search
@@ -2,6 +2,20 @@
|
|||||||
|
|
||||||
Every release, newest first, generated from the commits in each release.
|
Every release, newest first, generated from the commits in each release.
|
||||||
|
|
||||||
|
## v0.1.3 — 2026-09-26
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- draw the settings on the plugin card, not a click deeper
|
||||||
|
|
||||||
|
|
||||||
|
## v0.1.2 — 2026-09-26
|
||||||
|
|
||||||
|
### Documented
|
||||||
|
|
||||||
|
- lead the install instructions with the published git spec
|
||||||
|
|
||||||
|
|
||||||
## v0.1.1 — 2026-09-26
|
## v0.1.1 — 2026-09-26
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -49,6 +49,22 @@ about a millisecond; the only per-query network cost is one embedding call.
|
|||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dsh plugin --profile web add git+https://git.notexpectedyet.com/Not-Expected-Yet/dsh-recall.git
|
||||||
|
```
|
||||||
|
|
||||||
|
That form installs whatever the default branch holds, pinned to a commit in the
|
||||||
|
profile's lockfile. The semver fragment installs the newest release tag instead,
|
||||||
|
and is what makes `dsh plugin update` follow releases — see
|
||||||
|
[Releases](#releases) for the tag and versioning rules:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dsh plugin --profile web add 'git+https://git.notexpectedyet.com/Not-Expected-Yet/dsh-recall.git#semver:^0.1.0'
|
||||||
|
```
|
||||||
|
|
||||||
|
To run your own copy instead, add the directory — that becomes a `link:`
|
||||||
|
dependency which tracks the working tree, so an edit needs no reinstall:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
dsh plugin --profile web add /path/to/dsh-recall
|
dsh plugin --profile web add /path/to/dsh-recall
|
||||||
```
|
```
|
||||||
@@ -65,9 +81,11 @@ a fact:
|
|||||||
embeddingApiBase: http://127.0.0.1:11434 # replace with your endpoint
|
embeddingApiBase: http://127.0.0.1:11434 # replace with your endpoint
|
||||||
```
|
```
|
||||||
|
|
||||||
Or edit every setting from the UI: **Plugins → dsh-recall → Configure**. The
|
Or edit every setting from the UI: **Plugins** in the sidebar → the
|
||||||
plugin ships **two halves**, and the page appears only when both are present and
|
**dsh-recall** card → its settings are on that card, below the description.
|
||||||
the deployment serves the namespace:
|
(Not Settings → *Built-in plugins*: that section is a read-only inventory of
|
||||||
|
what the deployment ships.) The plugin ships **two halves**, and the section
|
||||||
|
appears only when both are present and the deployment serves the namespace:
|
||||||
|
|
||||||
- the **host half** (`index.js`) exports a `Config` schema whose every field is
|
- the **host half** (`index.js`) exports a `Config` schema whose every field is
|
||||||
`.volatile()`. That schema *is* the settings page's description — the Harness
|
`.volatile()`. That schema *is* the settings page's description — the Harness
|
||||||
@@ -76,11 +94,16 @@ the deployment serves the namespace:
|
|||||||
a schema without those markers has no settings surface at all rather than an
|
a schema without those markers has no settings surface at all rather than an
|
||||||
empty one;
|
empty one;
|
||||||
- the **browser half** (`client/client.js`) renders that form into the Plugins
|
- the **browser half** (`client/client.js`) renders that form into the Plugins
|
||||||
panel's per-row configuration seat, `plugins.row.config`, keyed
|
panel's per-bundle configuration seat, `plugins.bundle.config`, keyed by the
|
||||||
`<bundle package>#<row id>` — here `dsh-recall#dsh-recall`. Registering it is
|
bundle's package name. Registering it is what draws the section; without it
|
||||||
what adds the **Configure** control to the plugin's row.
|
there is no settings UI however complete the schema is.
|
||||||
|
|
||||||
A served namespace with no page draws no control, and a page whose namespace is
|
The sibling seat `plugins.row.config` — keyed `<package>#<row id>` — draws one
|
||||||
|
row's configuration on that row's own page. That is the right home for one row
|
||||||
|
of a bundle that declares several; this bundle declares one, so its settings
|
||||||
|
belong on the card.
|
||||||
|
|
||||||
|
A served namespace with no page draws nothing, and a page whose namespace is
|
||||||
not served is deliberately not registered — so both are required. A restart 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
|
needed for a newly installed browser half to appear, because client bundle bytes
|
||||||
are snapshotted when the profile activates.
|
are snapshotted when the profile activates.
|
||||||
|
|||||||
+23
-16
@@ -12,10 +12,11 @@
|
|||||||
* binding `settingsScope` and registering into a `settings.plugin.item` slot.
|
* binding `settingsScope` and registering into a `settings.plugin.item` slot.
|
||||||
* Neither exists in 0.1.7. The generated settings document is keyed by the
|
* Neither exists in 0.1.7. The generated settings document is keyed by the
|
||||||
* plugin's own profile entry id, and a plugin that wants a page renders it as a
|
* plugin's own profile entry id, and a plugin that wants a page renders it as a
|
||||||
* contribution to the Plugins panel: `plugins.row.config`, keyed
|
* contribution to the Plugins panel — `plugins.bundle.config`, keyed by the
|
||||||
* `<bundle package>#<row id>`. That key is what puts a **configure** control on
|
* bundle's package name, which the page draws as a section on the plugin's own
|
||||||
* the plugin's row — without a contribution there is no control and no page,
|
* card. Without a contribution there is no section, however complete the schema
|
||||||
* however complete the schema is.
|
* is; the sibling seat `plugins.row.config` would instead put it one click
|
||||||
|
* deeper, on a single row's page.
|
||||||
*
|
*
|
||||||
* **The page is the framework's form, not a form of our own.** The card used to
|
* **The page is the framework's form, not a form of our own.** The card used to
|
||||||
* reproduce `PluginCard`'s chrome by hand — the `<li>` root, the disclosure
|
* reproduce `PluginCard`'s chrome by hand — the `<li>` root, the disclosure
|
||||||
@@ -70,13 +71,17 @@ window.__ModuleLoader__.load({
|
|||||||
/**
|
/**
|
||||||
* The seat this plugin's configuration page renders in.
|
* The seat this plugin's configuration page renders in.
|
||||||
*
|
*
|
||||||
* Keyed `<bundle package name>#<row id>`, both as the profile's patch
|
* `plugins.bundle.config`, keyed by the BUNDLE's package name: the Plugins
|
||||||
* declares them. For this bundle the two coincide, which is a coincidence
|
* page draws that contribution as a section on the plugin's own card,
|
||||||
* and not a rule — the constants are kept separate so that stays visible.
|
* between its description and its rows. That is where someone opening
|
||||||
|
* "dsh-recall" expects its settings — the alternative seat,
|
||||||
|
* `plugins.row.config` (keyed `<package>#<row id>`), draws them on a page
|
||||||
|
* one click deeper, behind the row's title button, which is the right home
|
||||||
|
* for one row of a bundle that declares several. This bundle declares one
|
||||||
|
* row, so the card is the honest place.
|
||||||
*/
|
*/
|
||||||
const BUNDLE_PACKAGE = 'dsh-recall'
|
const BUNDLE_PACKAGE = 'dsh-recall'
|
||||||
const BUNDLE_ROW = 'dsh-recall'
|
const BUNDLE_CONFIG_KEY = BUNDLE_PACKAGE
|
||||||
const ROW_CONFIG_KEY = `${BUNDLE_PACKAGE}#${BUNDLE_ROW}`
|
|
||||||
|
|
||||||
const TITLE = 'Recall'
|
const TITLE = 'Recall'
|
||||||
const DESCRIPTION =
|
const DESCRIPTION =
|
||||||
@@ -486,10 +491,12 @@ window.__ModuleLoader__.load({
|
|||||||
/**
|
/**
|
||||||
* The plugin's configuration page.
|
* The plugin's configuration page.
|
||||||
*
|
*
|
||||||
* The Plugins page asks a configuration entry twice: once for a one-liner to
|
* The seat asks for `page`, the form with its save control; the `summary`
|
||||||
* stand in for a missing description (`summary`), and once for the body of
|
* branch answers the other shape a configuration entry can be asked for —
|
||||||
* the plugin's own page (`page`). Only the second draws a save control —
|
* the one-liner standing in for a missing description — because a component
|
||||||
* and only one save writes, because the form discards its drafts on unmount.
|
* registered under a seat that only ever asks for `page` is also the natural
|
||||||
|
* thing to reuse where that shape arrives. Only a save writes, and the form
|
||||||
|
* discards its drafts on unmount.
|
||||||
*/
|
*/
|
||||||
function RecallSettingsCard(props) {
|
function RecallSettingsCard(props) {
|
||||||
if (props.view === 'summary') return DESCRIPTION
|
if (props.view === 'summary') return DESCRIPTION
|
||||||
@@ -705,11 +712,11 @@ window.__ModuleLoader__.load({
|
|||||||
scoped.effect(
|
scoped.effect(
|
||||||
() =>
|
() =>
|
||||||
scoped.configForms.whileServed([SETTINGS_ENTRY], () =>
|
scoped.configForms.whileServed([SETTINGS_ENTRY], () =>
|
||||||
scoped.slots.inject('plugins.row.config', () =>
|
scoped.slots.inject('plugins.bundle.config', () =>
|
||||||
scoped.slots.register(
|
scoped.slots.register(
|
||||||
{
|
{
|
||||||
name: 'plugins.row.config',
|
name: 'plugins.bundle.config',
|
||||||
key: ROW_CONFIG_KEY,
|
key: BUNDLE_CONFIG_KEY,
|
||||||
inject: () => card.inject(),
|
inject: () => card.inject(),
|
||||||
},
|
},
|
||||||
RecallSettingsCard,
|
RecallSettingsCard,
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "dsh-recall",
|
"name": "dsh-recall",
|
||||||
"version": "0.1.1",
|
"version": "0.1.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Local-embedding code recall for DeepSeek Harness — returns ranked excerpts with line ranges instead of whole files, so the context window stops growing with every read.",
|
"description": "Local-embedding code recall for DeepSeek Harness — returns ranked excerpts with line ranges instead of whole files, so the context window stops growing with every read.",
|
||||||
|
|||||||
+18
-13
@@ -7,10 +7,13 @@
|
|||||||
* leaving the page to be eyeballed in a running app, because the failures this
|
* leaving the page to be eyeballed in a running app, because the failures this
|
||||||
* file exists to catch are structural and invisible until someone opens Plugins:
|
* file exists to catch are structural and invisible until someone opens Plugins:
|
||||||
*
|
*
|
||||||
* - the configuration page is registered into `plugins.row.config` under
|
* - the configuration page is registered into `plugins.bundle.config` under
|
||||||
* `<bundle package>#<row id>`. The 0.1.5 seat (`settings.plugin.item`, bound
|
* the bundle's package name, which is the seat the Plugins page draws as a
|
||||||
* through `settingsScope`) does not exist in 0.1.7, so a page left in it
|
* section on the plugin's own card. The 0.1.5 seat (`settings.plugin.item`,
|
||||||
* registers against a slot nobody declares and simply never appears.
|
* bound through `settingsScope`) does not exist in 0.1.7, so a page left in
|
||||||
|
* it registers against a slot nobody declares and simply never appears; the
|
||||||
|
* sibling seat `plugins.row.config` renders one click deeper instead, on a
|
||||||
|
* single row's page, which is not where someone opening the card looks.
|
||||||
* - the right-sidebar tab needs a TYPE registered before its body means
|
* - the right-sidebar tab needs a TYPE registered before its body means
|
||||||
* anything: the keyed body slot is dispatched under the definition's `id`.
|
* anything: the keyed body slot is dispatched under the definition's `id`.
|
||||||
* - the field list here and the `Config` schema in index.js must name the same
|
* - the field list here and the `Config` schema in index.js must name the same
|
||||||
@@ -322,7 +325,7 @@ function mount(options = {}) {
|
|||||||
* does, so the component under test sees the props a real render would give it.
|
* does, so the component under test sees the props a real render would give it.
|
||||||
*/
|
*/
|
||||||
const card = (view) => {
|
const card = (view) => {
|
||||||
const item = byName.get('plugins.row.config')
|
const item = byName.get('plugins.bundle.config')
|
||||||
assert.ok(item !== undefined, 'no settings page was registered')
|
assert.ok(item !== undefined, 'no settings page was registered')
|
||||||
const props = { ...item.meta.inject(), view }
|
const props = { ...item.meta.inject(), view }
|
||||||
delete props.hooks
|
delete props.hooks
|
||||||
@@ -364,13 +367,15 @@ test('the client module claims the slot registry in its inject list', () => {
|
|||||||
assert.deepEqual(module.inject, ['slots'])
|
assert.deepEqual(module.inject, ['slots'])
|
||||||
})
|
})
|
||||||
|
|
||||||
test('the configuration page claims the 0.1.7 seat, keyed as the patch declares it', () => {
|
test('the configuration page claims the seat the plugin card draws', () => {
|
||||||
const { registered } = mount()
|
const { registered } = mount()
|
||||||
const page = registered.find((item) => item.meta.name === 'plugins.row.config')
|
const page = registered.find((item) => item.meta.name === 'plugins.bundle.config')
|
||||||
assert.ok(page !== undefined, 'the page must register into plugins.row.config')
|
assert.ok(page !== undefined, 'the page must register into plugins.bundle.config')
|
||||||
// `<bundle package name>#<row id>`: the row id is the one this bundle's own
|
// Keyed by the BUNDLE's package name, which is what the Plugins page
|
||||||
// cordis.patch.yml declares, which is what the Plugins page dispatches by.
|
// dispatches this seat with (`entryKey: pkg.name`). The sibling seat,
|
||||||
assert.equal(page.meta.key, 'dsh-recall#dsh-recall')
|
// `plugins.row.config`, would be keyed `<package>#<row id>` and would render
|
||||||
|
// one click deeper, on the row's own page.
|
||||||
|
assert.equal(page.meta.key, 'dsh-recall')
|
||||||
assert.equal(typeof page.meta.inject, 'function')
|
assert.equal(typeof page.meta.inject, 'function')
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -385,7 +390,7 @@ test('no page is registered for a namespace the Host does not serve', () => {
|
|||||||
// onto fields nothing would accept.
|
// onto fields nothing would accept.
|
||||||
const { registered } = mount({ served: ['some-other-plugin'] })
|
const { registered } = mount({ served: ['some-other-plugin'] })
|
||||||
assert.equal(
|
assert.equal(
|
||||||
registered.some((item) => item.meta.name === 'plugins.row.config'),
|
registered.some((item) => item.meta.name === 'plugins.bundle.config'),
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -431,7 +436,7 @@ test('the browser half contributes three seats, none of them the retired 0.1.5 o
|
|||||||
const { registered } = mount()
|
const { registered } = mount()
|
||||||
assert.deepEqual(registered.map((item) => item.meta.name).sort(), [
|
assert.deepEqual(registered.map((item) => item.meta.name).sort(), [
|
||||||
'conversation.session.header.corner',
|
'conversation.session.header.corner',
|
||||||
'plugins.row.config',
|
'plugins.bundle.config',
|
||||||
'sidebar.right.pane.tab',
|
'sidebar.right.pane.tab',
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in new issue
Block a user