@mzzsfy/dsh-cron-board 0.4.0 → 0.4.2
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/package.json +1 -1
- package/src/client.js +3 -0
- package/src/session-driver.mjs +3 -2
- package/test/client-id.test.mjs +25 -0
- package/test/index.test.mjs +3 -2
- package/test/session-driver.test.mjs +19 -3
package/package.json
CHANGED
package/src/client.js
CHANGED
|
@@ -355,6 +355,9 @@ if (typeof window !== 'undefined' && window.__ModuleLoader__) {
|
|
|
355
355
|
if (existing) return
|
|
356
356
|
const style = document.createElement('style')
|
|
357
357
|
style.id = 'dsh-cron-board-style'
|
|
358
|
+
// 官方契约:插件自注样式必须自带 data-plugin,否则任意后续插件材质化时
|
|
359
|
+
// claimStyles 会把它归属给该插件,其 HMR 重建即整批误删本插件样式
|
|
360
|
+
style.setAttribute('data-plugin', '@mzzsfy/dsh-cron-board')
|
|
358
361
|
style.textContent = STYLE
|
|
359
362
|
document.head.appendChild(style)
|
|
360
363
|
}
|
package/src/session-driver.mjs
CHANGED
|
@@ -38,11 +38,12 @@ async function resolveWorkspaceId(registry, workdir) {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export function createSessionDriver({ getSessionController, getWorkspaceRegistry, agents, sessionQuery }) {
|
|
41
|
-
// pinned 会话存在性:持久层 headers 比对(冷会话不在 agents 注册表)
|
|
41
|
+
// pinned 会话存在性:持久层 headers 比对(冷会话不在 agents 注册表);
|
|
42
|
+
// 记录形态为官方 SessionRecord(dsh-session-query),id 在 header.id
|
|
42
43
|
async function pinnedExists(sessionId) {
|
|
43
44
|
if (!sessionQuery || typeof sessionQuery.listSessions !== 'function') return Boolean(agents.get(sessionId))
|
|
44
45
|
const records = await sessionQuery.listSessions(ADMISSION_SIGNAL)
|
|
45
|
-
return records.some((record) => record && record.id === sessionId)
|
|
46
|
+
return records.some((record) => record && record.header && record.header.id === sessionId)
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
// pinned 可用性:已删除(不在持久层)或已归档(从所有分组视图隐藏)均视为丢失,触发重建
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// client.js 注册 id 与样式标记守卫:loader 按 graph row id(完整包名)匹配注册,短名即加载失败;
|
|
2
|
+
// 样式注入缺 data-plugin 会被宿主 claimStyles 误归属给后续材质化插件,其 HMR 重建即整批误删。
|
|
3
|
+
import { readFileSync } from 'node:fs'
|
|
4
|
+
import { dirname, join } from 'node:path'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
import test from 'node:test'
|
|
7
|
+
import assert from 'node:assert/strict'
|
|
8
|
+
|
|
9
|
+
const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
10
|
+
const { name } = JSON.parse(readFileSync(join(PKG_ROOT, 'package.json'), 'utf8'))
|
|
11
|
+
|
|
12
|
+
test('client.js 注册 id 为完整包名', () => {
|
|
13
|
+
const source = readFileSync(join(PKG_ROOT, 'src', 'client.js'), 'utf8')
|
|
14
|
+
const match = source.match(/__ModuleLoader__\.load\(\{\s*id:\s*'([^']+)'/)
|
|
15
|
+
assert.ok(match, 'client.js 缺少 __ModuleLoader__.load 注册')
|
|
16
|
+
assert.equal(match[1], name)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('client.js 样式注入自带 data-plugin', () => {
|
|
20
|
+
const source = readFileSync(join(PKG_ROOT, 'src', 'client.js'), 'utf8')
|
|
21
|
+
const injections = source.split("createElement('style')").length - 1
|
|
22
|
+
assert.ok(injections > 0, 'client.js 无样式注入点')
|
|
23
|
+
const marked = source.split(`setAttribute('data-plugin', '${name}')`).length - 1
|
|
24
|
+
assert.equal(marked, injections, '每个样式注入点都必须自带 data-plugin(值=注册包名),防宿主 claimStyles 误归属后随他插件 HMR 整批误删')
|
|
25
|
+
})
|
package/test/index.test.mjs
CHANGED
|
@@ -106,10 +106,11 @@ function makeFullCtx({ timerAvailable = true } = {}) {
|
|
|
106
106
|
if (name === 'agentPresets') return { defaultId: '', list: async () => [] }
|
|
107
107
|
if (name === 'sessionQuery') {
|
|
108
108
|
return {
|
|
109
|
-
// 镜像宿主最严准入契约:守护 driver 总是传信号(真实宿主各版本为可选链)
|
|
109
|
+
// 镜像宿主最严准入契约:守护 driver 总是传信号(真实宿主各版本为可选链);
|
|
110
|
+
// 记录形态镜像官方 SessionRecord(dsh-session-query):id 在 header.id
|
|
110
111
|
listSessions: async (signal) => {
|
|
111
112
|
signal.throwIfAborted()
|
|
112
|
-
return [...sessions.values()].map((entry) => ({ id: entry.id }))
|
|
113
|
+
return [...sessions.values()].map((entry) => ({ header: { id: entry.id }, live: true, persisted: false }))
|
|
113
114
|
},
|
|
114
115
|
}
|
|
115
116
|
}
|
|
@@ -10,7 +10,7 @@ import { join } from 'node:path'
|
|
|
10
10
|
import { createSessionDriver } from '../src/session-driver.mjs'
|
|
11
11
|
|
|
12
12
|
// 可控桩:会话注册表 + 控制器(autoIdle 模拟宿主投递后处理完成转 idle;投递即终态下仅影响忙判定)
|
|
13
|
-
function makeStubs({ autoIdle = true } = {}) {
|
|
13
|
+
function makeStubs({ autoIdle = true, persisted = [] } = {}) {
|
|
14
14
|
const sessions = new Map()
|
|
15
15
|
let nextId = 0
|
|
16
16
|
const created = []
|
|
@@ -42,10 +42,14 @@ function makeStubs({ autoIdle = true } = {}) {
|
|
|
42
42
|
get: (id) => sessions.get(id),
|
|
43
43
|
}
|
|
44
44
|
const sessionQuery = {
|
|
45
|
-
// 镜像宿主最严准入契约:守护 driver 总是传信号(真实宿主各版本为可选链,将来收紧不崩)
|
|
45
|
+
// 镜像宿主最严准入契约:守护 driver 总是传信号(真实宿主各版本为可选链,将来收紧不崩);
|
|
46
|
+
// 记录形态镜像官方 SessionRecord(dsh-session-query):id 在 header.id
|
|
46
47
|
async listSessions(signal) {
|
|
47
48
|
signal.throwIfAborted()
|
|
48
|
-
return [
|
|
49
|
+
return [
|
|
50
|
+
...[...sessions.values()].map((entry) => ({ header: { id: entry.id }, live: true, persisted: false })),
|
|
51
|
+
...persisted.map((id) => ({ header: { id }, live: false, persisted: true })),
|
|
52
|
+
]
|
|
49
53
|
},
|
|
50
54
|
}
|
|
51
55
|
return { sessions, created, createRequests, prompts, sessionController, agents, sessionQuery }
|
|
@@ -109,6 +113,18 @@ test('session-driver:pinned 复用同一会话,投递指向 S1', async () => {
|
|
|
109
113
|
assert.equal(stubs.created.length, 0)
|
|
110
114
|
})
|
|
111
115
|
|
|
116
|
+
test('session-driver:pinned 冷会话仅持久层可见时复用不重建', async () => {
|
|
117
|
+
const stubs = makeStubs({ persisted: ['cold-1'] })
|
|
118
|
+
const driver = makeDriver(stubs)
|
|
119
|
+
// When pinned 指向的会话不在 agents 注册表,仅持久层 headers 可见
|
|
120
|
+
const outcome = await driver.run({ job: { ...BASE_JOB, session: { mode: 'pinned', pinnedSessionId: 'cold-1' } }, env: {} })
|
|
121
|
+
// Then 复用冷会话投递,不触发新建
|
|
122
|
+
assert.equal(outcome.status, 'success')
|
|
123
|
+
assert.equal(outcome.sessionId, 'cold-1')
|
|
124
|
+
assert.equal(stubs.prompts[0].sessionId, 'cold-1')
|
|
125
|
+
assert.equal(stubs.created.length, 0)
|
|
126
|
+
})
|
|
127
|
+
|
|
112
128
|
test('session-driver:pinned 忙时跳过,不投递', async () => {
|
|
113
129
|
const stubs = makeStubs()
|
|
114
130
|
stubs.sessions.set('s-1', { id: 's-1', status: 'running' })
|