Files
deepseek-harness/examples/desktop/test/fork-compare.test.js
T
ZiyaZhang e8f5c0b51b feat(desktop): DSH Electron desktop shell — harness internals visualized
Minimal Electron shell over the DSH JSON-RPC runtime — a first-look at
what a ChatGPT.app-style host on top of the DeepSeek Harness looks
like, with the harness's normally-invisible internals (trace timeline,
context surface, subagent tree, compaction, plugin registry, rubrics)
brought forward as first-class UI surfaces so plugin authors and
researchers can see what the agent is actually doing.

Runs against three keyless-to-live profiles (stdio-echo works on
master out of the box; daemon-echo / daemon-vibe-echo activate once
the daemon-demo lands; stdio-deepseek and daemon-vibe hit the real
DeepSeek API when you supply a key). HARNESS_DEV auto-resolves to the
in-repo runtime when this shell ships under examples/desktop/, so a
fresh clone launches without config; env DSH_DEV_ROOT overrides for
custom layouts, and a sibling deepseek-harness-dev/ checkout is the
original dev workflow.

Cold-clone gate (P0 fixes for first-time-clone usability):
- HARNESS_DEV: 3-candidate resolver (env → walk-up in-repo marker →
  sibling), unit-tested via mock fs so ordering is locked without
  needing either real layout on disk.
- config yml leaves rewritten at assemble time so the sibling-clone
  paths (../../deepseek-harness-dev/examples/echo-agent/…) become
  the in-repo paths (../../echo-agent/…) in the released tree —
  source yml stays usable for local dev, released tree ships a
  working shape.
- pnpm-workspace.yaml allowBuilds.electron = true (was placeholder).
- missing-key card in stdio-deepseek offers a one-click switch to
  stdio-echo (the keyless profile that works on master) rather than
  daemon-echo (blocked on the not-yet-shipped daemon-demo).
- assemble-oss-release.sh rewrites the source-side breadcrumb name
  'dsh-desktop-demo' → 'dsh-desktop' for the released package.json.

FOUC guard on the onboarding gate (41fc5df carried) keeps the
first-launch splash from flashing before the runtime probe finishes.

Test suite (1634 tests in source, 3990 in the runtime repo) covers
resolver ordering, renderer classifiers, trace timeline shape,
compaction diff rendering, rubric parity, and the missing-key
onboarding paths.
2026-07-18 12:59:34 -07:00

446 lines
16 KiB
JavaScript

// Task #168 / step 4 — fork-compare tests.
//
// Covers:
// pure helpers — buildBadgeText, normaliseEventsResponse, summariseEvent,
// extractText, short
// DOM builder — openForkCompare creates the drawer on first call, paints
// both columns from a mock sessionEvents bridge, clipping the parent
// stream to seq<=boundary and the child stream to seq>boundary; Refresh
// re-hydrates; Close hides.
'use strict'
const test = require('node:test')
const assert = require('node:assert/strict')
// Install a minimal global DOM before requiring the module so the CommonJS
// export path is what runs (window is undefined in Node, so the module
// registers only as module.exports; we then install `window`/`document`
// after require for the DOM builder tests).
const FC = require('../src/renderer/fork-compare.js')
// ---- pure helpers --------------------------------------------------------
test('short trims long ids and passes short ones through', () => {
assert.equal(FC.short('abcdef1234567890'), 'abcdef12…')
assert.equal(FC.short('short'), 'short')
assert.equal(FC.short(null), '')
})
test('buildBadgeText names parent/child + optional seq + source label', () => {
const s = FC.buildBadgeText({
parentId: 'parent-1234567890',
childId: 'child-abcdef',
seq: 42,
source: 'config',
})
assert.match(s, /Fork of parent-1/)
assert.match(s, /child-ab/)
assert.match(s, /@ seq 42/)
assert.match(s, /source: edited config/)
})
test('buildBadgeText omits seq + source when absent', () => {
const s = FC.buildBadgeText({ parentId: 'p1', childId: 'c1' })
assert.doesNotMatch(s, /@ seq/)
assert.doesNotMatch(s, /source:/)
})
test('normaliseEventsResponse accepts [], {events:[]}, {items:[]}', () => {
assert.deepEqual(FC.normaliseEventsResponse([{ seq: 1 }]), [{ seq: 1 }])
assert.deepEqual(FC.normaliseEventsResponse({ events: [{ seq: 2 }] }), [{ seq: 2 }])
assert.deepEqual(FC.normaliseEventsResponse({ items: [{ seq: 3 }] }), [{ seq: 3 }])
assert.deepEqual(FC.normaliseEventsResponse(null), [])
})
test('summariseEvent produces a compact one-liner per kind', () => {
assert.equal(FC.summariseEvent({ type: 'message/user', text: 'hi' }), 'hi')
assert.equal(
FC.summariseEvent({ type: 'tool/call', data: { name: 'bash' } }),
'bash(…)',
)
assert.equal(
FC.summariseEvent({ type: 'tool/result', data: { isError: true } }),
'(error)',
)
assert.equal(
FC.summariseEvent({ type: 'request/header', data: { header: { config: { model: 'X' } } } }),
'model=X',
)
})
test('extractText handles scalar text, content-blocks, and data.content', () => {
assert.equal(FC.extractText({ text: 'plain' }), 'plain')
assert.equal(
FC.extractText({ content: [{ type: 'text', text: 'a' }, { type: 'other' }, { type: 'text', text: 'b' }] }),
'ab',
)
assert.equal(
FC.extractText({ data: { content: [{ type: 'text', text: 'c' }] } }),
'c',
)
})
// ---- DOM builder ---------------------------------------------------------
//
// We install a minimal document into globalThis so openForkCompare has
// somewhere to build the drawer. Everything Node lacks (getElementById on
// the whole document, appendChild on body) is faked.
function installFakeDom() {
const doc = makeMinimalDoc()
globalThis.document = doc
globalThis.window = { document: doc, dsh: null, __dshCompareHistory: null }
FC.__resetForTests()
// Bug D layer 4 (2026-07-18): openForkCompare requires a recent trusted
// user gesture + boot to be past BOOT_QUIET_MS. Neither hold in a node
// test process, so we cheat both explicitly.
FC.__setBootAtForTests(Date.now() - 60_000) // pretend renderer booted 1 min ago
FC.__markGestureForTests(Date.now())
return doc
}
function tearDownFakeDom() {
delete globalThis.document
delete globalThis.window
FC.__resetForTests()
}
function makeMinimalDoc() {
const store = new Map()
function makeEl(tag) {
const el = {
tagName: (tag || 'div').toUpperCase(),
children: [],
_classSet: new Set(),
dataset: {},
_listeners: {},
_attrs: {},
_text: '',
_id: '',
_innerHTML: '',
hidden: false,
title: '',
}
Object.defineProperty(el, 'className', {
get() { return Array.from(this._classSet).join(' ') },
set(v) { this._classSet = new Set(String(v || '').split(/\s+/).filter(Boolean)) },
})
Object.defineProperty(el, 'textContent', {
get() {
if (this._text) return this._text
let s = ''
for (const c of this.children) s += (c.textContent || '')
return s
},
set(v) { this._text = String(v == null ? '' : v); this.children = [] },
})
Object.defineProperty(el, 'innerHTML', {
get() { return this._innerHTML },
set(v) {
this._innerHTML = String(v == null ? '' : v)
// Simulate "innerHTML = '' clears children" — the only usage in the
// module under test.
if (v === '' || v == null) this.children = []
},
})
Object.defineProperty(el, 'id', {
get() { return this._id },
set(v) {
if (this._id && store.get(this._id) === this) store.delete(this._id)
this._id = String(v == null ? '' : v)
if (this._id) store.set(this._id, this)
},
})
Object.defineProperty(el, 'isConnected', {
get() {
let n = this
while (n) {
if (n === doc.body) return true
n = n.parentNode
}
return false
},
})
el.classList = {
add: (c) => el._classSet.add(c),
remove: (c) => el._classSet.delete(c),
contains: (c) => el._classSet.has(c),
}
el.setAttribute = (k, v) => { el._attrs[k] = String(v) }
el.getAttribute = (k) => (k in el._attrs ? el._attrs[k] : null)
el.appendChild = (child) => {
if (child.parentNode) {
const idx = child.parentNode.children.indexOf(child)
if (idx >= 0) child.parentNode.children.splice(idx, 1)
}
el.children.push(child); child.parentNode = el; return child
}
el.addEventListener = (evt, fn) => { (el._listeners[evt] = el._listeners[evt] || []).push(fn) }
el.click = () => { for (const fn of (el._listeners.click || [])) fn({ stopPropagation() {} }) }
el.focus = () => {}
el.ownerDocument = doc
return el
}
const doc = {
createElement: (t) => makeEl(t),
getElementById: (id) => store.get(id) || null,
}
doc.body = makeEl('body')
return doc
}
test('openForkCompare builds the drawer once, paints both columns clipped by seq', async () => {
installFakeDom()
try {
const events = [
{ seq: 0, type: 'message/user', text: 'hello' },
{ seq: 1, type: 'request/header', data: { header: { config: { model: 'X' } } } },
{ seq: 2, type: 'tool/call', data: { name: 'bash' } },
{ seq: 3, type: 'message/assistant', text: 'done' },
]
const forkExtras = [
{ seq: 3, type: 'message/assistant', text: 'done' }, // parent's own last event (inherited)
{ seq: 4, type: 'message/user', text: 'edit re-run intent' },
{ seq: 5, type: 'message/assistant', text: 'ok!' },
]
const seen = []
globalThis.window.dsh = {
sessionEvents: async (sid) => {
seen.push(sid)
if (sid === 'parent') return { events }
if (sid === 'child') return { events: forkExtras }
return { events: [] }
},
}
FC.openForkCompare({ parentId: 'parent', childId: 'child', seq: 3, source: 'tool' })
// Two async fetches — flush.
await new Promise((r) => setTimeout(r, 15))
const doc = globalThis.document
const badge = doc.getElementById('fork-compare-badge')
assert.ok(badge, 'badge element exists')
assert.match(badge.textContent, /@ seq 3/)
assert.match(badge.textContent, /edited tool args/)
const leftStream = doc.getElementById('fork-compare-left-stream')
const rightStream = doc.getElementById('fork-compare-right-stream')
// Left column: 4 event rows (seq 0..3)
const leftRows = leftStream.children.filter((c) => c._classSet.has('fork-compare-row'))
assert.equal(leftRows.length, 4)
// Right column: 2 events (seq 4 + 5 — seq 3 is inherited from parent)
const rightRows = rightStream.children.filter((c) => c._classSet.has('fork-compare-row'))
assert.equal(rightRows.length, 2)
// Both session ids were fetched.
assert.ok(seen.includes('parent'))
assert.ok(seen.includes('child'))
// Drawer is visible.
assert.equal(doc.getElementById('fork-compare-drawer').hidden, false)
} finally {
tearDownFakeDom()
}
})
test('openForkCompare surfaces fetch errors inline (no throw)', async () => {
installFakeDom()
try {
globalThis.window.dsh = {
sessionEvents: async () => { throw new Error('boom') },
}
FC.openForkCompare({ parentId: 'p', childId: 'c', seq: 5 })
await new Promise((r) => setTimeout(r, 10))
const doc = globalThis.document
const leftStream = doc.getElementById('fork-compare-left-stream')
const rightStream = doc.getElementById('fork-compare-right-stream')
assert.match(leftStream.textContent, /could not load parent history/i)
assert.match(rightStream.textContent, /could not load fork history/i)
} finally {
tearDownFakeDom()
}
})
test('closeForkCompare hides the drawer', async () => {
installFakeDom()
try {
globalThis.window.dsh = { sessionEvents: async () => ({ events: [] }) }
FC.openForkCompare({ parentId: 'p', childId: 'c' })
await new Promise((r) => setTimeout(r, 10))
const doc = globalThis.document
assert.equal(doc.getElementById('fork-compare-drawer').hidden, false)
FC.closeForkCompare()
assert.equal(doc.getElementById('fork-compare-drawer').hidden, true)
} finally {
tearDownFakeDom()
}
})
test('empty fork stream surfaces the "waiting for next turn" meta line', async () => {
installFakeDom()
try {
globalThis.window.dsh = {
sessionEvents: async (sid) => (sid === 'p'
? { events: [{ seq: 0, type: 'message/user', text: 'hi' }] }
: { events: [{ seq: 0, type: 'message/user', text: 'hi' }] }),
}
FC.openForkCompare({ parentId: 'p', childId: 'c', seq: 0 })
await new Promise((r) => setTimeout(r, 10))
const doc = globalThis.document
const rightStream = doc.getElementById('fork-compare-right-stream')
assert.match(rightStream.textContent, /waiting for the next turn/i)
} finally {
tearDownFakeDom()
}
})
// ---- Bug D regressions (2026-07-18) -------------------------------------
test('Bug D: openForkCompare refuses to open while renderer is replaying', async () => {
installFakeDom()
try {
globalThis.window.__dshRenderer = { state: { replayingId: 'some-old-session' } }
globalThis.window.dsh = { sessionEvents: async () => ({ events: [] }) }
FC.openForkCompare({ parentId: 'p', childId: 'c', seq: 3 })
await new Promise((r) => setTimeout(r, 5))
const doc = globalThis.document
// The drawer was never even built — nothing landed in the DOM.
assert.equal(doc.getElementById('fork-compare-drawer'), null,
'replay path must not build a fork-compare drawer')
} finally {
tearDownFakeDom()
}
})
test('Bug D: openForkCompare opens normally when replayingId is null', async () => {
installFakeDom()
try {
globalThis.window.__dshRenderer = { state: { replayingId: null } }
globalThis.window.dsh = { sessionEvents: async () => ({ events: [] }) }
FC.openForkCompare({ parentId: 'p', childId: 'c', seq: 3 })
await new Promise((r) => setTimeout(r, 10))
const doc = globalThis.document
assert.ok(doc.getElementById('fork-compare-drawer'),
'a normal open (no replay) must build the drawer')
assert.equal(doc.getElementById('fork-compare-drawer').hidden, false)
} finally {
tearDownFakeDom()
}
})
test('Bug D: click on drawer root (backdrop gutter) closes the drawer', async () => {
installFakeDom()
try {
globalThis.window.dsh = { sessionEvents: async () => ({ events: [] }) }
FC.openForkCompare({ parentId: 'p', childId: 'c' })
await new Promise((r) => setTimeout(r, 10))
const doc = globalThis.document
const root = doc.getElementById('fork-compare-drawer')
assert.equal(root.hidden, false)
// Simulate a click whose target IS the root (i.e., the 40px gutter).
// Our doc.click() bubbles a target the module reads as e.target.
// The listener we registered checks e.target === root.
for (const fn of (root._listeners.click || [])) fn({ target: root })
assert.equal(root.hidden, true,
'clicking the drawer root gutter must close the drawer')
} finally {
tearDownFakeDom()
}
})
test('Bug D: Escape key closes the drawer when it is open', async () => {
installFakeDom()
try {
// Escape needs a doc-level keydown listener; extend the fake doc.
// openForkCompare installs TWO keydown listeners: the gesture watcher
// (a bump function, non-closing) and the Escape closer. Grab them all
// and fire Escape past every registered listener so we don't guess
// which slot ensureEscListener occupies.
const listeners = []
globalThis.document.addEventListener = (evt, fn) => {
listeners.push({ evt, fn })
}
globalThis.window.dsh = { sessionEvents: async () => ({ events: [] }) }
FC.openForkCompare({ parentId: 'p', childId: 'c' })
await new Promise((r) => setTimeout(r, 10))
const doc = globalThis.document
assert.equal(doc.getElementById('fork-compare-drawer').hidden, false)
const keyListeners = listeners.filter((l) => l.evt === 'keydown')
assert.ok(keyListeners.length >= 1,
'openForkCompare must install at least one keydown listener')
// Fire Escape past every keydown listener; the Escape closer will react,
// the gesture bumper will ignore the untrusted synthetic event.
for (const l of keyListeners) l.fn({ key: 'Escape', stopPropagation() {} })
assert.equal(doc.getElementById('fork-compare-drawer').hidden, true,
'Escape must close the drawer')
} finally {
tearDownFakeDom()
}
})
// ---- Bug D layer 4: user-gesture guard ----------------------------------
test('Bug D L4: openForkCompare refuses to open during boot-quiet window', () => {
installFakeDom()
try {
// Force boot age to zero so the boot-quiet gate slams.
FC.__setBootAtForTests(Date.now())
FC.__markGestureForTests(Date.now())
const ret = FC.openForkCompare({ parentId: 'p', childId: 'c' })
assert.deepEqual(ret, { blocked: 'boot-quiet' },
'return value must surface the block reason')
const doc = globalThis.document
assert.equal(doc.getElementById('fork-compare-drawer'), null,
'no drawer element must exist when open is blocked during boot')
} finally {
tearDownFakeDom()
}
})
test('Bug D L4: openForkCompare refuses to open without a recent user gesture', () => {
installFakeDom()
try {
// Boot is old (installFakeDom set it to -60s) but the gesture stamp
// is stale beyond the 5s window.
FC.__markGestureForTests(Date.now() - 10_000)
const ret = FC.openForkCompare({ parentId: 'p', childId: 'c' })
assert.deepEqual(ret, { blocked: 'no-gesture' },
'a >5s-old gesture must block open')
const doc = globalThis.document
assert.equal(doc.getElementById('fork-compare-drawer'), null,
'no drawer built when gesture is stale')
} finally {
tearDownFakeDom()
}
})
test('Bug D L4: openForkCompare refuses to open with zero gestures ever recorded', () => {
installFakeDom()
try {
// Explicitly clear the stamp — simulates the boot-time auto-open path
// the user hit (no user click preceded the call).
FC.__markGestureForTests(0)
const ret = FC.openForkCompare({ parentId: 'p', childId: 'c' })
assert.deepEqual(ret, { blocked: 'no-gesture' })
const doc = globalThis.document
assert.equal(doc.getElementById('fork-compare-drawer'), null,
'a fresh renderer with zero user gestures must never auto-open the fork-compare drawer')
} finally {
tearDownFakeDom()
}
})
test('Bug D L4: markUserGesture stamps within window, then open succeeds', async () => {
installFakeDom()
try {
FC.__markGestureForTests(0)
// Legitimate button handler calls markUserGesture then openForkCompare.
FC.markUserGesture()
globalThis.window.dsh = { sessionEvents: async () => ({ events: [] }) }
FC.openForkCompare({ parentId: 'p', childId: 'c' })
await new Promise((r) => setTimeout(r, 10))
const doc = globalThis.document
assert.ok(doc.getElementById('fork-compare-drawer'),
'markUserGesture + openForkCompare inside one handler must succeed')
assert.equal(doc.getElementById('fork-compare-drawer').hidden, false)
} finally {
tearDownFakeDom()
}
})