dsh-wisp 1.34.1 → 1.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -0
- package/build.mjs +32 -3
- package/lib/client.js +3584 -3374
- package/lib/client.template.js +3578 -3374
- package/package.json +1 -1
- package/verify-wisp.mjs +94 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-wisp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.36.0",
|
|
4
4
|
"description": "DeepSeek娘 — an unofficial floating desktop companion for the DeepSeek Harness UI. Zero dependencies; sprites inlined as data URIs; schedules on the Client timer service instead of the trapped browser timer globals.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
package/verify-wisp.mjs
CHANGED
|
@@ -78,7 +78,11 @@ const linesInBundle = () => {
|
|
|
78
78
|
if (linesCache !== undefined) return linesCache
|
|
79
79
|
linesCache = null
|
|
80
80
|
if (typeof clientSrc === 'string') {
|
|
81
|
-
|
|
81
|
+
/* 中文池现在叫 LINES_ZH(英文是覆盖层,最后合并成 LINES)。
|
|
82
|
+
这里读**中文池**:测试验的是"她说的那句话确实来自对应池子",
|
|
83
|
+
而中文字面量永远存在,不受语言环境影响。 */
|
|
84
|
+
const match = clientSrc.match(/const LINES_ZH = (\{[\s\S]*?\n {4}\})/)
|
|
85
|
+
|| clientSrc.match(/const LINES = (\{[\s\S]*?\n {4}\})/)
|
|
82
86
|
if (match) {
|
|
83
87
|
try { linesCache = new Function(`return ${match[1]}`)() } catch (e) { linesCache = null }
|
|
84
88
|
}
|
|
@@ -3430,8 +3434,12 @@ head('3y-3. the focus timer, and going quiet while the page is hidden')
|
|
|
3430
3434
|
quiet.document.visibilityState = 'hidden'
|
|
3431
3435
|
quiet.document.dispatch('visibilitychange', {})
|
|
3432
3436
|
const timers = quietApi.doctor().timers
|
|
3433
|
-
|
|
3434
|
-
|
|
3437
|
+
/* 絮叨与踱步停掉(只给看得见的人看),但**轮询放慢而不是停掉** ——
|
|
3438
|
+
值班的前提是还看得见:你走开时跑完的轮次和出的错,都要被记下来。 */
|
|
3439
|
+
check(timers.paused === true && timers.chatter === false && timers.wander === false,
|
|
3440
|
+
'hiding the page stops the chatter and the wander', JSON.stringify(timers))
|
|
3441
|
+
check(timers.poll === true && timers.pollMs === 5000,
|
|
3442
|
+
'but the poll keeps a slow watch instead of stopping (she is on duty)', JSON.stringify(timers))
|
|
3435
3443
|
|
|
3436
3444
|
/* 藏起来期间:来了一堆报错,她也不该有任何反应(轮询停了) */
|
|
3437
3445
|
quiet.state.errors = 3
|
|
@@ -3454,6 +3462,89 @@ head('3y-3. the focus timer, and going quiet while the page is hidden')
|
|
|
3454
3462
|
quiet.state.busy = false
|
|
3455
3463
|
quiet.advance(3000, 200)
|
|
3456
3464
|
check(moodOf(quiet) === 'worried', 'and now the same errors do get a reaction', moodOf(quiet))
|
|
3465
|
+
/* ---- 值班:走开期间跑完的轮次与报错,回来要报账 ------------------------------ */
|
|
3466
|
+
const saidNow = () => quiet.all('wisp-say').filter((el) => el.removed !== true)
|
|
3467
|
+
.map((el) => el.textContent).join(' ')
|
|
3468
|
+
quiet.document.visibilityState = 'hidden'
|
|
3469
|
+
quiet.document.dispatch('visibilitychange', {})
|
|
3470
|
+
quiet.state.busy = true
|
|
3471
|
+
quiet.advance(60000, 5000) // 你走开之后,她看着一轮跑了一分钟
|
|
3472
|
+
quiet.state.errors = 5
|
|
3473
|
+
quiet.state.busy = false
|
|
3474
|
+
quiet.advance(180000, 5000) // 一共走开三分钟(超过"回来问候"的门槛)
|
|
3475
|
+
check(saidNow() === '', 'while you are away she takes notes but says nothing', saidNow())
|
|
3476
|
+
|
|
3477
|
+
quiet.document.visibilityState = 'visible'
|
|
3478
|
+
quiet.document.dispatch('visibilitychange', {})
|
|
3479
|
+
quiet.advance(1000, 200)
|
|
3480
|
+
const report = saidNow()
|
|
3481
|
+
check(/轮/.test(report) && /跑完/.test(report),
|
|
3482
|
+
'coming back, she reports how many runs finished while you were away', report)
|
|
3483
|
+
check(/错/.test(report), 'and she mentions the errors she saw', report)
|
|
3484
|
+
const book = quietApi.doctor().today
|
|
3485
|
+
check(book.runs >= 1 && book.errors >= 1 && book.longestMs > 0,
|
|
3486
|
+
'and the day book recorded the runs, the errors and the longest one',
|
|
3487
|
+
JSON.stringify(book))
|
|
3488
|
+
|
|
3489
|
+
/* ---- 单轮跑得异常久:她会中途说一声,而且同一轮只说一次 ---------------------- */
|
|
3490
|
+
quiet.state.busy = true
|
|
3491
|
+
/* 刚好推过"单轮跑太久"的阈值。推 11 分钟是不行的:她的话早就过期了(气泡有存活时间),
|
|
3492
|
+
于是断言会看到空字符串 —— 断言本身没错,是喂给它的时间不对。 */
|
|
3493
|
+
/* 多推几步:busySince 是在推进开始后的第一个轮询才记下的,卡在 601000 会差 200ms。 */
|
|
3494
|
+
quiet.advance(604800, 1200)
|
|
3495
|
+
const longLine = saidNow()
|
|
3496
|
+
const during = quietApi.doctor()
|
|
3497
|
+
check(/分钟/.test(longLine), 'a single run that drags on gets a check-in',
|
|
3498
|
+
`她说的是「${longLine}」;runInFlight=${during.runInFlightMs} longRunSaid=${during.longRunSaid} paused=${during.timers.paused}`)
|
|
3499
|
+
quiet.state.busy = false
|
|
3500
|
+
quiet.advance(3000, 500)
|
|
3501
|
+
|
|
3502
|
+
/* ---- 今日小结:把她记着的东西一次说完 ---------------------------------------- */
|
|
3503
|
+
quietApi.saySummary()
|
|
3504
|
+
quiet.advance(200, 50)
|
|
3505
|
+
const summaryLine = saidNow()
|
|
3506
|
+
/* 词池里有三个变体(今天…/今天:…/这一天…),所以断言**内容**而不是某一个措辞 */
|
|
3507
|
+
check(/轮/.test(summaryLine) && /错/.test(summaryLine) && /分钟/.test(summaryLine),
|
|
3508
|
+
'the daily summary reads back what she has been tracking', summaryLine)
|
|
3509
|
+
check(/\d/.test(summaryLine), 'with real numbers', summaryLine)
|
|
3510
|
+
check(summaryLine.indexOf('{') < 0, 'and no placeholder is left unfilled', summaryLine)
|
|
3511
|
+
check(typeof quietApi.today.runs === 'number' && quietApi.today.runs >= 1,
|
|
3512
|
+
'the day book is also readable from the api', JSON.stringify(quietApi.today))
|
|
3513
|
+
|
|
3514
|
+
/* ---- 英文台词:英文环境下她说英文,而且**一个汉字都不该出现** -------------------
|
|
3515
|
+
语言是加载时判定的(读 navigator.language),所以这个 harness 要在 evaluate 之前
|
|
3516
|
+
把 navigator 摆好。中文是兜底:没翻的条目仍然会说中文,这一条只验"翻译层真的生效"。 */
|
|
3517
|
+
const en = createHarness({ timer: true, composerText: '', storageSeed: { 'dsh-wisp-lang': 'en' } })
|
|
3518
|
+
const keepEn = active
|
|
3519
|
+
active = en
|
|
3520
|
+
en.evaluate(clientSrc)
|
|
3521
|
+
en.module().default.apply(en.ctx, { reactions: false, wander: false, celebrate: false })
|
|
3522
|
+
en.advance(1000, 200)
|
|
3523
|
+
en.win.__wisp.saySummary()
|
|
3524
|
+
en.advance(200, 50)
|
|
3525
|
+
const enLine = en.all('wisp-say').filter((el) => el.removed !== true)
|
|
3526
|
+
.map((el) => el.textContent).join(' ')
|
|
3527
|
+
check(/[A-Za-z]/.test(enLine), 'with an english locale she answers in english',
|
|
3528
|
+
`${enLine} | ${JSON.stringify(en.win.__wisp.doctor().lang)}`)
|
|
3529
|
+
check(!/[\u4e00-\u9fa5]/.test(enLine), 'and the line contains no chinese characters', enLine)
|
|
3530
|
+
en.win.__wisp.destroy()
|
|
3531
|
+
active = keepEn
|
|
3532
|
+
|
|
3533
|
+
/* 对照组:强制中文时同一句话必须是中文 —— 否则上面那条可能只是"恰好没触发" */
|
|
3534
|
+
const zh = createHarness({ timer: true, composerText: '', storageSeed: { 'dsh-wisp-lang': 'zh' } })
|
|
3535
|
+
const keepZh = active
|
|
3536
|
+
active = zh
|
|
3537
|
+
zh.evaluate(clientSrc)
|
|
3538
|
+
zh.module().default.apply(zh.ctx, { reactions: false, wander: false, celebrate: false })
|
|
3539
|
+
zh.advance(1000, 200)
|
|
3540
|
+
zh.win.__wisp.saySummary()
|
|
3541
|
+
zh.advance(200, 50)
|
|
3542
|
+
const zhLine = zh.all('wisp-say').filter((el) => el.removed !== true)
|
|
3543
|
+
.map((el) => el.textContent).join(' ')
|
|
3544
|
+
check(/[\u4e00-\u9fa5]/.test(zhLine), 'forcing chinese keeps her speaking chinese', zhLine)
|
|
3545
|
+
zh.win.__wisp.destroy()
|
|
3546
|
+
active = keepZh
|
|
3547
|
+
|
|
3457
3548
|
quiet.win.__wisp.destroy()
|
|
3458
3549
|
active = keepQuiet
|
|
3459
3550
|
}
|