sage-mem 0.7.2 → 0.8.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.
@@ -1,461 +1,461 @@
1
- /**
2
- * sage-mem — 手写 strict typert host manifest。
3
- * typert-loader 在插件挂载时读 package.json 的 exports["./typert"],
4
- * import 本文件并把 TYPERT 注册进 ctx.typert.local(strict 定义)。
5
- * schema 必须是 zod v4 实例(typert-loader 校验 "_zod" in schema)。
6
- */
7
- import { z } from 'zod'
8
-
9
- // 文件名:与 host 侧 safeName 同一套底线 —— 非空、无路径分隔符与 Windows 非法字符、
10
- // 以 .md 结尾、长度有界。(真正的目录逃逸防护仍在 host 侧 safeName。)
11
- const fileNameSchema = z.string().min(1).max(255).regex(/^[^\\/:*?"<>|\u0000-\u001f]+\.md$/)
12
- // 正文:512 KB 上限。理由是「记忆要塞进 system prompt」——单条正常量级在几十 KB,
13
- // 到半兆量级基本是写错了目标(贴了日志/代码进来)。与 lib/index.js 的 MAX_FILE_BYTES 一致。
14
- const fileContentSchema = z.string().max(512 * 1024)
15
-
16
- // autodream 报告引用:比 fileNameSchema 宽——旧版报告列表里的条目带 `dream/` 前缀
17
- // (新版 `autodream/` 不加前缀只给裸文件名)。这里放行斜杠,真正的目录逃逸防护
18
- // 在 host 侧 AutodreamEngine.readReport 里(先剥已知前缀、再对 basename 走 safeName)。
19
- const reportRefSchema = z.string().min(1).max(320)
20
-
21
- const starmapStarSchema = z.object({
22
- 'file': z.string().readonly(),
23
- 'kind': z.string().readonly(),
24
- 'title': z.string().readonly(),
25
- 'desc': z.string().readonly(),
26
- 'bytes': z.number().readonly(),
27
- 'mtimeMs': z.number().readonly(),
28
- }).readonly()
29
- const starmapListSchema = z.object({
30
- 'count': z.number().readonly(),
31
- 'stars': z.array(starmapStarSchema).readonly(),
32
- }).readonly()
33
- const starmapReadSchema = z.object({
34
- 'name': z.string().readonly(),
35
- 'content': z.string().readonly(),
36
- }).readonly()
37
-
38
- const fileSchema = z.object({
39
- 'file': z.string().readonly(),
40
- 'type': z.string().readonly(),
41
- 'description': z.string().readonly(),
42
- 'size': z.number().readonly(),
43
- // 自定义标签:来自 frontmatter 的 tags(flow / block / 逗号三种写法都收)。
44
- // strict 模式下 host 多返回的字段会被剥掉,所以「列表页要能按标签筛」这件事
45
- // 必须在这里显式声明,否则前端永远拿到 undefined。
46
- 'tags': z.array(z.string()).readonly(),
47
- }).readonly()
48
-
49
- const listResultSchema = z.array(fileSchema)
50
- const readResultSchema = z.object({
51
- 'name': z.string().readonly(),
52
- 'content': z.string().readonly(),
53
- }).readonly()
54
- // 写/删失败不再抛异常,走 { ok: false, error } 分支:error 必须声明,否则 strict
55
- // 校验会把它当未知字段剥掉,设置页只能看到一个没有原因的 ok:false。
56
- const writeResultSchema = z.object({
57
- 'ok': z.boolean().readonly(),
58
- 'file': z.string().readonly(),
59
- 'error': z.string().readonly().optional(),
60
- }).readonly()
61
- const deleteResultSchema = z.object({
62
- 'ok': z.boolean().readonly(),
63
- 'error': z.string().readonly().optional(),
64
- }).readonly()
65
-
66
- // ── autodream(夜间记忆整理)───────────────────────────────────────────────
67
- // 配置的每一项都可写;lastResult 是一个「成功/失败两条分支共用」的结构,
68
- // 所以除了三个必有字段外全是 optional —— 用 strict 校验两种形态的并集,
69
- // 比给成功与失败各来一套 schema 少一半维护面。
70
- const autodreamConfigSchema = z.object({
71
- 'enabled': z.boolean().readonly(),
72
- 'trigger': z.string().readonly(),
73
- 'apply': z.boolean().readonly(),
74
- 'source': z.string().readonly(),
75
- 'minHours': z.number().readonly(),
76
- 'minSessions': z.number().readonly(),
77
- 'provider': z.string().readonly(),
78
- 'model': z.string().readonly(),
79
- 'maxSteps': z.number().readonly(),
80
- 'maxSnapshotKeep': z.number().readonly(),
81
- 'rollbackScope': z.string().readonly(),
82
- }).readonly()
83
-
84
- const autodreamPathsSchema = z.object({
85
- 'memoryDir': z.string().readonly(),
86
- 'configPath': z.string().readonly(),
87
- 'stateRoot': z.string().readonly(),
88
- 'home': z.string().readonly(),
89
- }).readonly()
90
-
91
- const autodreamRouteSchema = z.object({
92
- 'provider': z.string().readonly(),
93
- 'model': z.string().readonly(),
94
- 'fromDefault': z.boolean().readonly(),
95
- 'source': z.string().readonly(),
96
- 'error': z.string().readonly().nullable(),
97
- }).readonly()
98
-
99
- const autodreamLastResultSchema = z.object({
100
- 'at': z.number().readonly(),
101
- 'atHuman': z.string().readonly(),
102
- 'ok': z.boolean().readonly(),
103
- 'apply': z.boolean().readonly().optional(),
104
- 'error': z.string().readonly().optional(),
105
- 'touched': z.array(z.string()).readonly().optional(),
106
- 'problemsBefore': z.number().readonly().optional(),
107
- 'problemsAfter': z.number().readonly().optional(),
108
- 'tokensIn': z.number().readonly().optional(),
109
- 'tokensOut': z.number().readonly().optional(),
110
- 'runId': z.string().readonly().optional(),
111
- 'changeCount': z.number().readonly().optional(),
112
- 'preflight': z.boolean().readonly().optional(),
113
- 'snapshotId': z.string().readonly().nullable().optional(),
114
- 'report': z.string().readonly().optional(),
115
- }).readonly()
116
-
117
- const autodreamConfigResultSchema = z.object({
118
- 'config': autodreamConfigSchema,
119
- 'route': autodreamRouteSchema.nullable(),
120
- 'lastRunAt': z.number().readonly(),
121
- 'lastResult': autodreamLastResultSchema.nullable(),
122
- 'paths': autodreamPathsSchema,
123
- 'defaults': autodreamConfigSchema,
124
- }).readonly()
125
-
126
- const autodreamStepSchema = z.object({
127
- 'step': z.number().readonly(),
128
- 'tools': z.array(z.string()).readonly(),
129
- 'chars': z.number().readonly(),
130
- 'at': z.number().readonly(),
131
- }).readonly()
132
-
133
- const autodreamStatusSchema = z.object({
134
- 'running': z.boolean().readonly(),
135
- 'phase': z.string().readonly(),
136
- 'startedAt': z.number().readonly(),
137
- 'runId': z.string().readonly(),
138
- 'steps': z.array(autodreamStepSchema).readonly(),
139
- 'config': autodreamConfigSchema,
140
- 'route': autodreamRouteSchema.nullable(),
141
- 'lastRunAt': z.number().readonly(),
142
- 'hoursSince': z.number().readonly().nullable(),
143
- 'lastResult': autodreamLastResultSchema.nullable(),
144
- 'retryAfter': z.number().readonly(),
145
- 'gate': z.object({ 'minHours': z.number().readonly(), 'minSessions': z.number().readonly() }).readonly().nullable(),
146
- 'paths': autodreamPathsSchema,
147
- }).readonly()
148
-
149
- const autodreamRunResultSchema = z.object({
150
- 'ok': z.boolean().readonly(),
151
- 'error': z.string().readonly().optional(),
152
- 'report': z.string().readonly().optional(),
153
- 'touched': z.array(z.string()).readonly().optional(),
154
- 'runId': z.string().readonly().optional(),
155
- 'changeCount': z.number().readonly().optional(),
156
- 'snapshotId': z.string().readonly().nullable().optional(),
157
- }).readonly()
158
-
159
- // setConfig 的补丁:全部 optional —— 设置面板每次只改动一项,传整个对象反而
160
- // 容易把没碰过的字段用旧值覆盖回去。
161
- const autodreamPatchSchema = z.object({
162
- 'enabled': z.boolean().optional(),
163
- 'trigger': z.string().optional(),
164
- 'apply': z.boolean().optional(),
165
- 'source': z.string().optional(),
166
- 'minHours': z.number().optional(),
167
- 'minSessions': z.number().optional(),
168
- 'provider': z.string().optional(),
169
- 'model': z.string().optional(),
170
- 'maxSteps': z.number().optional(),
171
- 'maxSnapshotKeep': z.number().optional(),
172
- 'rollbackScope': z.string().optional(),
173
- }).readonly()
174
-
175
- const reportListSchema = z.array(z.object({
176
- 'name': z.string().readonly(),
177
- 'bytes': z.number().readonly(),
178
- 'at': z.number().readonly(),
179
- 'atHuman': z.string().readonly(),
180
- 'legacy': z.boolean().readonly(),
181
- }).readonly()).readonly()
182
-
183
- const snapshotListSchema = z.array(z.object({
184
- 'name': z.string().readonly(),
185
- 'at': z.number().readonly(),
186
- 'atHuman': z.string().readonly(),
187
- 'files': z.number().readonly(),
188
- 'path': z.string().readonly(),
189
- 'runId': z.string().readonly().nullable(),
190
- 'kind': z.string().readonly(),
191
- 'legacy': z.boolean().readonly(),
192
- }).readonly()).readonly()
193
-
194
- // ── autodream 回滚点 / 整理声明 / 模型目录(2026-10-01 新增)──
195
- // 「运行」是这四样东西的共同线索:runId 同时是快照目录名、运行记录目录名与报告文件名,
196
- // 所以 listRuns 的一条记录能把「改了哪些文件、为什么、能不能退」一次串起来。
197
- const runListSchema = z.array(z.object({
198
- 'runId': z.string().readonly(),
199
- 'at': z.number().readonly(),
200
- 'atHuman': z.string().readonly(),
201
- 'mode': z.string().readonly(),
202
- 'reason': z.string().readonly(),
203
- 'changeCount': z.number().readonly(),
204
- 'report': z.string().readonly().nullable(),
205
- 'snapshotId': z.string().readonly().nullable(),
206
- 'snapshotAvailable': z.boolean().readonly(),
207
- 'rolledBackAt': z.number().readonly(),
208
- 'rolledBackAtHuman': z.string().readonly(),
209
- }).readonly()).readonly()
210
-
211
- // manifest 是机读记录,字段面宽且在演进;这里用宽松对象接住,
212
- // 前端的「整理声明」区只读 markdown,manifest 留给后续工具消费。
213
- const declarationSchema = z.object({
214
- 'runId': z.string().readonly(),
215
- 'markdown': z.string().readonly(),
216
- 'manifest': z.unknown(),
217
- }).readonly()
218
-
219
- const rollbackResultSchema = z.object({
220
- 'ok': z.boolean().readonly(),
221
- 'error': z.string().readonly().optional(),
222
- 'restored': z.number().readonly().optional(),
223
- 'parked': z.number().readonly().optional(),
224
- 'skipped': z.number().readonly().optional(),
225
- 'protection': z.string().readonly().optional(),
226
- 'report': z.string().readonly().optional(),
227
- }).readonly()
228
-
229
- const modelListSchema = z.object({
230
- 'routes': z.array(z.object({
231
- 'provider': z.string().readonly(),
232
- 'model': z.string().readonly(),
233
- 'label': z.string().readonly(),
234
- 'isDefault': z.boolean().readonly(),
235
- }).readonly()).readonly(),
236
- 'defaultRoute': z.object({
237
- 'provider': z.string().readonly(),
238
- 'model': z.string().readonly(),
239
- }).readonly().nullable(),
240
- 'catalogAvailable': z.boolean().readonly(),
241
- 'note': z.string().readonly(),
242
- }).readonly()
243
-
244
- // 四个新方法的入参形状不同,但都是「一个对象参数」;合并成一个全 optional 的 schema,
245
- // 免得为每个方法各写一份。注意 zod 默认会**丢掉未声明的键**,所以用到的字段必须在这里列全。
246
- const autodreamOptsSchema = z.object({
247
- 'reason': z.string().optional(),
248
- 'limit': z.number().optional(),
249
- 'runId': z.string().optional(),
250
- 'snapshotId': z.string().optional(),
251
- 'scope': z.string().optional(),
252
- }).readonly()
253
-
254
- export const TYPERT = {
255
- package: 'sage-mem',
256
- face: 'host',
257
- schemas: [],
258
- invocations: [
259
- {
260
- id: 'sage-mem#memory/listFiles',
261
- service: 'memory',
262
- namespace: 'memory',
263
- method: 'listFiles',
264
- invocation: { kind: 'direct' },
265
- parameters: [],
266
- result: { mode: 'strict', typeSymbol: 'sage-mem/types#FileList', schema: listResultSchema, create: () => listResultSchema },
267
- sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
268
- },
269
- {
270
- id: 'sage-mem#memory/readFile',
271
- service: 'memory',
272
- namespace: 'memory',
273
- method: 'readFile',
274
- invocation: { kind: 'direct' },
275
- parameters: [
276
- { name: 'name', wire: 'name', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#FileName', schema: fileNameSchema, create: () => fileNameSchema } },
277
- ],
278
- result: { mode: 'strict', typeSymbol: 'sage-mem/types#FileContent', schema: readResultSchema, create: () => readResultSchema },
279
- sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
280
- },
281
- {
282
- id: 'sage-mem#memory/writeFile',
283
- service: 'memory',
284
- namespace: 'memory',
285
- method: 'writeFile',
286
- invocation: { kind: 'direct' },
287
- parameters: [
288
- { name: 'name', wire: 'name', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#FileName', schema: fileNameSchema, create: () => fileNameSchema } },
289
- { name: 'content', wire: 'content', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#FileContent', schema: fileContentSchema, create: () => fileContentSchema } },
290
- ],
291
- result: { mode: 'strict', typeSymbol: 'sage-mem/types#WriteResult', schema: writeResultSchema, create: () => writeResultSchema },
292
- sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
293
- },
294
- {
295
- id: 'sage-mem#memory/deleteFile',
296
- service: 'memory',
297
- namespace: 'memory',
298
- method: 'deleteFile',
299
- invocation: { kind: 'direct' },
300
- parameters: [
301
- { name: 'name', wire: 'name', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#FileName', schema: fileNameSchema, create: () => fileNameSchema } },
302
- ],
303
- result: { mode: 'strict', typeSymbol: 'sage-mem/types#DeleteResult', schema: deleteResultSchema, create: () => deleteResultSchema },
304
- sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
305
- },
306
- {
307
- id: 'sage-mem#starmap/listStars',
308
- service: 'starmap',
309
- namespace: 'starmap',
310
- method: 'listStars',
311
- invocation: { kind: 'direct' },
312
- parameters: [],
313
- result: { mode: 'strict', typeSymbol: 'sage-mem/types#StarmapList', schema: starmapListSchema, create: () => starmapListSchema },
314
- sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
315
- },
316
- {
317
- id: 'sage-mem#starmap/readFile',
318
- service: 'starmap',
319
- namespace: 'starmap',
320
- method: 'readFile',
321
- invocation: { kind: 'direct' },
322
- parameters: [
323
- { name: 'name', wire: 'name', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#FileName', schema: fileNameSchema, create: () => fileNameSchema } },
324
- ],
325
- result: { mode: 'strict', typeSymbol: 'sage-mem/types#StarmapRead', schema: starmapReadSchema, create: () => starmapReadSchema },
326
- sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
327
- },
328
- // ── autodream 的七个方法 ──
329
- // 全部挂在 package `sage-mem` 下(和 memory 同一份 manifest),
330
- // 所以前端直接 ctx.get('remote.autodream') 就能用,不需要像 starmap 那样
331
- // 在 client 侧再 $mount 一次 —— 那个 mount 是因为 starmap 当年是独立包
332
- // (package: 'sage-starmap'),合并进 sage-mem 后一直没改回来。
333
- {
334
- id: 'sage-mem#autodream/getConfig',
335
- service: 'autodream',
336
- namespace: 'autodream',
337
- method: 'getConfig',
338
- invocation: { kind: 'direct' },
339
- parameters: [],
340
- result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamConfigResult', schema: autodreamConfigResultSchema, create: () => autodreamConfigResultSchema },
341
- sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
342
- },
343
- {
344
- id: 'sage-mem#autodream/setConfig',
345
- service: 'autodream',
346
- namespace: 'autodream',
347
- method: 'setConfig',
348
- invocation: { kind: 'direct' },
349
- parameters: [
350
- { name: 'patch', wire: 'patch', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamPatch', schema: autodreamPatchSchema, create: () => autodreamPatchSchema } },
351
- ],
352
- result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamConfigResult', schema: autodreamConfigResultSchema, create: () => autodreamConfigResultSchema },
353
- sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
354
- },
355
- {
356
- id: 'sage-mem#autodream/status',
357
- service: 'autodream',
358
- namespace: 'autodream',
359
- method: 'status',
360
- invocation: { kind: 'direct' },
361
- parameters: [],
362
- result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamStatus', schema: autodreamStatusSchema, create: () => autodreamStatusSchema },
363
- sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
364
- },
365
- {
366
- id: 'sage-mem#autodream/runNow',
367
- service: 'autodream',
368
- namespace: 'autodream',
369
- method: 'runNow',
370
- invocation: { kind: 'direct' },
371
- parameters: [
372
- { name: 'opts', wire: 'opts', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamOpts', schema: autodreamOptsSchema, create: () => autodreamOptsSchema } },
373
- ],
374
- result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamRunResult', schema: autodreamRunResultSchema, create: () => autodreamRunResultSchema },
375
- sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
376
- },
377
- {
378
- id: 'sage-mem#autodream/listReports',
379
- service: 'autodream',
380
- namespace: 'autodream',
381
- method: 'listReports',
382
- invocation: { kind: 'direct' },
383
- parameters: [],
384
- result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamReportList', schema: reportListSchema, create: () => reportListSchema },
385
- sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
386
- },
387
- {
388
- id: 'sage-mem#autodream/readReport',
389
- service: 'autodream',
390
- namespace: 'autodream',
391
- method: 'readReport',
392
- invocation: { kind: 'direct' },
393
- parameters: [
394
- { name: 'name', wire: 'name', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamReportRef', schema: reportRefSchema, create: () => reportRefSchema } },
395
- ],
396
- result: { mode: 'strict', typeSymbol: 'sage-mem/types#FileContent', schema: readResultSchema, create: () => readResultSchema },
397
- sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
398
- },
399
- {
400
- id: 'sage-mem#autodream/listSnapshots',
401
- service: 'autodream',
402
- namespace: 'autodream',
403
- method: 'listSnapshots',
404
- invocation: { kind: 'direct' },
405
- parameters: [],
406
- result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamSnapshotList', schema: snapshotListSchema, create: () => snapshotListSchema },
407
- sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
408
- },
409
- {
410
- id: 'sage-mem#autodream/listRuns',
411
- service: 'autodream',
412
- namespace: 'autodream',
413
- method: 'listRuns',
414
- invocation: { kind: 'direct' },
415
- parameters: [
416
- { name: 'opts', wire: 'opts', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamOpts', schema: autodreamOptsSchema, create: () => autodreamOptsSchema } },
417
- ],
418
- result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamRunList', schema: runListSchema, create: () => runListSchema },
419
- sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
420
- },
421
- {
422
- id: 'sage-mem#autodream/readDeclaration',
423
- service: 'autodream',
424
- namespace: 'autodream',
425
- method: 'readDeclaration',
426
- invocation: { kind: 'direct' },
427
- parameters: [
428
- { name: 'opts', wire: 'opts', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamOpts', schema: autodreamOptsSchema, create: () => autodreamOptsSchema } },
429
- ],
430
- result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamDeclaration', schema: declarationSchema, create: () => declarationSchema },
431
- sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
432
- },
433
- {
434
- id: 'sage-mem#autodream/rollback',
435
- service: 'autodream',
436
- namespace: 'autodream',
437
- method: 'rollback',
438
- invocation: { kind: 'direct' },
439
- parameters: [
440
- { name: 'opts', wire: 'opts', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamOpts', schema: autodreamOptsSchema, create: () => autodreamOptsSchema } },
441
- ],
442
- result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamRollbackResult', schema: rollbackResultSchema, create: () => rollbackResultSchema },
443
- sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
444
- },
445
- {
446
- id: 'sage-mem#autodream/listModels',
447
- service: 'autodream',
448
- namespace: 'autodream',
449
- method: 'listModels',
450
- invocation: { kind: 'direct' },
451
- parameters: [],
452
- result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamModelList', schema: modelListSchema, create: () => modelListSchema },
453
- sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
454
- },
455
- ],
456
- model: {
457
- "services": [],
458
- "events": [],
459
- "objects": [],
460
- },
461
- }
1
+ /**
2
+ * sage-mem — 手写 strict typert host manifest。
3
+ * typert-loader 在插件挂载时读 package.json 的 exports["./typert"],
4
+ * import 本文件并把 TYPERT 注册进 ctx.typert.local(strict 定义)。
5
+ * schema 必须是 zod v4 实例(typert-loader 校验 "_zod" in schema)。
6
+ */
7
+ import { z } from 'zod'
8
+
9
+ // 文件名:与 host 侧 safeName 同一套底线 —— 非空、无路径分隔符与 Windows 非法字符、
10
+ // 以 .md 结尾、长度有界。(真正的目录逃逸防护仍在 host 侧 safeName。)
11
+ const fileNameSchema = z.string().min(1).max(255).regex(/^[^\\/:*?"<>|\u0000-\u001f]+\.md$/)
12
+ // 正文:512 KB 上限。理由是「记忆要塞进 system prompt」——单条正常量级在几十 KB,
13
+ // 到半兆量级基本是写错了目标(贴了日志/代码进来)。与 lib/index.js 的 MAX_FILE_BYTES 一致。
14
+ const fileContentSchema = z.string().max(512 * 1024)
15
+
16
+ // autodream 报告引用:比 fileNameSchema 宽——旧版报告列表里的条目带 `dream/` 前缀
17
+ // (新版 `autodream/` 不加前缀只给裸文件名)。这里放行斜杠,真正的目录逃逸防护
18
+ // 在 host 侧 AutodreamEngine.readReport 里(先剥已知前缀、再对 basename 走 safeName)。
19
+ const reportRefSchema = z.string().min(1).max(320)
20
+
21
+ const starmapStarSchema = z.object({
22
+ 'file': z.string().readonly(),
23
+ 'kind': z.string().readonly(),
24
+ 'title': z.string().readonly(),
25
+ 'desc': z.string().readonly(),
26
+ 'bytes': z.number().readonly(),
27
+ 'mtimeMs': z.number().readonly(),
28
+ }).readonly()
29
+ const starmapListSchema = z.object({
30
+ 'count': z.number().readonly(),
31
+ 'stars': z.array(starmapStarSchema).readonly(),
32
+ }).readonly()
33
+ const starmapReadSchema = z.object({
34
+ 'name': z.string().readonly(),
35
+ 'content': z.string().readonly(),
36
+ }).readonly()
37
+
38
+ const fileSchema = z.object({
39
+ 'file': z.string().readonly(),
40
+ 'type': z.string().readonly(),
41
+ 'description': z.string().readonly(),
42
+ 'size': z.number().readonly(),
43
+ // 自定义标签:来自 frontmatter 的 tags(flow / block / 逗号三种写法都收)。
44
+ // strict 模式下 host 多返回的字段会被剥掉,所以「列表页要能按标签筛」这件事
45
+ // 必须在这里显式声明,否则前端永远拿到 undefined。
46
+ 'tags': z.array(z.string()).readonly(),
47
+ }).readonly()
48
+
49
+ const listResultSchema = z.array(fileSchema)
50
+ const readResultSchema = z.object({
51
+ 'name': z.string().readonly(),
52
+ 'content': z.string().readonly(),
53
+ }).readonly()
54
+ // 写/删失败不再抛异常,走 { ok: false, error } 分支:error 必须声明,否则 strict
55
+ // 校验会把它当未知字段剥掉,设置页只能看到一个没有原因的 ok:false。
56
+ const writeResultSchema = z.object({
57
+ 'ok': z.boolean().readonly(),
58
+ 'file': z.string().readonly(),
59
+ 'error': z.string().readonly().optional(),
60
+ }).readonly()
61
+ const deleteResultSchema = z.object({
62
+ 'ok': z.boolean().readonly(),
63
+ 'error': z.string().readonly().optional(),
64
+ }).readonly()
65
+
66
+ // ── autodream(夜间记忆整理)───────────────────────────────────────────────
67
+ // 配置的每一项都可写;lastResult 是一个「成功/失败两条分支共用」的结构,
68
+ // 所以除了三个必有字段外全是 optional —— 用 strict 校验两种形态的并集,
69
+ // 比给成功与失败各来一套 schema 少一半维护面。
70
+ const autodreamConfigSchema = z.object({
71
+ 'enabled': z.boolean().readonly(),
72
+ 'trigger': z.string().readonly(),
73
+ 'apply': z.boolean().readonly(),
74
+ 'source': z.string().readonly(),
75
+ 'minHours': z.number().readonly(),
76
+ 'minSessions': z.number().readonly(),
77
+ 'provider': z.string().readonly(),
78
+ 'model': z.string().readonly(),
79
+ 'maxSteps': z.number().readonly(),
80
+ 'maxSnapshotKeep': z.number().readonly(),
81
+ 'rollbackScope': z.string().readonly(),
82
+ }).readonly()
83
+
84
+ const autodreamPathsSchema = z.object({
85
+ 'memoryDir': z.string().readonly(),
86
+ 'configPath': z.string().readonly(),
87
+ 'stateRoot': z.string().readonly(),
88
+ 'home': z.string().readonly(),
89
+ }).readonly()
90
+
91
+ const autodreamRouteSchema = z.object({
92
+ 'provider': z.string().readonly(),
93
+ 'model': z.string().readonly(),
94
+ 'fromDefault': z.boolean().readonly(),
95
+ 'source': z.string().readonly(),
96
+ 'error': z.string().readonly().nullable(),
97
+ }).readonly()
98
+
99
+ const autodreamLastResultSchema = z.object({
100
+ 'at': z.number().readonly(),
101
+ 'atHuman': z.string().readonly(),
102
+ 'ok': z.boolean().readonly(),
103
+ 'apply': z.boolean().readonly().optional(),
104
+ 'error': z.string().readonly().optional(),
105
+ 'touched': z.array(z.string()).readonly().optional(),
106
+ 'problemsBefore': z.number().readonly().optional(),
107
+ 'problemsAfter': z.number().readonly().optional(),
108
+ 'tokensIn': z.number().readonly().optional(),
109
+ 'tokensOut': z.number().readonly().optional(),
110
+ 'runId': z.string().readonly().optional(),
111
+ 'changeCount': z.number().readonly().optional(),
112
+ 'preflight': z.boolean().readonly().optional(),
113
+ 'snapshotId': z.string().readonly().nullable().optional(),
114
+ 'report': z.string().readonly().optional(),
115
+ }).readonly()
116
+
117
+ const autodreamConfigResultSchema = z.object({
118
+ 'config': autodreamConfigSchema,
119
+ 'route': autodreamRouteSchema.nullable(),
120
+ 'lastRunAt': z.number().readonly(),
121
+ 'lastResult': autodreamLastResultSchema.nullable(),
122
+ 'paths': autodreamPathsSchema,
123
+ 'defaults': autodreamConfigSchema,
124
+ }).readonly()
125
+
126
+ const autodreamStepSchema = z.object({
127
+ 'step': z.number().readonly(),
128
+ 'tools': z.array(z.string()).readonly(),
129
+ 'chars': z.number().readonly(),
130
+ 'at': z.number().readonly(),
131
+ }).readonly()
132
+
133
+ const autodreamStatusSchema = z.object({
134
+ 'running': z.boolean().readonly(),
135
+ 'phase': z.string().readonly(),
136
+ 'startedAt': z.number().readonly(),
137
+ 'runId': z.string().readonly(),
138
+ 'steps': z.array(autodreamStepSchema).readonly(),
139
+ 'config': autodreamConfigSchema,
140
+ 'route': autodreamRouteSchema.nullable(),
141
+ 'lastRunAt': z.number().readonly(),
142
+ 'hoursSince': z.number().readonly().nullable(),
143
+ 'lastResult': autodreamLastResultSchema.nullable(),
144
+ 'retryAfter': z.number().readonly(),
145
+ 'gate': z.object({ 'minHours': z.number().readonly(), 'minSessions': z.number().readonly() }).readonly().nullable(),
146
+ 'paths': autodreamPathsSchema,
147
+ }).readonly()
148
+
149
+ const autodreamRunResultSchema = z.object({
150
+ 'ok': z.boolean().readonly(),
151
+ 'error': z.string().readonly().optional(),
152
+ 'report': z.string().readonly().optional(),
153
+ 'touched': z.array(z.string()).readonly().optional(),
154
+ 'runId': z.string().readonly().optional(),
155
+ 'changeCount': z.number().readonly().optional(),
156
+ 'snapshotId': z.string().readonly().nullable().optional(),
157
+ }).readonly()
158
+
159
+ // setConfig 的补丁:全部 optional —— 设置面板每次只改动一项,传整个对象反而
160
+ // 容易把没碰过的字段用旧值覆盖回去。
161
+ const autodreamPatchSchema = z.object({
162
+ 'enabled': z.boolean().optional(),
163
+ 'trigger': z.string().optional(),
164
+ 'apply': z.boolean().optional(),
165
+ 'source': z.string().optional(),
166
+ 'minHours': z.number().optional(),
167
+ 'minSessions': z.number().optional(),
168
+ 'provider': z.string().optional(),
169
+ 'model': z.string().optional(),
170
+ 'maxSteps': z.number().optional(),
171
+ 'maxSnapshotKeep': z.number().optional(),
172
+ 'rollbackScope': z.string().optional(),
173
+ }).readonly()
174
+
175
+ const reportListSchema = z.array(z.object({
176
+ 'name': z.string().readonly(),
177
+ 'bytes': z.number().readonly(),
178
+ 'at': z.number().readonly(),
179
+ 'atHuman': z.string().readonly(),
180
+ 'legacy': z.boolean().readonly(),
181
+ }).readonly()).readonly()
182
+
183
+ const snapshotListSchema = z.array(z.object({
184
+ 'name': z.string().readonly(),
185
+ 'at': z.number().readonly(),
186
+ 'atHuman': z.string().readonly(),
187
+ 'files': z.number().readonly(),
188
+ 'path': z.string().readonly(),
189
+ 'runId': z.string().readonly().nullable(),
190
+ 'kind': z.string().readonly(),
191
+ 'legacy': z.boolean().readonly(),
192
+ }).readonly()).readonly()
193
+
194
+ // ── autodream 回滚点 / 整理声明 / 模型目录(新增)──
195
+ // 「运行」是这四样东西的共同线索:runId 同时是快照目录名、运行记录目录名与报告文件名,
196
+ // 所以 listRuns 的一条记录能把「改了哪些文件、为什么、能不能退」一次串起来。
197
+ const runListSchema = z.array(z.object({
198
+ 'runId': z.string().readonly(),
199
+ 'at': z.number().readonly(),
200
+ 'atHuman': z.string().readonly(),
201
+ 'mode': z.string().readonly(),
202
+ 'reason': z.string().readonly(),
203
+ 'changeCount': z.number().readonly(),
204
+ 'report': z.string().readonly().nullable(),
205
+ 'snapshotId': z.string().readonly().nullable(),
206
+ 'snapshotAvailable': z.boolean().readonly(),
207
+ 'rolledBackAt': z.number().readonly(),
208
+ 'rolledBackAtHuman': z.string().readonly(),
209
+ }).readonly()).readonly()
210
+
211
+ // manifest 是机读记录,字段面宽且在演进;这里用宽松对象接住,
212
+ // 前端的「整理声明」区只读 markdown,manifest 留给后续工具消费。
213
+ const declarationSchema = z.object({
214
+ 'runId': z.string().readonly(),
215
+ 'markdown': z.string().readonly(),
216
+ 'manifest': z.unknown(),
217
+ }).readonly()
218
+
219
+ const rollbackResultSchema = z.object({
220
+ 'ok': z.boolean().readonly(),
221
+ 'error': z.string().readonly().optional(),
222
+ 'restored': z.number().readonly().optional(),
223
+ 'parked': z.number().readonly().optional(),
224
+ 'skipped': z.number().readonly().optional(),
225
+ 'protection': z.string().readonly().optional(),
226
+ 'report': z.string().readonly().optional(),
227
+ }).readonly()
228
+
229
+ const modelListSchema = z.object({
230
+ 'routes': z.array(z.object({
231
+ 'provider': z.string().readonly(),
232
+ 'model': z.string().readonly(),
233
+ 'label': z.string().readonly(),
234
+ 'isDefault': z.boolean().readonly(),
235
+ }).readonly()).readonly(),
236
+ 'defaultRoute': z.object({
237
+ 'provider': z.string().readonly(),
238
+ 'model': z.string().readonly(),
239
+ }).readonly().nullable(),
240
+ 'catalogAvailable': z.boolean().readonly(),
241
+ 'note': z.string().readonly(),
242
+ }).readonly()
243
+
244
+ // 四个新方法的入参形状不同,但都是「一个对象参数」;合并成一个全 optional 的 schema,
245
+ // 免得为每个方法各写一份。注意 zod 默认会**丢掉未声明的键**,所以用到的字段必须在这里列全。
246
+ const autodreamOptsSchema = z.object({
247
+ 'reason': z.string().optional(),
248
+ 'limit': z.number().optional(),
249
+ 'runId': z.string().optional(),
250
+ 'snapshotId': z.string().optional(),
251
+ 'scope': z.string().optional(),
252
+ }).readonly()
253
+
254
+ export const TYPERT = {
255
+ package: 'sage-mem',
256
+ face: 'host',
257
+ schemas: [],
258
+ invocations: [
259
+ {
260
+ id: 'sage-mem#memory/listFiles',
261
+ service: 'memory',
262
+ namespace: 'memory',
263
+ method: 'listFiles',
264
+ invocation: { kind: 'direct' },
265
+ parameters: [],
266
+ result: { mode: 'strict', typeSymbol: 'sage-mem/types#FileList', schema: listResultSchema, create: () => listResultSchema },
267
+ sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
268
+ },
269
+ {
270
+ id: 'sage-mem#memory/readFile',
271
+ service: 'memory',
272
+ namespace: 'memory',
273
+ method: 'readFile',
274
+ invocation: { kind: 'direct' },
275
+ parameters: [
276
+ { name: 'name', wire: 'name', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#FileName', schema: fileNameSchema, create: () => fileNameSchema } },
277
+ ],
278
+ result: { mode: 'strict', typeSymbol: 'sage-mem/types#FileContent', schema: readResultSchema, create: () => readResultSchema },
279
+ sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
280
+ },
281
+ {
282
+ id: 'sage-mem#memory/writeFile',
283
+ service: 'memory',
284
+ namespace: 'memory',
285
+ method: 'writeFile',
286
+ invocation: { kind: 'direct' },
287
+ parameters: [
288
+ { name: 'name', wire: 'name', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#FileName', schema: fileNameSchema, create: () => fileNameSchema } },
289
+ { name: 'content', wire: 'content', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#FileContent', schema: fileContentSchema, create: () => fileContentSchema } },
290
+ ],
291
+ result: { mode: 'strict', typeSymbol: 'sage-mem/types#WriteResult', schema: writeResultSchema, create: () => writeResultSchema },
292
+ sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
293
+ },
294
+ {
295
+ id: 'sage-mem#memory/deleteFile',
296
+ service: 'memory',
297
+ namespace: 'memory',
298
+ method: 'deleteFile',
299
+ invocation: { kind: 'direct' },
300
+ parameters: [
301
+ { name: 'name', wire: 'name', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#FileName', schema: fileNameSchema, create: () => fileNameSchema } },
302
+ ],
303
+ result: { mode: 'strict', typeSymbol: 'sage-mem/types#DeleteResult', schema: deleteResultSchema, create: () => deleteResultSchema },
304
+ sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
305
+ },
306
+ {
307
+ id: 'sage-mem#starmap/listStars',
308
+ service: 'starmap',
309
+ namespace: 'starmap',
310
+ method: 'listStars',
311
+ invocation: { kind: 'direct' },
312
+ parameters: [],
313
+ result: { mode: 'strict', typeSymbol: 'sage-mem/types#StarmapList', schema: starmapListSchema, create: () => starmapListSchema },
314
+ sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
315
+ },
316
+ {
317
+ id: 'sage-mem#starmap/readFile',
318
+ service: 'starmap',
319
+ namespace: 'starmap',
320
+ method: 'readFile',
321
+ invocation: { kind: 'direct' },
322
+ parameters: [
323
+ { name: 'name', wire: 'name', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#FileName', schema: fileNameSchema, create: () => fileNameSchema } },
324
+ ],
325
+ result: { mode: 'strict', typeSymbol: 'sage-mem/types#StarmapRead', schema: starmapReadSchema, create: () => starmapReadSchema },
326
+ sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
327
+ },
328
+ // ── autodream 的七个方法 ──
329
+ // 全部挂在 package `sage-mem` 下(和 memory 同一份 manifest),
330
+ // 所以前端直接 ctx.get('remote.autodream') 就能用,不需要像 starmap 那样
331
+ // 在 client 侧再 $mount 一次 —— 那个 mount 是因为 starmap 曾是独立包
332
+ // (package: 'sage-starmap'),合并进 sage-mem 后一直没改回来。
333
+ {
334
+ id: 'sage-mem#autodream/getConfig',
335
+ service: 'autodream',
336
+ namespace: 'autodream',
337
+ method: 'getConfig',
338
+ invocation: { kind: 'direct' },
339
+ parameters: [],
340
+ result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamConfigResult', schema: autodreamConfigResultSchema, create: () => autodreamConfigResultSchema },
341
+ sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
342
+ },
343
+ {
344
+ id: 'sage-mem#autodream/setConfig',
345
+ service: 'autodream',
346
+ namespace: 'autodream',
347
+ method: 'setConfig',
348
+ invocation: { kind: 'direct' },
349
+ parameters: [
350
+ { name: 'patch', wire: 'patch', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamPatch', schema: autodreamPatchSchema, create: () => autodreamPatchSchema } },
351
+ ],
352
+ result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamConfigResult', schema: autodreamConfigResultSchema, create: () => autodreamConfigResultSchema },
353
+ sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
354
+ },
355
+ {
356
+ id: 'sage-mem#autodream/status',
357
+ service: 'autodream',
358
+ namespace: 'autodream',
359
+ method: 'status',
360
+ invocation: { kind: 'direct' },
361
+ parameters: [],
362
+ result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamStatus', schema: autodreamStatusSchema, create: () => autodreamStatusSchema },
363
+ sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
364
+ },
365
+ {
366
+ id: 'sage-mem#autodream/runNow',
367
+ service: 'autodream',
368
+ namespace: 'autodream',
369
+ method: 'runNow',
370
+ invocation: { kind: 'direct' },
371
+ parameters: [
372
+ { name: 'opts', wire: 'opts', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamOpts', schema: autodreamOptsSchema, create: () => autodreamOptsSchema } },
373
+ ],
374
+ result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamRunResult', schema: autodreamRunResultSchema, create: () => autodreamRunResultSchema },
375
+ sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
376
+ },
377
+ {
378
+ id: 'sage-mem#autodream/listReports',
379
+ service: 'autodream',
380
+ namespace: 'autodream',
381
+ method: 'listReports',
382
+ invocation: { kind: 'direct' },
383
+ parameters: [],
384
+ result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamReportList', schema: reportListSchema, create: () => reportListSchema },
385
+ sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
386
+ },
387
+ {
388
+ id: 'sage-mem#autodream/readReport',
389
+ service: 'autodream',
390
+ namespace: 'autodream',
391
+ method: 'readReport',
392
+ invocation: { kind: 'direct' },
393
+ parameters: [
394
+ { name: 'name', wire: 'name', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamReportRef', schema: reportRefSchema, create: () => reportRefSchema } },
395
+ ],
396
+ result: { mode: 'strict', typeSymbol: 'sage-mem/types#FileContent', schema: readResultSchema, create: () => readResultSchema },
397
+ sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
398
+ },
399
+ {
400
+ id: 'sage-mem#autodream/listSnapshots',
401
+ service: 'autodream',
402
+ namespace: 'autodream',
403
+ method: 'listSnapshots',
404
+ invocation: { kind: 'direct' },
405
+ parameters: [],
406
+ result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamSnapshotList', schema: snapshotListSchema, create: () => snapshotListSchema },
407
+ sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
408
+ },
409
+ {
410
+ id: 'sage-mem#autodream/listRuns',
411
+ service: 'autodream',
412
+ namespace: 'autodream',
413
+ method: 'listRuns',
414
+ invocation: { kind: 'direct' },
415
+ parameters: [
416
+ { name: 'opts', wire: 'opts', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamOpts', schema: autodreamOptsSchema, create: () => autodreamOptsSchema } },
417
+ ],
418
+ result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamRunList', schema: runListSchema, create: () => runListSchema },
419
+ sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
420
+ },
421
+ {
422
+ id: 'sage-mem#autodream/readDeclaration',
423
+ service: 'autodream',
424
+ namespace: 'autodream',
425
+ method: 'readDeclaration',
426
+ invocation: { kind: 'direct' },
427
+ parameters: [
428
+ { name: 'opts', wire: 'opts', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamOpts', schema: autodreamOptsSchema, create: () => autodreamOptsSchema } },
429
+ ],
430
+ result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamDeclaration', schema: declarationSchema, create: () => declarationSchema },
431
+ sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
432
+ },
433
+ {
434
+ id: 'sage-mem#autodream/rollback',
435
+ service: 'autodream',
436
+ namespace: 'autodream',
437
+ method: 'rollback',
438
+ invocation: { kind: 'direct' },
439
+ parameters: [
440
+ { name: 'opts', wire: 'opts', source: 'json', codec: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamOpts', schema: autodreamOptsSchema, create: () => autodreamOptsSchema } },
441
+ ],
442
+ result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamRollbackResult', schema: rollbackResultSchema, create: () => rollbackResultSchema },
443
+ sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
444
+ },
445
+ {
446
+ id: 'sage-mem#autodream/listModels',
447
+ service: 'autodream',
448
+ namespace: 'autodream',
449
+ method: 'listModels',
450
+ invocation: { kind: 'direct' },
451
+ parameters: [],
452
+ result: { mode: 'strict', typeSymbol: 'sage-mem/types#AutodreamModelList', schema: modelListSchema, create: () => modelListSchema },
453
+ sourceLocation: { "file": "lib/index.js", "line": 1, "column": 1 },
454
+ },
455
+ ],
456
+ model: {
457
+ "services": [],
458
+ "events": [],
459
+ "objects": [],
460
+ },
461
+ }