@xgjktech/xg-openclaw-shared 0.2.2 → 0.2.4

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.
@@ -0,0 +1,37 @@
1
+ import type { ActionDispatchEvent } from "./action-types.js";
2
+ export interface ActionStore {
3
+ get(eventId: string): ActionDispatchEvent | undefined;
4
+ set(event: ActionDispatchEvent): void;
5
+ delete(eventId: string): void;
6
+ list(): ActionDispatchEvent[];
7
+ listActionsByOrigin(origin: {
8
+ channel: string;
9
+ to: string;
10
+ }): ActionDispatchEvent[];
11
+ }
12
+ export declare class ActionStoreError extends Error {
13
+ constructor(message: string, options?: {
14
+ cause?: unknown;
15
+ });
16
+ }
17
+ /**
18
+ * SqliteActionStore:动作指令的唯一写者。读写走事务,异常一律转 ActionStoreError。
19
+ */
20
+ export declare class SqliteActionStore implements ActionStore {
21
+ private readonly db;
22
+ constructor(dbPath: string);
23
+ close(): void;
24
+ get(eventId: string): ActionDispatchEvent | undefined;
25
+ set(event: ActionDispatchEvent): void;
26
+ delete(eventId: string): void;
27
+ list(): ActionDispatchEvent[];
28
+ listActionsByOrigin(origin: {
29
+ channel: string;
30
+ to: string;
31
+ }): ActionDispatchEvent[];
32
+ }
33
+ /**
34
+ * IM 侧只读入口:以 readOnly 模式打开同一 DB,杜绝误写。
35
+ */
36
+ export declare function openActionStoreReadonly(dbPath: string): Pick<ActionStore, "get" | "list" | "listActionsByOrigin">;
37
+ //# sourceMappingURL=action-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-store.d.ts","sourceRoot":"","sources":["../src/action-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAAC;IACtD,GAAG,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACtC,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,IAAI,IAAI,mBAAmB,EAAE,CAAC;IAC9B,mBAAmB,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,mBAAmB,EAAE,CAAC;CACrF;AAED,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAI3D;AAsJD;;GAEG;AACH,qBAAa,iBAAkB,YAAW,WAAW;IACnD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAe;gBAEtB,MAAM,EAAE,MAAM;IAI1B,KAAK,IAAI,IAAI;IAIb,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAIrD,GAAG,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;IAyCrC,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQ7B,IAAI,IAAI,mBAAmB,EAAE;IAI7B,mBAAmB,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,mBAAmB,EAAE;CAGpF;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,GACb,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,MAAM,GAAG,qBAAqB,CAAC,CAkB3D"}
@@ -0,0 +1,202 @@
1
+ import { DatabaseSync } from "node:sqlite";
2
+ export class ActionStoreError extends Error {
3
+ constructor(message, options) {
4
+ super(message, options);
5
+ this.name = "ActionStoreError";
6
+ }
7
+ }
8
+ const BUSY_TIMEOUT_MS = 5000;
9
+ const MAX_RETAIN_RECORDS = 1000;
10
+ const RETENTION_MS = 7 * 24 * 60 * 60 * 1000; // 7 天
11
+ const CREATE_TABLE_SQL = `
12
+ CREATE TABLE IF NOT EXISTS actions (
13
+ event_id TEXT PRIMARY KEY,
14
+ action TEXT NOT NULL,
15
+ target TEXT NOT NULL,
16
+ version INTEGER NOT NULL,
17
+ origin_channel TEXT,
18
+ origin_to TEXT,
19
+ created_at TEXT NOT NULL,
20
+ doc TEXT NOT NULL
21
+ ) STRICT;
22
+ `;
23
+ const CREATE_INDEX_CREATED_AT_SQL = `
24
+ CREATE INDEX IF NOT EXISTS idx_actions_created_at ON actions(created_at);
25
+ `;
26
+ const CREATE_INDEX_ORIGIN_SQL = `
27
+ CREATE INDEX IF NOT EXISTS idx_actions_origin ON actions(origin_channel, origin_to);
28
+ `;
29
+ function listColumnNames(db) {
30
+ const rows = db.prepare("PRAGMA table_info(actions);").all();
31
+ return new Set(rows.map((row) => row.name));
32
+ }
33
+ function parseActionDoc(row) {
34
+ try {
35
+ return JSON.parse(row.doc);
36
+ }
37
+ catch (cause) {
38
+ throw new ActionStoreError(`action ${row.event_id} 的 doc 列不是合法 JSON`, { cause });
39
+ }
40
+ }
41
+ function ensureSchema(db) {
42
+ db.exec(CREATE_TABLE_SQL);
43
+ db.exec(CREATE_INDEX_CREATED_AT_SQL);
44
+ db.exec(CREATE_INDEX_ORIGIN_SQL);
45
+ }
46
+ function openDatabase(dbPath, options) {
47
+ try {
48
+ const db = new DatabaseSync(dbPath, { readOnly: options.readOnly });
49
+ db.exec(`PRAGMA busy_timeout = ${BUSY_TIMEOUT_MS};`);
50
+ if (!options.readOnly) {
51
+ db.exec("PRAGMA journal_mode = WAL;");
52
+ ensureSchema(db);
53
+ }
54
+ return db;
55
+ }
56
+ catch (cause) {
57
+ throw new ActionStoreError(`打开 ActionStore 数据库失败: ${dbPath}`, { cause });
58
+ }
59
+ }
60
+ function readActionRow(db, eventId) {
61
+ return db
62
+ .prepare("SELECT event_id, action, target, version, origin_channel, origin_to, created_at, doc FROM actions WHERE event_id = ?")
63
+ .get(eventId);
64
+ }
65
+ function readAllActionRows(db) {
66
+ return db
67
+ .prepare("SELECT event_id, action, target, version, origin_channel, origin_to, created_at, doc FROM actions ORDER BY created_at DESC")
68
+ .all();
69
+ }
70
+ function readActionRowsByOrigin(db, origin) {
71
+ return db
72
+ .prepare(`SELECT event_id, action, target, version, origin_channel, origin_to, created_at, doc FROM actions
73
+ WHERE origin_channel = ? AND origin_to = ?
74
+ ORDER BY created_at DESC`)
75
+ .all(origin.channel, origin.to);
76
+ }
77
+ function getAction(db, eventId, errorPrefix) {
78
+ try {
79
+ const row = readActionRow(db, eventId);
80
+ return row === undefined ? undefined : parseActionDoc(row);
81
+ }
82
+ catch (cause) {
83
+ if (cause instanceof ActionStoreError)
84
+ throw cause;
85
+ throw new ActionStoreError(`${errorPrefix} action ${eventId} 失败`, { cause });
86
+ }
87
+ }
88
+ function listActions(db, errorPrefix) {
89
+ try {
90
+ return readAllActionRows(db).map((row) => parseActionDoc(row));
91
+ }
92
+ catch (cause) {
93
+ if (cause instanceof ActionStoreError)
94
+ throw cause;
95
+ throw new ActionStoreError(`${errorPrefix} action 列表失败`, { cause });
96
+ }
97
+ }
98
+ function listActionsByOrigin(db, origin, errorPrefix) {
99
+ try {
100
+ return readActionRowsByOrigin(db, origin).map((row) => parseActionDoc(row));
101
+ }
102
+ catch (cause) {
103
+ if (cause instanceof ActionStoreError)
104
+ throw cause;
105
+ throw new ActionStoreError(`${errorPrefix} action 按 origin 列表失败`, { cause });
106
+ }
107
+ }
108
+ function runTtlCleanup(db, nowMs) {
109
+ const cutoffIso = new Date(nowMs - RETENTION_MS).toISOString();
110
+ db.prepare("DELETE FROM actions WHERE created_at < ?").run(cutoffIso);
111
+ db.prepare(`DELETE FROM actions WHERE event_id NOT IN (
112
+ SELECT event_id FROM actions ORDER BY created_at DESC LIMIT ${MAX_RETAIN_RECORDS}
113
+ )`).run();
114
+ }
115
+ /**
116
+ * SqliteActionStore:动作指令的唯一写者。读写走事务,异常一律转 ActionStoreError。
117
+ */
118
+ export class SqliteActionStore {
119
+ db;
120
+ constructor(dbPath) {
121
+ this.db = openDatabase(dbPath, { readOnly: false });
122
+ }
123
+ close() {
124
+ this.db.close();
125
+ }
126
+ get(eventId) {
127
+ return getAction(this.db, eventId, "读取");
128
+ }
129
+ set(event) {
130
+ try {
131
+ this.db.exec("BEGIN IMMEDIATE");
132
+ try {
133
+ const createdAt = event.timestamp ?? new Date().toISOString();
134
+ this.db
135
+ .prepare(`INSERT INTO actions (event_id, action, target, version, origin_channel, origin_to, created_at, doc)
136
+ VALUES (@eventId, @action, @target, @version, @originChannel, @originTo, @createdAt, @doc)
137
+ ON CONFLICT(event_id) DO UPDATE SET
138
+ action = excluded.action,
139
+ target = excluded.target,
140
+ version = excluded.version,
141
+ origin_channel = excluded.origin_channel,
142
+ origin_to = excluded.origin_to,
143
+ created_at = excluded.created_at,
144
+ doc = excluded.doc`)
145
+ .run({
146
+ eventId: event.eventId,
147
+ action: event.action,
148
+ target: event.target,
149
+ version: event.version,
150
+ originChannel: event.origin?.channel ?? null,
151
+ originTo: event.origin?.to ?? null,
152
+ createdAt: createdAt,
153
+ doc: JSON.stringify(event),
154
+ });
155
+ runTtlCleanup(this.db, Date.now());
156
+ this.db.exec("COMMIT");
157
+ }
158
+ catch (cause) {
159
+ this.db.exec("ROLLBACK");
160
+ throw cause;
161
+ }
162
+ }
163
+ catch (cause) {
164
+ throw new ActionStoreError(`写入 action ${event.eventId} 失败`, { cause });
165
+ }
166
+ }
167
+ delete(eventId) {
168
+ try {
169
+ this.db.prepare("DELETE FROM actions WHERE event_id = ?").run(eventId);
170
+ }
171
+ catch (cause) {
172
+ throw new ActionStoreError(`删除 action ${eventId} 失败`, { cause });
173
+ }
174
+ }
175
+ list() {
176
+ return listActions(this.db, "列出");
177
+ }
178
+ listActionsByOrigin(origin) {
179
+ return listActionsByOrigin(this.db, origin, "列出");
180
+ }
181
+ }
182
+ /**
183
+ * IM 侧只读入口:以 readOnly 模式打开同一 DB,杜绝误写。
184
+ */
185
+ export function openActionStoreReadonly(dbPath) {
186
+ const db = openDatabase(dbPath, { readOnly: true });
187
+ return {
188
+ get(eventId) {
189
+ return getAction(db, eventId, "只读读取");
190
+ },
191
+ list() {
192
+ return listActions(db, "只读列出");
193
+ },
194
+ listActionsByOrigin(origin) {
195
+ const columns = listColumnNames(db);
196
+ if (!columns.has("origin_channel") || !columns.has("origin_to")) {
197
+ return [];
198
+ }
199
+ return listActionsByOrigin(db, origin, "只读列出");
200
+ },
201
+ };
202
+ }
@@ -0,0 +1,28 @@
1
+ import type { PlanOrigin } from "./plan-types.js";
2
+ export type ActionStatus = "completed" | "running" | "pending" | "failed";
3
+ export interface ActionScopeControl {
4
+ activeSessionOnly?: boolean;
5
+ }
6
+ export interface ActionDispatchPayload {
7
+ data: Record<string, unknown>;
8
+ }
9
+ export interface ActionDispatchEvent {
10
+ eventId: string;
11
+ event: "action_dispatch";
12
+ action: string;
13
+ topic?: string;
14
+ target: string;
15
+ version: number;
16
+ status: ActionStatus;
17
+ scopeControl?: ActionScopeControl;
18
+ payload: ActionDispatchPayload;
19
+ timestamp: string;
20
+ origin?: PlanOrigin;
21
+ }
22
+ export declare class ActionInvariantError extends Error {
23
+ constructor(message: string);
24
+ }
25
+ export declare function isActionStatus(value: unknown): value is ActionStatus;
26
+ export declare function isActionDispatchEvent(value: unknown): value is ActionDispatchEvent;
27
+ export declare function assertActionDispatchEventInvariants(event: ActionDispatchEvent): void;
28
+ //# sourceMappingURL=action-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-types.d.ts","sourceRoot":"","sources":["../src/action-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAI1E,MAAM,WAAW,kBAAkB;IACjC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,iBAAiB,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,YAAY,CAAC;IACrB,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,OAAO,EAAE,qBAAqB,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAEpE;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,mBAAmB,CA+BlF;AAED,wBAAgB,mCAAmC,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI,CAkCpF"}
@@ -0,0 +1,83 @@
1
+ const ACTION_STATUSES = ["completed", "running", "pending", "failed"];
2
+ export class ActionInvariantError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "ActionInvariantError";
6
+ }
7
+ }
8
+ export function isActionStatus(value) {
9
+ return typeof value === "string" && ACTION_STATUSES.includes(value);
10
+ }
11
+ export function isActionDispatchEvent(value) {
12
+ if (typeof value !== "object" || value === null) {
13
+ return false;
14
+ }
15
+ const evt = value;
16
+ if (typeof evt["eventId"] !== "string" || evt["eventId"].trim() === "")
17
+ return false;
18
+ if (evt["event"] !== "action_dispatch")
19
+ return false;
20
+ if (typeof evt["action"] !== "string" || evt["action"].trim() === "")
21
+ return false;
22
+ if (evt["topic"] !== undefined && typeof evt["topic"] !== "string")
23
+ return false;
24
+ if (typeof evt["target"] !== "string" || evt["target"].trim() === "")
25
+ return false;
26
+ if (typeof evt["version"] !== "number" || !Number.isFinite(evt["version"]) || evt["version"] <= 0) {
27
+ return false;
28
+ }
29
+ if (!isActionStatus(evt["status"]))
30
+ return false;
31
+ if (evt["scopeControl"] !== undefined) {
32
+ if (typeof evt["scopeControl"] !== "object" || evt["scopeControl"] === null)
33
+ return false;
34
+ const scopeCtrl = evt["scopeControl"];
35
+ if (scopeCtrl["activeSessionOnly"] !== undefined &&
36
+ typeof scopeCtrl["activeSessionOnly"] !== "boolean") {
37
+ return false;
38
+ }
39
+ }
40
+ if (typeof evt["payload"] !== "object" || evt["payload"] === null)
41
+ return false;
42
+ const payload = evt["payload"];
43
+ if (typeof payload["data"] !== "object" || payload["data"] === null)
44
+ return false;
45
+ if (typeof evt["timestamp"] !== "string" || evt["timestamp"].trim() === "")
46
+ return false;
47
+ return true;
48
+ }
49
+ export function assertActionDispatchEventInvariants(event) {
50
+ if (typeof event.eventId !== "string" || event.eventId.trim() === "") {
51
+ throw new ActionInvariantError("eventId 不能为空");
52
+ }
53
+ if (event.event !== "action_dispatch") {
54
+ throw new ActionInvariantError(`event 必须为 'action_dispatch',实际为: ${event.event}`);
55
+ }
56
+ if (typeof event.action !== "string" || event.action.trim() === "") {
57
+ throw new ActionInvariantError("action 不能为空");
58
+ }
59
+ if (event.topic !== undefined && typeof event.topic !== "string") {
60
+ throw new ActionInvariantError("topic 类型必须为 string");
61
+ }
62
+ if (typeof event.target !== "string" || event.target.trim() === "") {
63
+ throw new ActionInvariantError("target 不能为空");
64
+ }
65
+ if (event.target.length > 128) {
66
+ throw new ActionInvariantError("target 长度不能超过 128");
67
+ }
68
+ if (typeof event.version !== "number" || !Number.isFinite(event.version) || event.version <= 0) {
69
+ throw new ActionInvariantError(`version 取值非法: ${event.version}`);
70
+ }
71
+ if (!isActionStatus(event.status)) {
72
+ throw new ActionInvariantError(`status 取值非法: ${event.status}`);
73
+ }
74
+ if (typeof event.payload !== "object" || event.payload === null) {
75
+ throw new ActionInvariantError("payload 必须是非空对象");
76
+ }
77
+ if (typeof event.payload.data !== "object" || event.payload.data === null) {
78
+ throw new ActionInvariantError("payload.data 必须是非空对象");
79
+ }
80
+ if (typeof event.timestamp !== "string" || event.timestamp.trim() === "") {
81
+ throw new ActionInvariantError("timestamp 不能为空");
82
+ }
83
+ }
package/dist/index.d.ts CHANGED
@@ -4,4 +4,8 @@ export type { PlanStore, PlanSummary } from "./plan-store.js";
4
4
  export { SqlitePlanStore, openPlanStoreReadonly, resolvePlanDbPath, PlanStoreError } from "./plan-store.js";
5
5
  export type { PlanEventPayload, PlanEventSummary } from "./plan-events.js";
6
6
  export { planEventStream, isPlanEventPayload } from "./plan-events.js";
7
+ export type { ActionStatus, ActionScopeControl, ActionDispatchPayload, ActionDispatchEvent, } from "./action-types.js";
8
+ export { ActionInvariantError, isActionStatus, isActionDispatchEvent, assertActionDispatchEventInvariants, } from "./action-types.js";
9
+ export type { ActionStore } from "./action-store.js";
10
+ export { SqliteActionStore, openActionStoreReadonly, ActionStoreError } from "./action-store.js";
7
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5F,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE5F,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE5G,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5F,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE5F,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE5G,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEvE,YAAY,EACV,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,qBAAqB,EACrB,mCAAmC,GACpC,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js CHANGED
@@ -2,3 +2,5 @@
2
2
  export { assertPlanInvariants, isPlanCancelled, PlanInvariantError } from "./plan-types.js";
3
3
  export { SqlitePlanStore, openPlanStoreReadonly, resolvePlanDbPath, PlanStoreError } from "./plan-store.js";
4
4
  export { planEventStream, isPlanEventPayload } from "./plan-events.js";
5
+ export { ActionInvariantError, isActionStatus, isActionDispatchEvent, assertActionDispatchEventInvariants, } from "./action-types.js";
6
+ export { SqliteActionStore, openActionStoreReadonly, ActionStoreError } from "./action-store.js";
@@ -11,7 +11,7 @@ export interface PlanEventSummary {
11
11
  inProgress: number;
12
12
  }
13
13
  /**
14
- * plan_execute 推进后发出的事件 payload(缝隙 A 定义,两插件共用)。
14
+ * 计划推进后发出的事件 payload(缝隙 A 定义,两插件共用;当前事件链路休眠,仅编译兼容保留)。
15
15
  * 路由定位字段(deliveryContext/agentAccountId/messageChannel/sessionKey)均可选:
16
16
  * 能从工具工厂 ctx 取到就带,取不到就省略——事件是尽力而为,不因缺字段而阻断。
17
17
  */
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@xgjktech/xg-openclaw-shared",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "xgjktech OpenClaw 插件共享层:Plan 数据模型/不变量、SQLite PlanStore、计划事件契约",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "engines": {
8
- "node": ">=22.19.0"
8
+ "node": ">=22.22.3 <23 || >=24.15.0 <25 || >=25.9.0"
9
9
  },
10
10
  "exports": {
11
11
  ".": {
@@ -22,6 +22,8 @@
22
22
  "registry": "https://registry.npmjs.org/"
23
23
  },
24
24
  "scripts": {
25
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
26
+ "prebuild": "npm run clean",
25
27
  "build": "tsc -p tsconfig.json",
26
28
  "typecheck": "tsc -p tsconfig.json --noEmit",
27
29
  "pretest": "npm run build",