dsh-later 1.0.0 → 1.2.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/CHANGELOG.md +247 -0
- package/README.en.md +55 -2
- package/README.md +53 -2
- package/icon.svg +10 -0
- package/lib/bar-geometry.js +139 -0
- package/lib/client.js +1349 -423
- package/lib/command-outcome.js +15 -0
- package/lib/commands.js +56 -8
- package/lib/delivery.js +66 -0
- package/lib/domain.js +6 -0
- package/lib/index.js +152 -29
- package/lib/ownership-store.js +113 -15
- package/lib/presence.js +122 -4
- package/lib/projection.js +149 -20
- package/lib/runtime.js +160 -24
- package/lib/schedule-compat.js +179 -0
- package/lib/schedule-summary-store.js +160 -0
- package/lib/schedule-summary.js +113 -0
- package/lib/types/bar-geometry.d.ts +111 -0
- package/lib/types/command-outcome.d.ts +19 -0
- package/lib/types/delivery.d.ts +51 -0
- package/lib/types/domain.d.ts +32 -0
- package/lib/types/index.d.ts +28 -8
- package/lib/types/ownership-store.d.ts +42 -2
- package/lib/types/presence.d.ts +75 -4
- package/lib/types/projection.d.ts +68 -6
- package/lib/types/runtime.d.ts +58 -1
- package/lib/types/schedule-compat.d.ts +111 -0
- package/lib/types/schedule-summary-store.d.ts +75 -0
- package/lib/types/schedule-summary.d.ts +92 -0
- package/lib/types/upstream-compat.d.ts +123 -0
- package/lib/types/user-tools.d.ts +48 -7
- package/lib/upstream-compat.js +143 -0
- package/lib/user-tools.js +268 -44
- package/package.json +25 -22
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { z } from 'zod';
|
|
17
17
|
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
18
|
-
import type {
|
|
18
|
+
import type { AfterScheduleRecord, AtScheduleRecord, EveryScheduleRecord } from '@deepseek-ai/dsh-schedule';
|
|
19
|
+
import type { PausedEntry } from './ownership-store.js';
|
|
19
20
|
import type { UserScheduleProjectionValue } from './domain.js';
|
|
20
21
|
/** 投影 wire 值 schema(wire.viewSchema:离开宿主前校验客户端载荷)。 */
|
|
21
22
|
export declare const userSchedulesSchema: z.ZodObject<{
|
|
@@ -28,6 +29,11 @@ export declare const userSchedulesSchema: z.ZodObject<{
|
|
|
28
29
|
scheduled_at: z.ZodString;
|
|
29
30
|
created_at: z.ZodOptional<z.ZodString>;
|
|
30
31
|
delivery_mode: z.ZodLiteral<"session-local">;
|
|
32
|
+
status: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"active">, z.ZodLiteral<"paused">]>>;
|
|
33
|
+
remaining_seconds: z.ZodOptional<z.ZodNumber>;
|
|
34
|
+
paused_at: z.ZodOptional<z.ZodString>;
|
|
35
|
+
schedule_id: z.ZodOptional<z.ZodString>;
|
|
36
|
+
window_seconds: z.ZodOptional<z.ZodNumber>;
|
|
31
37
|
}, z.core.$strict>>;
|
|
32
38
|
}, z.core.$strict>;
|
|
33
39
|
export declare const userSchedulesStateSchema: z.ZodObject<{
|
|
@@ -43,11 +49,37 @@ export declare const userSchedulesStateSchema: z.ZodObject<{
|
|
|
43
49
|
createdAt: z.ZodOptional<z.ZodNumber>;
|
|
44
50
|
}, z.core.$loose>>;
|
|
45
51
|
seedSeq: z.ZodNumber;
|
|
52
|
+
paused: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
53
|
+
uid: z.ZodString;
|
|
54
|
+
prompt: z.ZodString;
|
|
55
|
+
delivery: z.ZodUnion<readonly [z.ZodLiteral<"context">, z.ZodLiteral<"user">]>;
|
|
56
|
+
kind: z.ZodLiteral<"after">;
|
|
57
|
+
remainingSeconds: z.ZodNumber;
|
|
58
|
+
originalScheduledAt: z.ZodString;
|
|
59
|
+
originalAfterSeconds: z.ZodOptional<z.ZodNumber>;
|
|
60
|
+
lastScheduleId: z.ZodString;
|
|
61
|
+
pausedAt: z.ZodNumber;
|
|
62
|
+
}, z.core.$strip>>>;
|
|
46
63
|
}, z.core.$strip>;
|
|
47
|
-
/**
|
|
48
|
-
|
|
64
|
+
/**
|
|
65
|
+
* 活动存储记录:dsh-schedule 记录 + 创建时刻(来自 create 事件的 time)。
|
|
66
|
+
*
|
|
67
|
+
* 显式按**本插件产出的三种 kind** 收窄,而非直接用 `ScheduleRecord`:
|
|
68
|
+
* 0.1.7 的联合新增了 daily/weekly/cron,它们的字段面
|
|
69
|
+
* (`afterSeconds` / `everySeconds`)与本插件的 wire 契约不同,透传会让
|
|
70
|
+
* `wireItemOf` 读到不存在的字段。
|
|
71
|
+
*
|
|
72
|
+
* 逐个具名引用而非 `Extract`:`Extract<ScheduleRecord, {kind:'after'|…}>`
|
|
73
|
+
* 在本仓库的 tsc 配置下不触发收窄(判别式联合的 `Extract` 需 kind 为
|
|
74
|
+
* 单字面量,逐个列举后交集才正确)。
|
|
75
|
+
*/
|
|
76
|
+
export type StoredScheduleRecord = (AfterScheduleRecord & {
|
|
49
77
|
readonly createdAt?: number;
|
|
50
|
-
}
|
|
78
|
+
}) | (AtScheduleRecord & {
|
|
79
|
+
readonly createdAt?: number;
|
|
80
|
+
}) | (EveryScheduleRecord & {
|
|
81
|
+
readonly createdAt?: number;
|
|
82
|
+
});
|
|
51
83
|
/** 投影内部状态(plain JSON:owned/active 用数组承载)。 */
|
|
52
84
|
export interface UserScheduleProjectionState {
|
|
53
85
|
/** 会话 id(init 由 header 注入)。 */
|
|
@@ -58,6 +90,8 @@ export interface UserScheduleProjectionState {
|
|
|
58
90
|
readonly active: readonly StoredScheduleRecord[];
|
|
59
91
|
/** 已见 `session/end-seed` 的 seq;更早的继承前缀一律忽略。 */
|
|
60
92
|
readonly seedSeq: number;
|
|
93
|
+
/** sidecar 暂停留档镜像。 */
|
|
94
|
+
readonly paused: readonly PausedEntry[];
|
|
61
95
|
}
|
|
62
96
|
/** 初始状态:按会话 id 从所有权 sidecar 装载(进程重启后恢复 GUI 归属)。 */
|
|
63
97
|
export declare function initUserScheduleProjection(header?: {
|
|
@@ -67,7 +101,19 @@ export declare function initUserScheduleProjection(header?: {
|
|
|
67
101
|
* 增量 fold。返回同一引用当事件无关;返回新状态当 owned/active 发生变化。
|
|
68
102
|
*/
|
|
69
103
|
export declare function applyUserScheduleProjection(state: UserScheduleProjectionState, event: SessionEvent): UserScheduleProjectionState;
|
|
70
|
-
/**
|
|
104
|
+
/**
|
|
105
|
+
* 投影 view:活动 + 暂停(同列表;paused 靠 status 区分,dock 原地冻结)。
|
|
106
|
+
*
|
|
107
|
+
* ⚠️ 这里是**唯一**能让「删除暂停项」生效的地方。原因链:
|
|
108
|
+
* - 删除暂停项只清 sidecar、**不写会话事件**(补写 `schedule/change` delete 会
|
|
109
|
+
* 因为该 id 在 pause 时已被删除而抛 `targets inactive id`,把日志读坏);
|
|
110
|
+
* - 投影 cell 只在事件到达时由 `apply` 推进,且跨进程持久化(projcache),
|
|
111
|
+
* 客户端又按 seq「更高者胜」消费控制帧——没有新事件就没有新帧;
|
|
112
|
+
* - 于是 `state.paused` 会永久停留在最后一次事件时的快照上。
|
|
113
|
+
* 因此 view 不能直接信任 `state.paused`,必须**以 sidecar 为准重读**:
|
|
114
|
+
* sidecar 是暂停留档的权威存储(`ownship-store`),`state.paused` 只是镜像。
|
|
115
|
+
* 这样无论 cell 多陈旧,读出来的 paused 列表都与真实留档一致。
|
|
116
|
+
*/
|
|
71
117
|
export declare function viewUserScheduleProjection(state: UserScheduleProjectionState): UserScheduleProjectionValue;
|
|
72
118
|
/**
|
|
73
119
|
* 投影单元声明(传给 sessionProjections.register)。
|
|
@@ -93,6 +139,17 @@ export declare const userSchedulesProjectionUnit: {
|
|
|
93
139
|
createdAt: z.ZodOptional<z.ZodNumber>;
|
|
94
140
|
}, z.core.$loose>>;
|
|
95
141
|
seedSeq: z.ZodNumber;
|
|
142
|
+
paused: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
143
|
+
uid: z.ZodString;
|
|
144
|
+
prompt: z.ZodString;
|
|
145
|
+
delivery: z.ZodUnion<readonly [z.ZodLiteral<"context">, z.ZodLiteral<"user">]>;
|
|
146
|
+
kind: z.ZodLiteral<"after">;
|
|
147
|
+
remainingSeconds: z.ZodNumber;
|
|
148
|
+
originalScheduledAt: z.ZodString;
|
|
149
|
+
originalAfterSeconds: z.ZodOptional<z.ZodNumber>;
|
|
150
|
+
lastScheduleId: z.ZodString;
|
|
151
|
+
pausedAt: z.ZodNumber;
|
|
152
|
+
}, z.core.$strip>>>;
|
|
96
153
|
}, z.core.$strip>;
|
|
97
154
|
readonly init: typeof initUserScheduleProjection;
|
|
98
155
|
readonly apply: typeof applyUserScheduleProjection;
|
|
@@ -107,9 +164,14 @@ export declare const userSchedulesProjectionUnit: {
|
|
|
107
164
|
scheduled_at: z.ZodString;
|
|
108
165
|
created_at: z.ZodOptional<z.ZodString>;
|
|
109
166
|
delivery_mode: z.ZodLiteral<"session-local">;
|
|
167
|
+
status: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"active">, z.ZodLiteral<"paused">]>>;
|
|
168
|
+
remaining_seconds: z.ZodOptional<z.ZodNumber>;
|
|
169
|
+
paused_at: z.ZodOptional<z.ZodString>;
|
|
170
|
+
schedule_id: z.ZodOptional<z.ZodString>;
|
|
171
|
+
window_seconds: z.ZodOptional<z.ZodNumber>;
|
|
110
172
|
}, z.core.$strict>>;
|
|
111
173
|
}, z.core.$strict>;
|
|
112
174
|
readonly view: typeof viewUserScheduleProjection;
|
|
113
175
|
};
|
|
114
|
-
readonly stateVersion:
|
|
176
|
+
readonly stateVersion: 4;
|
|
115
177
|
};
|
package/lib/types/runtime.d.ts
CHANGED
|
@@ -19,6 +19,13 @@ import type { Context } from '@deepseek-ai/cordis';
|
|
|
19
19
|
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
20
20
|
import type { ScheduleRecord, OneShotScheduleRecord, EveryScheduleRecord } from '@deepseek-ai/dsh-schedule';
|
|
21
21
|
import type { UserScheduleDelivery } from './domain.js';
|
|
22
|
+
import type { DeliveryMode } from './delivery.js';
|
|
23
|
+
/** runtime 关心的设置子集(插话投递策略)。 */
|
|
24
|
+
export interface SteerDeliverySettings {
|
|
25
|
+
readonly steerDelivery: DeliveryMode;
|
|
26
|
+
readonly confirmDelivery: boolean;
|
|
27
|
+
readonly onUnconfirmed: 'keep' | 'discard';
|
|
28
|
+
}
|
|
22
29
|
/** 一次「用户提醒决策」:一批同形态到期一次性、或一批到期固定间隔、或下一次等待目标。
|
|
23
30
|
*
|
|
24
31
|
* P1-5:one-shot 从单条改为**同投递形态的批次**——网页关闭期间积压的多条
|
|
@@ -41,10 +48,31 @@ type UserDecision = {
|
|
|
41
48
|
target?: number;
|
|
42
49
|
};
|
|
43
50
|
export declare function dueUserDecision(active: readonly ScheduleRecord[], now: number, delivery?: ReadonlyMap<string, UserScheduleDelivery>): UserDecision;
|
|
51
|
+
/**
|
|
52
|
+
* 多条到期一次性提醒的合并注入 framing(P1-5)。
|
|
53
|
+
* 形状与 dsh-schedule 的固定间隔批次 framing 完全一致:
|
|
54
|
+
* 动态字段全部经 JSON 转义,保持「非信任提醒内容」的防护语义。
|
|
55
|
+
*
|
|
56
|
+
* ⚠️ 这是**上游文案的本地副本**。0.2.0 起 dsh-schedule 把 one-shot 与 recurring
|
|
57
|
+
* 两条 framing 统一收敛为一句 `SCHEDULED_MESSAGE_FRAMING`,取代了此前
|
|
58
|
+
* 「Present all due reminders … not new user instructions.」的长句。
|
|
59
|
+
* 本插件只对**多条合并**这一种上游不提供的形态自渲染(单条走
|
|
60
|
+
* `renderReminderFraming`,自动跟随上游),故此处需手工对齐,否则同一会话里
|
|
61
|
+
* 单条与批次的防护措辞会不一致。
|
|
62
|
+
*/
|
|
63
|
+
export declare function renderOneShotBatchFraming(records: readonly OneShotScheduleRecord[]): string;
|
|
44
64
|
/** 每个 agent 的独立调度器。 */
|
|
45
65
|
export declare class UserScheduleRuntime {
|
|
46
66
|
private readonly ctx;
|
|
47
67
|
private readonly agent;
|
|
68
|
+
/**
|
|
69
|
+
* 读取当前生效设置(每次调用按需取值,与工具/命令同源)。
|
|
70
|
+
*
|
|
71
|
+
* 注入而非直接读 ctx.settings:settings 的注册在 index 的 `ctx.inject(['settings'])`
|
|
72
|
+
* 回调里完成,runtime 拿不到那个 scope;把它做成闭包注入,保证「设置 UI 改了立刻生效」
|
|
73
|
+
* 这一既有语义(`applies: 'live'`)在插话路径上同样成立。
|
|
74
|
+
*/
|
|
75
|
+
private readonly getSettings;
|
|
48
76
|
private readonly stop;
|
|
49
77
|
private resolveStop;
|
|
50
78
|
private timer;
|
|
@@ -55,7 +83,7 @@ export declare class UserScheduleRuntime {
|
|
|
55
83
|
private failures;
|
|
56
84
|
private idleWait;
|
|
57
85
|
private disposal;
|
|
58
|
-
constructor(ctx: Context, agent: Agent);
|
|
86
|
+
constructor(ctx: Context, agent: Agent, getSettings: () => SteerDeliverySettings);
|
|
59
87
|
/** 是否仍为活动 root agent。 */
|
|
60
88
|
private isLive;
|
|
61
89
|
/** 发起一次重算(合并多个触发为一次)。 */
|
|
@@ -95,8 +123,37 @@ export declare class UserScheduleRuntime {
|
|
|
95
123
|
code: string;
|
|
96
124
|
message: string;
|
|
97
125
|
}>;
|
|
126
|
+
/**
|
|
127
|
+
* 按配置把消息投进队列。
|
|
128
|
+
*
|
|
129
|
+
* `followup`(默认)入 `next-turn`:与 `next-step` 是两条独立队列,
|
|
130
|
+
* `claim('next-step', …)` 不触碰它,**结构上不存在**与 `turn/start` 竞争的窗口。
|
|
131
|
+
* `steer` 入 `next-step`,更快但会在撞上回合启动时被吞(见 delivery.ts 注释)。
|
|
132
|
+
*/
|
|
133
|
+
private deliver;
|
|
134
|
+
/**
|
|
135
|
+
* 核对投递是否真正进入会话日志。
|
|
136
|
+
*
|
|
137
|
+
* 关闭确认时直接返回 true(fire-and-forget,保持旧语义)。
|
|
138
|
+
*/
|
|
139
|
+
private verifyDelivery;
|
|
98
140
|
/** 执行一次用户提醒决策与派发。 */
|
|
99
141
|
private driveOnce;
|
|
142
|
+
/**
|
|
143
|
+
* 暂停项的插话投递。
|
|
144
|
+
*
|
|
145
|
+
* 暂停项不在日志里(其日志记录在 pause 时被删),所以从 sidecar 留档取材:
|
|
146
|
+
* `PausedEntry` 已含 `prompt` 与 `delivery`,足以构造消息。呈现方式与
|
|
147
|
+
* {@link buildMessage} 的 one-shot 分支保持一致(`user` 代发 vs `context` 注入),
|
|
148
|
+
* 避免两条路径的语义分叉。
|
|
149
|
+
*
|
|
150
|
+
* 投递成功后清掉留档:提醒已送达,不应再留在待发送列表。这与 dispatch 会把记录
|
|
151
|
+
* 移出 `active` 语义一致。(清留档不写会话事件,故投影不会自动刷新——客户端已用
|
|
152
|
+
* 本地摘除 + 投影对账处理同类情况,与"删除暂停项"同源。)
|
|
153
|
+
*
|
|
154
|
+
* @returns `undefined` 表示该 id 不是暂停项,交由调用方走常规日志路径。
|
|
155
|
+
*/
|
|
156
|
+
private steerPausedById;
|
|
100
157
|
/**
|
|
101
158
|
* 构造注入的消息,按投递形态分流:
|
|
102
159
|
* - `user`(`/later` 显式请求的延迟发送):原样内容 + `source.kind='user'`,
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-schedule 0.1.5 → 0.1.7 的版本桥接层。
|
|
3
|
+
*
|
|
4
|
+
* 0.1.7 对 `dsh-schedule` 做了三处破坏性变更,本模块把差异收敛为三个函数,
|
|
5
|
+
* 使 `user-tools.ts` / `runtime.ts` 不必写版本分支:
|
|
6
|
+
*
|
|
7
|
+
* 1. `allocateScheduleId(folded)` → 删除。0.1.5 用确定性递增
|
|
8
|
+
* (`schedule-1`、`schedule-2`…,靠 `seenIds` 避让),0.1.7 内联改为
|
|
9
|
+
* `ScheduleId(\`schedule-${randomUUID()}\`)`(见 0.1.7 `ScheduleService.create`)。
|
|
10
|
+
* 本插件的 `ownership-store` 把 id 当**不透明字符串**处理(无排序、无数字
|
|
11
|
+
* 解析,见 docs/verification.md),故行为差异对功能无影响。
|
|
12
|
+
*
|
|
13
|
+
* 2. `createAfterScheduleRecord` 新增第 5 个必填参数 `title`。0.1.7 起
|
|
14
|
+
* `decodeStoredTitle` 会在读取时校验:缺失 / 未 trim / 超长(>120)的
|
|
15
|
+
* 存量记录抛 `ScheduleLogError`——**不是跳过,是整份日志拒读**。
|
|
16
|
+
*
|
|
17
|
+
* 3. `renderEveryReminderBatchFraming` → 改名
|
|
18
|
+
* `renderRecurringReminderBatchFraming`(语义与参数不变)。
|
|
19
|
+
*
|
|
20
|
+
* @module dsh-later/schedule-compat
|
|
21
|
+
*/
|
|
22
|
+
import * as sched from '@deepseek-ai/dsh-schedule';
|
|
23
|
+
import type { ScheduleRecord } from '@deepseek-ai/dsh-schedule';
|
|
24
|
+
declare const ScheduleId: typeof sched.ScheduleId;
|
|
25
|
+
/** 0.1.7 `MAX_TITLE_LENGTH`;0.1.5 无此概念,该常量在此仅作截断阈值。 */
|
|
26
|
+
export declare const SCHEDULE_TITLE_MAX = 120;
|
|
27
|
+
/**
|
|
28
|
+
* 0.1.7 的 `allocateScheduleId` 等价物。
|
|
29
|
+
*
|
|
30
|
+
* 随机 UUID 而非递增序号:与官方 `ScheduleService.create` 行为一致,且并发
|
|
31
|
+
* 创建时天然无碰撞。0.1.5 下也可用(`ScheduleId` 是纯 brand 校验,任意
|
|
32
|
+
* 非空字符串通过),因此本函数在两个代次上语义相同,无需双轨。
|
|
33
|
+
*
|
|
34
|
+
* @param _folded 仅为**保持调用点不变**而接受 0.1.5 的 `folded` 参数;0.1.7
|
|
35
|
+
* 不再需要它来避让碰撞(UUID 本身唯一),故不使用。
|
|
36
|
+
*/
|
|
37
|
+
export declare function allocateScheduleIdCompat(_folded?: unknown): ReturnType<typeof ScheduleId>;
|
|
38
|
+
/**
|
|
39
|
+
* 从提醒正文派生 `title`。
|
|
40
|
+
*
|
|
41
|
+
* 0.1.7 要求 title 非空、已 trim、≤120 字符。实测本插件历史 496 条提醒中
|
|
42
|
+
* 最长 575 字符(27 条超限,占 5.4%),故**必须截断**而非直接透传 prompt。
|
|
43
|
+
* 截断在词边界优先,找不到合适边界时按字符硬切并补省略号,保证结果始终
|
|
44
|
+
* 是合法 title(`scheduleTitle` 不会抛)。
|
|
45
|
+
*/
|
|
46
|
+
export declare function deriveScheduleTitle(prompt: string): string;
|
|
47
|
+
/** `createAfterScheduleRecord` 的跨版本包装。 */
|
|
48
|
+
export declare function createAfterRecord(id: ReturnType<typeof ScheduleId>, prompt: string, afterSeconds: number, now: number): ScheduleRecord;
|
|
49
|
+
/** `createAtScheduleRecord` 的跨版本包装。 */
|
|
50
|
+
export declare function createAtRecord(id: ReturnType<typeof ScheduleId>, prompt: string, scheduledAt: string, now: number): ScheduleRecord;
|
|
51
|
+
/** `createEveryScheduleRecord` 的跨版本包装。 */
|
|
52
|
+
export declare function createEveryRecord(id: ReturnType<typeof ScheduleId>, prompt: string, everySeconds: number, now: number): ScheduleRecord;
|
|
53
|
+
/**
|
|
54
|
+
* 周期提醒批次的 framing 渲染。
|
|
55
|
+
*
|
|
56
|
+
* 0.1.5 导出 `renderEveryReminderBatchFraming`,0.1.7 改名为
|
|
57
|
+
* `renderRecurringReminderBatchFraming`(并扩展到 daily/weekly/cron,本插件
|
|
58
|
+
* 只产生 `every` 记录)。两代参数与返回结构一致,按存在性择一。
|
|
59
|
+
*/
|
|
60
|
+
export declare function renderRecurringBatchFraming(reminders: readonly unknown[]): string;
|
|
61
|
+
/**
|
|
62
|
+
* 提醒注入消息的 `source`。
|
|
63
|
+
*
|
|
64
|
+
* 0.1.5 的 `MessageSourceMap` 含 `plugin: { kind:'plugin'; plugin:string }`;
|
|
65
|
+
* 0.1.7 **删除了 `plugin` 与 `host` 两个 kind**,改由内核为每个生产者登记
|
|
66
|
+
* 具名 kind。官方 `dsh-schedule` 在 0.1.7 里注入提醒用的正是
|
|
67
|
+
* `source: { kind: 'schedule' }`(见其 `lib/index.js` 的 `agent.followup` 调用点)
|
|
68
|
+
* —— 与本插件投递的语义一致,故 0.1.7 走 `schedule`。
|
|
69
|
+
*
|
|
70
|
+
* `form:'notice'` + `summary` 两代都在(`ContextFormed` 未变),保留。
|
|
71
|
+
*
|
|
72
|
+
* 不能用具名类型断言跨代:source 的字面量 union 在两代不同,断言只会把
|
|
73
|
+
* 编译错误推迟到运行期。
|
|
74
|
+
*/
|
|
75
|
+
export declare function scheduleMessageSource(boundedSummary: string): Record<string, unknown>;
|
|
76
|
+
/**
|
|
77
|
+
* `foldScheduleEvents` 结果的读视图收窄。
|
|
78
|
+
*
|
|
79
|
+
* 0.1.5 的 `FoldedSchedules.active` 是 `ScheduleRecord[]`;0.1.7 改为
|
|
80
|
+
* `LegacyScheduleRecord[]`(title 可选)。本插件只消费 `id` / `kind` /
|
|
81
|
+
* `prompt` / `afterSeconds` / `everySeconds` / `scheduledAt`,这些字段在
|
|
82
|
+
* `Legacy*` 视图中全部存在,故收窄无损。
|
|
83
|
+
*/
|
|
84
|
+
export declare function asLegacySchedules(folded: unknown): {
|
|
85
|
+
readonly active: readonly ScheduleRecord[];
|
|
86
|
+
readonly seenIds: ReadonlySet<string>;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* `schedule/change` 事件里 `create` 操作的载荷类型。
|
|
90
|
+
*
|
|
91
|
+
* 0.1.7 起内核把「事件载荷」与「内部记录」拆成两个类型:
|
|
92
|
+
* - `ScheduleCreateChange.schedule` 是 **`LegacyScheduleRecord`**(title 可选)
|
|
93
|
+
* - `ScheduleRecord` 是 Host 内部的新格式(title 必填,且含 daily/weekly/cron)
|
|
94
|
+
*
|
|
95
|
+
* 本插件只产生 `after` / `at` / `every` 三种(见 buildScheduleRecord),三者都是
|
|
96
|
+
* `Legacy*` 的对应分支去掉「title 必填」后的结果,故结构兼容。
|
|
97
|
+
*
|
|
98
|
+
* 但 TS 层面 `ScheduleRecord`(6 变体联合)对 `LegacyScheduleRecord`(3 变体)
|
|
99
|
+
* 不可赋值——**这不是运行时问题,是联合宽度问题**。故在此显式收窄:本插件
|
|
100
|
+
* 的产出已经过 `createAfter/At/EveryRecord` 限定,不含 daily/weekly/cron。
|
|
101
|
+
*/
|
|
102
|
+
export declare function toChangePayload(record: ScheduleRecord): never;
|
|
103
|
+
/**
|
|
104
|
+
* `foldScheduleEvents().active` 元素的读取侧类型。
|
|
105
|
+
*
|
|
106
|
+
* 0.1.5 直接返回 `ScheduleRecord`;0.1.7 返回 `LegacyScheduleRecord`
|
|
107
|
+
* (title 可选,因为历史事件没有)。本插件读路径只在 title 存在时展示,
|
|
108
|
+
* 缺失时回退到 prompt——故按 Legacy 收窄是**语义正确**的,而非绕过检查。
|
|
109
|
+
*/
|
|
110
|
+
export declare function asLegacyRecords(records: readonly unknown[]): readonly ScheduleRecord[];
|
|
111
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 定时摘要 store:把 {@link buildScheduleSummary} 的纯计算接到宿主 `sessions`
|
|
3
|
+
* 服务上,得到一个**可订阅的公共数据源**。
|
|
4
|
+
*
|
|
5
|
+
* 为什么需要它(issue #17):dsh-later 自己的侧栏 badge 与外部插件(如
|
|
6
|
+
* dsh-group-status)都需要「全会话定时任务摘要」。两条独立通路会各自订阅
|
|
7
|
+
* `sessions.list`、各自周期 `refresh()`,既浪费 RPC 又容易漂移。本 store 是
|
|
8
|
+
* **唯一**的数据权威:内部负责列表订阅、状态 tick(scheduled→urgent→overdue)
|
|
9
|
+
* 与 `session.list` 读 RPC 补时效;外部只读 {@link ScheduleSummaryStore.getSnapshot}
|
|
10
|
+
* 或订阅变更。
|
|
11
|
+
*
|
|
12
|
+
* 跨插件使用方式(消费方声明 `dsh.client.external: ["dsh-later"]` 后):
|
|
13
|
+
* ```js
|
|
14
|
+
* const later = require('dsh-later/client')
|
|
15
|
+
* const store = later.getScheduleSummaryStore()
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* 本模块零 DOM / 零 React 依赖(`document` / `window` 一律经 `globalThis`
|
|
19
|
+
* 结构化探测),宿主 tsc 与浏览器 esbuild 都能编译,`node --test` 也能直接跑。
|
|
20
|
+
* @module dsh-later/schedule-summary-store
|
|
21
|
+
*/
|
|
22
|
+
import { type ScheduleSummaryMap, type ScheduleSummarySource } from './schedule-summary.js';
|
|
23
|
+
/** 摘要状态重算周期(本地时钟,零网络)。 */
|
|
24
|
+
export declare const SUMMARY_STATE_TICK_MS = 30000;
|
|
25
|
+
/** `session.list` 重拉周期(读 RPC;仅页面可见时执行)。 */
|
|
26
|
+
export declare const SUMMARY_REFRESH_INTERVAL_MS = 60000;
|
|
27
|
+
/** 宿主 `sessions` 服务的结构子集(只用到列表快照与 refresh)。 */
|
|
28
|
+
export interface ScheduleSummarySessionsLike {
|
|
29
|
+
/** 会话列表 store(快照 + 变更订阅)。 */
|
|
30
|
+
readonly list: {
|
|
31
|
+
getSnapshot(): ScheduleSummarySource;
|
|
32
|
+
subscribe(listener: () => void): () => void;
|
|
33
|
+
};
|
|
34
|
+
/** 重拉会话列表(读 RPC,不写会话日志)。 */
|
|
35
|
+
refresh(): Promise<unknown>;
|
|
36
|
+
}
|
|
37
|
+
/** 可订阅的定时摘要 store。 */
|
|
38
|
+
export interface ScheduleSummaryStore {
|
|
39
|
+
/** 当前摘要(引用稳定;内容变化时才换成新对象)。 */
|
|
40
|
+
getSnapshot(): ScheduleSummaryMap;
|
|
41
|
+
/** 订阅变更;返回退订函数。 */
|
|
42
|
+
subscribe(listener: () => void): () => void;
|
|
43
|
+
/** 立即按最新会话列表快照重算(内容有变化才通知)。 */
|
|
44
|
+
reload(): void;
|
|
45
|
+
/** 释放订阅/定时器(宿主卸载时调用)。 */
|
|
46
|
+
dispose(): void;
|
|
47
|
+
}
|
|
48
|
+
export interface ScheduleSummaryStoreOptions {
|
|
49
|
+
/** 状态重算周期(毫秒);缺省 {@link SUMMARY_STATE_TICK_MS}。 */
|
|
50
|
+
readonly stateTickMs?: number;
|
|
51
|
+
/** 会话列表重拉周期(毫秒);缺省 {@link SUMMARY_REFRESH_INTERVAL_MS}。 */
|
|
52
|
+
readonly refreshIntervalMs?: number;
|
|
53
|
+
/** 当前时刻注入(单测用);缺省 `Date.now`。 */
|
|
54
|
+
readonly now?: () => number;
|
|
55
|
+
/** 是否允许发起 refresh RPC;缺省「页面可见时允许」。 */
|
|
56
|
+
readonly canRefresh?: () => boolean;
|
|
57
|
+
/** 是否自动周期 refresh;缺省 true(单测可关)。 */
|
|
58
|
+
readonly autoRefresh?: boolean;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 创建定时摘要 store(宿主 `apply` 内创建一次,全插件共享)。
|
|
62
|
+
* @param sessions - 宿主 `sessions` 服务。
|
|
63
|
+
* @param options - 周期/时钟/刷新策略覆盖(单测用)。
|
|
64
|
+
* @returns 可订阅 store。
|
|
65
|
+
*/
|
|
66
|
+
export declare function createScheduleSummaryStore(sessions: ScheduleSummarySessionsLike, options?: ScheduleSummaryStoreOptions): ScheduleSummaryStore;
|
|
67
|
+
/**
|
|
68
|
+
* 登记/撤销当前 store(由 dsh-later 自身 `apply` 调用;外部插件不要调用)。
|
|
69
|
+
* @param store - 生效的 store;undefined 表示撤销。
|
|
70
|
+
*/
|
|
71
|
+
export declare function setActiveScheduleSummaryStore(store: ScheduleSummaryStore | undefined): void;
|
|
72
|
+
/** 读取当前生效的 store;dsh-later 未加载时为 undefined。 */
|
|
73
|
+
export declare function getScheduleSummaryStore(): ScheduleSummaryStore | undefined;
|
|
74
|
+
/** 订阅 store 登记变化(供 React hook 在 store 迟到时仍能重渲染)。 */
|
|
75
|
+
export declare function subscribeScheduleSummaryStore(listener: () => void): () => void;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 定时任务摘要:dsh-later 对外暴露的**公共数据面**(跨会话 / 跨插件)。
|
|
3
|
+
*
|
|
4
|
+
* 关键事实(本插件「路线 B」的数据源):`userSchedules` 是 client-visible 投影,
|
|
5
|
+
* 宿主在 `session.list` 基线里为**每个**会话携带 projections 块(live 会话走注册
|
|
6
|
+
* 表现值、冷会话走持久化投影缓存),客户端把它合入
|
|
7
|
+
* `SessionSummary.projectionValues`。因此**任何**持有 `sessions` 服务的客户端插件
|
|
8
|
+
* 都能读到全会话的定时任务,本模块只负责把它折叠成稳定形状。
|
|
9
|
+
*
|
|
10
|
+
* 契约形状(issue #17):`Map<SessionId, { count, nextAt, state }>`——即
|
|
11
|
+
* {@link ScheduleSummaryMap}。dsh-later 通过 `dsh-later/client` 导出
|
|
12
|
+
* {@link buildScheduleSummary}(纯函数)、`createScheduleSummaryStore`(可订阅
|
|
13
|
+
* store)与 `useScheduleSummary`(React hook),消费方按需选用。
|
|
14
|
+
*
|
|
15
|
+
* 本模块零 DOM / 零 React 依赖:宿主、浏览器与 `node --test` 都能直接跑。
|
|
16
|
+
* @module dsh-later/schedule-summary
|
|
17
|
+
*/
|
|
18
|
+
import { type PresenceBadgeState, type PresenceScheduleLike, type PresenceSummary } from './presence.js';
|
|
19
|
+
/** `userSchedules` 投影值在 `projectionValues` 里的键名。 */
|
|
20
|
+
export declare const SCHEDULE_PROJECTION_KEY = "userSchedules";
|
|
21
|
+
/**
|
|
22
|
+
* 一条会话的定时摘要:数量 + 下次触发 + 视觉状态。
|
|
23
|
+
*
|
|
24
|
+
* `state` 是**快照时刻**由 {@link badgeStateFor} 判定的结果(`scheduled` /
|
|
25
|
+
* `urgent` ≤5min / `overdue` 已到期未派发),因此 store 每次重算/定时 tick 都会
|
|
26
|
+
* 刷新它;暂停项计入 `count`/`pausedCount`,但**不参与** `nextAt`(见 presence 模块
|
|
27
|
+
* 对暂停语义的说明)。
|
|
28
|
+
*/
|
|
29
|
+
export interface ScheduleSummaryEntry extends PresenceSummary {
|
|
30
|
+
/** 该会话的 badge 状态(按快照时刻判定)。 */
|
|
31
|
+
readonly state: PresenceBadgeState;
|
|
32
|
+
}
|
|
33
|
+
/** 会话 id → 该会话的定时摘要(**仅**包含有任务的会话)。 */
|
|
34
|
+
export type ScheduleSummaryMap = ReadonlyMap<string, ScheduleSummaryEntry>;
|
|
35
|
+
/** 摘要所需的最小会话列表快照面(`SessionListState` 的结构子集)。 */
|
|
36
|
+
export interface ScheduleSummarySource {
|
|
37
|
+
/** 会话 id → 会话行事实(只用到 `projectionValues`)。 */
|
|
38
|
+
readonly byId: Readonly<Record<string, ScheduleSummaryRowLike | undefined>>;
|
|
39
|
+
}
|
|
40
|
+
/** 会话行事实的结构子集。 */
|
|
41
|
+
export interface ScheduleSummaryRowLike {
|
|
42
|
+
/** 该会话的投影现值(含 `userSchedules`)。 */
|
|
43
|
+
readonly projectionValues?: Readonly<Record<string, unknown>>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 从 `projectionValues` 里取出任务数组(容错:形状不对一律当作无任务)。
|
|
47
|
+
* @param projectionValues - 会话行的投影现值集合。
|
|
48
|
+
* @returns 任务数组;缺失或形状非法时 undefined。
|
|
49
|
+
*/
|
|
50
|
+
export declare function schedulesOfProjection(projectionValues: Readonly<Record<string, unknown>> | undefined): readonly PresenceScheduleLike[] | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* 全会话归纳:把会话列表快照折叠成 {@link ScheduleSummaryMap}。
|
|
53
|
+
* @param source - 会话列表快照(`sessions.list.getSnapshot()`)。
|
|
54
|
+
* @param now - 判定 `state` 的当前时刻(epoch ms)。
|
|
55
|
+
* @returns 会话 id → 摘要;无任务的会话不出现在 map 里。
|
|
56
|
+
*/
|
|
57
|
+
export declare function buildScheduleSummary(source: ScheduleSummarySource, now: number): ScheduleSummaryMap;
|
|
58
|
+
/**
|
|
59
|
+
* 两份摘要是否等价(逐条比对五个字段)。store 用它决定是否需要通知订阅者,
|
|
60
|
+
* 避免每次重算都产生新的 Map 引用导致 React 无谓重渲染。
|
|
61
|
+
*
|
|
62
|
+
* `progressFrom` 一并比对:它虽然通常随 `nextAt` 同进同退,但暂停→恢复会让
|
|
63
|
+
* 同一条任务重新拥有窗口起点,此时 `nextAt` 可能未变而窗口已换 —— 漏比会
|
|
64
|
+
* 让进度环停在上一个窗口的比例上。
|
|
65
|
+
* @param a - 旧摘要。
|
|
66
|
+
* @param b - 新摘要。
|
|
67
|
+
* @returns 键集合与每条内容都相同时为 true。
|
|
68
|
+
*/
|
|
69
|
+
export declare function sameScheduleSummary(a: ScheduleSummaryMap, b: ScheduleSummaryMap): boolean;
|
|
70
|
+
/** 分组聚合结果(折叠的工作区分组徽标直接用这一份)。 */
|
|
71
|
+
export interface GroupScheduleSummary {
|
|
72
|
+
/** 组内**有任务**的会话数。 */
|
|
73
|
+
readonly sessions: number;
|
|
74
|
+
/** 组内任务总数(含暂停项)。 */
|
|
75
|
+
readonly count: number;
|
|
76
|
+
/** 组内暂停项数量。 */
|
|
77
|
+
readonly pausedCount: number;
|
|
78
|
+
/** 组内最早触发时刻(epoch ms);全部暂停或缺省时为 undefined。 */
|
|
79
|
+
readonly nextAt?: number;
|
|
80
|
+
/** 组内最高优先级状态(overdue > urgent > scheduled);无任务时为 undefined。 */
|
|
81
|
+
readonly state?: PresenceBadgeState;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 按**分组**聚合摘要:给定组内会话 id,折叠出可直接渲染的分组事实。
|
|
85
|
+
*
|
|
86
|
+
* 消费方(如 dsh-group-status 的 `GroupLiveStatus`)只需把组内会话 id 传进来,
|
|
87
|
+
* 无需理解 `nextAt`/暂停语义。
|
|
88
|
+
* @param summary - {@link ScheduleSummaryMap}。
|
|
89
|
+
* @param sessionIds - 组内会话 id(顺序无关;不在摘要里的会被忽略)。
|
|
90
|
+
* @returns 分组级摘要;组内无任务时 `sessions`/`count` 为 0、`state` 缺省。
|
|
91
|
+
*/
|
|
92
|
+
export declare function summarizeScheduleGroup(summary: ScheduleSummaryMap, sessionIds: Iterable<string>): GroupScheduleSummary;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 上游内核跨代兼容层:把「鸭子类型双轨探测 + peer 代次矩阵」收敛到单文件。
|
|
3
|
+
*
|
|
4
|
+
* 背景(docs/verification.md):DSH 内核 0.1.1 → 0.1.2 之间有多处不兼容,
|
|
5
|
+
* 此前散落在 user-tools / index / package.json 各处。上游每发新 rc 需要:
|
|
6
|
+
* 1. package.json peer + dev 各包补一枚举项(node-semver 不把预发布算进范围)
|
|
7
|
+
* 2. Session API 形状若有变化,只改本模块的 read* 函数
|
|
8
|
+
*
|
|
9
|
+
* 新 rc 落地 checklist:
|
|
10
|
+
* - 在 KERNEL_GENERATIONS 追加一代(id + peerRange + sessionApi)
|
|
11
|
+
* - 跑 `node scripts/sync-peer-matrix.mjs` 重写 package.json peer 枚举
|
|
12
|
+
* - 跑 `npm test`(含 tests/upstream-compat.test.mjs 矩阵护栏)
|
|
13
|
+
*
|
|
14
|
+
* @module dsh-later/upstream-compat
|
|
15
|
+
*/
|
|
16
|
+
import type { Session, SessionEvent } from '@deepseek-ai/dsh-session';
|
|
17
|
+
/**
|
|
18
|
+
* 已验证的内核代次(peer 枚举的唯一事实来源)。
|
|
19
|
+
*
|
|
20
|
+
* - `id`:semver 精确版本(发布 tag)
|
|
21
|
+
* - `peerRange`:写入 package.json 的范围(node-semver 预发布需显式枚举)
|
|
22
|
+
* - `sessionApi`:Session 读日志的形状(见 readOwnEvents / readInheritedEventCount)
|
|
23
|
+
*/
|
|
24
|
+
export declare const KERNEL_GENERATIONS: readonly [{
|
|
25
|
+
readonly id: "0.1.1-rc.2";
|
|
26
|
+
readonly peerRange: "^0.1.1-rc.2";
|
|
27
|
+
readonly sessionApi: "legacy-events";
|
|
28
|
+
}, {
|
|
29
|
+
readonly id: "0.1.2-rc.1";
|
|
30
|
+
readonly peerRange: "^0.1.2-rc.1";
|
|
31
|
+
readonly sessionApi: "own-events";
|
|
32
|
+
}, {
|
|
33
|
+
/**
|
|
34
|
+
* `0.1.5` 代次:Session 形状未变(仍 `ownEvents()` + `inheritedEventCount`),
|
|
35
|
+
* 且插件依赖的 `dsh-schedule` 导出面完整 —— 实测 `rc.1/rc.2/rc.3` 逐个
|
|
36
|
+
* `import()` 全部 15 个 host 模块均通过(见 docs/verification.md)。
|
|
37
|
+
*/
|
|
38
|
+
readonly id: "0.1.5-rc.1";
|
|
39
|
+
readonly peerRange: "^0.1.5-rc.1";
|
|
40
|
+
readonly sessionApi: "own-events";
|
|
41
|
+
}, {
|
|
42
|
+
/**
|
|
43
|
+
* `0.1.7` 代次:Session 形状仍未变(`ownEvents()` + `inheritedEventCount`);
|
|
44
|
+
* `dsh-schedule` 的三处破坏性变更(`allocateScheduleId` 删除、
|
|
45
|
+
* `renderEveryReminderBatchFraming` 改名 `renderRecurringReminderBatchFraming`、
|
|
46
|
+
* `createAfterScheduleRecord` 新增必填 `title`)**全部收敛在
|
|
47
|
+
* `schedule-compat.ts`**——调用点 `user-tools.ts` / `runtime.ts` 不含版本分支。
|
|
48
|
+
*
|
|
49
|
+
* 三条差异在 bridge 里按「存在性择一」(framing)或「统一用新语义」
|
|
50
|
+
* (UUID id、title 派生)处理,两代行为一致,故可安全同时声明这两个范围。
|
|
51
|
+
*
|
|
52
|
+
* 不单列 0.1.6-alpha.*:alpha 线无独立兼容面,且 0.1.7 已覆盖其功能面。
|
|
53
|
+
*/
|
|
54
|
+
readonly id: "0.1.7-rc.2";
|
|
55
|
+
readonly peerRange: "^0.1.7-rc.2";
|
|
56
|
+
readonly sessionApi: "own-events";
|
|
57
|
+
}, {
|
|
58
|
+
/**
|
|
59
|
+
* `0.2.0` 代次:内核跨了次版本号(0.1 → 0.2),但本插件依赖的 API 面
|
|
60
|
+
* **全部保持**。逐项核对(见 docs/verification.md「0.2.0 兼容核对」):
|
|
61
|
+
*
|
|
62
|
+
* - Session:形状未变(`ownEvents()` + `inheritedEventCount`)
|
|
63
|
+
* - dsh-schedule:0.1.7 的三处破坏性变更即为 0.2.0 现状;`foldScheduleEvents`
|
|
64
|
+
* / `renderReminderFraming` / `resolveEveryOccurrence` / `decodeScheduleChange`
|
|
65
|
+
* / `scheduleView` / `ScheduleId` 导出面完整,且
|
|
66
|
+
* `renderRecurringReminderBatchFraming` 仍在 —— `schedule-compat.ts` 无需改动
|
|
67
|
+
* - dsh-llm:`createUserMessage` / `boundContextSummary` 仍在;`MessageSourceMap`
|
|
68
|
+
* 已无 `plugin` kind,仅剩 user/model/tool/system-prompt,而 dsh-schedule
|
|
69
|
+
* 声明的 `schedule` kind 经 module augmentation 并入 —— 0.1.7 分支继续适用
|
|
70
|
+
* - dsh-agent:`followup()`(next-turn)与 `steer()`(next-step)语义未变
|
|
71
|
+
* - dsh-tools:`defineTool` 仍在
|
|
72
|
+
*
|
|
73
|
+
* 实证:以 0.2.0-rc.2 类型面对 `src/**`(host 端)跑 `tsc --noEmit` **零错误**,
|
|
74
|
+
* 且本地 183 项测试全绿。
|
|
75
|
+
*
|
|
76
|
+
* 附带影响:0.2.0 内核开始**强制**校验本范围(peer 不满足即整插件不加载,
|
|
77
|
+
* 此前只是警告)。故这一代次的缺失曾让插件在 0.2.0 上完全失效。
|
|
78
|
+
*/
|
|
79
|
+
readonly id: "0.2.0-rc.2";
|
|
80
|
+
readonly peerRange: "^0.2.0-rc.2";
|
|
81
|
+
readonly sessionApi: "own-events";
|
|
82
|
+
}];
|
|
83
|
+
/**
|
|
84
|
+
* 随内核代次一起 bump 的 peer 包(宿主 hoisting 变化会波及这些运行时 import)。
|
|
85
|
+
* cordis / schemastery 等独立 semver 包**不**列入——它们不随内核 rc 枚举。
|
|
86
|
+
*/
|
|
87
|
+
export declare const KERNEL_SCOPED_PACKAGES: readonly ["@deepseek-ai/dsh-agent", "@deepseek-ai/dsh-commands", "@deepseek-ai/dsh-llm", "@deepseek-ai/dsh-schedule", "@deepseek-ai/dsh-session", "@deepseek-ai/dsh-session-projection", "@deepseek-ai/dsh-settings", "@deepseek-ai/dsh-tools"];
|
|
88
|
+
/** 由 KERNEL_GENERATIONS 拼出的 peer 范围串(`a || b`)。 */
|
|
89
|
+
export declare function peerRangeFor(packageName: string): string;
|
|
90
|
+
/** 全部需逐代枚举的 `{ package, range }`(sync-peer-matrix / 矩阵测试共用)。 */
|
|
91
|
+
export declare function peerMatrixEntries(): ReadonlyArray<{
|
|
92
|
+
packageName: string;
|
|
93
|
+
range: string;
|
|
94
|
+
}>;
|
|
95
|
+
/** Session 读日志的最小结构(鸭子类型;两代公有面)。 */
|
|
96
|
+
export interface SessionLogSurface {
|
|
97
|
+
readonly header?: {
|
|
98
|
+
readonly seedLength?: unknown;
|
|
99
|
+
} | undefined;
|
|
100
|
+
readonly events?: readonly SessionEvent[] | undefined;
|
|
101
|
+
readonly ownEvents?: (() => readonly SessionEvent[]) | undefined;
|
|
102
|
+
readonly inheritedEventCount?: unknown;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 读取「本会话自有」事件日志(不含 fork 继承前缀时由调用方配合 offset)。
|
|
106
|
+
*
|
|
107
|
+
* - 0.1.2+:`session.ownEvents()`(推荐;仅 live 段)
|
|
108
|
+
* - 0.1.1:`session.events`(含 seed;配合 seedLength 切片)
|
|
109
|
+
*/
|
|
110
|
+
export declare function readOwnEvents(session: SessionLogSurface | Session): readonly SessionEvent[];
|
|
111
|
+
/**
|
|
112
|
+
* 读取「fork 继承前缀长度」——`foldScheduleEvents` 第二参数。
|
|
113
|
+
*
|
|
114
|
+
* - 0.1.2+:`session.inheritedEventCount`(SessionLogOffset 品牌数字,运行时仍是 number)
|
|
115
|
+
* - 0.1.1:`session.header.seedLength`(等价物;此前实现漏了这条回退)
|
|
116
|
+
* - 均缺失:0(新建会话 / 测试假 Session)
|
|
117
|
+
*
|
|
118
|
+
* 统一以裸 `number` 返回:cache key 可用 `===`;传入 foldScheduleEvents 时
|
|
119
|
+
* 0.1.2 的 brandshape 校验接受 safe integer。
|
|
120
|
+
*/
|
|
121
|
+
export declare function readInheritedEventCount(session: SessionLogSurface | Session): number;
|
|
122
|
+
/** 探测到的 sessionApi 代次(诊断 / 测试用;不参与业务分支)。 */
|
|
123
|
+
export declare function detectSessionApi(session: SessionLogSurface | Session): 'own-events' | 'legacy-events';
|