DSH 0.1.7-alpha.1 is 1299 commits past 0.1.6-alpha.2 and rewrites four
contracts this plugin was built on. The peer floor moves to
^0.1.7-alpha.1 (semver's prerelease rule means ^0.1.6-alpha.2 can never
match a 0.1.7 prerelease); 0.1.6-alpha.2 and earlier stay on v0.19.1.
Released as 0.21.0-alpha.1 (dist-tag alpha).
Hard breaks:
- dsh-settings was rewritten: register(ns, schema) is gone, a form is
addressed by the plugin row's Loader entry id and read from the
module's exported Config. The preferences are merged into Config and
marked volatile — which requires DSH's own schemastery, because only
that build wraps a volatile field in the cosmokit reference the
loader's volatile commit walks. With the public package a settings
write reports success and revision 1 while the effective value never
changes.
- ui-primitives renamed its whole icon family (IconXxx14/16 ->
IconXxxRegular/Medium): 26 imported symbols, 17 files. The failing
mode is render-time, not load-time. Five call sites that relied on the
old 14px default now pass size={14} explicitly.
- Session format v4 rejects source.kind === 'plugin'; the side-chat
boundary injection now writes plugin:dsh-better-sidebar, the same kind
DSH's own v3->v4 migration produces, so historical threads survive.
Tool results moved to role 'tool' with top-level content/isError; all
four parsers accept both shapes.
- The client session snapshot dropped subagentsByParent/jobsBySession
and the on-demand subagent-catalog observation API. The Tasks page
reads projectionsBySession and a new jobs.list route.
Yields and convergence:
- The read-only previews go to DSH's documentpreview (Office->PDF, a
spreadsheet worker, zoom, per-directory refresh); editor.canOpen
refuses those 26 extensions. Markdown, HTML (with its sandbox
switches) and the editable code buffer stay.
- The host browser kind is desktop-profile-only now, so the web e2e
lanes expect no browser entry and assert its absence.
- Link takeover claims only urlTarget links and passes the rest to the
host, fixing a regression from the 0.1.6 round: the fallback pointed
at a 'browser' type the plugin no longer registers, so http links in
its own markdown did nothing.
Also fixed, found along the way:
- The file tree refreshes live (new directory watch over the plugin's
own socket), since the plugin owns the `files` kind.
- ctx.sessions.list has no `current` field at either tag; the three
readers were dead. They now use ctx.sidebarRight.mounted.
- package.json.files was missing lib/client-locale.js.
- Two genuinely dead call sites: sessions.openSubagent/open/
refreshSubagents do not exist on the current baseline, so the
topology click, the jump-back and the retry were all no-ops.
- The test harness window shim lacked addEventListener, which the 0.1.7
primitives call at module-evaluation time; and the e2e token exchange
needs Playwright's request stack, not Node's fetch.
77 lines
2.6 KiB
TypeScript
77 lines
2.6 KiB
TypeScript
/**
|
|
* Browser globals for specs that pull browser-bound modules. Import this
|
|
* FIRST in a spec file: unlike statements after imports (which vitest
|
|
* hoists above the module body), an import statement evaluates in order,
|
|
* so this runs before any later import's module graph (xterm's UMD wrapper
|
|
* checks `self` and its color defaults probe `document` at evaluation time;
|
|
* window/localStorage are only touched at runtime by the store).
|
|
*/
|
|
const g = globalThis as Record<string, unknown>
|
|
|
|
if (g.self === undefined) g.self = globalThis
|
|
|
|
const elementStub = (): Record<string, unknown> => ({
|
|
style: {},
|
|
dataset: {},
|
|
textContent: '',
|
|
classList: { add: () => {}, remove: () => {}, contains: () => false },
|
|
setAttribute: () => {},
|
|
getAttribute: () => null,
|
|
hasAttribute: () => false,
|
|
appendChild: () => {},
|
|
addEventListener: () => {},
|
|
removeEventListener: () => {},
|
|
getBoundingClientRect: () => ({ left: 0, top: 0, width: 0, height: 0 }),
|
|
// xterm's color palette probe measures a canvas context at module load.
|
|
getContext: () => null,
|
|
})
|
|
|
|
if (g.document === undefined) {
|
|
g.document = {
|
|
createElement: () => elementStub(),
|
|
createDocumentFragment: () => elementStub(),
|
|
addEventListener: () => {},
|
|
removeEventListener: () => {},
|
|
defaultView: globalThis,
|
|
body: elementStub(),
|
|
// CodeMirror's view module probes the UA and injects styles at load;
|
|
// the plugin's css-inline prologue probes for existing style tags.
|
|
documentElement: elementStub(),
|
|
head: elementStub(),
|
|
querySelector: () => null,
|
|
querySelectorAll: () => [],
|
|
styleSheets: [],
|
|
}
|
|
}
|
|
|
|
if (g.navigator === undefined) {
|
|
g.navigator = { userAgent: 'node', platform: 'node', vendor: '', maxTouchPoints: 0 }
|
|
}
|
|
|
|
if (g.window === undefined) {
|
|
g.window = {
|
|
clearTimeout: () => {},
|
|
setTimeout: (_fn: () => void) => 0,
|
|
innerWidth: 1024,
|
|
innerHeight: 768,
|
|
getComputedStyle: () => ({ getPropertyValue: () => '' }),
|
|
// DSH 0.1.7's ui-primitives subscribes at MODULE EVALUATION time (a shared
|
|
// scroll/resize placement effect), so a window stub without these throws
|
|
// before any spec body runs.
|
|
addEventListener: () => {},
|
|
removeEventListener: () => {},
|
|
dispatchEvent: () => true,
|
|
matchMedia: () => ({ matches: false, addEventListener: () => {}, removeEventListener: () => {} }),
|
|
// desktop-env.ts reads the shell's URL stamps from location.search
|
|
// (Sidebar renders with parseDesktopEnv even in specs).
|
|
location: { search: '' },
|
|
}
|
|
}
|
|
|
|
if (g.localStorage === undefined) {
|
|
g.localStorage = {
|
|
getItem: () => null,
|
|
setItem: () => {},
|
|
}
|
|
}
|