@coralai/sps-cli 0.50.24 → 0.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -1
- package/dist/commands/projectInit.d.ts +15 -0
- package/dist/commands/projectInit.d.ts.map +1 -1
- package/dist/commands/projectInit.js +191 -3
- package/dist/commands/projectInit.js.map +1 -1
- package/dist/commands/wikiCommand.d.ts +77 -0
- package/dist/commands/wikiCommand.d.ts.map +1 -0
- package/dist/commands/wikiCommand.js +489 -0
- package/dist/commands/wikiCommand.js.map +1 -0
- package/dist/console/routes/projects.d.ts.map +1 -1
- package/dist/console/routes/projects.js +1 -0
- package/dist/console/routes/projects.js.map +1 -1
- package/dist/console-assets/assets/{index-BgOHCIG1.css → index-DlwaKe2l.css} +1 -1
- package/dist/console-assets/assets/{index-QBai48VV.js → index-Gjim492C.js} +1 -1
- package/dist/console-assets/index.html +2 -2
- package/dist/core/taskPrompts.d.ts +12 -0
- package/dist/core/taskPrompts.d.ts.map +1 -1
- package/dist/core/taskPrompts.js +14 -0
- package/dist/core/taskPrompts.js.map +1 -1
- package/dist/core/wiki/frontmatter.d.ts +55 -0
- package/dist/core/wiki/frontmatter.d.ts.map +1 -0
- package/dist/core/wiki/frontmatter.js +109 -0
- package/dist/core/wiki/frontmatter.js.map +1 -0
- package/dist/core/wiki/hot.d.ts +27 -0
- package/dist/core/wiki/hot.d.ts.map +1 -0
- package/dist/core/wiki/hot.js +124 -0
- package/dist/core/wiki/hot.js.map +1 -0
- package/dist/core/wiki/index-builder.d.ts +37 -0
- package/dist/core/wiki/index-builder.d.ts.map +1 -0
- package/dist/core/wiki/index-builder.js +130 -0
- package/dist/core/wiki/index-builder.js.map +1 -0
- package/dist/core/wiki/linter.d.ts +76 -0
- package/dist/core/wiki/linter.d.ts.map +1 -0
- package/dist/core/wiki/linter.js +280 -0
- package/dist/core/wiki/linter.js.map +1 -0
- package/dist/core/wiki/log.d.ts +24 -0
- package/dist/core/wiki/log.d.ts.map +1 -0
- package/dist/core/wiki/log.js +107 -0
- package/dist/core/wiki/log.js.map +1 -0
- package/dist/core/wiki/manifest.d.ts +59 -0
- package/dist/core/wiki/manifest.d.ts.map +1 -0
- package/dist/core/wiki/manifest.js +180 -0
- package/dist/core/wiki/manifest.js.map +1 -0
- package/dist/core/wiki/page.d.ts +72 -0
- package/dist/core/wiki/page.d.ts.map +1 -0
- package/dist/core/wiki/page.js +221 -0
- package/dist/core/wiki/page.js.map +1 -0
- package/dist/core/wiki/reader.d.ts +102 -0
- package/dist/core/wiki/reader.d.ts.map +1 -0
- package/dist/core/wiki/reader.js +225 -0
- package/dist/core/wiki/reader.js.map +1 -0
- package/dist/core/wiki/scaffold.d.ts +42 -0
- package/dist/core/wiki/scaffold.d.ts.map +1 -0
- package/dist/core/wiki/scaffold.js +223 -0
- package/dist/core/wiki/scaffold.js.map +1 -0
- package/dist/core/wiki/searcher.d.ts +73 -0
- package/dist/core/wiki/searcher.d.ts.map +1 -0
- package/dist/core/wiki/searcher.js +216 -0
- package/dist/core/wiki/searcher.js.map +1 -0
- package/dist/core/wiki/sources.d.ts +84 -0
- package/dist/core/wiki/sources.d.ts.map +1 -0
- package/dist/core/wiki/sources.js +261 -0
- package/dist/core/wiki/sources.js.map +1 -0
- package/dist/core/wiki/types.d.ts +904 -0
- package/dist/core/wiki/types.d.ts.map +1 -0
- package/dist/core/wiki/types.js +109 -0
- package/dist/core/wiki/types.js.map +1 -0
- package/dist/engines/StageEngine.d.ts +17 -1
- package/dist/engines/StageEngine.d.ts.map +1 -1
- package/dist/engines/StageEngine.js +85 -0
- package/dist/engines/StageEngine.js.map +1 -1
- package/dist/main.js +78 -1
- package/dist/main.js.map +1 -1
- package/dist/services/ProjectService.d.ts +2 -0
- package/dist/services/ProjectService.d.ts.map +1 -1
- package/dist/services/ProjectService.js.map +1 -1
- package/dist/shared/wikiPaths.d.ts +38 -0
- package/dist/shared/wikiPaths.d.ts.map +1 -0
- package/dist/shared/wikiPaths.js +89 -0
- package/dist/shared/wikiPaths.js.map +1 -0
- package/package.json +1 -1
- package/skills/wiki-update/SKILL.md +300 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../src/core/wiki/manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { FrontmatterError } from './frontmatter.js';
|
|
2
|
+
import type { Frontmatter, Page, PageType } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* 读单页。文件不存在返 null。frontmatter 损坏抛 FrontmatterError。
|
|
5
|
+
*/
|
|
6
|
+
export declare function readPage(filePath: string): Page | null;
|
|
7
|
+
/**
|
|
8
|
+
* 读单页(宽松版本):损坏不抛,返 ParseFailure 标记。
|
|
9
|
+
* 用于 list 扫描时一页坏不阻塞整体。
|
|
10
|
+
*/
|
|
11
|
+
export type ReadResult = {
|
|
12
|
+
ok: true;
|
|
13
|
+
page: Page;
|
|
14
|
+
} | {
|
|
15
|
+
ok: false;
|
|
16
|
+
filePath: string;
|
|
17
|
+
error: FrontmatterError;
|
|
18
|
+
};
|
|
19
|
+
export declare function tryReadPage(filePath: string): ReadResult | null;
|
|
20
|
+
/**
|
|
21
|
+
* 写一页。父目录不存在自动建。frontmatter 写前 zod 校验(serializeFrontmatter 内部
|
|
22
|
+
* 假设已校验,这里通过 page.frontmatter 的类型推断保证)。
|
|
23
|
+
*
|
|
24
|
+
* - 已存在:覆盖
|
|
25
|
+
* - 不存在:创建
|
|
26
|
+
*
|
|
27
|
+
* 返回写入的最终 filePath(绝对路径)。
|
|
28
|
+
*/
|
|
29
|
+
export declare function writePage(repoDir: string, type: PageType, title: string, frontmatter: Frontmatter, body: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* 删除一页。文件不存在 = no-op。
|
|
32
|
+
*/
|
|
33
|
+
export declare function deletePage(repoDir: string, type: PageType, title: string): boolean;
|
|
34
|
+
export interface ListOptions {
|
|
35
|
+
/** 限定类型(默认全部 5 类) */
|
|
36
|
+
readonly types?: readonly PageType[];
|
|
37
|
+
/** 是否包含损坏的页(带 ok=false 的 entry);默认 false(只返成功的) */
|
|
38
|
+
readonly includeFailures?: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 列出指定项目下所有 wiki page。
|
|
42
|
+
*
|
|
43
|
+
* 类型 dir 不存在 → 跳过(不算错误,project 可能没创建那种类型)。
|
|
44
|
+
* 单页损坏 → 默认跳过;includeFailures=true 时保留。
|
|
45
|
+
*/
|
|
46
|
+
export declare function listPages(repoDir: string, opts?: ListOptions): ReadResult[];
|
|
47
|
+
/**
|
|
48
|
+
* 仅返成功读取的页。语法糖(list 90% 场景)。
|
|
49
|
+
*/
|
|
50
|
+
export declare function listValidPages(repoDir: string, opts?: ListOptions): Page[];
|
|
51
|
+
/**
|
|
52
|
+
* 按 pageId(如 "modules/PipelineService")查找 page。
|
|
53
|
+
* 自动从 id 拆出 type 和 title。
|
|
54
|
+
*/
|
|
55
|
+
export declare function getPageById(repoDir: string, pageId: string): Page | null;
|
|
56
|
+
/**
|
|
57
|
+
* 按 wikilink "[[Page Name]]" 查找 page。会扫所有 type 直到找到第一个 title 匹配。
|
|
58
|
+
* 用于解析 frontmatter related 字段或 body 里的 wikilink。
|
|
59
|
+
*
|
|
60
|
+
* Wikilink 可以带 type 前缀 "[[modules/PipelineService]]" —— 这种走 getPageById。
|
|
61
|
+
*/
|
|
62
|
+
export declare function findPageByWikilink(repoDir: string, wikilink: string): Page | null;
|
|
63
|
+
/**
|
|
64
|
+
* 给定文件绝对路径,反推 pageId(type + title)。
|
|
65
|
+
* 无效路径返 null。
|
|
66
|
+
*/
|
|
67
|
+
export declare function resolvePageId(repoDir: string, filePath: string): {
|
|
68
|
+
type: PageType;
|
|
69
|
+
title: string;
|
|
70
|
+
pageId: string;
|
|
71
|
+
} | null;
|
|
72
|
+
//# sourceMappingURL=page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../src/core/wiki/page.ts"],"names":[],"mappings":"AAoCA,OAAO,EAAE,gBAAgB,EAA0C,MAAM,kBAAkB,CAAC;AAC5F,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI9D;;GAEG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAWtD;AAWD;;;GAGG;AACH,MAAM,MAAM,UAAU,GAClB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE,GACxB;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAE7D,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CA0B/D;AAID;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE,MAAM,GACX,MAAM,CAcR;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAKlF;AAID,MAAM,WAAW,WAAW;IAC1B,qBAAqB;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IACrC,mDAAmD;IACnD,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;CACpC;AAUD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,UAAU,EAAE,CAgC/E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,IAAI,EAAE,CAI9E;AAID;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAYxE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAajF;AAID;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAE1D"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module core/wiki/page
|
|
3
|
+
* @description Wiki page CRUD:读 / 写 / 列表 / 取
|
|
4
|
+
*
|
|
5
|
+
* @layer core
|
|
6
|
+
*
|
|
7
|
+
* 这层负责文件系统操作 + frontmatter 解析。**不做** schema 推断、不做内容生成、
|
|
8
|
+
* 不做检索——那些是上层 reader/searcher 的事。
|
|
9
|
+
*
|
|
10
|
+
* 错误策略:
|
|
11
|
+
* - 不存在的 page:返 null,调用方决定怎么处理
|
|
12
|
+
* - 损坏的 page(frontmatter 解析失败):返 ParseFailure,**不抛**——避免一页坏阻塞 list
|
|
13
|
+
* - 写入:写前校验 frontmatter,失败时抛 FrontmatterError
|
|
14
|
+
*
|
|
15
|
+
* 测试要点:
|
|
16
|
+
* - round-trip:write → read → frontmatter / body 等价
|
|
17
|
+
* - 损坏 page 不影响 list 其他页
|
|
18
|
+
* - parseWikiPageId 反推一致
|
|
19
|
+
*/
|
|
20
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync, } from 'node:fs';
|
|
21
|
+
import { dirname, resolve } from 'node:path';
|
|
22
|
+
import { parseWikiPageId, wikiPageDir, wikiPageFile, wikiPageId, } from '../../shared/wikiPaths.js';
|
|
23
|
+
import { FrontmatterError, parseFrontmatter, serializeFrontmatter } from './frontmatter.js';
|
|
24
|
+
// ─── 单页读取 ─────────────────────────────────────────────────────
|
|
25
|
+
/**
|
|
26
|
+
* 读单页。文件不存在返 null。frontmatter 损坏抛 FrontmatterError。
|
|
27
|
+
*/
|
|
28
|
+
export function readPage(filePath) {
|
|
29
|
+
if (!existsSync(filePath))
|
|
30
|
+
return null;
|
|
31
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
32
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
33
|
+
// 文件路径反推 pageId
|
|
34
|
+
// 文件路径形如 .../wiki/<type>s/<title>.md ——但我们这里只有绝对 filePath,
|
|
35
|
+
// 没有 repoDir 上下文。所以 pageId 通过路径基础名推:
|
|
36
|
+
const pageId = inferPageIdFromPath(filePath, frontmatter);
|
|
37
|
+
return { pageId, filePath, frontmatter, body };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 从绝对 filePath + frontmatter.type 推 pageId。
|
|
41
|
+
* 假设:filePath 形如 `<...>/<type>s/<title>.md`。
|
|
42
|
+
*/
|
|
43
|
+
function inferPageIdFromPath(filePath, fm) {
|
|
44
|
+
const base = filePath.replace(/\.md$/, '').split('/').pop() ?? fm.title;
|
|
45
|
+
return wikiPageId(fm.type, base);
|
|
46
|
+
}
|
|
47
|
+
export function tryReadPage(filePath) {
|
|
48
|
+
if (!existsSync(filePath))
|
|
49
|
+
return null;
|
|
50
|
+
let content;
|
|
51
|
+
try {
|
|
52
|
+
content = readFileSync(filePath, 'utf-8');
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
return {
|
|
56
|
+
ok: false,
|
|
57
|
+
filePath,
|
|
58
|
+
error: new FrontmatterError(`read failed: ${errMsg(err)}`, err),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
63
|
+
const pageId = inferPageIdFromPath(filePath, frontmatter);
|
|
64
|
+
return { ok: true, page: { pageId, filePath, frontmatter, body } };
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
return {
|
|
68
|
+
ok: false,
|
|
69
|
+
filePath,
|
|
70
|
+
error: err instanceof FrontmatterError
|
|
71
|
+
? err
|
|
72
|
+
: new FrontmatterError(`parse failed: ${errMsg(err)}`, err),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// ─── 单页写入 ─────────────────────────────────────────────────────
|
|
77
|
+
/**
|
|
78
|
+
* 写一页。父目录不存在自动建。frontmatter 写前 zod 校验(serializeFrontmatter 内部
|
|
79
|
+
* 假设已校验,这里通过 page.frontmatter 的类型推断保证)。
|
|
80
|
+
*
|
|
81
|
+
* - 已存在:覆盖
|
|
82
|
+
* - 不存在:创建
|
|
83
|
+
*
|
|
84
|
+
* 返回写入的最终 filePath(绝对路径)。
|
|
85
|
+
*/
|
|
86
|
+
export function writePage(repoDir, type, title, frontmatter, body) {
|
|
87
|
+
if (frontmatter.type !== type) {
|
|
88
|
+
throw new Error(`Page type mismatch: dir says "${type}" but frontmatter says "${frontmatter.type}"`);
|
|
89
|
+
}
|
|
90
|
+
const filePath = wikiPageFile(repoDir, type, title);
|
|
91
|
+
const dir = dirname(filePath);
|
|
92
|
+
if (!existsSync(dir)) {
|
|
93
|
+
mkdirSync(dir, { recursive: true });
|
|
94
|
+
}
|
|
95
|
+
const content = serializeFrontmatter(frontmatter, body);
|
|
96
|
+
writeFileSync(filePath, content, { encoding: 'utf-8', mode: 0o644 });
|
|
97
|
+
return filePath;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* 删除一页。文件不存在 = no-op。
|
|
101
|
+
*/
|
|
102
|
+
export function deletePage(repoDir, type, title) {
|
|
103
|
+
const filePath = wikiPageFile(repoDir, type, title);
|
|
104
|
+
if (!existsSync(filePath))
|
|
105
|
+
return false;
|
|
106
|
+
rmSync(filePath, { force: true });
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
const ALL_PAGE_TYPES = [
|
|
110
|
+
'module',
|
|
111
|
+
'concept',
|
|
112
|
+
'decision',
|
|
113
|
+
'lesson',
|
|
114
|
+
'source',
|
|
115
|
+
];
|
|
116
|
+
/**
|
|
117
|
+
* 列出指定项目下所有 wiki page。
|
|
118
|
+
*
|
|
119
|
+
* 类型 dir 不存在 → 跳过(不算错误,project 可能没创建那种类型)。
|
|
120
|
+
* 单页损坏 → 默认跳过;includeFailures=true 时保留。
|
|
121
|
+
*/
|
|
122
|
+
export function listPages(repoDir, opts = {}) {
|
|
123
|
+
const types = opts.types ?? ALL_PAGE_TYPES;
|
|
124
|
+
const out = [];
|
|
125
|
+
for (const t of types) {
|
|
126
|
+
const dir = wikiPageDir(repoDir, t);
|
|
127
|
+
if (!existsSync(dir))
|
|
128
|
+
continue;
|
|
129
|
+
let entries;
|
|
130
|
+
try {
|
|
131
|
+
entries = readdirSync(dir);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
for (const name of entries) {
|
|
137
|
+
if (!name.endsWith('.md'))
|
|
138
|
+
continue;
|
|
139
|
+
// _index.md 是辅助索引,不算 page
|
|
140
|
+
if (name.startsWith('_'))
|
|
141
|
+
continue;
|
|
142
|
+
const filePath = resolve(dir, name);
|
|
143
|
+
try {
|
|
144
|
+
const stat = statSync(filePath);
|
|
145
|
+
if (!stat.isFile())
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const result = tryReadPage(filePath);
|
|
152
|
+
if (!result)
|
|
153
|
+
continue;
|
|
154
|
+
if (!result.ok && !opts.includeFailures)
|
|
155
|
+
continue;
|
|
156
|
+
out.push(result);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return out;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* 仅返成功读取的页。语法糖(list 90% 场景)。
|
|
163
|
+
*/
|
|
164
|
+
export function listValidPages(repoDir, opts = {}) {
|
|
165
|
+
return listPages(repoDir, { ...opts, includeFailures: false })
|
|
166
|
+
.filter((r) => r.ok)
|
|
167
|
+
.map((r) => r.page);
|
|
168
|
+
}
|
|
169
|
+
// ─── 按 id 取 ─────────────────────────────────────────────────────
|
|
170
|
+
/**
|
|
171
|
+
* 按 pageId(如 "modules/PipelineService")查找 page。
|
|
172
|
+
* 自动从 id 拆出 type 和 title。
|
|
173
|
+
*/
|
|
174
|
+
export function getPageById(repoDir, pageId) {
|
|
175
|
+
const slashIdx = pageId.indexOf('/');
|
|
176
|
+
if (slashIdx === -1)
|
|
177
|
+
return null;
|
|
178
|
+
const typeWithS = pageId.slice(0, slashIdx);
|
|
179
|
+
const title = pageId.slice(slashIdx + 1);
|
|
180
|
+
// typeWithS 是复数("modules"),去 s 得到 type
|
|
181
|
+
if (!typeWithS.endsWith('s'))
|
|
182
|
+
return null;
|
|
183
|
+
const type = typeWithS.slice(0, -1);
|
|
184
|
+
if (!ALL_PAGE_TYPES.includes(type))
|
|
185
|
+
return null;
|
|
186
|
+
const filePath = wikiPageFile(repoDir, type, title);
|
|
187
|
+
return readPage(filePath);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* 按 wikilink "[[Page Name]]" 查找 page。会扫所有 type 直到找到第一个 title 匹配。
|
|
191
|
+
* 用于解析 frontmatter related 字段或 body 里的 wikilink。
|
|
192
|
+
*
|
|
193
|
+
* Wikilink 可以带 type 前缀 "[[modules/PipelineService]]" —— 这种走 getPageById。
|
|
194
|
+
*/
|
|
195
|
+
export function findPageByWikilink(repoDir, wikilink) {
|
|
196
|
+
const stripped = wikilink.replace(/^\[\[/, '').replace(/\]\]$/, '');
|
|
197
|
+
if (stripped.includes('/')) {
|
|
198
|
+
return getPageById(repoDir, stripped);
|
|
199
|
+
}
|
|
200
|
+
// 无前缀:扫所有 type 找 title 匹配(注意可能多个 type 同名,按数组顺序取第一个)
|
|
201
|
+
for (const type of ALL_PAGE_TYPES) {
|
|
202
|
+
const filePath = wikiPageFile(repoDir, type, stripped);
|
|
203
|
+
if (existsSync(filePath)) {
|
|
204
|
+
return readPage(filePath);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
// ─── 反向查询:路径 → page meta ───────────────────────────────────
|
|
210
|
+
/**
|
|
211
|
+
* 给定文件绝对路径,反推 pageId(type + title)。
|
|
212
|
+
* 无效路径返 null。
|
|
213
|
+
*/
|
|
214
|
+
export function resolvePageId(repoDir, filePath) {
|
|
215
|
+
return parseWikiPageId(repoDir, filePath);
|
|
216
|
+
}
|
|
217
|
+
// ─── helpers ──────────────────────────────────────────────────────
|
|
218
|
+
function errMsg(err) {
|
|
219
|
+
return err instanceof Error ? err.message : String(err);
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.js","sourceRoot":"","sources":["../../../src/core/wiki/page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EACL,UAAU,EACV,SAAS,EACT,WAAW,EACX,YAAY,EACZ,MAAM,EACN,QAAQ,EACR,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EACL,eAAe,EAEf,WAAW,EACX,YAAY,EACZ,UAAU,GACX,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAG5F,iEAAiE;AAEjE;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,QAAgB;IACvC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAChD,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAExD,gBAAgB;IAChB,2DAA2D;IAC3D,qCAAqC;IACrC,MAAM,MAAM,GAAG,mBAAmB,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAE1D,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;AACjD,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAAC,QAAgB,EAAE,EAAe;IAC5D,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC;IACxE,OAAO,UAAU,CAAC,EAAE,CAAC,IAAoB,EAAE,IAAI,CAAC,CAAC;AACnD,CAAC;AAUD,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,EAAE,EAAE,KAAK;YACT,QAAQ;YACR,KAAK,EAAE,IAAI,gBAAgB,CAAC,gBAAgB,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC;SAChE,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACxD,MAAM,MAAM,GAAG,mBAAmB,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QAC1D,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC;IACrE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,EAAE,EAAE,KAAK;YACT,QAAQ;YACR,KAAK,EACH,GAAG,YAAY,gBAAgB;gBAC7B,CAAC,CAAC,GAAG;gBACL,CAAC,CAAC,IAAI,gBAAgB,CAAC,iBAAiB,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC;SAChE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,iEAAiE;AAEjE;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CACvB,OAAe,EACf,IAAc,EACd,KAAa,EACb,WAAwB,EACxB,IAAY;IAEZ,IAAI,WAAW,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,iCAAiC,IAAI,2BAA2B,WAAW,CAAC,IAAI,GAAG,CACpF,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACpD,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,MAAM,OAAO,GAAG,oBAAoB,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IACxD,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrE,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,IAAc,EAAE,KAAa;IACvE,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACpD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,MAAM,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAClC,OAAO,IAAI,CAAC;AACd,CAAC;AAWD,MAAM,cAAc,GAAwB;IAC1C,QAAQ;IACR,SAAS;IACT,UAAU;IACV,QAAQ;IACR,QAAQ;CACT,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,OAAoB,EAAE;IAC/D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,cAAc,CAAC;IAC3C,MAAM,GAAG,GAAiB,EAAE,CAAC;IAE7B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACpC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAC/B,IAAI,OAAiB,CAAC;QACtB,IAAI,CAAC;YACH,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;YAC3B,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAAE,SAAS;YACpC,0BAA0B;YAC1B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAS;YACnC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACpC,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;gBAChC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;oBAAE,SAAS;YAC/B,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YACD,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;YACrC,IAAI,CAAC,MAAM;gBAAE,SAAS;YACtB,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe;gBAAE,SAAS;YAClD,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,OAAoB,EAAE;IACpE,OAAO,SAAS,CAAC,OAAO,EAAE,EAAE,GAAG,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC;SAC3D,MAAM,CAAC,CAAC,CAAC,EAAiC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAClD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED,mEAAmE;AAEnE;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,MAAc;IACzD,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,QAAQ,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACjC,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;IACzC,uCAAuC;IACvC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAa,CAAC;IAChD,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEhD,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACpD,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe,EAAE,QAAgB;IAClE,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACpE,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACxC,CAAC;IACD,oDAAoD;IACpD,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QACvD,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8DAA8D;AAE9D;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,OAAe,EACf,QAAgB;IAEhB,OAAO,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAC5C,CAAC;AAED,qEAAqE;AAErE,SAAS,MAAM,CAAC,GAAY;IAC1B,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC1D,CAAC"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module core/wiki/reader
|
|
3
|
+
* @description wikiRead():5 层确定性检索 + 类型优先级 + token 预算
|
|
4
|
+
*
|
|
5
|
+
* @layer core
|
|
6
|
+
*
|
|
7
|
+
* doc-28 §10 Wiki 读取原则的代码实现。**这是 Worker prompt 注入的入口**。
|
|
8
|
+
*
|
|
9
|
+
* 5 层叠加:
|
|
10
|
+
* L1 永远 — hot.md 全文 ~500 字
|
|
11
|
+
* L2 永远 — index.md 节选 top-N 行 ~500 字
|
|
12
|
+
* L3 优先 — pinned wiki_pages(card frontmatter) ~50×N 字
|
|
13
|
+
* L4 按 skill — 卡 skills ∩ 页 tags → top-3 ~50×3 字
|
|
14
|
+
* L5 按关键词 — BM25(card.title + card.desc)→top-3 ~50×3 字
|
|
15
|
+
*
|
|
16
|
+
* 优先级排序(命中多页):
|
|
17
|
+
* lesson = 3 / decision = 3 / concept = 2 / module = 1 / source = 1
|
|
18
|
+
* stale page → 跳过(status=stale 或 mtime 太老)
|
|
19
|
+
*
|
|
20
|
+
* Token 预算硬上限 1500 字(~2000 token),超出砍 L5 keyword 命中。
|
|
21
|
+
*
|
|
22
|
+
* 设计原则(Karpathy):
|
|
23
|
+
* - **确定性**——同输入同输出,纯函数(除文件 I/O)
|
|
24
|
+
* - **Push 而非 Pull**——Worker 不需要学怎么查,结果已经摆好
|
|
25
|
+
* - **TL;DR 而非全文**——让 Worker 自己决定要不要 Read 完整 page
|
|
26
|
+
*/
|
|
27
|
+
import type { PageType } from './types.js';
|
|
28
|
+
export interface ReadInput {
|
|
29
|
+
/** Repo 根目录(用于查 wiki/) */
|
|
30
|
+
readonly repoDir: string;
|
|
31
|
+
/** 当前卡片 title + description(用作 BM25 查询) */
|
|
32
|
+
readonly cardTitle: string;
|
|
33
|
+
readonly cardDesc: string;
|
|
34
|
+
/** 卡 frontmatter 的 skills(用作 tag 匹配) */
|
|
35
|
+
readonly cardSkills: readonly string[];
|
|
36
|
+
/** 卡 labels(暂未用,预留扩展) */
|
|
37
|
+
readonly cardLabels?: readonly string[];
|
|
38
|
+
/** 卡 frontmatter wiki_pages 显式 pin 的 page ids */
|
|
39
|
+
readonly pinnedPages?: readonly string[];
|
|
40
|
+
}
|
|
41
|
+
export interface PageContextEntry {
|
|
42
|
+
readonly pageId: string;
|
|
43
|
+
readonly title: string;
|
|
44
|
+
readonly type: PageType;
|
|
45
|
+
readonly tldr: string;
|
|
46
|
+
/** 命中来源——用于 prompt 渲染时分组显示 */
|
|
47
|
+
readonly source: 'pinned' | 'skill' | 'keyword';
|
|
48
|
+
/** 内部排序权重(debug) */
|
|
49
|
+
readonly priority: number;
|
|
50
|
+
}
|
|
51
|
+
export interface WikiContext {
|
|
52
|
+
/** L1: hot.md 全文 */
|
|
53
|
+
readonly hot: string;
|
|
54
|
+
/** L2: index.md 节选 top-N 行 */
|
|
55
|
+
readonly indexSummary: string;
|
|
56
|
+
/** L3+L4+L5 合并去重 + 预算后的 page 列表 */
|
|
57
|
+
readonly pages: readonly PageContextEntry[];
|
|
58
|
+
/** 可观察性:本次注入的 token 预估 */
|
|
59
|
+
readonly tokensEstimate: number;
|
|
60
|
+
}
|
|
61
|
+
export interface ReadOptions {
|
|
62
|
+
/** Layer 2 节选行数(默认 30) */
|
|
63
|
+
readonly indexLines?: number;
|
|
64
|
+
/** Layer 4 skill 命中 top-N(默认 3) */
|
|
65
|
+
readonly skillTopN?: number;
|
|
66
|
+
/** Layer 5 keyword 命中 top-N(默认 3) */
|
|
67
|
+
readonly keywordTopN?: number;
|
|
68
|
+
/** Token 预算硬上限(默认 2000) */
|
|
69
|
+
readonly budgetTokens?: number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 读取 wiki 注入到 Worker prompt 的上下文。
|
|
73
|
+
*
|
|
74
|
+
* 步骤:
|
|
75
|
+
* 1. Layer 1: hot.md 全文
|
|
76
|
+
* 2. Layer 2: index.md 节选
|
|
77
|
+
* 3. Layer 3: pinned pages(按 id 取)
|
|
78
|
+
* 4. 列所有 page 建临时 searcher
|
|
79
|
+
* 5. Layer 4: skill 匹配
|
|
80
|
+
* 6. Layer 5: BM25 关键词
|
|
81
|
+
* 7. 合并去重 → 类型优先级排序 → 预算截断
|
|
82
|
+
* 8. 装载 TL;DR 入 PageContextEntry
|
|
83
|
+
*
|
|
84
|
+
* 失败模式:任何 layer 失败(文件丢/解析错)单独 swallow,不阻塞其他 layer。
|
|
85
|
+
*/
|
|
86
|
+
export declare function wikiRead(input: ReadInput, opts?: ReadOptions): WikiContext;
|
|
87
|
+
/**
|
|
88
|
+
* WikiContext → prompt 注入 markdown。
|
|
89
|
+
*
|
|
90
|
+
* 格式(doc-28 §10):
|
|
91
|
+
* # 项目知识 - 当前状态
|
|
92
|
+
* <hot.md 全文>
|
|
93
|
+
* ---
|
|
94
|
+
* # 知识地图(节选)
|
|
95
|
+
* <index summary>
|
|
96
|
+
* ---
|
|
97
|
+
* # 与本任务相关的页
|
|
98
|
+
* ## [[id]] (type) [via source]
|
|
99
|
+
* TL;DR: ...
|
|
100
|
+
*/
|
|
101
|
+
export declare function formatWikiContext(ctx: WikiContext): string;
|
|
102
|
+
//# sourceMappingURL=reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../../src/core/wiki/reader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH,OAAO,KAAK,EAAQ,QAAQ,EAAE,MAAM,YAAY,CAAC;AAIjD,MAAM,WAAW,SAAS;IACxB,0BAA0B;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,2CAA2C;IAC3C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,wCAAwC;IACxC,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,yBAAyB;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,iDAAiD;IACjD,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8BAA8B;IAC9B,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;IAChD,oBAAoB;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,oBAAoB;IACpB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,8BAA8B;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,mCAAmC;IACnC,QAAQ,CAAC,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC5C,0BAA0B;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAID,MAAM,WAAW,WAAW;IAC1B,0BAA0B;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,mCAAmC;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,qCAAqC;IACrC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,2BAA2B;IAC3B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAuBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,SAAS,EAChB,IAAI,GAAE,WAAgB,GACrB,WAAW,CAyEb;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CA0B1D"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module core/wiki/reader
|
|
3
|
+
* @description wikiRead():5 层确定性检索 + 类型优先级 + token 预算
|
|
4
|
+
*
|
|
5
|
+
* @layer core
|
|
6
|
+
*
|
|
7
|
+
* doc-28 §10 Wiki 读取原则的代码实现。**这是 Worker prompt 注入的入口**。
|
|
8
|
+
*
|
|
9
|
+
* 5 层叠加:
|
|
10
|
+
* L1 永远 — hot.md 全文 ~500 字
|
|
11
|
+
* L2 永远 — index.md 节选 top-N 行 ~500 字
|
|
12
|
+
* L3 优先 — pinned wiki_pages(card frontmatter) ~50×N 字
|
|
13
|
+
* L4 按 skill — 卡 skills ∩ 页 tags → top-3 ~50×3 字
|
|
14
|
+
* L5 按关键词 — BM25(card.title + card.desc)→top-3 ~50×3 字
|
|
15
|
+
*
|
|
16
|
+
* 优先级排序(命中多页):
|
|
17
|
+
* lesson = 3 / decision = 3 / concept = 2 / module = 1 / source = 1
|
|
18
|
+
* stale page → 跳过(status=stale 或 mtime 太老)
|
|
19
|
+
*
|
|
20
|
+
* Token 预算硬上限 1500 字(~2000 token),超出砍 L5 keyword 命中。
|
|
21
|
+
*
|
|
22
|
+
* 设计原则(Karpathy):
|
|
23
|
+
* - **确定性**——同输入同输出,纯函数(除文件 I/O)
|
|
24
|
+
* - **Push 而非 Pull**——Worker 不需要学怎么查,结果已经摆好
|
|
25
|
+
* - **TL;DR 而非全文**——让 Worker 自己决定要不要 Read 完整 page
|
|
26
|
+
*/
|
|
27
|
+
import { readHot } from './hot.js';
|
|
28
|
+
import { readIndexSummary } from './index-builder.js';
|
|
29
|
+
import { getPageById, listValidPages } from './page.js';
|
|
30
|
+
import { extractTLDR, WikiSearcher } from './searcher.js';
|
|
31
|
+
const DEFAULT_OPTS = {
|
|
32
|
+
indexLines: 30,
|
|
33
|
+
skillTopN: 3,
|
|
34
|
+
keywordTopN: 3,
|
|
35
|
+
budgetTokens: 2000,
|
|
36
|
+
};
|
|
37
|
+
// 类型优先级(数字越大越靠前)
|
|
38
|
+
const TYPE_PRIORITY = {
|
|
39
|
+
lesson: 3,
|
|
40
|
+
decision: 3,
|
|
41
|
+
concept: 2,
|
|
42
|
+
module: 1,
|
|
43
|
+
source: 1,
|
|
44
|
+
};
|
|
45
|
+
// 启发式:1 个汉字/英文单词 ≈ 1.5 token(粗估)
|
|
46
|
+
const CHARS_PER_TOKEN = 1.5;
|
|
47
|
+
// ─── 主入口 ───────────────────────────────────────────────────────
|
|
48
|
+
/**
|
|
49
|
+
* 读取 wiki 注入到 Worker prompt 的上下文。
|
|
50
|
+
*
|
|
51
|
+
* 步骤:
|
|
52
|
+
* 1. Layer 1: hot.md 全文
|
|
53
|
+
* 2. Layer 2: index.md 节选
|
|
54
|
+
* 3. Layer 3: pinned pages(按 id 取)
|
|
55
|
+
* 4. 列所有 page 建临时 searcher
|
|
56
|
+
* 5. Layer 4: skill 匹配
|
|
57
|
+
* 6. Layer 5: BM25 关键词
|
|
58
|
+
* 7. 合并去重 → 类型优先级排序 → 预算截断
|
|
59
|
+
* 8. 装载 TL;DR 入 PageContextEntry
|
|
60
|
+
*
|
|
61
|
+
* 失败模式:任何 layer 失败(文件丢/解析错)单独 swallow,不阻塞其他 layer。
|
|
62
|
+
*/
|
|
63
|
+
export function wikiRead(input, opts = {}) {
|
|
64
|
+
const cfg = { ...DEFAULT_OPTS, ...opts };
|
|
65
|
+
// L1
|
|
66
|
+
const hot = safeRead(() => readHot(input.repoDir), '');
|
|
67
|
+
// L2
|
|
68
|
+
const indexSummary = safeRead(() => readIndexSummary(input.repoDir, cfg.indexLines), '');
|
|
69
|
+
// 拉所有 page 一次(reader.ts 调用频率低 = 卡启动一次;现读 OK)
|
|
70
|
+
const pages = safeRead(() => listValidPages(input.repoDir), []);
|
|
71
|
+
// L3: pinned
|
|
72
|
+
const pinned = (input.pinnedPages ?? [])
|
|
73
|
+
.map((id) => getPageById(input.repoDir, id))
|
|
74
|
+
.filter((p) => p !== null);
|
|
75
|
+
// 临时 searcher 用 IndexedDoc(pageToIndexed 来自 searcher.ts)
|
|
76
|
+
const searcher = new WikiSearcher(pages.map(pageToIndexedAdapter));
|
|
77
|
+
// L4: skill
|
|
78
|
+
const bySkill = searcher
|
|
79
|
+
.searchByTags(input.cardSkills, cfg.skillTopN)
|
|
80
|
+
.map((r) => ({ pageId: r.pageId, source: 'skill' }));
|
|
81
|
+
// L5: keyword
|
|
82
|
+
const byKeyword = searcher
|
|
83
|
+
.search(`${input.cardTitle} ${input.cardDesc}`, cfg.keywordTopN)
|
|
84
|
+
.map((r) => ({ pageId: r.pageId, source: 'keyword' }));
|
|
85
|
+
// 合并去重(按 source 优先级:pinned > skill > keyword)
|
|
86
|
+
const dedup = new Map();
|
|
87
|
+
for (const p of pinned)
|
|
88
|
+
dedup.set(p.pageId, { source: 'pinned' });
|
|
89
|
+
for (const r of bySkill) {
|
|
90
|
+
if (!dedup.has(r.pageId))
|
|
91
|
+
dedup.set(r.pageId, { source: r.source });
|
|
92
|
+
}
|
|
93
|
+
for (const r of byKeyword) {
|
|
94
|
+
if (!dedup.has(r.pageId))
|
|
95
|
+
dedup.set(r.pageId, { source: r.source });
|
|
96
|
+
}
|
|
97
|
+
// 把每个 page 加载完整 + 排序
|
|
98
|
+
const entries = [];
|
|
99
|
+
for (const [pageId, meta] of dedup) {
|
|
100
|
+
const page = pages.find((p) => p.pageId === pageId);
|
|
101
|
+
if (!page)
|
|
102
|
+
continue;
|
|
103
|
+
if (isStalePage(page))
|
|
104
|
+
continue;
|
|
105
|
+
entries.push({
|
|
106
|
+
pageId,
|
|
107
|
+
title: page.frontmatter.title,
|
|
108
|
+
type: page.frontmatter.type,
|
|
109
|
+
tldr: extractTLDR(page.body),
|
|
110
|
+
source: meta.source,
|
|
111
|
+
priority: priorityOf(page.frontmatter.type, meta.source),
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
// 优先级排序
|
|
115
|
+
entries.sort((a, b) => b.priority - a.priority);
|
|
116
|
+
// 预算截断:估算 token,超出从尾部砍 keyword 命中(保 pinned + skill + 高优类型)
|
|
117
|
+
const trimmed = applyBudget(entries, hot, indexSummary, cfg.budgetTokens);
|
|
118
|
+
const tokensEstimate = estimateTokens(hot, indexSummary, trimmed);
|
|
119
|
+
return {
|
|
120
|
+
hot,
|
|
121
|
+
indexSummary,
|
|
122
|
+
pages: trimmed,
|
|
123
|
+
tokensEstimate,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
// ─── Prompt 渲染 ──────────────────────────────────────────────────
|
|
127
|
+
/**
|
|
128
|
+
* WikiContext → prompt 注入 markdown。
|
|
129
|
+
*
|
|
130
|
+
* 格式(doc-28 §10):
|
|
131
|
+
* # 项目知识 - 当前状态
|
|
132
|
+
* <hot.md 全文>
|
|
133
|
+
* ---
|
|
134
|
+
* # 知识地图(节选)
|
|
135
|
+
* <index summary>
|
|
136
|
+
* ---
|
|
137
|
+
* # 与本任务相关的页
|
|
138
|
+
* ## [[id]] (type) [via source]
|
|
139
|
+
* TL;DR: ...
|
|
140
|
+
*/
|
|
141
|
+
export function formatWikiContext(ctx) {
|
|
142
|
+
const sections = [];
|
|
143
|
+
if (ctx.hot.trim().length > 0) {
|
|
144
|
+
// hot 已经是带 frontmatter 的完整文档;展示时去掉 frontmatter 块
|
|
145
|
+
const hotBody = stripFrontmatter(ctx.hot).trim();
|
|
146
|
+
sections.push('# 项目知识 - 当前状态\n\n' + hotBody);
|
|
147
|
+
}
|
|
148
|
+
if (ctx.indexSummary.trim().length > 0) {
|
|
149
|
+
sections.push('# 知识地图(节选)\n\n' + ctx.indexSummary.trim());
|
|
150
|
+
}
|
|
151
|
+
if (ctx.pages.length > 0) {
|
|
152
|
+
const lines = ['# 与本任务相关的页', ''];
|
|
153
|
+
for (const p of ctx.pages) {
|
|
154
|
+
const tag = p.source === 'pinned' ? '📌 pinned' : p.source === 'skill' ? 'via skill' : 'via keyword';
|
|
155
|
+
lines.push(`## [[${p.pageId}]] (${p.type}, ${tag})`);
|
|
156
|
+
lines.push(`TL;DR: ${p.tldr.replace(/\s+/g, ' ').trim().slice(0, 300)}`);
|
|
157
|
+
lines.push('');
|
|
158
|
+
}
|
|
159
|
+
lines.push('完整内容:直接 Read 文件,或 `sps wiki read "<keyword>"` 找更多。');
|
|
160
|
+
sections.push(lines.join('\n'));
|
|
161
|
+
}
|
|
162
|
+
return sections.join('\n\n---\n\n');
|
|
163
|
+
}
|
|
164
|
+
// ─── Helpers (private) ────────────────────────────────────────────
|
|
165
|
+
function pageToIndexedAdapter(p) {
|
|
166
|
+
// 复用 searcher 的工厂;这里手写一份避免循环引用复杂度
|
|
167
|
+
return {
|
|
168
|
+
pageId: p.pageId,
|
|
169
|
+
title: p.frontmatter.title,
|
|
170
|
+
tags: p.frontmatter.tags,
|
|
171
|
+
tldr: extractTLDR(p.body),
|
|
172
|
+
body: p.body,
|
|
173
|
+
type: p.frontmatter.type,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function priorityOf(type, source) {
|
|
177
|
+
// pinned 永远最高(用户/Worker 显式指定)
|
|
178
|
+
// 其他按类型权重
|
|
179
|
+
const sourceBonus = source === 'pinned' ? 100 : source === 'skill' ? 10 : 0;
|
|
180
|
+
return sourceBonus + (TYPE_PRIORITY[type] ?? 1);
|
|
181
|
+
}
|
|
182
|
+
function isStalePage(page) {
|
|
183
|
+
return page.frontmatter.status === 'stale';
|
|
184
|
+
}
|
|
185
|
+
function applyBudget(entries, hot, indexSummary, budgetTokens) {
|
|
186
|
+
const baseTokens = estimateChars(hot) + estimateChars(indexSummary);
|
|
187
|
+
const baseTok = baseTokens / CHARS_PER_TOKEN;
|
|
188
|
+
if (baseTok >= budgetTokens) {
|
|
189
|
+
// hot+index 已超预算 → 不加任何 page
|
|
190
|
+
return [];
|
|
191
|
+
}
|
|
192
|
+
const remaining = budgetTokens - baseTok;
|
|
193
|
+
// 每页 TL;DR 估 ~80 token(300 字符 / 1.5 + 一些 metadata)
|
|
194
|
+
const PER_PAGE_TOKENS = 80;
|
|
195
|
+
const maxPages = Math.max(0, Math.floor(remaining / PER_PAGE_TOKENS));
|
|
196
|
+
if (entries.length <= maxPages)
|
|
197
|
+
return entries.slice();
|
|
198
|
+
// 砍法:保留 pinned + skill,只砍 keyword 末尾
|
|
199
|
+
const pinned = entries.filter((e) => e.source === 'pinned');
|
|
200
|
+
const skill = entries.filter((e) => e.source === 'skill');
|
|
201
|
+
const keyword = entries.filter((e) => e.source === 'keyword');
|
|
202
|
+
const need = Math.max(0, maxPages - pinned.length - skill.length);
|
|
203
|
+
return [...pinned, ...skill, ...keyword.slice(0, need)];
|
|
204
|
+
}
|
|
205
|
+
function estimateTokens(hot, indexSummary, entries) {
|
|
206
|
+
const charCount = estimateChars(hot) +
|
|
207
|
+
estimateChars(indexSummary) +
|
|
208
|
+
entries.reduce((sum, e) => sum + e.title.length + e.tldr.length + 30, 0);
|
|
209
|
+
return Math.ceil(charCount / CHARS_PER_TOKEN);
|
|
210
|
+
}
|
|
211
|
+
function estimateChars(s) {
|
|
212
|
+
return s.length;
|
|
213
|
+
}
|
|
214
|
+
function stripFrontmatter(content) {
|
|
215
|
+
return content.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, '');
|
|
216
|
+
}
|
|
217
|
+
function safeRead(fn, fallback) {
|
|
218
|
+
try {
|
|
219
|
+
return fn();
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
return fallback;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reader.js","sourceRoot":"","sources":["../../../src/core/wiki/reader.ts"],"names":[],"mappings":"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"}
|