/** * Tests for the browser half. * * There is no browser here, so the bundle is evaluated the way the real module * loader would — inside `window.__ModuleLoader__.load` — with a fake `require` * that supplies React and `@deepseek-ai/dsh-client-ui-primitives` and THROWS on * anything else. That last part is the useful one: it proves the bundle stays * inside the platform's seed table, which is the constraint a hand-written * client half is most likely to break. * * Two things are therefore stubbed, and it is worth being plain about what that * does and does not prove: * * * React. The card itself calls no hooks — the shared primitives do — so the * double only has to implement `createElement`, and component resolution is * the tree walk below. * * `@deepseek-ai/dsh-client-ui-primitives`. It is a real ESM package that * imports React, `clsx`, zustand and thirty stylesheets, so it cannot be * loaded under plain Node; the double reproduces the shipped * `SettingsFormModel` staging semantics (read back from the package's own * `lib/index.js`) closely enough that this card's field specs — which are * the part this repo owns — are exercised for real, and renders the shared * components as their documented props describe. * * `docs-contract` at the bottom of this file covers the other direction: that * the slot and service names this bundle binds to are the ones the installed * harness actually ships. */ import assert from 'node:assert/strict' import { existsSync, readFileSync } from 'node:fs' import { join } from 'node:path' import { test } from 'node:test' const SOURCE = readFileSync(new URL('../client/client.js', import.meta.url), 'utf8') /** Where a global dsh installation keeps its packages, if there is one. */ const DSH_PACKAGES = '/usr/local/lib/node_modules/@deepseek-ai/dsh/node_modules/@deepseek-ai' // --------------------------------------------------------------------------- // The two doubles // --------------------------------------------------------------------------- /** * The shipped `SettingsFormModel`, reduced to the reads and the one write this * card drives. Staging, the plan, the revision fence and the "a refused save * keeps its drafts" rule are the shipped behaviour, not an invention: they are * the reason the card uses this model instead of writing on every keystroke. * * A store is a plain snapshot holder here; the shipped one is a uSES-compatible * observable, which is all `store.set`/`getSnapshot` need to stand in for. */ class SettingsFormModel { constructor(scope, specs, secrets = []) { this.scope = scope this.specs = new Map(specs.map((spec) => [spec.field, spec])) this.secretSpecs = new Map(secrets.map((spec) => [spec.field, spec])) this.staged = new Map() this.listeners = new Set() this.saving = false this.failed = false this.unsubscribe = scope.subscribe(() => this.publish()) } bind(project) { const store = { snapshot: project(), getSnapshot() { return this.snapshot }, set(next) { this.snapshot = next }, subscribe() { return () => {} }, } this.listeners.add(() => store.set(project())) return store } shell() { const snapshot = this.scope.getSnapshot() const plan = this.plan() return { available: snapshot.status === 'ready', writable: snapshot.writable, dirty: plan.length > 0, invalid: plan.some((item) => item.run === undefined && item.op === undefined), saving: this.saving, failed: this.failed, } } field(field) { const staged = this.staged.get(field) if (this.secretSpecs.has(field)) { return { text: staged?.text ?? '', overridden: false, invalid: false } } const spec = this.spec(field) if (staged === undefined) { return { text: spec.format(this.sectionValue(field)), overridden: this.stored(field), invalid: false } } const write = staged.clear ? { kind: 'clear' } : spec.parse(staged.text) return { text: staged.text, overridden: write?.kind === 'set', invalid: write === undefined } } actions() { return { edit: (field, text) => this.stage(field, { text, clear: false }), resetField: (field) => this.stage(field, { text: this.spec(field).format(this.baseValue(field)), clear: true }), save: () => this.save(), discard: () => { if (this.staged.size === 0 && !this.failed) return this.staged.clear() this.baseline = undefined this.failed = false this.publish() }, } } async save() { const plan = this.plan() if (!plan.length || this.saving || !this.scope.getSnapshot().writable) return if (plan.some((item) => item.run === undefined && item.op === undefined)) return this.saving = true this.failed = false this.publish() try { const ops = plan.flatMap((item) => (item.op === undefined ? [] : [item.op])) let landed = !ops.length || (await this.scope.mutate(ops, this.baseline?.revision)) if (!landed) { this.failed = true return } for (const item of plan) if (item.run) landed = (await item.run()) && landed if (landed) { this.staged.clear() this.baseline = undefined } this.failed = !landed } catch { this.failed = true } finally { this.saving = false this.publish() } } plan() { const plan = [] for (const [field, staged] of this.staged) { const secret = this.secretSpecs.get(field) if (secret !== undefined) { const value = staged.text.trim() if (value !== '') plan.push({ field, run: () => secret.write(value) }) continue } const spec = this.spec(field) if (staged.clear) { if (this.stored(field)) plan.push({ field, op: { op: 'unset', path: [field] } }) continue } if (staged.text === spec.format(this.sectionValue(field))) continue const write = spec.parse(staged.text) if (write === undefined) plan.push({ field }) else if (write.kind === 'clear') plan.push({ field, op: { op: 'unset', path: [field] } }) else plan.push({ field, op: { op: 'set', path: [field], value: write.value } }) } return plan } stage(field, edit) { this.baseline ??= this.scope.getSnapshot() this.staged.set(field, edit) this.failed = false this.publish() } publish() { for (const listener of this.listeners) listener() } dispose() { this.unsubscribe() this.listeners.clear() } spec(field) { const spec = this.specs.get(field) if (spec === undefined) throw new Error(`no spec for "${field}"`) return spec } sectionValue(field) { return this.scope.getSnapshot().value?.[field] } baseValue(field) { return this.scope.getSnapshot().base?.[field] } userLayer() { const user = this.scope.getSnapshot().user return user !== null && typeof user === 'object' ? user : {} } stored(field) { return Object.hasOwn(this.userLayer(), field) } } /** The shipped number and text specs, verbatim. */ const numberField = (field) => ({ field, format: (value) => (typeof value === 'number' ? String(value) : ''), parse: (text) => { const trimmed = text.trim() if (trimmed === '') return { kind: 'clear' } const parsed = Number(trimmed) return Number.isFinite(parsed) ? { kind: 'set', value: parsed } : undefined }, }) const textField = (field) => ({ field, format: (value) => (typeof value === 'string' ? value : ''), parse: (text) => { const trimmed = text.trim() return trimmed === '' ? { kind: 'clear' } : { kind: 'set', value: trimmed } }, }) /** * The shared components, rendered as the props they document. * * Every one of them is a plain function, so expanding the tree never needs a * hook runtime: the card's own composition is what is under test. */ function primitivesDouble() { const h = (type, props, ...children) => ({ type, props: props ?? {}, children }) const SettingsForm = (props) => h( 'form', { 'data-labels': JSON.stringify(props.labels), // The real form disables Save until something is staged, nothing is // invalid, no write is in flight, and the document accepts writes. 'data-can-save': String(props.state.dirty && !props.state.invalid && !props.state.saving && props.state.writable), onSave: props.onSave, onDiscard: props.onDiscard, }, h('button', { type: 'button', disabled: !(props.state.dirty && !props.state.invalid && props.state.writable), onClick: props.onSave }, props.labels.save), props.children, ) const SettingsValueField = (props) => h( 'div', { 'data-field': props.id }, h('label', { htmlFor: props.id }, props.label), h('input', { id: props.id, type: 'text', value: props.text, disabled: props.disabled, 'aria-label': props.label, 'data-invalid': String(props.invalid), 'data-overridden': String(props.overridden), onChange: (event) => props.onEdit(event.target.value), }), props.overridden ? h('button', { type: 'button', disabled: props.disabled, onClick: props.onReset }, props.resetLabel) : null, h('div', { 'data-hint': true }, props.invalid ? props.invalidLabel : props.hint), ) const SettingsSecretField = (props) => h( 'div', { 'data-field': props.id }, h('label', { htmlFor: props.id }, props.label), h('input', { id: props.id, type: 'password', value: props.text, disabled: props.disabled, 'aria-label': props.label, autoComplete: 'off', onChange: (event) => props.onEdit(event.target.value), }), h('div', { 'data-state': true }, props.stateLabel), h('div', { 'data-configured': String(props.configured) }), ) // The real primitive is a labelled checkbox: the label WRAPS the control. const Checkbox = (props) => h( 'label', {}, h('input', { type: 'checkbox', checked: Boolean(props.checked), disabled: props.disabled, 'aria-label': props.label, onChange: (event) => props.onChange(event.target.checked), }), props.label, ) return { SettingsForm, SettingsFormModel, SettingsSecretField, SettingsValueField, Checkbox, settingsNumberField: numberField, settingsTextField: textField } } /** * Minimal React: `createElement` is the only hook-free seam the card needs. * * Children land in `props.children` as well as on the wrapper, because that is * where a real element carries them and what the shared components read. */ const fakeReact = { createElement: (type, props, ...children) => { const merged = { ...(props ?? {}) } if (children.length > 0) merged.children = children.length === 1 ? children[0] : children return { type, props: merged, children } }, } // --------------------------------------------------------------------------- // Harness // --------------------------------------------------------------------------- /** Evaluate the bundle against a fake loader and return its exports. */ function loadBundle(requireImpl) { let loaded const window = { __ModuleLoader__: { load: (spec) => { loaded = spec } } } new Function('window', SOURCE)(window) assert.ok(loaded !== undefined, 'the bundle must call window.__ModuleLoader__.load') const primitives = primitivesDouble() const exported = loaded.factory( requireImpl ?? ((name) => { if (name === 'react') return fakeReact if (name === 'react/jsx-runtime') return { jsx: fakeReact.createElement, jsxs: fakeReact.createElement, Fragment: 'Fragment' } if (name === '@deepseek-ai/dsh-client-ui-primitives') return primitives throw new Error(`the client bundle required "${name}", which is not in the platform seed table`) }), ) return { id: loaded.id, exported, primitives } } const READY = { status: 'ready', value: { embeddingModel: 'ollama/example:latest', embeddingDimensions: 768, embeddingApiBase: 'http://127.0.0.1:11434', embeddingParamsJson: '{}', binary: '', autoInstall: true, sourceDir: '', sourceDirExclude: ['**/dist/**'], useDefaultExcludes: true, maxIndexUnits: 5000, ignoreFile: '', stateDir: '', embeddingRequestDelay: 0, timeoutMs: 600_000, }, base: {}, user: {}, revision: 7, writable: true, mode: 'host', } /** A settings scope stand-in recording the mutations it was asked to make. */ function fakeScope(snapshot = READY, { landed = true } = {}) { const calls = { mutate: [], subscriptions: 0 } return { calls, getSnapshot: () => snapshot, subscribe(listener) { calls.subscriptions += 1 return () => {} }, async mutate(ops, revision) { calls.mutate.push({ ops, revision }) return landed }, } } /** * Register the card the way the host would, and hand back everything a test * needs to drive it: the registration options, the injected face, and a render * function. */ function registered({ snapshot = READY, served = true, secrets = [], landed = true } = {}) { const { id, exported, primitives } = loadBundle() const scope = fakeScope(snapshot, { landed }) const effects = [] const injects = [] const whileServed = [] const dictionaries = new Map() let registration let component const configForms = { get: (ns) => { assert.equal(ns, 'dsh-slopo') return scope }, whileServed: (namespaces, register) => { whileServed.push(namespaces) const off = served ? register(new Set(namespaces)) : undefined return () => off?.() }, describe: () => ({ getSnapshot: () => ({ view: { namespaces: [{ ns: 'dsh-slopo', secrets }] } }), }), } /** A `ctx.inject` child: an effect scope plus the slots registry. */ const childEffect = (effect, _label) => { effects.push(effect()) } const ctx = { effect: childEffect, locale: { register(ns, dicts) { dictionaries.set(ns, dicts.en) return () => {} }, bind: (ns) => { const dict = dictionaries.get(ns) ?? {} return (key) => dict[key] ?? key }, }, inject(deps, callback) { injects.push(deps) callback({ configForms, effect: childEffect, slots: { inject(_name, produce) { produce() return () => {} }, register(options, render) { registration = options component = render }, }, }) }, } exported.apply(ctx) const t = ctx.locale.bind('dsh-slopo') const injectFace = () => ({ t: (key) => t(key), ...registration.inject() }) const render = (extra = {}) => { const face = { ...injectFace(), ...extra } const state = face.hooks.slopoCard.getSnapshot() return component({ ...face, view: 'page', useSlopoCard: (select) => select(state) }) } return { id, exported, primitives, scope, effects, injects, whileServed, registration: () => registration, render, t } } // --------------------------------------------------------------------------- // Tree helpers // --------------------------------------------------------------------------- /** Resolve function components by calling them, until a host element or null. */ function expand(node, depth = 0) { if (depth > 60) throw new Error('the component tree did not settle') if (node === null || node === undefined) return null if (typeof node !== 'object') return node if (Array.isArray(node)) return node if (typeof node.type === 'function') return expand(node.type(node.props), depth + 1) return node } /** Depth-first walk over a rendered tree, expanding components as it goes. */ function findAll(node, predicate, out = []) { if (node === null || node === undefined) return out if (Array.isArray(node)) { for (const child of node) findAll(child, predicate, out) return out } if (typeof node !== 'object') return out if (typeof node.type === 'function') { findAll(expand(node), predicate, out) return out } if (predicate(node)) out.push(node) for (const child of node.children ?? []) findAll(child, predicate, out) return out } const inputFor = (tree, label) => findAll(tree, (node) => node.type === 'input' && node.props['aria-label'] === label)[0] const saveButton = (tree) => findAll(tree, (node) => node.type === 'button' && node.children.includes('Save'))[0] // --------------------------------------------------------------------------- // Bundle identity and the seed table // --------------------------------------------------------------------------- test('the bundle id matches the package name the loader is told about', () => { const { id } = loadBundle() assert.equal(id, 'dsh-slopo') }) test('the client bundle requires nothing outside the platform seed table', () => { // loadBundle() throws on any specifier other than the two seed words. assert.doesNotThrow(() => loadBundle()) }) test('the bundle exports the package name and the services it needs', () => { const { exported } = loadBundle() assert.equal(exported.name, 'dsh-slopo') // `locale` is required because the card's copy rides a dictionary; `slots` // because the registration is a slot. assert.deepEqual(exported.inject, ['slots', 'locale']) }) // --------------------------------------------------------------------------- // The registration contract — the part that regressed // --------------------------------------------------------------------------- test('the card registers into plugins.bundle.config, keyed by the bundle package name', () => { const { registration, exported } = registered() assert.equal(exported.name, 'dsh-slopo') assert.equal(registration().name, 'plugins.bundle.config') // The key must equal the bundle's package name: the Plugins page dispatches // this slot by `pkg.name`, and nothing else. assert.equal(registration().key, 'dsh-slopo') // `locale` is what injects the card's `t`. assert.equal(registration().locale, 'dsh-slopo') }) test('the card no longer binds the pre-0.1.7 settings surface', () => { // `settings.plugin.item` and the `settingsScope` service were removed from the // harness; a bundle that still names them renders nothing at all, and does it // silently. The header comment names them on purpose, so the scan is over the // code: strip comments first, then look. const code = SOURCE.replace(/\/\*[\s\S]*?\*\//g, '').replace(/^\s*\/\/.*$/gm, '') assert.doesNotMatch(code, /settingsScope/) assert.doesNotMatch(code, /settings\.plugin\.item/) assert.doesNotMatch(code, /installSection/) }) test('the card asks for configForms, and does it optionally', () => { const { injects } = registered() assert.deepEqual(injects, [['configForms']]) }) test('the registration stands only while the Host serves the namespace', () => { const served = registered({ served: true }) assert.deepEqual(served.whileServed, [['dsh-slopo']]) assert.ok(served.registration() !== undefined) // A deployment that does not serve the entry leaves no card behind. const unserved = registered({ served: false }) assert.equal(unserved.registration(), undefined) }) test('the injected face carries the card store and the form actions', () => { const { registration } = registered() const face = registration().inject() assert.ok(face.hooks.slopoCard !== undefined, 'the card reads its state through a hook') for (const action of ['edit', 'resetField', 'save', 'discard']) { assert.equal(typeof face[action], 'function', `missing form action "${action}"`) } }) test('teardown releases the form subscription', () => { const { scope, effects } = registered() assert.equal(scope.calls.subscriptions, 1) // The second effect is the whileServed one; the first disposes the form. assert.equal(typeof effects[0], 'function') effects[0]() // Disposing twice is not the card's business, but the disposer must exist and // must not throw before the form's own disposer has a chance to run. assert.doesNotThrow(() => effects[1]()) }) // --------------------------------------------------------------------------- // The card's controls // --------------------------------------------------------------------------- test('the card renders every setting the Host schema declares', () => { const { render } = registered() const tree = render() const labels = findAll(tree, (node) => node.type === 'label').map((node) => node.children.join('')) for (const expected of [ 'Embedding model', 'Embedding dimensions', 'Embedding API base', 'Embedding API key', 'Extra embedding parameters', 'slopo executable', 'Install slopo with uv when missing', 'Source directory', 'Extra exclude patterns', 'Exclude node_modules and build output', 'Refuse to embed more than this many units', 'Ignore file', 'State directory', 'Delay between embedding requests', 'Foreground timeout', ]) { assert.ok(labels.some((label) => label.includes(expected)), `no control labelled "${expected}"`) } }) test('the API key is a write-only password control that reports only whether one is stored', () => { const { render } = registered({ secrets: [{ path: ['embeddingApiKey'], set: true }] }) const tree = render() const input = inputFor(tree, 'Embedding API key') assert.equal(input.props.type, 'password') assert.equal(input.props.value, '', 'a secret never rides back into the control') assert.match(findAll(tree, (node) => node.props['data-state'] === true).map((node) => node.children.join('')).join(''), /A key is stored/) }) test('a deployment with no key says so', () => { const { render } = registered({ secrets: [{ path: ['embeddingApiKey'], set: false }] }) const tree = render() assert.equal(findAll(tree, (node) => node.props['data-configured'] === 'true').length, 0) assert.match(findAll(tree, (node) => node.props['data-state'] === true).map((node) => node.children.join('')).join(''), /No key is stored/) }) test('the current value of every ordinary field is rendered', () => { const { render } = registered() const tree = render() assert.equal(inputFor(tree, 'Embedding model').props.value, 'ollama/example:latest') assert.equal(inputFor(tree, 'Embedding dimensions').props.value, '768') assert.equal(inputFor(tree, 'Extra exclude patterns').props.value, '**/dist/**') assert.equal(inputFor(tree, 'Install slopo with uv when missing').props.checked, true) }) test('a read-only deployment disables every control', () => { const { render } = registered({ snapshot: { ...READY, writable: false, mode: 'memory' } }) const tree = render() const controls = findAll(tree, (node) => node.type === 'input') assert.ok(controls.length >= 15) for (const control of controls) assert.equal(control.props.disabled, true, control.props['aria-label']) assert.equal(saveButton(tree).props.disabled, true) }) test('the card hands an unavailable namespace to the shared form instead of hiding', () => { // The form is what swaps in the "not served" line, from `state.available`. // Hiding here would leave the Plugins page with a configured-but-empty card. const { render } = registered({ snapshot: { ...READY, status: 'unavailable' } }) const form = expand(render()) assert.equal(JSON.parse(form.props['data-labels']).unavailable.startsWith('This plugin is not loaded'), true) }) // --------------------------------------------------------------------------- // Saving: the field specs this repo owns // --------------------------------------------------------------------------- /** Stage one edit, then click Save the way the form does. */ async function stageAndSave(render, label, next) { const input = inputFor(render(), label) input.props.onChange({ target: { value: next } }) const form = render() const save = saveButton(form) assert.equal(save.props.disabled, false, 'a staged edit must enable Save') await save.props.onClick() } test('Save sends one fenced mutation, at the revision the drafts were read from', async () => { const { render, scope } = registered() await stageAndSave(render, 'Embedding model', 'ollama/other:latest') assert.equal(scope.calls.mutate.length, 1) assert.deepEqual(scope.calls.mutate[0].ops, [ { op: 'set', path: ['embeddingModel'], value: 'ollama/other:latest' }, ]) assert.equal(scope.calls.mutate[0].revision, 7) }) test('a whole number field is sent as a number, not the string the input holds', async () => { const { render, scope } = registered() await stageAndSave(render, 'Embedding dimensions', '1024') assert.deepEqual(scope.calls.mutate[0].ops, [{ op: 'set', path: ['embeddingDimensions'], value: 1024 }]) }) test('a number that is not a number blocks the save instead of being dropped', async () => { const { render, scope } = registered() const tree = render() inputFor(tree, 'Embedding dimensions').props.onChange({ target: { value: 'not-a-number' } }) const form = render() assert.equal(saveButton(form).props.disabled, true, 'an invalid draft must disable Save') await saveButton(form).props.onClick() assert.deepEqual(scope.calls.mutate, []) // …and the field says why. assert.equal(inputFor(form, 'Embedding dimensions').props['data-invalid'], 'true') }) test('an exclude list round-trips through comma-separated text', async () => { const { render, scope } = registered() await stageAndSave(render, 'Extra exclude patterns', '**/test/**, *.min.js') assert.deepEqual(scope.calls.mutate[0].ops, [ { op: 'set', path: ['sourceDirExclude'], value: ['**/test/**', '*.min.js'] }, ]) }) test('a switch writes a real boolean', async () => { const { render, scope } = registered() const tree = render() inputFor(tree, 'Install slopo with uv when missing').props.onChange({ target: { checked: false } }) await saveButton(render()).props.onClick() assert.deepEqual(scope.calls.mutate[0].ops, [{ op: 'set', path: ['autoInstall'], value: false }]) }) test('clearing a field is an unset, so it re-inherits rather than becoming empty', async () => { const { render, scope } = registered({ snapshot: { ...READY, user: { embeddingModel: 'ollama/example:latest' } }, }) await stageAndSave(render, 'Embedding model', '') assert.deepEqual(scope.calls.mutate[0].ops, [{ op: 'unset', path: ['embeddingModel'] }]) }) test('an overridden field is marked and offers its own reset', async () => { const { render, scope } = registered({ snapshot: { ...READY, base: { embeddingDimensions: 0 }, user: { embeddingDimensions: 768 }, }, }) const tree = render() const field = inputFor(tree, 'Embedding dimensions') assert.equal(field.props['data-overridden'], 'true') const reset = findAll(tree, (node) => node.type === 'button' && node.children.includes('Reset to default'))[0] assert.ok(reset !== undefined, 'an overridden field must offer a reset') reset.props.onClick() await saveButton(render()).props.onClick() assert.deepEqual(scope.calls.mutate[0].ops, [{ op: 'unset', path: ['embeddingDimensions'] }]) }) test('a secret draft is written one way, and a blank one writes nothing', async () => { const { render, scope } = registered() inputFor(render(), 'Embedding API key').props.onChange({ target: { value: 'sk-secret' } }) await saveButton(render()).props.onClick() assert.deepEqual(scope.calls.mutate[0].ops, [{ op: 'set', path: ['embeddingApiKey'], value: 'sk-secret' }]) const blank = registered() inputFor(blank.render(), 'Embedding API key').props.onChange({ target: { value: ' ' } }) await saveButton(blank.render()).props.onClick() assert.deepEqual(blank.scope.calls.mutate, [], 'a blank secret draft must not clear the stored key') }) test('a refused save keeps its drafts so they can be corrected', async () => { const { render, scope } = registered({ landed: false }) const tree = render() inputFor(tree, 'Embedding model').props.onChange({ target: { value: 'ollama/try-again:latest' } }) await saveButton(render()).props.onClick() assert.equal(scope.calls.mutate.length, 1) // Still dirty: nothing was accepted, so nothing is thrown away. assert.equal(saveButton(render()).props.disabled, false) assert.equal(inputFor(render(), 'Embedding model').props.value, 'ollama/try-again:latest') }) // --------------------------------------------------------------------------- // Contract against the installed harness // --------------------------------------------------------------------------- const harnessPresent = existsSync(DSH_PACKAGES) test( 'the slot this card binds to is declared by the installed harness', { skip: harnessPresent ? false : 'no global dsh installation to read the slot catalog from' }, () => { const catalog = readFileSync(join(DSH_PACKAGES, 'dsh-cordis-client-runner/lib/client.js'), 'utf8') assert.match(catalog, /key: "plugins\.bundle\.config"/, 'plugins.bundle.config must exist in the slot catalog') assert.doesNotMatch(catalog, /key: "settings\.plugin\.item"/, 'settings.plugin.item must be gone') }, ) test( 'every primitive the card requires is exported by the installed package', { skip: harnessPresent ? false : 'no global dsh installation to read the primitives package from' }, () => { const bundle = readFileSync(join(DSH_PACKAGES, 'dsh-client-ui-primitives/lib/index.js'), 'utf8') const exported = new Set( (bundle.match(/export \{([^}]*)\};/g) ?? []) .flatMap((line) => line.slice(8, -2).split(',')) .map((name) => name.trim().split(/\s+as\s+/).pop()), ) for (const name of [ 'Checkbox', 'SettingsForm', 'SettingsFormModel', 'SettingsSecretField', 'SettingsValueField', 'settingsNumberField', 'settingsTextField', ]) { assert.ok(exported.has(name), `@deepseek-ai/dsh-client-ui-primitives does not export "${name}"`) } // The card reads the entry's secret slots off the shared describe mirror. const settings = readFileSync(join(DSH_PACKAGES, 'dsh-client-ui-settings/lib/client.js'), 'utf8') assert.match(settings, /super\(ctx, "configForms"\)/, 'configForms must be the settings domain service') }, ) test( 'the installed plugin-manager declares plugins.bundle.config as a keyed child of the Plugins page', { skip: harnessPresent ? false : 'no global dsh installation to read the plugin manager from' }, () => { const manager = readFileSync(join(DSH_PACKAGES, 'dsh-client-ui-plugin-manager/lib/client.js'), 'utf8') assert.match(manager, /"plugins\.bundle\.config": \{\s*kind: "keyed"/) // …and dispatches it by the bundle's package name. assert.match(manager, /renderSlot\("plugins\.bundle\.config", \{ view: "page" \}, \{ entryKey: pkg\.name \}\)/) }, )