@capyclaw/ppt-workbench 2.4.0 → 2.4.1

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.
@@ -1,82 +1,82 @@
1
- /**
2
- * dsh-plugin-kit 运行时调优层。
3
- *
4
- * 默认值与进化搜索(evolution/ NSGA-II)的 founder 基线保持一致;
5
- * 生产环境可用 DSH_TUNING_JSON 覆盖(按包名分组),测试/评估用 setTuning 注入。
6
- *
7
- * DSH_TUNING_JSON 形如:
8
- * {"dsh-plugin-kit": {"fileLockPollMs": 25, "journalMaxBytes": 2097152}}
9
- */
10
-
11
- const DEFAULTS = {
12
- /* fs-lock:元数据文件锁
13
- * pollMs=10 由 NSGA-II 进化搜索固化(evolution/,2026-11-01):
14
- * 24 路竞争延迟 2202→1400ms;10ms 为延迟与轮询 IO 的膝点。 */
15
- fileLockSyncTimeoutMs: 10000,
16
- fileLockSyncStaleMs: 30000,
17
- fileLockAsyncTimeoutMs: 30000,
18
- fileLockPollMs: 10,
19
- fileLockFreshGraceMs: 2000,
20
-
21
- /* 编辑器租约:wait() 轮询节奏 */
22
- leaseWaitPollMs: 200,
23
- leaseWaitTimeoutMs: 4000,
24
-
25
- /* JournalStore:journal 轮转阈值与尾读默认行数
26
- * 512KB 由进化搜索固化:尾读 p95 4.3→1.9ms、磁盘 -70%、追加吞吐 +8%。 */
27
- journalMaxBytes: 512 * 1024,
28
- journalTailLimit: 8,
29
-
30
- /* WorkspaceManager catalog 写节流(降低全局 catalog 锁竞争) */
31
- catalogThrottleMs: 5000,
32
-
33
- /* WorkspaceClient token 校验缓存 */
34
- tokenVerifyCacheMs: 30000,
35
-
36
- /* HTTP 服务三级超时(keepAliveTimeoutMs 必须小于 headersTimeoutMs) */
37
- requestTimeoutMs: 30000,
38
- headersTimeoutMs: 10000,
39
- keepAliveTimeoutMs: 5000,
40
- }
41
-
42
- let overrides = {}
43
- let envLoaded = false
44
-
45
- function loadEnv() {
46
- if (envLoaded) return
47
- envLoaded = true
48
- try {
49
- const raw = process.env.DSH_TUNING_JSON
50
- if (!raw) return
51
- const parsed = JSON.parse(raw)
52
- if (!parsed || typeof parsed !== 'object') return
53
- const own = parsed['dsh-plugin-kit'] && typeof parsed['dsh-plugin-kit'] === 'object'
54
- ? parsed['dsh-plugin-kit']
55
- : parsed
56
- for (const key of Object.keys(DEFAULTS)) {
57
- if (own[key] !== undefined) overrides[key] = own[key]
58
- }
59
- } catch { /* 非法 JSON 静默忽略:调优失败不能阻塞启动 */ }
60
- }
61
-
62
- /** 当前生效参数(默认值 + env + setTuning 覆盖)。 */
63
- export function tuning() {
64
- loadEnv()
65
- return { ...DEFAULTS, ...overrides }
66
- }
67
-
68
- /** 测试/评估注入。只接受已知键,避免拼写错误静默生效。 */
69
- export function setTuning(patch = {}) {
70
- loadEnv()
71
- for (const [key, value] of Object.entries(patch)) {
72
- if (key in DEFAULTS) overrides[key] = value
73
- }
74
- }
75
-
76
- /** 恢复到默认值 + env 覆盖。 */
77
- export function resetTuning() {
78
- overrides = {}
79
- envLoaded = false
80
- }
81
-
82
- export const TUNING_DEFAULTS = { ...DEFAULTS }
1
+ /**
2
+ * @capyclaw/plugin-kit 运行时调优层。
3
+ *
4
+ * 默认值与进化搜索(evolution/ NSGA-II)的 founder 基线保持一致;
5
+ * 生产环境可用 DSH_TUNING_JSON 覆盖(按包名分组),测试/评估用 setTuning 注入。
6
+ *
7
+ * DSH_TUNING_JSON 形如:
8
+ * {"@capyclaw/plugin-kit": {"fileLockPollMs": 25, "journalMaxBytes": 2097152}}
9
+ */
10
+
11
+ const DEFAULTS = {
12
+ /* fs-lock:元数据文件锁
13
+ * pollMs=10 由 NSGA-II 进化搜索固化(evolution/,2026-11-01):
14
+ * 24 路竞争延迟 2202→1400ms;10ms 为延迟与轮询 IO 的膝点。 */
15
+ fileLockSyncTimeoutMs: 10000,
16
+ fileLockSyncStaleMs: 30000,
17
+ fileLockAsyncTimeoutMs: 30000,
18
+ fileLockPollMs: 10,
19
+ fileLockFreshGraceMs: 2000,
20
+
21
+ /* 编辑器租约:wait() 轮询节奏 */
22
+ leaseWaitPollMs: 200,
23
+ leaseWaitTimeoutMs: 4000,
24
+
25
+ /* JournalStore:journal 轮转阈值与尾读默认行数
26
+ * 512KB 由进化搜索固化:尾读 p95 4.3→1.9ms、磁盘 -70%、追加吞吐 +8%。 */
27
+ journalMaxBytes: 512 * 1024,
28
+ journalTailLimit: 8,
29
+
30
+ /* WorkspaceManager catalog 写节流(降低全局 catalog 锁竞争) */
31
+ catalogThrottleMs: 5000,
32
+
33
+ /* WorkspaceClient token 校验缓存 */
34
+ tokenVerifyCacheMs: 30000,
35
+
36
+ /* HTTP 服务三级超时(keepAliveTimeoutMs 必须小于 headersTimeoutMs) */
37
+ requestTimeoutMs: 30000,
38
+ headersTimeoutMs: 10000,
39
+ keepAliveTimeoutMs: 5000,
40
+ }
41
+
42
+ let overrides = {}
43
+ let envLoaded = false
44
+
45
+ function loadEnv() {
46
+ if (envLoaded) return
47
+ envLoaded = true
48
+ try {
49
+ const raw = process.env.DSH_TUNING_JSON
50
+ if (!raw) return
51
+ const parsed = JSON.parse(raw)
52
+ if (!parsed || typeof parsed !== 'object') return
53
+ const own = parsed['@capyclaw/plugin-kit'] && typeof parsed['@capyclaw/plugin-kit'] === 'object'
54
+ ? parsed['@capyclaw/plugin-kit']
55
+ : parsed
56
+ for (const key of Object.keys(DEFAULTS)) {
57
+ if (own[key] !== undefined) overrides[key] = own[key]
58
+ }
59
+ } catch { /* 非法 JSON 静默忽略:调优失败不能阻塞启动 */ }
60
+ }
61
+
62
+ /** 当前生效参数(默认值 + env + setTuning 覆盖)。 */
63
+ export function tuning() {
64
+ loadEnv()
65
+ return { ...DEFAULTS, ...overrides }
66
+ }
67
+
68
+ /** 测试/评估注入。只接受已知键,避免拼写错误静默生效。 */
69
+ export function setTuning(patch = {}) {
70
+ loadEnv()
71
+ for (const [key, value] of Object.entries(patch)) {
72
+ if (key in DEFAULTS) overrides[key] = value
73
+ }
74
+ }
75
+
76
+ /** 恢复到默认值 + env 覆盖。 */
77
+ export function resetTuning() {
78
+ overrides = {}
79
+ envLoaded = false
80
+ }
81
+
82
+ export const TUNING_DEFAULTS = { ...DEFAULTS }
@@ -1,2 +1,2 @@
1
- /** 兼容入口:单实例锁实现统一来自 dsh-plugin-kit 的构建快照。 */
2
- export * from './infra/single-instance.mjs'
1
+ /** 兼容入口:单实例锁实现统一来自 @capyclaw/plugin-kit 的构建快照。 */
2
+ export * from './infra/single-instance.mjs'
@@ -1,28 +1,28 @@
1
- /** 兼容层:checkpoint 名称与载荷沿用 PPT 字段,底层由 DocumentSession 写入。 */
2
- export { checkpointName } from 'dsh-document-workbench/session'
3
-
4
- export function buildCheckpoint(doc, name, meta = {}) {
5
- const pending = (doc.seq | 0) > (doc.applied_seq | 0)
6
- const deck = doc.deck || { title: '未命名', slides: [] }
7
- return {
8
- name,
9
- seq: doc.seq | 0,
10
- appliedSeq: doc.applied_seq | 0,
11
- pending,
12
- title: doc.title || deck.title || '未命名',
13
- slides: Array.isArray(deck.slides) ? deck.slides.length : 0,
14
- deck,
15
- meta: meta && typeof meta === 'object' ? meta : {},
16
- createdAt: new Date().toISOString(),
17
- }
18
- }
19
-
20
- export function listCheckpoints(backend) {
21
- return backend.listCheckpoints()
22
- }
23
-
24
- export function readCheckpoint(backend, name) {
25
- const payload = backend.readCheckpoint(name)
26
- if (!payload || !payload.deck) throw new Error('checkpoint 内容损坏: ' + name)
27
- return payload
28
- }
1
+ /** 兼容层:checkpoint 名称与载荷沿用 PPT 字段,底层由 DocumentSession 写入。 */
2
+ export { checkpointName } from '@capyclaw/document-workbench/session'
3
+
4
+ export function buildCheckpoint(doc, name, meta = {}) {
5
+ const pending = (doc.seq | 0) > (doc.applied_seq | 0)
6
+ const deck = doc.deck || { title: '未命名', slides: [] }
7
+ return {
8
+ name,
9
+ seq: doc.seq | 0,
10
+ appliedSeq: doc.applied_seq | 0,
11
+ pending,
12
+ title: doc.title || deck.title || '未命名',
13
+ slides: Array.isArray(deck.slides) ? deck.slides.length : 0,
14
+ deck,
15
+ meta: meta && typeof meta === 'object' ? meta : {},
16
+ createdAt: new Date().toISOString(),
17
+ }
18
+ }
19
+
20
+ export function listCheckpoints(backend) {
21
+ return backend.listCheckpoints()
22
+ }
23
+
24
+ export function readCheckpoint(backend, name) {
25
+ const payload = backend.readCheckpoint(name)
26
+ if (!payload || !payload.deck) throw new Error('checkpoint 内容损坏: ' + name)
27
+ return payload
28
+ }
@@ -1,52 +1,52 @@
1
- /** PPT 兼容层:标准会话信封 + PPT 的 deck 初始文档与标题同步。 */
2
- import {
3
- applyAck as baseAck,
4
- applyPush as basePush,
5
- applyServer as baseServer,
6
- applyShotRequest as baseShotRequest,
7
- applyShotResult as baseShotResult,
8
- applyState as baseState,
9
- applyUi as baseUi,
10
- createSessionState,
11
- pendingOf,
12
- } from 'dsh-document-workbench/session'
13
-
14
- export const EMPTY_DECK = () => ({ title: '', slides: [] })
15
-
16
- export const EMPTY_DOC = () => createSessionState({ title: '' })
17
-
18
- export function applyPush(doc, cmds, title, now) {
19
- return basePush(doc, cmds, title, now)
20
- }
21
-
22
- export function applyServer(doc, seq, applied, error, now) {
23
- return baseServer(doc, seq, applied, error, {
24
- now,
25
- stateCompact: true,
26
- onApplied: (next) => {
27
- if (next.title && next.deck) next.deck.title = next.title
28
- },
29
- })
30
- }
31
-
32
- export function applyAck(doc, seq, applied, error, now) {
33
- return baseAck(doc, seq, applied, error, now)
34
- }
35
-
36
- export function applyState(doc, deck, seq, now) {
37
- return baseState(doc, deck, seq, { now, documentKey: 'deck' })
38
- }
39
-
40
- export function applyUi(doc, cmds, now) {
41
- return baseUi(doc, cmds, now)
42
- }
43
-
44
- export function applyShotRequest(doc, now) {
45
- return baseShotRequest(doc, now)
46
- }
47
-
48
- export function applyShotResult(doc, req, data, now) {
49
- return baseShotResult(doc, req, data, now)
50
- }
51
-
52
- export { pendingOf }
1
+ /** PPT 兼容层:标准会话信封 + PPT 的 deck 初始文档与标题同步。 */
2
+ import {
3
+ applyAck as baseAck,
4
+ applyPush as basePush,
5
+ applyServer as baseServer,
6
+ applyShotRequest as baseShotRequest,
7
+ applyShotResult as baseShotResult,
8
+ applyState as baseState,
9
+ applyUi as baseUi,
10
+ createSessionState,
11
+ pendingOf,
12
+ } from '@capyclaw/document-workbench/session'
13
+
14
+ export const EMPTY_DECK = () => ({ title: '', slides: [] })
15
+
16
+ export const EMPTY_DOC = () => createSessionState({ title: '' })
17
+
18
+ export function applyPush(doc, cmds, title, now) {
19
+ return basePush(doc, cmds, title, now)
20
+ }
21
+
22
+ export function applyServer(doc, seq, applied, error, now) {
23
+ return baseServer(doc, seq, applied, error, {
24
+ now,
25
+ stateCompact: true,
26
+ onApplied: (next) => {
27
+ if (next.title && next.deck) next.deck.title = next.title
28
+ },
29
+ })
30
+ }
31
+
32
+ export function applyAck(doc, seq, applied, error, now) {
33
+ return baseAck(doc, seq, applied, error, now)
34
+ }
35
+
36
+ export function applyState(doc, deck, seq, now) {
37
+ return baseState(doc, deck, seq, { now, documentKey: 'deck' })
38
+ }
39
+
40
+ export function applyUi(doc, cmds, now) {
41
+ return baseUi(doc, cmds, now)
42
+ }
43
+
44
+ export function applyShotRequest(doc, now) {
45
+ return baseShotRequest(doc, now)
46
+ }
47
+
48
+ export function applyShotResult(doc, req, data, now) {
49
+ return baseShotResult(doc, req, data, now)
50
+ }
51
+
52
+ export { pendingOf }
@@ -1,34 +1,34 @@
1
- /**
2
- * PPT 桥存储 facade:通用版本化会话来自 dsh-document-workbench,
3
- * 本文件只保留 deck 的初始文档、summary 与标题同步。
4
- */
5
- import { DocumentSession, OWNER_TTL } from 'dsh-document-workbench/session'
6
- import { FileBridgeBackend } from './backends/file-backend.mjs'
7
- import { EMPTY_DOC } from './doc.mjs'
8
-
9
- export * from './sanitize.mjs'
10
- export { OWNER_TTL, FileBridgeBackend }
11
-
12
- export class BridgeStore extends DocumentSession {
13
- constructor(fileOrOptions) {
14
- let backend
15
- if (typeof fileOrOptions === 'string') backend = new FileBridgeBackend(fileOrOptions)
16
- else if (fileOrOptions && fileOrOptions.backend) backend = fileOrOptions.backend
17
- else throw new Error('BridgeStore 需要 file 路径或 backend')
18
-
19
- super({
20
- backend,
21
- initialDoc: EMPTY_DOC(),
22
- documentKey: 'deck',
23
- stateCompact: true,
24
- summary: (doc) => ({
25
- title: doc.deck && doc.deck.title ? doc.deck.title : '未命名',
26
- slides: doc.deck && Array.isArray(doc.deck.slides) ? doc.deck.slides.length : 0,
27
- }),
28
- checkpointDocument: () => ({ title: '未命名', slides: [] }),
29
- onApplied: (doc) => {
30
- if (doc.title && doc.deck) doc.deck.title = doc.title
31
- },
32
- })
33
- }
34
- }
1
+ /**
2
+ * PPT 桥存储 facade:通用版本化会话来自 @capyclaw/document-workbench,
3
+ * 本文件只保留 deck 的初始文档、summary 与标题同步。
4
+ */
5
+ import { DocumentSession, OWNER_TTL } from '@capyclaw/document-workbench/session'
6
+ import { FileBridgeBackend } from './backends/file-backend.mjs'
7
+ import { EMPTY_DOC } from './doc.mjs'
8
+
9
+ export * from './sanitize.mjs'
10
+ export { OWNER_TTL, FileBridgeBackend }
11
+
12
+ export class BridgeStore extends DocumentSession {
13
+ constructor(fileOrOptions) {
14
+ let backend
15
+ if (typeof fileOrOptions === 'string') backend = new FileBridgeBackend(fileOrOptions)
16
+ else if (fileOrOptions && fileOrOptions.backend) backend = fileOrOptions.backend
17
+ else throw new Error('BridgeStore 需要 file 路径或 backend')
18
+
19
+ super({
20
+ backend,
21
+ initialDoc: EMPTY_DOC(),
22
+ documentKey: 'deck',
23
+ stateCompact: true,
24
+ summary: (doc) => ({
25
+ title: doc.deck && doc.deck.title ? doc.deck.title : '未命名',
26
+ slides: doc.deck && Array.isArray(doc.deck.slides) ? doc.deck.slides.length : 0,
27
+ }),
28
+ checkpointDocument: () => ({ title: '未命名', slides: [] }),
29
+ onApplied: (doc) => {
30
+ if (doc.title && doc.deck) doc.deck.title = doc.title
31
+ },
32
+ })
33
+ }
34
+ }
@@ -1,2 +1,2 @@
1
- /** 兼容层:deck owner 租约的通用实现位于 dsh-document-workbench/session。 */
2
- export { OWNER_TTL, claimOwner, ownerStatus, releaseOwner } from 'dsh-document-workbench/session'
1
+ /** 兼容层:deck owner 租约的通用实现位于 @capyclaw/document-workbench/session。 */
2
+ export { OWNER_TTL, claimOwner, ownerStatus, releaseOwner } from '@capyclaw/document-workbench/session'
@@ -1,32 +1,32 @@
1
- /** 桥协议白名单:通用信封来自 dsh-document-workbench,PPT 只需声明 deck 字段与上限。 */
2
- import { createSessionSanitizers } from 'dsh-document-workbench/session'
3
-
4
- export const MAX_CMDS = 100 // 单队指令条数上限
5
- export const MAX_TOTAL = 8 * 1024 * 1024 // 单队总量上限(字节)
6
- export const MAX_SHOT = 4 * 1024 * 1024 // 截图 dataURL 上限
7
-
8
- const sanitizers = createSessionSanitizers({
9
- documentKey: 'deck',
10
- maxCmds: MAX_CMDS,
11
- maxTotal: MAX_TOTAL,
12
- maxShot: MAX_SHOT,
13
- maxTitle: 120,
14
- maxError: 2000,
15
- maxId: 64,
16
- })
17
-
18
- const {
19
- sanitizeAck,
20
- sanitizeClaim,
21
- sanitizePush,
22
- sanitizeShotResult,
23
- sanitizeState: baseSanitizeState,
24
- } = sanitizers
25
-
26
- export { sanitizeAck, sanitizeClaim, sanitizePush, sanitizeShotResult }
27
-
28
- /** 兼容旧 API:返回 { deck, seq };通用 bridge 会把它归一化为 value。 */
29
- export function sanitizeState(body) {
30
- const data = baseSanitizeState(body)
31
- return data ? { deck: data.value, seq: data.seq } : null
32
- }
1
+ /** 桥协议白名单:通用信封来自 @capyclaw/document-workbench,PPT 只需声明 deck 字段与上限。 */
2
+ import { createSessionSanitizers } from '@capyclaw/document-workbench/session'
3
+
4
+ export const MAX_CMDS = 100 // 单队指令条数上限
5
+ export const MAX_TOTAL = 8 * 1024 * 1024 // 单队总量上限(字节)
6
+ export const MAX_SHOT = 4 * 1024 * 1024 // 截图 dataURL 上限
7
+
8
+ const sanitizers = createSessionSanitizers({
9
+ documentKey: 'deck',
10
+ maxCmds: MAX_CMDS,
11
+ maxTotal: MAX_TOTAL,
12
+ maxShot: MAX_SHOT,
13
+ maxTitle: 120,
14
+ maxError: 2000,
15
+ maxId: 64,
16
+ })
17
+
18
+ const {
19
+ sanitizeAck,
20
+ sanitizeClaim,
21
+ sanitizePush,
22
+ sanitizeShotResult,
23
+ sanitizeState: baseSanitizeState,
24
+ } = sanitizers
25
+
26
+ export { sanitizeAck, sanitizeClaim, sanitizePush, sanitizeShotResult }
27
+
28
+ /** 兼容旧 API:返回 { deck, seq };通用 bridge 会把它归一化为 value。 */
29
+ export function sanitizeState(body) {
30
+ const data = baseSanitizeState(body)
31
+ return data ? { deck: data.value, seq: data.seq } : null
32
+ }
@@ -1,2 +1,2 @@
1
- /** 参数校验统一来自 dsh-tool-host 公共插件(底层为 dsh-plugin-kit)。 */
1
+ /** 参数校验统一来自 dsh-tool-host 公共插件(底层为 @capyclaw/plugin-kit)。 */
2
2
  export { validateToolArguments } from './shared/tool-host.mjs'