@longzai-intelligence-kol-markdown/core 0.0.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.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @longzai-intelligence-kol-markdown/core
2
+
3
+ 转换核心:KolContent 行契约镜像、属主导出只读源与 registry 快照读取、确定性渲染(条目档/分区 README/档案/目录册)、平台分区写入、verify 体检、init 数据仓脚手架(含 .lzi skills 真源模板)。
@@ -0,0 +1,871 @@
1
+ import { ConfigLoadError } from "@longzai-intelligence-kol-markdown/config";
2
+ import { KolContent, KolContent as KolContent$1, KolContentSchema, REGISTRY_SNAPSHOT_FILENAME, RegistrySnapshot, RegistrySnapshot as RegistrySnapshot$1, toContentsExportFilename } from "@longzai-intelligence-kol/core";
3
+ import { CatalogRefreshOptions, CatalogRefreshResult as CatalogRefreshResult$1, GitIdentity, HashDrift, RenderedDocument, Result, failure, success } from "@longzai-intelligence-markdown/data-engine";
4
+ import * as z from "zod";
5
+ export * from "@longzai-intelligence-kol-markdown/config";
6
+ //#region src/env/env.schema.d.ts
7
+ /**
8
+ * 台账导出根环境变量名(lzi-kol export-contents 产物父目录)
9
+ */
10
+ declare const ENV_CONTENTS_EXPORT_DIR = "LZI_KOL_MARKDOWN_CONTENTS_EXPORT_DIR";
11
+ /**
12
+ * 环境变量原始 schema(台账导出根必填非空;结构声明与引擎 EnvKit 同源)
13
+ */
14
+ declare const kolMarkdownEnvSchema: z.ZodObject<{
15
+ LZI_KOL_MARKDOWN_CONTENTS_EXPORT_DIR: z.ZodString;
16
+ }, z.core.$strip>;
17
+ /**
18
+ * 解析后的环境配置(绝对路径形态)
19
+ */
20
+ type KolMarkdownEnv = {
21
+ /**
22
+ * 台账导出根绝对路径(其下 <kol-slug>/ 子目录含 contents-<day>.ndjson + registry.json;只读消费)
23
+ */
24
+ readonly contentsExportDir: string;
25
+ };
26
+ /**
27
+ * 环境配置错误(缺失/非法,附缺失变量名清单;引擎 EnvError 形态)
28
+ */
29
+ type EnvError = {
30
+ /**
31
+ * 错误码
32
+ */
33
+ readonly code: 'ENV_INVALID';
34
+ /**
35
+ * 人读错误信息
36
+ */
37
+ readonly message: string;
38
+ /**
39
+ * 缺失或非法的变量名清单
40
+ */
41
+ readonly missing: readonly string[];
42
+ };
43
+ /**
44
+ * 域环境工具族实例(变量声明 + 装配语义;机制由引擎承载)
45
+ */
46
+ declare const envKit: import("@longzai-intelligence-markdown/data-engine").EnvKit<KolMarkdownEnv>;
47
+ /**
48
+ * 从进程环境解析配置(zod 校验 + 绝对路径化;机制经引擎 EnvKit)
49
+ *
50
+ * @param processEnv - 进程环境(缺省 process.env;测试注入)
51
+ * @returns 解析成功为绝对路径形态 env;失败为缺失变量清单错误
52
+ */
53
+ declare function resolveEnv(processEnv?: NodeJS.ProcessEnv): ReturnType<typeof envKit.resolveEnv>;
54
+ /**
55
+ * 供 env-template.utils 消费的域工具族实例(模板渲染与解析同源同族)
56
+ */
57
+ declare const kolMarkdownEnvKit: import("@longzai-intelligence-markdown/data-engine").EnvKit<KolMarkdownEnv>;
58
+ //#endregion
59
+ //#region src/env/env-template.utils.d.ts
60
+ /**
61
+ * .env 模板入参
62
+ */
63
+ type EnvTemplateParams = {
64
+ /**
65
+ * 台账导出根(缺省取中性占位符;生成真实 .env 时应显式传入)
66
+ */
67
+ readonly contentsExportDir?: string;
68
+ /**
69
+ * 模板标题(缺省工具名;数据仓 .env.example 生成时传工具名)
70
+ */
71
+ readonly title?: string;
72
+ };
73
+ /**
74
+ * 渲染 .env 文件内容
75
+ *
76
+ * @param params - 模板入参(contentsExportDir/title 可选覆盖;空串路径表示留空待填)
77
+ * @returns .env 文件全文(单变量 + 注释行)
78
+ */
79
+ declare function renderEnvTemplate(params?: EnvTemplateParams): string;
80
+ //#endregion
81
+ //#region src/runtime-env.utils.d.ts
82
+ /**
83
+ * 解析命中通道
84
+ */
85
+ type RuntimeEnvChannel = 'config-file';
86
+ /**
87
+ * 运行时环境(合并形态:dataRoot 出配置文件,contentsExportDir 出 .env)
88
+ */
89
+ type RuntimeEnv = {
90
+ /**
91
+ * 数据根绝对路径(配置文件承载;就地自指以文件所在目录绝对化)
92
+ */
93
+ readonly dataRoot: string;
94
+ /**
95
+ * 台账导出根绝对路径(.env 承载;只读消费)
96
+ */
97
+ readonly contentsExportDir: string;
98
+ };
99
+ /**
100
+ * 解析成功结果
101
+ */
102
+ type RuntimeEnvResolution = {
103
+ /**
104
+ * 命中通道(恒 config-file:配置文件必备后无整体 env 通道)
105
+ */
106
+ readonly channel: RuntimeEnvChannel;
107
+ /**
108
+ * 合并后的运行时环境
109
+ */
110
+ readonly env: RuntimeEnv;
111
+ /**
112
+ * 命中的配置文件绝对路径
113
+ */
114
+ readonly configPath: string;
115
+ };
116
+ /**
117
+ * 解析错误(配置文件缺失/非法 / env 缺失)
118
+ */
119
+ type RuntimeEnvError = ConfigLoadError | EnvError;
120
+ /**
121
+ * 解析结果
122
+ */
123
+ type RuntimeEnvResult = {
124
+ readonly ok: true;
125
+ readonly value: RuntimeEnvResolution;
126
+ } | {
127
+ readonly ok: false;
128
+ readonly error: RuntimeEnvError;
129
+ };
130
+ /**
131
+ * 解析运行时环境(配置文件必备 + 台账导出根 env 字段级合并,见模块注释)
132
+ *
133
+ * @param explicitConfigPath - 显式配置文件路径(可选;缺省自 cwd 向上发现)
134
+ * @returns 成功为合并形态运行时环境与配置文件路径;失败为可读错误
135
+ */
136
+ declare function resolveRuntimeEnv(explicitConfigPath?: string): Promise<RuntimeEnvResult>;
137
+ //#endregion
138
+ //#region src/source/contents-source.adapter.d.ts
139
+ /**
140
+ * 日列表的日期范围过滤
141
+ */
142
+ type DayRange = {
143
+ /**
144
+ * 起始日(含,YYYY-MM-DD)
145
+ */
146
+ readonly from?: string;
147
+ /**
148
+ * 截止日(含,YYYY-MM-DD)
149
+ */
150
+ readonly to?: string;
151
+ };
152
+ /**
153
+ * 源错误
154
+ */
155
+ type ContentsSourceError = {
156
+ /**
157
+ * 错误码
158
+ */
159
+ readonly code: 'DIR_NOT_FOUND' | 'DAY_INVALID' | 'DAY_FILE_MISSING' | 'ROW_INVALID' | 'KOL_MISMATCH';
160
+ /**
161
+ * 人读错误信息
162
+ */
163
+ readonly message: string;
164
+ };
165
+ /**
166
+ * 只读源门面
167
+ */
168
+ type ContentsSource = {
169
+ /**
170
+ * 列出导出子目录全部日(升序,可加范围过滤;空目录返回空数组)
171
+ *
172
+ * @param range - 日期范围过滤(可选)
173
+ * @returns 日字符串列表(YYYY-MM-DD 升序)
174
+ */
175
+ listDays(range?: DayRange): readonly string[];
176
+ /**
177
+ * 取某日全部内容行(逐行镜像守卫;可按 kol_slug 过滤)
178
+ *
179
+ * @param day - 目标日(YYYY-MM-DD)
180
+ * @param kolSlug - 期望 KOL slug(行不匹配报 KOL_MISMATCH;可选)
181
+ * @returns 行守卫通过为记录列表;失败为可读错误(含行定位)
182
+ */
183
+ getContentsByDay(day: string, kolSlug?: string): Result<readonly KolContent$1[], ContentsSourceError>;
184
+ };
185
+ /**
186
+ * 枚举导出根下全部 KOL slug(<kol-slug>/ 子目录含 contents-<day>.ndjson 形制文件
187
+ * 即认;非 KOL 目录静默忽略)
188
+ *
189
+ * @param exportRoot - 台账导出根(lzi-kol export-contents 产物父目录)
190
+ * @returns KOL slug 列表(升序;空根为空数组);根不存在为 DIR_NOT_FOUND 错误
191
+ */
192
+ declare function listKolSlugs(exportRoot: string): Result<readonly string[], ContentsSourceError>;
193
+ /**
194
+ * 打开只读源(单 KOL 导出子目录消费门面)
195
+ *
196
+ * @param exportDir - 单 KOL 导出子目录(导出根下 <kol-slug>/)
197
+ * @returns 打开成功为源门面;目录不存在为 DIR_NOT_FOUND 错误
198
+ */
199
+ declare function createContentsSource(exportDir: string): Result<ContentsSource, ContentsSourceError>;
200
+ //#endregion
201
+ //#region src/source/registry-snapshot.reader.d.ts
202
+ /**
203
+ * 快照读取错误
204
+ */
205
+ type RegistrySnapshotError = {
206
+ /**
207
+ * 错误码
208
+ */
209
+ readonly code: 'SNAPSHOT_INVALID';
210
+ /**
211
+ * 人读错误信息
212
+ */
213
+ readonly message: string;
214
+ };
215
+ /**
216
+ * 读取 registry 快照(缺失返回 null;损坏报错)
217
+ *
218
+ * @param exportDir - 属主导出子目录
219
+ * @returns 快照在位为守卫后的快照;缺失为 null;损坏为可读错误
220
+ */
221
+ declare function readRegistrySnapshot(exportDir: string): Result<RegistrySnapshot$1 | null, RegistrySnapshotError>;
222
+ //#endregion
223
+ //#region src/render/content-document.mapper.d.ts
224
+ /**
225
+ * 内容类型复数目录名
226
+ *
227
+ * @param contentType - 内容类型
228
+ * @returns 复数目录名(未知类型回落 misc)
229
+ */
230
+ declare function contentTypeDir(contentType: string): string;
231
+ /**
232
+ * 分区键(kolSlug + platform/contentType → 单数据仓多 KOL 分区标识)
233
+ *
234
+ * @param kolSlug - KOL slug(分区第一轴)
235
+ * @param platform - 平台标识
236
+ * @param contentType - 内容类型
237
+ * @returns 分区键(如 kols/xiao-lin/youtube/videos)
238
+ */
239
+ declare function partitionKeyOf(kolSlug: string, platform: string, contentType: string): string;
240
+ /**
241
+ * 条目档文件名(含保留字守卫)
242
+ *
243
+ * @param content - 单内容行
244
+ * @returns 条目档文件名(<sanitized-id>.md)
245
+ * @throws {@link Error} 标识 sanitize 后与保留字冲突
246
+ */
247
+ declare function entryFilenameOf(content: KolContent$1): string;
248
+ /**
249
+ * 渲染内容条目档(确定性输出;hash 仅覆盖正文)
250
+ *
251
+ * @param content - 单内容行
252
+ * @param generatedAt - 生成时刻(ISO8601,白名单字段,不参与 hash)
253
+ * @returns 完整文档与正文哈希
254
+ */
255
+ declare function renderContentDocument(content: KolContent$1, generatedAt: string): RenderedDocument;
256
+ //#endregion
257
+ //#region src/render/partition-readme.mapper.d.ts
258
+ /**
259
+ * 分区 README 行投影(索引表列字段;convert 自内容行投影、capture 自条目档头重建)
260
+ */
261
+ type PartitionReadmeRow = {
262
+ /**
263
+ * 平台内内容唯一标识
264
+ */
265
+ readonly platform_content_id: string;
266
+ /**
267
+ * 标题(不可得为 null)
268
+ */
269
+ readonly title: string | null;
270
+ /**
271
+ * 发布时刻(不可得为 null)
272
+ */
273
+ readonly published_at: string | null;
274
+ /**
275
+ * 内容页 URL(不可得为 null)
276
+ */
277
+ readonly source_url: string | null;
278
+ };
279
+ /**
280
+ * 渲染分区 README
281
+ *
282
+ * @param partition - 分区键(如 kols/<slug>/<platform>/<contentType>)
283
+ * @param rows - 该分区全部条目行投影(调用方排序后传入)
284
+ * @param generatedAt - 生成时刻(白名单字段)
285
+ * @returns 完整文档与正文哈希
286
+ */
287
+ declare function renderPartitionReadme(partition: string, rows: readonly PartitionReadmeRow[], generatedAt: string): RenderedDocument;
288
+ //#endregion
289
+ //#region src/render/profile.mapper.d.ts
290
+ /**
291
+ * 渲染 KOL 档案
292
+ *
293
+ * @param snapshot - 属主 registry 快照
294
+ * @param generatedAt - 生成时刻(白名单字段)
295
+ * @returns 完整文档与正文哈希
296
+ */
297
+ declare function renderProfileKol(snapshot: RegistrySnapshot$1, generatedAt: string): RenderedDocument;
298
+ //#endregion
299
+ //#region src/render/catalog.mapper.d.ts
300
+ /**
301
+ * 目录册条目(分区粒度)
302
+ */
303
+ type CatalogEntry = {
304
+ /**
305
+ * 分区键(如 kols/xiao-lin/youtube/videos)
306
+ */
307
+ readonly partition: string;
308
+ /**
309
+ * 该分区条目档实测计数
310
+ */
311
+ readonly count: number;
312
+ };
313
+ /**
314
+ * 目录册渲染产物
315
+ */
316
+ type RenderedCatalog = {
317
+ /**
318
+ * 完整 markdown 文档(frontmatter + 正文)
319
+ */
320
+ readonly content: string;
321
+ /**
322
+ * 正文规范化哈希
323
+ */
324
+ readonly hash: string;
325
+ };
326
+ /**
327
+ * 渲染目录册(确定性输出;hash 仅覆盖正文)
328
+ *
329
+ * @param entries - 分区条目列表(partition 升序)
330
+ * @param generatedAt - 生成时刻(白名单字段)
331
+ * @returns 完整文档与正文哈希
332
+ */
333
+ declare function renderCatalog(entries: readonly CatalogEntry[], generatedAt: string): RenderedCatalog;
334
+ /**
335
+ * 数据根 README 渲染(init/catalog ensureRoot 用;单数据仓全域形态)
336
+ *
337
+ * @returns README.md 全文
338
+ */
339
+ declare function renderDataRootReadme(): string;
340
+ //#endregion
341
+ //#region src/repo/content-index.service.d.ts
342
+ /**
343
+ * 管理器构造项
344
+ */
345
+ type ContentIndexServiceOptions = {
346
+ /**
347
+ * 数据根绝对路径
348
+ */
349
+ readonly dataRoot: string;
350
+ };
351
+ /**
352
+ * 单分区写入行为开关
353
+ */
354
+ type WritePartitionOptions = {
355
+ /**
356
+ * 干跑:只计算不落盘
357
+ */
358
+ readonly dryRun?: boolean;
359
+ };
360
+ /**
361
+ * 单分区写入结果
362
+ */
363
+ type PartitionWriteResult = {
364
+ /**
365
+ * 分区键
366
+ */
367
+ readonly partition: string;
368
+ /**
369
+ * 分区目录绝对路径
370
+ */
371
+ readonly partitionDir: string;
372
+ /**
373
+ * 本次写入文档数(含分区 README)
374
+ */
375
+ readonly written: number;
376
+ /**
377
+ * 幂等跳过文档数(含分区 README)
378
+ */
379
+ readonly skipped: number;
380
+ };
381
+ /**
382
+ * 内容分区索引管理器(引擎 PartitionWriter 委托)
383
+ */
384
+ declare class ContentIndexService {
385
+ /**
386
+ * 数据根绝对路径
387
+ */
388
+ readonly dataRoot: string;
389
+ /**
390
+ * 引擎分区写入器实例
391
+ */
392
+ private readonly writer;
393
+ /**
394
+ * 构造管理器
395
+ *
396
+ * @param options - 构造项(dataRoot 必填)
397
+ * @returns 管理器实例
398
+ */
399
+ constructor(options: ContentIndexServiceOptions);
400
+ /**
401
+ * 写入单分区:条目档 + 分区 README(幂等跳过;零 git)
402
+ *
403
+ * @param partition - 分区键(platform/contentType 复数)
404
+ * @param entries - 该分区内容行列表(内部按 platform_content_id 升序落盘)
405
+ * @param options - 行为开关(dryRun)
406
+ * @returns 写入统计
407
+ * @throws {@link Error} 条目标识非法或与保留字冲突时抛出
408
+ */
409
+ writePartition(partition: string, entries: readonly KolContent$1[], options?: WritePartitionOptions): Promise<PartitionWriteResult>;
410
+ }
411
+ //#endregion
412
+ //#region src/repo/profile.service.d.ts
413
+ /**
414
+ * 管理器构造项
415
+ */
416
+ type ProfileServiceOptions = {
417
+ /**
418
+ * 数据根绝对路径
419
+ */
420
+ readonly dataRoot: string;
421
+ };
422
+ /**
423
+ * 档案刷新结果
424
+ */
425
+ type ProfileRefreshResult = {
426
+ /**
427
+ * 档案文件绝对路径
428
+ */
429
+ readonly path: string;
430
+ /**
431
+ * 是否写入(快照缺失/同 hash 跳过为 false)
432
+ */
433
+ readonly written: boolean;
434
+ /**
435
+ * 跳过原因(写入成功为 null)
436
+ */
437
+ readonly skippedReason: null | 'snapshot-missing' | 'hash-unchanged';
438
+ };
439
+ /**
440
+ * KOL 档案管理器
441
+ */
442
+ declare class ProfileService {
443
+ /**
444
+ * 数据根绝对路径
445
+ */
446
+ readonly dataRoot: string;
447
+ /**
448
+ * 构造管理器
449
+ *
450
+ * @param options - 构造项(dataRoot 必填)
451
+ * @returns 管理器实例
452
+ */
453
+ constructor(options: ProfileServiceOptions);
454
+ /**
455
+ * 刷新档案(快照 → 渲染 → 幂等写入)
456
+ *
457
+ * @param kolSlug - KOL slug(档案分区第一轴)
458
+ * @param snapshot - 台账 registry 快照(null = 未导出,提示跳过)
459
+ * @param dryRun - 干跑(只计算不落盘)
460
+ * @returns 刷新结果
461
+ */
462
+ refresh(kolSlug: string, snapshot: RegistrySnapshot$1 | null, dryRun: boolean): Promise<ProfileRefreshResult>;
463
+ }
464
+ //#endregion
465
+ //#region src/repo/catalog.service.d.ts
466
+ /**
467
+ * 管理器构造项
468
+ */
469
+ type CatalogServiceOptions = {
470
+ /**
471
+ * 数据根绝对路径
472
+ */
473
+ readonly dataRoot: string;
474
+ /**
475
+ * 提交身份(仅 --commit 时消费;测试/CI 注入)
476
+ */
477
+ readonly gitIdentity?: GitIdentity;
478
+ };
479
+ /**
480
+ * 刷新行为开关
481
+ */
482
+ type RefreshOptions = CatalogRefreshOptions;
483
+ /**
484
+ * 刷新结果
485
+ */
486
+ type CatalogRefreshResult = CatalogRefreshResult$1<CatalogEntry>;
487
+ /**
488
+ * 总目录册管理器(引擎 CatalogService 委托)
489
+ */
490
+ declare class CatalogService {
491
+ /**
492
+ * 数据根绝对路径
493
+ */
494
+ readonly dataRoot: string;
495
+ /**
496
+ * 引擎目录册服务实例
497
+ */
498
+ private readonly service;
499
+ /**
500
+ * 构造管理器
501
+ *
502
+ * @param options - 构造项
503
+ * @returns 管理器实例
504
+ */
505
+ constructor(options: CatalogServiceOptions);
506
+ /**
507
+ * 扫描平台分区
508
+ *
509
+ * @returns 目录册条目列表(partition 升序)
510
+ */
511
+ scan(): Promise<readonly CatalogEntry[]>;
512
+ /**
513
+ * 确保数据根骨架就绪(目录 + README/.gitignore/.env.example;零 git)
514
+ *
515
+ * @param dryRun - 干跑时不做任何落盘
516
+ * @returns 本次新建的根文件相对路径清单
517
+ */
518
+ ensureRoot(dryRun: boolean): Promise<readonly string[]>;
519
+ /**
520
+ * 刷新目录册:扫描 → 比对 → 变更才写 →(仅显式 commit 时)提交
521
+ *
522
+ * @param options - 行为开关(dryRun/commit)
523
+ * @returns 刷新结果
524
+ */
525
+ refresh(options?: RefreshOptions): Promise<CatalogRefreshResult>;
526
+ /**
527
+ * 对账现存 catalog.md 与磁盘实测(只报告不修复)
528
+ *
529
+ * @returns 问题清单(空 = 对账通过)
530
+ */
531
+ check(): Promise<readonly string[]>;
532
+ }
533
+ //#endregion
534
+ //#region src/capture.usecase.d.ts
535
+ /**
536
+ * 人工登记条目入参(CLI 参数式共用形态;capturedAt 缺省登记时刻、可显式回填)
537
+ */
538
+ type CaptureInput = {
539
+ /**
540
+ * KOL slug(数据仓分区第一轴)
541
+ */
542
+ readonly kolSlug: string;
543
+ /**
544
+ * 平台标识
545
+ */
546
+ readonly platform: string;
547
+ /**
548
+ * 内容类型(缺省 video)
549
+ */
550
+ readonly contentType?: string;
551
+ /**
552
+ * 平台内内容唯一标识(bvid / awemeId / 文章 id 等)
553
+ */
554
+ readonly platformContentId: string;
555
+ /**
556
+ * 标题
557
+ */
558
+ readonly title?: string;
559
+ /**
560
+ * 作者平台账号标识
561
+ */
562
+ readonly authorAccountId?: string;
563
+ /**
564
+ * 作者显示名
565
+ */
566
+ readonly authorName?: string;
567
+ /**
568
+ * 发布时刻(ISO 串或 YYYY-MM-DD)
569
+ */
570
+ readonly publishedAt?: string;
571
+ /**
572
+ * 登记时刻(ISO 串;缺省当前时刻;历史回填显式传入)
573
+ */
574
+ readonly capturedAt?: string;
575
+ /**
576
+ * 内容页 URL
577
+ */
578
+ readonly sourceUrl?: string;
579
+ /**
580
+ * 简介/描述
581
+ */
582
+ readonly description?: string;
583
+ /**
584
+ * 平台特有载荷(JSON 对象;view_count/like_count/duration_sec 等)
585
+ */
586
+ readonly payload?: Record<string, unknown>;
587
+ };
588
+ /**
589
+ * 登记行为开关
590
+ */
591
+ type CaptureOptions = {
592
+ /**
593
+ * 干跑:零落盘零提交
594
+ */
595
+ readonly dryRun?: boolean;
596
+ /**
597
+ * 是否执行 git 提交(缺省 false;--commit 开启)
598
+ */
599
+ readonly commit?: boolean;
600
+ /**
601
+ * 提交身份(仅 commit 时消费)
602
+ */
603
+ readonly gitIdentity?: GitIdentity;
604
+ };
605
+ /**
606
+ * 登记报告
607
+ */
608
+ type CaptureReport = {
609
+ /**
610
+ * 条目档绝对路径
611
+ */
612
+ readonly entryPath: string;
613
+ /**
614
+ * 条目是否写入(同字节跳过为 false)
615
+ */
616
+ readonly entryWritten: boolean;
617
+ /**
618
+ * 分区键
619
+ */
620
+ readonly partition: string;
621
+ /**
622
+ * 分区 README 是否重建
623
+ */
624
+ readonly partitionReadmeWritten: boolean;
625
+ /**
626
+ * 目录册刷新结果
627
+ */
628
+ readonly catalog: CatalogRefreshResult;
629
+ };
630
+ /**
631
+ * 登记错误
632
+ */
633
+ type CaptureError = {
634
+ /**
635
+ * 错误码
636
+ */
637
+ readonly code: 'INPUT_INVALID';
638
+ /**
639
+ * 人读错误信息(含 zod 问题摘要)
640
+ */
641
+ readonly message: string;
642
+ };
643
+ /**
644
+ * 执行人工登记(zod 守卫 → 条目档直写 → 分区 README 重建 → 目录册刷新)
645
+ *
646
+ * @param env - 解析后的运行时环境
647
+ * @param input - 条目入参
648
+ * @param options - 行为开关
649
+ * @returns 登记报告;失败为可读错误(含 zod 问题摘要)
650
+ */
651
+ declare function captureAdd(env: RuntimeEnv, input: CaptureInput, options?: CaptureOptions): Promise<Result<CaptureReport, CaptureError>>;
652
+ //#endregion
653
+ //#region src/convert.usecase.d.ts
654
+ /**
655
+ * 转换选择器(--day <d> / --from+--to / --all 三选一)
656
+ */
657
+ type ConvertSelection = {
658
+ /**
659
+ * 单日(YYYY-MM-DD)
660
+ */
661
+ readonly day?: string;
662
+ /**
663
+ * 起始日(含)
664
+ */
665
+ readonly from?: string;
666
+ /**
667
+ * 截止日(含)
668
+ */
669
+ readonly to?: string;
670
+ /**
671
+ * 全量
672
+ */
673
+ readonly all?: boolean;
674
+ };
675
+ /**
676
+ * 转换行为参数
677
+ */
678
+ type ConvertOptions = ConvertSelection & {
679
+ /**
680
+ * 限定 KOL slug(缺省 = 导出根下全部 KOL)
681
+ */
682
+ readonly kolSlug?: string;
683
+ /**
684
+ * 干跑:零落盘零提交
685
+ */
686
+ readonly dryRun?: boolean;
687
+ /**
688
+ * 是否执行 git 提交(缺省 true;--no-commit 关闭)
689
+ */
690
+ readonly commit?: boolean;
691
+ /**
692
+ * 提交身份(仅 commit 时消费)
693
+ */
694
+ readonly gitIdentity?: GitIdentity;
695
+ };
696
+ /**
697
+ * 转换总报告
698
+ */
699
+ type ConvertReport = {
700
+ /**
701
+ * 逐分区报告(partition 升序,跨 KOL 合并)
702
+ */
703
+ readonly partitions: readonly PartitionWriteResult[];
704
+ /**
705
+ * 逐 KOL 档案刷新结果(slug 升序)
706
+ */
707
+ readonly profiles: readonly ProfileRefreshResult[];
708
+ /**
709
+ * 目录册刷新结果
710
+ */
711
+ readonly catalog: CatalogRefreshResult;
712
+ };
713
+ /**
714
+ * 转换错误
715
+ */
716
+ type ConvertError = {
717
+ /**
718
+ * 错误码
719
+ */
720
+ readonly code: 'SELECTION_INVALID' | 'DAY_INVALID' | 'KOL_NOT_FOUND' | 'SOURCE_ERROR' | 'SNAPSHOT_ERROR';
721
+ /**
722
+ * 人读错误信息
723
+ */
724
+ readonly message: string;
725
+ };
726
+ /**
727
+ * 执行转换(编排门面;见模块注释主流程)
728
+ *
729
+ * @param env - 解析后的运行时环境
730
+ * @param options - 选择器与行为参数
731
+ * @returns 转换总报告;失败为可读错误
732
+ */
733
+ declare function runConvert(env: RuntimeEnv, options: ConvertOptions): Promise<Result<ConvertReport, ConvertError | ContentsSourceError>>;
734
+ //#endregion
735
+ //#region src/verify.usecase.d.ts
736
+ /**
737
+ * 体检报告
738
+ */
739
+ type VerifyReport = {
740
+ /**
741
+ * 哈希漂移清单(空 = 无漂移)
742
+ */
743
+ readonly hashDrifts: readonly HashDrift[];
744
+ /**
745
+ * 目录册对账问题清单(空 = 对账通过)
746
+ */
747
+ readonly issues: readonly string[];
748
+ };
749
+ /**
750
+ * 执行体检
751
+ *
752
+ * @param env - 解析后的运行时环境
753
+ * @returns 体检报告(hashDrifts/issues 空 = 通过)
754
+ */
755
+ declare function runVerify(env: RuntimeEnv): Promise<VerifyReport>;
756
+ //#endregion
757
+ //#region src/init/scaffold-templates.d.ts
758
+ /**
759
+ * 数据仓脚手架模板(init 用静态文本;单数据仓多 KOL 形态)
760
+ *
761
+ * 生成物:README(由 catalog.mapper 承载)、kols/README、docs/overview、
762
+ * docs/research/README、.lzi/skills 三 skill 真源、数据仓 package.json、
763
+ * CHANGELOG。模板为纯函数文本(零依赖;KOL 无关——单仓承载全部 KOL)。
764
+ */
765
+ /**
766
+ * kols 区 README 文本
767
+ *
768
+ * @returns README.md 全文
769
+ */
770
+ declare function kolsReadmeText(): string;
771
+ /**
772
+ * 调研记录区 README 文本
773
+ *
774
+ * @returns README.md 全文
775
+ */
776
+ declare function researchReadmeText(): string;
777
+ /**
778
+ * docs/overview 文本
779
+ *
780
+ * @returns overview.md 全文
781
+ */
782
+ declare function overviewText(): string;
783
+ /**
784
+ * 数据仓 package.json 文本
785
+ *
786
+ * @returns package.json 全文
787
+ */
788
+ declare function dataRepoPackageJsonText(): string;
789
+ /**
790
+ * 数据仓 CHANGELOG 文本
791
+ *
792
+ * @returns CHANGELOG.md 全文
793
+ */
794
+ declare function dataRepoChangelogText(): string;
795
+ /**
796
+ * 数据仓 .gitignore 文本(lzi-git 预设基线,与 lzi-git 工具产出一致;漂移由 gitignore:check 守护)
797
+ *
798
+ * @returns .gitignore 全文
799
+ */
800
+ declare function dataRepoGitignoreText(): string;
801
+ /**
802
+ * 数据仓 lzi-git.config.ts 文本(.gitignore 接管配置件)
803
+ *
804
+ * @returns lzi-git.config.ts 全文
805
+ */
806
+ declare function dataRepoLziGitConfigText(): string;
807
+ /**
808
+ * 数据仓 lzi-dev.config.ts 文本(changelog:add 通道前置件)
809
+ *
810
+ * @returns lzi-dev.config.ts 全文
811
+ */
812
+ declare function dataRepoLziDevConfigText(): string;
813
+ /**
814
+ * skill kol-research 文本
815
+ *
816
+ * @returns SKILL.md 全文
817
+ */
818
+ declare function skillKolResearchText(): string;
819
+ /**
820
+ * skill kol-capture 文本
821
+ *
822
+ * @returns SKILL.md 全文
823
+ */
824
+ declare function skillKolCaptureText(): string;
825
+ /**
826
+ * skill kol-ops 文本
827
+ *
828
+ * @returns SKILL.md 全文
829
+ */
830
+ declare function skillKolOpsText(): string;
831
+ //#endregion
832
+ //#region src/init/scaffold-data-repo.usecase.d.ts
833
+ /**
834
+ * init 入参
835
+ */
836
+ type InitOptions = {
837
+ /**
838
+ * 数据仓目标目录绝对路径
839
+ */
840
+ readonly targetDir: string;
841
+ /**
842
+ * 是否执行 git init(缺省 true)
843
+ */
844
+ readonly gitInit?: boolean;
845
+ };
846
+ /**
847
+ * init 写入产物
848
+ */
849
+ type InitReport = {
850
+ /**
851
+ * 数据仓根目录
852
+ */
853
+ readonly targetDir: string;
854
+ /**
855
+ * 本次新建文件相对路径清单(已存在跳过的不计)
856
+ */
857
+ readonly createdFiles: readonly string[];
858
+ /**
859
+ * git init 是否执行(已存在仓为 false)
860
+ */
861
+ readonly gitInitialized: boolean;
862
+ };
863
+ /**
864
+ * 执行 init 脚手架
865
+ *
866
+ * @param options - init 入参
867
+ * @returns init 产物报告
868
+ */
869
+ declare function runScaffoldDataRepo(options: InitOptions): Promise<InitReport>;
870
+ //#endregion
871
+ export { CaptureError, CaptureInput, CaptureOptions, CaptureReport, CatalogEntry, CatalogRefreshResult, CatalogService, CatalogServiceOptions, ContentIndexService, ContentIndexServiceOptions, ContentsSource, ContentsSourceError, ConvertError, ConvertOptions, ConvertReport, ConvertSelection, DayRange, ENV_CONTENTS_EXPORT_DIR, EnvError, EnvTemplateParams, InitOptions, InitReport, type KolContent, KolContentSchema, KolMarkdownEnv, PartitionReadmeRow, PartitionWriteResult, ProfileRefreshResult, ProfileService, ProfileServiceOptions, REGISTRY_SNAPSHOT_FILENAME, RefreshOptions, type RegistrySnapshot, RegistrySnapshotError, RenderedCatalog, type Result, RuntimeEnv, RuntimeEnvChannel, RuntimeEnvError, RuntimeEnvResolution, RuntimeEnvResult, VerifyReport, WritePartitionOptions, captureAdd, contentTypeDir, createContentsSource, dataRepoChangelogText, dataRepoGitignoreText, dataRepoLziDevConfigText, dataRepoLziGitConfigText, dataRepoPackageJsonText, entryFilenameOf, failure, kolMarkdownEnvKit, kolMarkdownEnvSchema, kolsReadmeText, listKolSlugs, overviewText, partitionKeyOf, readRegistrySnapshot, renderCatalog, renderContentDocument, renderDataRootReadme, renderEnvTemplate, renderPartitionReadme, renderProfileKol, researchReadmeText, resolveEnv, resolveRuntimeEnv, runConvert, runScaffoldDataRepo, runVerify, skillKolCaptureText, skillKolOpsText, skillKolResearchText, success, toContentsExportFilename };
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
1
+ import{loadKolMarkdownConfig as e,scaffoldConfigText as t}from"@longzai-intelligence-kol-markdown/config";import{KOL_CONTENT_TYPES as n,KOL_PLATFORMS as r,KolContentSchema as i,KolContentSchema as a,REGISTRY_SNAPSHOT_FILENAME as o,REGISTRY_SNAPSHOT_FILENAME as s,RegistrySnapshotSchema as c,parseContentsExportFilename as l,toContentsExportFilename as u,toContentsExportFilename as d}from"@longzai-intelligence-kol/core";import{atomicWrite as f,computeHashDrift as p,contentHash as m,createCatalogReconciler as h,createCatalogService as g,createEnvKit as _,createPartitionWriter as v,ensureGitRepo as y,failure as b,pipelineFrontmatter as x,readHeadIfExists as S,requireExactlyOne as ee,stringifyFrontmatter as C,success as w}from"@longzai-intelligence-markdown/data-engine";import{join as T,resolve as te}from"node:path";import*as E from"zod";import{existsSync as D,mkdirSync as O,readFileSync as k,readdirSync as A,writeFileSync as ne}from"node:fs";export*from"@longzai-intelligence-kol-markdown/config";const j=`LZI_KOL_MARKDOWN_CONTENTS_EXPORT_DIR`,re=E.object({[j]:E.string().min(1)}),M=_({variables:[{name:j,comment:`台账导出根:lzi-kol export-contents 产物父目录(其下 <kol-slug>/ 子目录;只读消费;跨项目路径唯一 env 通道)`,placeholder:`/path/to/longzai-intelligence-kol-registry/runs/exports/contents`}],toEnvConfig:e=>({contentsExportDir:te(e.LZI_KOL_MARKDOWN_CONTENTS_EXPORT_DIR??``)}),defaultTemplateTitle:`lzi-kol-markdown 环境配置`});function ie(e=process.env){return M.resolveEnv(e)}const ae=M;function N(e={}){let t={};return e.contentsExportDir!==void 0&&(t[j]=e.contentsExportDir),ae.renderEnvTemplate({values:t,title:e.title})}async function oe(t){let n=await e(t);if(!n.ok)return{ok:!1,error:n.error};let r=ie();return r.ok?{ok:!0,value:{channel:`config-file`,env:{dataRoot:n.config.dataRoot,contentsExportDir:r.value.contentsExportDir},configPath:n.path}}:{ok:!1,error:r.error}}const se=E.object({platform_content_id:E.string()});function ce(e){let t=se.safeParse(e);return t.success?t.data.platform_content_id:`(未知)`}function P(e){if(!D(e))return b({code:`DIR_NOT_FOUND`,message:`台账导出根不存在:${e}(应为 lzi-kol export-contents 产物父目录,其下 <kol-slug>/ 子目录形制 contents-<day>.ndjson)`});let t=[];for(let n of A(e,{withFileTypes:!0}))n.isDirectory()&&!n.name.startsWith(`.`)&&A(T(e,n.name)).some(e=>le(e))&&t.push(n.name);return w(t.sort())}function le(e){return l(e)!==null}function F(e){return D(e)?w({listDays(t){let n=A(e).map(e=>l(e)).filter(e=>e!==null).sort();return t===void 0?n:n.filter(e=>!(t.from!==void 0&&e<t.from||t.to!==void 0&&e>t.to))},getContentsByDay(t,n){if(!/^\d{4}-\d{2}-\d{2}$/.test(t))return b({code:`DAY_INVALID`,message:`日期格式非法:${t}(应为 YYYY-MM-DD)`});let r=T(e,d(t));if(!D(r))return b({code:`DAY_FILE_MISSING`,message:`第 ${t} 日导出文件缺失:${r}`});let i=k(r,`utf8`).split(`
2
+ `);i.length>0&&i[i.length-1]===``&&i.pop();let o=[];for(let[e,r]of i.entries()){let i;try{i=JSON.parse(r)}catch(n){return b({code:`ROW_INVALID`,message:`第 ${t} 日第 ${e} 行不是合法 JSON:${n instanceof Error?n.message:String(n)}`})}let s=a.safeParse(i);if(!s.success){let n=s.error.issues.map(e=>`${e.path.map(String).join(`.`)}: ${e.message}`).join(`; `);return b({code:`ROW_INVALID`,message:`第 ${t} 日第 ${e} 行(platform_content_id=${ce(i)})不符合 KolContent 契约:${n}`})}if(n!==void 0&&s.data.kol_slug!==n)return b({code:`KOL_MISMATCH`,message:`第 ${t} 日第 ${e} 行 kol_slug=${s.data.kol_slug} 与期望 ${n} 不符(导出子目录与数据仓配置错配)`});o.push(s.data)}return w(o)}}):b({code:`DIR_NOT_FOUND`,message:`属主导出子目录不存在:${e}(应为 lzi-kol export-contents 产物,形制 contents-<day>.ndjson)`})}function I(e){let t=T(e,s);if(!D(t))return w(null);let n;try{n=JSON.parse(k(t,`utf8`))}catch(e){return b({code:`SNAPSHOT_INVALID`,message:`registry.json 不是合法 JSON:${t}(${e instanceof Error?e.message:String(e)})`})}let r=c.safeParse(n);if(!r.success){let e=r.error.issues.map(e=>`${e.path.map(String).join(`.`)}: ${e.message}`).join(`; `);return b({code:`SNAPSHOT_INVALID`,message:`registry.json 不符合快照契约:${e}`})}return w(r.data)}const ue={video:`videos`,article:`articles`,post:`posts`,answer:`answers`,note:`notes`,tweet:`tweets`};function L(e){return ue[e]??`misc`}function R(e,t,n){return`kols/${e}/${t}/${L(n)}`}function z(e){let t=e.platform_content_id.replace(/[^A-Za-z0-9._-]+/g,`-`),n=`${t}.md`;if(n===`README.md`||t.length===0)throw Error(`条目标识非法或与保留字冲突:${e.platform_content_id}`);return n}function B(e){let t=Math.max(0,Math.floor(e)),n=Math.floor(t/3600),r=Math.floor(t%3600/60),i=t%60;return n>0?`${n}:${String(r).padStart(2,`0`)}:${String(i).padStart(2,`0`)}`:`${r}:${String(i).padStart(2,`0`)}`}function V(e,t){let n=e?.[t];if(typeof n==`number`)return n}const de=E.object({text:E.string(),start:E.number()}),fe=E.object({source:E.string(),model:E.string().nullable().default(null),language:E.string().nullable().default(null),word_count:E.number(),text:E.string(),segments:E.array(de).default([])});function pe(e){let t=fe.safeParse(e);return t.success?t.data:void 0}function me(e){let t=[];t.push(`# ${e.title??e.platform_content_id}`,``),t.push(`## 概览`,``),t.push(e.source_url===null?`- 内容:${e.platform_content_id}`:`- 内容:[${e.title??e.platform_content_id}](${e.source_url})`),t.push(e.author.name===null?`- 作者:${e.author.account_id??`-`}`:`- 作者:${e.author.name}${e.author.account_id===null?``:`(${e.author.account_id})`}`),t.push(`- 平台:${e.platform}(${e.content_type})`),t.push(`- 发布时间:${e.published_at??`-`}`);let n=V(e.payload,`duration_sec`);n!==void 0&&t.push(`- 时长:${B(n)}(${n}s)`);let r=V(e.payload,`view_count`),i=V(e.payload,`like_count`);(r!==void 0||i!==void 0)&&t.push(`- 播放:${r??`-`} / 点赞:${i??`-`}`),t.push(`- 采集:${e.capture_mode===`auto`?`平台属主自动聚合`:`人工登记(capture 通道)`}(${e.captured_at})`),t.push(``),t.push(`## 简介`,``),t.push(e.description??`(无简介)`,``);let a=pe(e.payload?.transcript);if(a===void 0)return t.push(`## 转写文案`,``,`(无转写载荷:属主仓补转写或人工补录后重跑 convert 收录)`,``),`${t.join(`
3
+ `)}\n`;t.push(`## 转写文案(时间戳分段)`,``);for(let e of a.segments)t.push(`- \`${B(e.start)}\` ${e.text}`);return t.push(``),t.push(`## 纯文本`,``),t.push(a.text.replaceAll(`
4
+ `,` `),``),`${t.join(`
5
+ `)}\n`}function H(e,t){let n=me(e),r=m(n),i=x({kind:`document`,feedPipelineId:`kol-markdown`,plugin:e.platform,sourceId:`kol-exports`,generatedAt:t,hash:r,tags:[],extra:{capture_mode:e.capture_mode,content_type:e.content_type,id:e.platform_content_id,author_id:e.author.account_id,author_name:e.author.name,captured_at:e.captured_at,duration_sec:V(e.payload,`duration_sec`)??null,kol_slug:e.kol_slug,like_count:V(e.payload,`like_count`)??null,platform:e.platform,published_at:e.published_at,source_url:e.source_url,title:e.title,view_count:V(e.payload,`view_count`)??null}});return{content:`${C(i)}\n${n}`,hash:r}}function U(e,t,n){let r=e.split(`/`),i=r[1]??``,a=r[2]??e,o=r[3]??``,s=[];s.push(`# ${i} / ${a} ${o}`.trimEnd(),``),s.push(`${t.length} 条内容。`,``),s.push(`| ID | 标题 | 发布时间 | 链接 |`,`|------|------|------|------|`);for(let e of t){let t=(e.title??`-`).replaceAll(`|`,`\\|`);s.push(`| ${e.platform_content_id} | ${t} | ${e.published_at?.slice(0,10)??`-`} | ${e.source_url??`-`} |`)}s.push(``);let c=`${s.join(`
6
+ `)}\n`,l=m(c),u=x({kind:`readme`,feedPipelineId:`kol-markdown`,plugin:a,sourceId:`kol-exports`,generatedAt:n,hash:l,tags:[],extra:{entry_count:t.length,partition:e}});return{content:`${C(u)}\n${c}`,hash:l}}function W(e,t){let n=[];n.push(`# ${e.kol.name}`,``),e.kol.aliases.length>0&&n.push(`别名:${e.kol.aliases.join(`、`)}`,``),n.push(`登记时刻:${e.kol.created_at}`,``),n.push(`## 平台账号注册表`,``),n.push(`| 平台 | 账号 | 显示名 | 模式 | 主页 |`,`|------|------|------|------|------|`);for(let t of e.accounts){let e=(t.account_name??`-`).replaceAll(`|`,`\\|`);n.push(`| ${t.platform} | ${t.account_id} | ${e} | ${t.mode} | ${t.account_url??`-`} |`)}n.push(``),n.push(`接线模式说明:auto = 平台属主仓自动聚合(youtube/douyin);manual = capture 人工登记通道(无工具平台)。`,``);let r=`${n.join(`
7
+ `)}\n`,i=m(r),a=x({kind:`profile`,feedPipelineId:`kol-markdown`,plugin:`kol`,sourceId:`kol-registry`,generatedAt:t,hash:i,tags:[],extra:{account_count:e.accounts.length,aliases:e.kol.aliases,kol_slug:e.kol.slug,name:e.kol.name}});return{content:`${C(a)}\n${r}`,hash:i}}function G(e,t){let n=e.reduce((e,t)=>e+t.count,0),r=new Set(e.map(e=>e.partition.split(`/`)[1]??``)).size,i=[];i.push(`# KOL 数据目录册`,``),i.push(`${r} KOL / ${e.length} 分区 / ${n} 条内容。`,``),i.push(`| 分区 | 条目数 | 目录 |`,`|------|------|------|`);for(let t of e)i.push(`| ${t.partition} | ${t.count} | [${t.partition}](${t.partition}/) |`);i.push(``);let a=`${i.join(`
8
+ `)}\n`,o=m(a),s=x({kind:`catalog`,feedPipelineId:`kol-markdown`,plugin:`kol`,sourceId:`kol-exports`,generatedAt:t,hash:o,tags:[],extra:{content_total:n,kol_count:r,partition_count:e.length}});return{content:`${C(s)}\n${a}`,hash:o}}function K(){let e=[];return e.push(`# Longzai Intelligence KOL Data`,``),e.push(`Longzai Intelligence KOL 追踪数据仓(单仓承载全部 KOL):由 lzi-kol-markdown 从台账统一导出流转换生成并托管。`,``),e.push(`## 组织`,``),e.push("- KOL 分区:`kols/<slug>/<platform>/<contentType>/<id>.md`(一篇一档,元数据一律 frontmatter)"),e.push("- `kols/<slug>/profile/kol.md`:KOL 档案与平台账号注册表(工具渲染自台账注册表)"),e.push("- `kols/<slug>/topics/`、`kols/<slug>/research/`:各 KOL 人工区(工具永不覆写)"),e.push("- `catalog.md`:全域总目录册(工具生成)"),e.push("- `docs/`:仓级文档与调研记录(人工区)"),e.push(``,`## 运维`,``),e.push("```bash"),e.push(`bun run kol:convert # 台账导出流 → 条目档/档案/目录册(幂等,默认托管 git 提交)`),e.push(`bun run kol:verify # content_hash 复算 + 目录册对账`),e.push(`bun run kol:catalog # 重建目录册`),e.push("```"),e.push(``),`${e.join(`
9
+ `)}\n`}var q=class{dataRoot;writer;constructor(e){this.dataRoot=e.dataRoot,this.writer=v({dataRoot:this.dataRoot,partitionDir:e=>T(this.dataRoot,e),entryRelPath:(e,t)=>`${e}/${z(t)}`,renderEntry:H,sortEntries:e=>[...e].sort((e,t)=>e.platform_content_id<t.platform_content_id?-1:+(e.platform_content_id>t.platform_content_id)),renderPartitionReadme:(e,t,n)=>U(e,t.map(e=>({platform_content_id:e.platform_content_id,title:e.title,published_at:e.published_at,source_url:e.source_url})),n)})}async writePartition(e,t,n={}){let r=await this.writer.writePartition(e,t,{dryRun:n.dryRun});return{partition:e,partitionDir:T(this.dataRoot,e),written:r.written,skipped:r.skipped}}},J=class{dataRoot;constructor(e){this.dataRoot=e.dataRoot}async refresh(e,t,n){let r=T(this.dataRoot,`kols`,e,`profile`,`kol.md`);if(t===null)return{path:r,written:!1,skippedReason:`snapshot-missing`};let i=W(t,(/* @__PURE__ */ new Date()).toISOString()),a=S(r);return a!==null&&a.content_hash===i.hash?{path:r,written:!1,skippedReason:`hash-unchanged`}:(n||(D(T(this.dataRoot,`kols`,e,`profile`))||O(T(this.dataRoot,`kols`,e,`profile`),{recursive:!0}),await f(r,i.content)),{path:r,written:!0,skippedReason:null})}};const he=[`# macOS`,`.DS_Store`,``,`# 机器本地配置(.env 本地实值;配置文件入库跟踪,不忽略)`,`.env`,``].join(`
10
+ `),ge=/* @__PURE__ */ new Set([`profile`,`topics`,`research`]);function _e(e){let t=T(e,`kols`);if(!D(t))return[];let n=[],r=[...A(t,{withFileTypes:!0})].filter(e=>e.isDirectory()&&!e.name.startsWith(`.`)).sort((e,t)=>e.name<t.name?-1:1);for(let e of r){let r=[...A(T(t,e.name),{withFileTypes:!0})].filter(e=>e.isDirectory()&&!e.name.startsWith(`.`)&&!ge.has(e.name)).sort((e,t)=>e.name<t.name?-1:1);for(let i of r){let r=[...A(T(t,e.name,i.name),{withFileTypes:!0})].filter(e=>e.isDirectory()&&!e.name.startsWith(`.`)).sort((e,t)=>e.name<t.name?-1:1);for(let a of r){let r=T(t,e.name,i.name,a.name),o=A(r).filter(e=>e.endsWith(`.md`)&&e!==`README.md`).length;o!==0&&n.push({partition:`kols/${e.name}/${i.name}/${a.name}`,count:o})}}}return n}function ve(e){return g({dataRoot:e.dataRoot,gitIdentity:e.gitIdentity,rootFiles:[{path:`.gitignore`,content:he},{path:`.env.example`,content:N({title:`lzi-kol-markdown 就地环境配置模板`})},{path:`README.md`,content:K()}],scan:async()=>_e(e.dataRoot),renderCatalog:(e,t)=>G(e,t),reconcile:h({countFields:[{headKey:`kol_count`,actual:e=>new Set(e.map(e=>e.partition.split(`/`)[1]??``)).size},{headKey:`partition_count`,actual:e=>e.length},{headKey:`content_total`,actual:e=>e.reduce((e,t)=>e+t.count,0)}],rowPattern:/\| \[(kols\/[a-z0-9-]+\/[a-z]+\/[a-z]+)\]\(\1\/\) \|/g,keyOfEntry:e=>e.partition,keyNoun:`分区`}),commit:{defaultEnabled:!1,message:e=>{let t=e.reduce((e,t)=>e+t.count,0);return`data(catalog): 更新 KOL 数据目录册(${e.length} 分区 / ${t} 条)`}}})}var Y=class{dataRoot;service;constructor(e){this.dataRoot=e.dataRoot,this.service=ve(e)}async scan(){return this.service.scan()}async ensureRoot(e){return this.service.ensureRoot(e)}async refresh(e={}){return this.service.refresh(e)}async check(){return this.service.check()}};const ye=E.object({id:E.string(),title:E.string().optional(),published_at:E.string().optional(),source_url:E.string().optional()});function X(e){return e===void 0||e===`null`?null:e}function be(e,t,n){let r=A(e).filter(e=>e.endsWith(`.md`)&&e!==`README.md`).sort(),i=[];for(let t of r){let n=ye.safeParse(S(T(e,t)));n.success&&i.push({platform_content_id:n.data.id,title:X(n.data.title),published_at:X(n.data.published_at),source_url:X(n.data.source_url)})}return i.length===0?``:U(t,i,n).content}function xe(e){return D(e)?k(e,`utf8`):``}async function Se(e,t,i={}){let o=r.find(e=>e===t.platform),s=t.contentType===void 0?`video`:n.find(e=>e===t.contentType);if(o===void 0||s===void 0){let e=r.join(` / `),i=n.join(` / `);return b({code:`INPUT_INVALID`,message:`platform/content_type 非法:${t.platform}/${t.contentType??`(video)`}(平台合法面:${e};类型合法面:${i})`})}let c={kol_slug:t.kolSlug,platform:o,content_type:s,platform_content_id:t.platformContentId,capture_mode:`manual`,title:t.title??null,author:{account_id:t.authorAccountId??null,name:t.authorName??null},published_at:t.publishedAt??null,captured_at:t.capturedAt??(/* @__PURE__ */ new Date()).toISOString(),source_url:t.sourceUrl??null,description:t.description??null,payload:t.payload??null},l=a.safeParse(c);if(!l.success){let e=l.error.issues.map(e=>`${e.path.map(String).join(`.`)}: ${e.message}`).join(`; `);return b({code:`INPUT_INVALID`,message:`条目不符合 KolContent 契约:${e}`})}let u=R(l.data.kol_slug,l.data.platform,l.data.content_type),d=T(e.dataRoot,u,z(l.data)),p=H(l.data,(/* @__PURE__ */ new Date()).toISOString()),m=D(d)?S(d):null,h=m===null||m.content_hash!==p.hash;i.dryRun!==!0&&h&&(O(T(e.dataRoot,u),{recursive:!0}),await f(d,p.content));let g=T(e.dataRoot,u,`README.md`),_=be(T(e.dataRoot,u),u,(/* @__PURE__ */ new Date()).toISOString()),v=_.length>0&&xe(g)!==_;i.dryRun!==!0&&v&&await f(g,_);let y=await new Y({dataRoot:e.dataRoot,gitIdentity:i.gitIdentity}).refresh({dryRun:i.dryRun===!0,commit:i.commit===!0});return w({entryPath:d,entryWritten:h,partition:u,partitionReadmeWritten:v,catalog:y})}function Ce(e){let t=ee({day:e.day!==void 0,range:e.from!==void 0||e.to!==void 0,all:e.all===!0});return t.ok?t.flag===`day`?/^\d{4}-\d{2}-\d{2}$/.test(e.day??``)?w({from:e.day,to:e.day}):b({code:`DAY_INVALID`,message:`--day 格式非法:${e.day}(应为 YYYY-MM-DD)`}):t.flag===`range`?e.from!==void 0&&!/^\d{4}-\d{2}-\d{2}$/.test(e.from)?b({code:`DAY_INVALID`,message:`--from 格式非法:${e.from}(应为 YYYY-MM-DD)`}):e.to!==void 0&&!/^\d{4}-\d{2}-\d{2}$/.test(e.to)?b({code:`DAY_INVALID`,message:`--to 格式非法:${e.to}(应为 YYYY-MM-DD)`}):w({from:e.from,to:e.to}):w({}):b({code:`SELECTION_INVALID`,message:`选择器非法:--day / --from+--to / --all 三选一(当前命中 `+(t.present.length===0?`无`:t.present.join(`+`))+`)`})}async function we(e,t,n,r){let i=T(e.contentsExportDir,t),a=F(i);if(!a.ok)return b(a.error);let o=I(i);if(!o.ok)return b({code:`SNAPSHOT_ERROR`,message:o.error.message});let s=[];for(let e of a.value.listDays(n)){let n=a.value.getContentsByDay(e,t);if(!n.ok)return b(n.error);s.push(...n.value)}let c=/* @__PURE__ */ new Map;for(let e of s){let t=R(e.kol_slug,e.platform,e.content_type);c.set(t,[...c.get(t)??[],e])}let l=new q({dataRoot:e.dataRoot}),u=[];for(let e of[...c.keys()].sort()){let t=await l.writePartition(e,c.get(e)??[],{dryRun:r});u.push(t)}let d=await new J({dataRoot:e.dataRoot}).refresh(t,o.value,r);return w({partitions:u,profile:d})}async function Te(e,t){let n=Ce(t);if(!n.ok)return b(n.error);let r=P(e.contentsExportDir);if(!r.ok)return b(r.error);let i=t.kolSlug===void 0?r.value:r.value.filter(e=>e===t.kolSlug);if(t.kolSlug!==void 0&&i.length===0)return b({code:`KOL_NOT_FOUND`,message:`导出根未见 KOL:${t.kolSlug}(应为 ${e.contentsExportDir} 下含 contents-<day>.ndjson 的子目录;台账零内容 KOL 不产出导出物)`});let a=[],o=[];for(let r of i){let i=await we(e,r,n.value,t.dryRun===!0);if(!i.ok)return b(i.error);a.push(...i.value.partitions),o.push(i.value.profile)}a.sort((e,t)=>e.partition<t.partition?-1:1);let s=await new Y({dataRoot:e.dataRoot,gitIdentity:t.gitIdentity}).refresh({dryRun:t.dryRun===!0,commit:t.commit!==!1});return w({partitions:a,profiles:o,catalog:s})}const Ee=/* @__PURE__ */ new Set([`profile`,`topics`,`research`]);function De(e){let t=[],n=T(e,`kols`);if(!Oe(n))return t;let r=A(n,{withFileTypes:!0}).filter(e=>e.isDirectory()&&!e.name.startsWith(`.`)).sort((e,t)=>e.name<t.name?-1:1);for(let e of r){let r=T(n,e.name),i=A(r,{withFileTypes:!0}).filter(e=>e.isDirectory()&&!e.name.startsWith(`.`)&&!Ee.has(e.name)).sort((e,t)=>e.name<t.name?-1:1);for(let e of i){let n=A(T(r,e.name),{withFileTypes:!0}).filter(e=>e.isDirectory()&&!e.name.startsWith(`.`)).sort((e,t)=>e.name<t.name?-1:1);for(let i of n){let n=T(r,e.name,i.name);for(let e of A(n))e.endsWith(`.md`)&&t.push(T(n,e))}}let a=T(r,`profile`,`kol.md`);S(a)!==null&&t.push(a)}return t}function Oe(e){try{return A(e),!0}catch{return!1}}async function ke(e){let t=[],n=De(e.dataRoot),{readFileSync:r}=await import(`node:fs`);for(let e of n){let n=p(e,r(e,`utf8`));n!==null&&t.push(n)}return{hashDrifts:t,issues:await new Y({dataRoot:e.dataRoot}).check()}}function Z(){return[`# KOL 分区(kols/)`,``,"单数据仓承载全部 KOL:`kols/<slug>/` 一 KOL 一域。",``,"- 工具域(禁手改):`<platform>/<contentType>/<id>.md` 条目档、`profile/kol.md` 档案——由 lzi-kol-markdown 从台账导出流渲染。","- 人工区(工具永不覆写):`topics/`(该 KOL 专题策展)、`research/`(该 KOL 调研记录)。",``,`新增 KOL = 台账仓(longzai-intelligence-kol-registry)register-kol 登记后 convert 自动建区;零内容 KOL 不产出导出物、本区不落空壳目录。`,``].join(`
11
+ `)}function Ae(){return[`# 调研记录(人工区)`,``,`KOL 前期调研与账号发现的过程记录(skill kol-research 产出指引);人工撰写,工具永不覆写。`,"建议命名:`<YYYY-MM-DD>-<主题>.md`;发现的平台账号应经 lzi-kol register-account 落注册表(本区只留过程)。",``].join(`
12
+ `)}function je(){return[`# 仓总览`,``,`本仓是 KOL 统一追踪体系(项目级约定,见 .lzi skills 与 docs)的数据仓(单仓承载全部 KOL)。`,`链路:lzi-kol(属主引擎:台账声明装载/人工登记/统一按日 NDJSON 导出)→ lzi-kol-markdown convert → 本仓(纯 markdown + frontmatter)。`,``,"- 数据面:`kols/<slug>/<platform>/<contentType>/<id>.md` 一篇一档;`kols/<slug>/profile/kol.md` 档案;`catalog.md` 全域目录册——均工具生成,禁手改。","- 人工面:各 `kols/<slug>/{topics,research}/`(该 KOL 策展与调研)与 `docs/`(仓级文档)——工具永不覆写。","- 运维:`bun run kol:convert` / `kol:verify` / `kol:catalog`;调研与采集 SOP 见 `.lzi/skills/`(kol-research / kol-capture / kol-ops)。",``].join(`
13
+ `)}function Me(){return`${JSON.stringify({name:`@longzai-intelligence-kol-data/root`,version:`0.0.1`,private:!0,description:`Longzai Intelligence KOL Data - KOL 追踪数据仓(单仓承载全部 KOL;lzi-kol-markdown 托管)`,license:`UNLICENSED`,workspaces:[`apps/*/*`,`packages/*`,`packages/*/*`,`packages/*/*/*`,`domains/*`,`domains/*/*`],type:`module`,scripts:{"kol:convert":`lzi-kol-markdown convert --all`,"kol:verify":`lzi-kol-markdown verify`,"kol:catalog":`lzi-kol-markdown catalog build`,"changelog:add":`lzi-dev-cli changelog add`,"gitignore:format":`lzi-git gitignore format`,"gitignore:check":`lzi-git gitignore check`,"agent:sync":`lzi-agent-cli sync`},devDependencies:{"@longzai-intelligence-agent-tools/cli":`^0.0.6`,"@longzai-intelligence-dev-tools/cli":`^0.2.30`,"@longzai-intelligence-git/cli":`^0.1.5`,"@longzai-intelligence-git/config":`^0.1.5`,"@longzai-intelligence-kol-markdown/cli":`^0.0.1`}},null,2)}\n`}function Ne(){return[`# 更新日志`,``,`本日志遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 规范。`,``,`## [未发布]`,``,`### 新增`,``,`- 仓立项:KOL 追踪数据仓(单仓承载全部 KOL;lzi-kol-markdown init 脚手架生成)`,``].join(`
14
+ `)}function Pe(){return(/* @__PURE__ */ `# 依赖与构建,*.log,*.tsbuildinfo,.cache/,build/,dist/,node_modules/,tsup.config.bundled_*.mjs,,# Electron,out/,,# Bun,.bun/,,# Turbo,.turbo/,,# SWC,.swc/,,# 测试覆盖率,.nyc_output/,coverage/,,# SQLite 数据库,*.db,*.db-journal,*.db-shm,*.db-wal,*.sqlite,*.sqlite-journal,*.sqlite-shm,*.sqlite-wal,*.sqlite3,,# 环境变量,.env,.env.*,!.env.example,,# JetBrains IDE,.idea/,,# macOS 系统文件,.DS_Store,,# npm,.npmrc,,# AI Agent 本地文件,CLAUDE.local.md,,# lzi 工具链产物,.lzi/issues/,AGENTS.md,CLAUDE.md,`.split(`,`)).join(`
15
+ `)}function Fe(){return[`import { defineConfig } from '@longzai-intelligence-git/config';`,``,`/**`,` * lzi-git 配置。`,` *`,` * .gitignore 格式化零配置:默认预设已覆盖本仓通用忽略项。`,` * 默认 injectMode='root-only':仅根 .gitignore 注入通用项。`,` * 数据仓特有模式归入尾部「其他」组保留,不会被删除。`,` */`,`export default defineConfig();`,``].join(`
16
+ `)}function Ie(){return[`import { defineConfig } from '@longzai-intelligence-dev-tools/config';`,``,`export default defineConfig({`,` clean: {`,` plugins: ['turbo', 'tsgo'],`,` },`,` publish: {`,` // 数据仓零代码零可发布子包`,` packages: [],`,` },`,` versionUpgrade: {`,` recursive: true,`,` depFields: {`,` dependencies: true,`,` devDependencies: true,`,` optionalDependencies: true,`,` peerDependencies: false,`,` overrides: false,`,` },`,` ignorePaths: ['**/node_modules/**', '**/dist/**', '**/.turbo/**'],`,` },`,`});`,``].join(`
17
+ `)}function Le(){return(/* @__PURE__ */ "---,lzi: true,name: kol-research,description: KOL 前期调研 SOP:发现 KOL 身份与各平台账号标识并落注册表,任何新 KOL 接入追踪体系前使用。,---,,# KOL 前期调研(kol-research),,## 一、调研目标,,确认 KOL 身份与全部平台在场账号,产出可直接登记的结构化结论(slug、各平台账号标识)。,,## 二、操作序,,1. 身份确认:搜索/官方页确认 KOM 名称、别名、领域;确定 slug(3-64 位小写字母数字连字符,如 xiao-lin、yu-bo)。,2. 平台遍历(browser-use / 搜索逐平台取证):, - youtube:频道页 → 频道 ID(UC 开头)或 @handle;, - douyin:主页 URL 中的 sec_uid(MS4wLjAB 开头长串);, - bilibili:空间页 mid(纯数字)与 UID;, - 微信公众号/微博/X/知乎:账号名与主页 URL 中可稳定定位的标识。,3. 落台账(m5 longzai-intelligence-kol-registry 台账仓,经 lzi-kol 引擎写声明):, ```bash, cd <m5>/longzai-intelligence-kol-registry && lzi-kol register-kol --slug <slug> --name <名>, lzi-kol register-account --kol <slug> --platform youtube --account-id UCxxx --mode auto, lzi-kol register-account --kol <slug> --platform bilibili --account-id <mid> --mode manual, ```, 模式判定:台账 sources/ 有源接线的平台 → auto;其余一律 manual。,4. 过程记录:本仓 kols/<slug>/research/<YYYY-MM-DD>-<主题>.md 留调研过程与证据链接(人工区)。,,## 三、纪律,,- 只登记有官方/可信证据的账号;存疑账号在调研记录中标注「待证实」,不入台账。,- 调研记录是人工区,工具永不覆写;台账声明(kols/<slug>.kol.ts)是注册唯一真源,kols/<slug>/profile/kol.md 由工具渲染。,- 不伪造任何标识:取不到就留空并如实记录。,".split(`,`)).join(`
18
+ `)}function Re(){return(/* @__PURE__ */ '---(lzi: true(name: kol-capture(description: 无工具平台内容采集 SOP:browser/搜索取证后经 lzi-kol-markdown capture add 直写数据仓,bilibili/公众号等缺采集工具平台的采集动作前使用。(---((# 无工具平台采集(kol-capture)((## 一、定位((bilibili、微信公众号、微博、X、知乎等平台暂无采集属主仓;本 SOP 用人工取证 + capture 登记通道把内容汇入与自动抓取同一条导出/渲染链路(lzi-kol 仓 ADR 0003)。未来平台属主仓建成后同键 auto 内容自动让位 manual,历史保留。((## 二、操作序((1. 取证(browser-use 打开内容页,只取公开可见信息):平台内容标识(bvid/文章 id/微博 id)、标题、作者账号、发布时间、URL、简介、可选计数(view/like/duration)。(2. 登记一条内容(直写数据仓分区,与 convert 产物同形):( ```bash( cd <kol-data 仓> && lzi-kol-markdown capture add \\( --kol <slug> --platform bilibili --id BV1xx411c7mD \\( --title <标题> --author-id <mid> --author-name <名> \\( --published-at 2026-09-20T10:00:00Z \\( --source-url https://www.bilibili.com/video/BV1xx411c7mD \\( --payload-json \'{"view_count":1000,"like_count":50,"duration_sec":301}\'( ```(3. 内容类型非视频时加 `--content-type article|post|answer|note|tweet`。(4. 落数据仓:`cd <kol-data 仓> && bun run kol:convert --all`(幂等;同 hash 零变更零提交;条目落 kols/<slug>/<platform>/ 分区)。((## 三、纪律((- 登记即校验:capture add 以 KolContent 契约 zod 守卫,坏数据直接拒绝——不绕过。(- 禁手改数据仓内容档与 catalog.md(工具生成面);更正 = 重新 capture add 覆写。(- 只取公开可见信息;不得伪造计数或时间,取不到的留空。('.split(`(`)).join(`
19
+ `)}function Q(){return(/* @__PURE__ */ '---,lzi: true,name: kol-ops,description: KOL 追踪日常运维 runbook:属主采集→统一导出→数据仓转换→对账的完整操作序与降级路径,例行追踪/灌数操作前使用。,---,,# 日常运维(kol-ops),,## 一、完整操作序(例行追踪),,1. 平台采集(m5 各属主仓,已有 auto 接线时):, ```bash, cd <m5>/longzai-intelligence-youtube && bun run dev -- save --channel <频道URL或ID>, bun run dev -- export-videos, cd <m5>/longzai-intelligence-douyin && bun run dev -- save --channel <主页URL> && bun run dev -- export-videos, ```,2. 统一导出(KOL 属主引擎,产物落台账仓运行域):, ```bash, cd <m5>/longzai-intelligence-kol-registry && lzi-kol export-contents, ```,3. 数据仓转换与对账(kol-data 仓;--kol 可限定单 KOL):, ```bash, bun run kol:convert && bun run kol:verify, ```,,## 二、降级路径,,- douyin 属主采集缺登录 cookie(LZI_DOUYIN_AUTH_COOKIE):save 不可用 → 走 skill kol-capture 人工登记通道(源接线已在台账 sources/ 常态在位,与 cookie 无关)。,- 某平台无采集工具:同上,一律 kol-capture 通道。,- 台账导出目录缺失:先执行 lzi-kol export-contents(产物落台账 runs/),再回到本步骤。,,## 三、纪律,,- convert 幂等:重跑零变更零提交;verify 必须全绿才算完成一轮。,- git 提交由 convert 托管(显式路径提交);出现漂移先 verify 定位,禁止手改内容档"修复"。,- changelog 条目一律走 `bun run changelog:add --`(写前读 changelog-writing skill)。,'.split(`,`)).join(`
20
+ `)}function $(e,t,n,r){let i=T(e,t),a=T(i,`..`);D(a)||O(a,{recursive:!0}),!D(i)&&(ne(i,n,`utf8`),r.push(t))}async function ze(e){D(e.targetDir)||O(e.targetDir,{recursive:!0});let n=[],r=t({dataRoot:`.`}),i=[`# macOS`,`.DS_Store`,``,`# 机器本地配置(.env 本地实值;配置文件入库跟踪,不忽略)`,`.env`,``].join(`
21
+ `);$(e.targetDir,`.gitignore`,i,n),$(e.targetDir,`package.json`,Me(),n),$(e.targetDir,`CHANGELOG.md`,Ne(),n),$(e.targetDir,`lzi-kol-markdown.config.ts`,r,n),$(e.targetDir,`lzi-dev.config.ts`,Ie(),n),$(e.targetDir,`.env.example`,N({title:`lzi-kol-markdown 就地环境配置模板`}),n),$(e.targetDir,`docs/overview.md`,je(),n),$(e.targetDir,`docs/research/README.md`,Ae(),n),$(e.targetDir,`kols/README.md`,Z(),n),$(e.targetDir,`.lzi/skills/kol-research/SKILL.md`,Le(),n),$(e.targetDir,`.lzi/skills/kol-capture/SKILL.md`,Re(),n),$(e.targetDir,`.lzi/skills/kol-ops/SKILL.md`,Q(),n);let a=e.gitInit!==!1&&await y(e.targetDir);return{targetDir:e.targetDir,createdFiles:n,gitInitialized:a}}export{Y as CatalogService,q as ContentIndexService,j as ENV_CONTENTS_EXPORT_DIR,i as KolContentSchema,J as ProfileService,o as REGISTRY_SNAPSHOT_FILENAME,Se as captureAdd,L as contentTypeDir,F as createContentsSource,Ne as dataRepoChangelogText,Pe as dataRepoGitignoreText,Ie as dataRepoLziDevConfigText,Fe as dataRepoLziGitConfigText,Me as dataRepoPackageJsonText,z as entryFilenameOf,b as failure,ae as kolMarkdownEnvKit,re as kolMarkdownEnvSchema,Z as kolsReadmeText,P as listKolSlugs,je as overviewText,R as partitionKeyOf,I as readRegistrySnapshot,G as renderCatalog,H as renderContentDocument,K as renderDataRootReadme,N as renderEnvTemplate,U as renderPartitionReadme,W as renderProfileKol,Ae as researchReadmeText,ie as resolveEnv,oe as resolveRuntimeEnv,Te as runConvert,ze as runScaffoldDataRepo,ke as runVerify,Re as skillKolCaptureText,Q as skillKolOpsText,Le as skillKolResearchText,w as success,u as toContentsExportFilename};
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@longzai-intelligence-kol-markdown/core",
3
+ "version": "0.0.1",
4
+ "description": "Longzai Intelligence KOL Markdown core - 行契约镜像 + 确定性渲染 + 平台分区写入 + 档案/目录册 + verify + init 脚手架",
5
+ "license": "UNLICENSED",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "type": "module",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ }
15
+ },
16
+ "scripts": {
17
+ "build": "lzi-builder",
18
+ "build:prod": "NODE_ENV=production bun run build",
19
+ "prepublishOnly": "bun run build:prod",
20
+ "typecheck": "bun run typecheck:app && bun run typecheck:node && bun run typecheck:test",
21
+ "typecheck:app": "lzi-tsgo typecheck tsconfig/app.json",
22
+ "typecheck:node": "lzi-tsgo typecheck tsconfig/node.json",
23
+ "typecheck:test": "lzi-tsgo typecheck tsconfig/test.json",
24
+ "lint": "oxlint && oxfmt --check",
25
+ "lint:fix": "oxlint --fix && oxfmt",
26
+ "test": "lzi-bun-cli test",
27
+ "test:watch": "lzi-bun-cli test --watch",
28
+ "test:coverage": "lzi-bun-cli test --coverage",
29
+ "clean": "lzi-dev-cli clean"
30
+ },
31
+ "dependencies": {
32
+ "@longzai-intelligence-kol-markdown/config": "0.0.1",
33
+ "@longzai-intelligence-kol/core": "^0.0.2",
34
+ "@longzai-intelligence-markdown/data-engine": "^0.0.1",
35
+ "zod": "^4.4.3"
36
+ },
37
+ "devDependencies": {
38
+ "@types/bun": "^1.3.14"
39
+ }
40
+ }