svharness 0.14.13 → 0.14.17
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 +148 -9
- package/assets/codechat-agent.ico +0 -0
- package/dist/adapters/codex.js +19 -0
- package/dist/adapters/index.js +2 -0
- package/dist/commands/doctor/utils.js +2 -0
- package/dist/commands/init.js +37 -129
- package/dist/commands/shell-integration.js +40 -3
- package/dist/commands/wiki.js +127 -0
- package/dist/config/index.js +2 -1
- package/dist/config/merge-options.js +19 -0
- package/dist/config/normalize.js +18 -0
- package/dist/core/state.js +39 -0
- package/dist/index.js +58 -10
- package/dist/lib/agent-launcher.js +14 -16
- package/dist/lib/codechat-runner-resolver.js +208 -0
- package/dist/lib/wiki/run-wiki-generation.js +161 -0
- package/dist/lib/win-registry.js +10 -0
- package/dist/utils/validate-args.js +1 -0
- package/dist/wiki/repowikiIndexer.js +19 -150
- package/dist/wiki/repowikiPrompts.js +296 -0
- package/dist/wiki/repowikiStructureNormalize.js +31 -1
- package/dist/wiki/wikiTasksWriter.js +59 -22
- package/docs/agent-launcher-design.md +127 -26
- package/docs/standalone-codechat-ps1.md +123 -0
- package/package.json +2 -1
- package/scripts/preuninstall.js +45 -5
- package/templates/_shared/build-rules/harness-build-rule-agent-agnostic.md +2 -2
- package/templates/_shared/build-rules/harness-build-rule-specs-schema.md +1 -1
- package/templates/_shared/build-skills/harness-build-skill-orchestrator.md +1 -1
- package/templates/_shared/build-skills/harness-build-skill-wiki-writer.md +15 -6
- package/templates/codechat/Start-CodeChat.ps1 +359 -0
- package/templates/svharness.config.example.yaml +7 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared wiki generation logic used by both `svharness build` (Step 6b) and
|
|
4
|
+
* the standalone `svharness wiki` subcommand.
|
|
5
|
+
*
|
|
6
|
+
* This module is harness-agnostic: callers provide absolute paths for the
|
|
7
|
+
* source repo root and output directory. The `build` path copies baseline code
|
|
8
|
+
* first and outputs to `<harness>/baseline/wiki/`; the standalone `wiki` path
|
|
9
|
+
* scans source in-place and outputs to `./wiki/`.
|
|
10
|
+
*/
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.runWikiGeneration = runWikiGeneration;
|
|
16
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
17
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
18
|
+
const wiki_1 = require("../../wiki");
|
|
19
|
+
/**
|
|
20
|
+
* Guard that the source directory exists and is non-empty.
|
|
21
|
+
* Throws if the directory is missing or empty.
|
|
22
|
+
*/
|
|
23
|
+
async function assertSourceNotEmpty(repoRootFs) {
|
|
24
|
+
const exists = await fs_extra_1.default.pathExists(repoRootFs);
|
|
25
|
+
const entries = exists ? await fs_extra_1.default.readdir(repoRootFs) : [];
|
|
26
|
+
if (!exists || entries.length === 0) {
|
|
27
|
+
throw new Error(`Wiki 源码目录为空或不存在:${repoRootFs}。` +
|
|
28
|
+
'请检查 --wiki-source 路径或基线拷贝结果。');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Generate baseline wiki content.
|
|
33
|
+
*
|
|
34
|
+
* This function is non-fatal: on failure it returns `{ ok: false }` instead of
|
|
35
|
+
* throwing, allowing callers (build) to continue with a warning.
|
|
36
|
+
*/
|
|
37
|
+
async function runWikiGeneration(input) {
|
|
38
|
+
const { repoRootFs, wikiOutputRootFs, wikiRelPath, wikiLang, wikiModel, wikiBaseUrl, wikiApiKey, projectName, cliVersion, mode, cwd, forceFull, sourceRootRel, wikiAudience = 'human', onLog, onProgress, } = input;
|
|
39
|
+
const log = onLog ?? (() => { });
|
|
40
|
+
const progressCb = onProgress ??
|
|
41
|
+
((p) => {
|
|
42
|
+
if (p.total > 0) {
|
|
43
|
+
log(` [${p.done}/${p.total}] ${p.detail}`);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
log(` ${p.detail}`);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
const langFolder = wikiLang === 'en' ? 'en' : 'zh';
|
|
50
|
+
const langRun = (0, wiki_1.langRunForRepowikiTarget)(langFolder);
|
|
51
|
+
if (mode === 'full') {
|
|
52
|
+
// --- Full generation (runRepowikiIndex) ---
|
|
53
|
+
let fullOk = false;
|
|
54
|
+
try {
|
|
55
|
+
await assertSourceNotEmpty(repoRootFs);
|
|
56
|
+
const cfg = await (0, wiki_1.resolveWikiRunConfig)({
|
|
57
|
+
cwd: cwd ?? process.cwd(),
|
|
58
|
+
apiKey: wikiApiKey,
|
|
59
|
+
baseUrl: wikiBaseUrl,
|
|
60
|
+
model: wikiModel,
|
|
61
|
+
});
|
|
62
|
+
log(` 源码根:${repoRootFs}`);
|
|
63
|
+
log(` 输出到:${node_path_1.default.join(wikiOutputRootFs, wikiRelPath)}`);
|
|
64
|
+
log(` 语言:${langFolder} · 模型:${cfg.model}`);
|
|
65
|
+
await (0, wiki_1.runRepowikiIndex)({
|
|
66
|
+
repoRootFs,
|
|
67
|
+
wikiOutputRootFs,
|
|
68
|
+
wikiRelPath,
|
|
69
|
+
baseUrl: cfg.baseUrl,
|
|
70
|
+
apiKey: cfg.apiKey,
|
|
71
|
+
model: cfg.model,
|
|
72
|
+
languages: [langRun],
|
|
73
|
+
comprehensiveSections: true,
|
|
74
|
+
wikiAudience,
|
|
75
|
+
forceFull: !!forceFull,
|
|
76
|
+
onLog: log,
|
|
77
|
+
onProgress: progressCb,
|
|
78
|
+
});
|
|
79
|
+
fullOk = true;
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
if ((0, wiki_1.isAbortError)(err)) {
|
|
83
|
+
log('wiki 生成被中断(已写出部分页可从 checkpoint 恢复)');
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
log(`wiki 生成失败:${err.message}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (fullOk) {
|
|
90
|
+
return { ok: true, mode: 'full', wikiPhase: 'done', wikiSource: undefined };
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
ok: false,
|
|
94
|
+
mode: 'full',
|
|
95
|
+
wikiPhase: 'pending',
|
|
96
|
+
wikiSource: 'cli-full-degraded',
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
// --- Tasks-only mode (runRepowikiOutlineOnly + writeWikiTasks) ---
|
|
100
|
+
try {
|
|
101
|
+
await assertSourceNotEmpty(repoRootFs);
|
|
102
|
+
const cfg = await (0, wiki_1.resolveWikiRunConfig)({
|
|
103
|
+
cwd: cwd ?? process.cwd(),
|
|
104
|
+
apiKey: wikiApiKey,
|
|
105
|
+
baseUrl: wikiBaseUrl,
|
|
106
|
+
model: wikiModel,
|
|
107
|
+
});
|
|
108
|
+
log(` 源码根:${repoRootFs}`);
|
|
109
|
+
log(` 输出到:${node_path_1.default.join(wikiOutputRootFs, wikiRelPath)}`);
|
|
110
|
+
log(` 语言:${langFolder} · 模型:${cfg.model}`);
|
|
111
|
+
log(' 模式:仅任务清单(tasks-only)');
|
|
112
|
+
const outline = await (0, wiki_1.runRepowikiOutlineOnly)({
|
|
113
|
+
repoRootFs,
|
|
114
|
+
wikiOutputRootFs,
|
|
115
|
+
wikiRelPath,
|
|
116
|
+
baseUrl: cfg.baseUrl,
|
|
117
|
+
apiKey: cfg.apiKey,
|
|
118
|
+
model: cfg.model,
|
|
119
|
+
languages: [langRun],
|
|
120
|
+
comprehensiveSections: true,
|
|
121
|
+
wikiAudience,
|
|
122
|
+
onLog: log,
|
|
123
|
+
onProgress: progressCb,
|
|
124
|
+
});
|
|
125
|
+
const resolvedSourceRootRel = sourceRootRel ??
|
|
126
|
+
(node_path_1.default.relative(wikiOutputRootFs, repoRootFs).replace(/\\/g, '/') || '.');
|
|
127
|
+
const tasksPath = await (0, wiki_1.writeWikiTasks)({
|
|
128
|
+
outline,
|
|
129
|
+
targetRoot: wikiOutputRootFs,
|
|
130
|
+
wikiRelPath,
|
|
131
|
+
projectName,
|
|
132
|
+
cliVersion,
|
|
133
|
+
model: cfg.model,
|
|
134
|
+
generatedAtIso: new Date().toISOString(),
|
|
135
|
+
sourceRootRel: resolvedSourceRootRel,
|
|
136
|
+
wikiAudience,
|
|
137
|
+
});
|
|
138
|
+
return {
|
|
139
|
+
ok: true,
|
|
140
|
+
mode: 'tasks',
|
|
141
|
+
wikiPhase: 'pending',
|
|
142
|
+
wikiSource: 'cli-tasks',
|
|
143
|
+
tasksPath,
|
|
144
|
+
pageCount: outline.pages.length,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
if ((0, wiki_1.isAbortError)(err)) {
|
|
149
|
+
log('wiki 任务清单生成被中断');
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
log(`wiki 任务清单生成失败:${err.message}`);
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
ok: false,
|
|
156
|
+
mode: 'tasks',
|
|
157
|
+
wikiPhase: 'pending',
|
|
158
|
+
wikiSource: 'cli-tasks',
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
package/dist/lib/win-registry.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SHELL_MENU_LABEL = exports.SHELL_MENU_KEY_DIR = exports.SHELL_MENU_KEY_BG = void 0;
|
|
4
4
|
exports.regSetDefault = regSetDefault;
|
|
5
|
+
exports.regSetString = regSetString;
|
|
5
6
|
exports.regDeleteKey = regDeleteKey;
|
|
6
7
|
exports.regKeyExists = regKeyExists;
|
|
7
8
|
const child_process_1 = require("child_process");
|
|
@@ -18,6 +19,15 @@ function regSetDefault(key, value) {
|
|
|
18
19
|
windowsHide: true,
|
|
19
20
|
});
|
|
20
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Set a named REG_SZ value on a registry key.
|
|
24
|
+
*/
|
|
25
|
+
function regSetString(key, name, value) {
|
|
26
|
+
(0, child_process_1.execSync)(`"${REG}" add "${key}" /v "${name}" /t REG_SZ /d "${quoteRegData(value)}" /f`, {
|
|
27
|
+
stdio: 'pipe',
|
|
28
|
+
windowsHide: true,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
21
31
|
/**
|
|
22
32
|
* Delete a registry key and subkeys.
|
|
23
33
|
*/
|
|
@@ -49,11 +49,12 @@ const repowikiCheckpoint_1 = require("./repowikiCheckpoint");
|
|
|
49
49
|
const repowikiGit_1 = require("./repowikiGit");
|
|
50
50
|
const repowikiConfig_1 = require("./repowikiConfig");
|
|
51
51
|
const repowikiStructureNav_1 = require("./repowikiStructureNav");
|
|
52
|
-
const
|
|
52
|
+
const repowikiPrompts_1 = require("./repowikiPrompts");
|
|
53
53
|
const repowikiMarkdownPost_1 = require("./repowikiMarkdownPost");
|
|
54
54
|
const repowikiMetadataContent_1 = require("./repowikiMetadataContent");
|
|
55
55
|
const repowikiMetadataJson_1 = require("./repowikiMetadataJson");
|
|
56
56
|
const wikiStructureXml_1 = require("./wikiStructureXml");
|
|
57
|
+
const repowikiStructureNormalize_1 = require("./repowikiStructureNormalize");
|
|
57
58
|
/** Canonical labels for outline + page generation (structure step uses `label`). */
|
|
58
59
|
exports.REPOWIKI_LANG_EN = {
|
|
59
60
|
folder: "en",
|
|
@@ -68,6 +69,9 @@ function langRunForRepowikiTarget(target) {
|
|
|
68
69
|
}
|
|
69
70
|
/** When `languages` is omitted, generate Simplified Chinese only. */
|
|
70
71
|
const DEFAULT_LANGS = [exports.REPOWIKI_LANG_ZH];
|
|
72
|
+
function resolveWikiAudience(audience) {
|
|
73
|
+
return audience ?? "human";
|
|
74
|
+
}
|
|
71
75
|
/** AbortSignal that never aborts — used as default when caller passes nothing. */
|
|
72
76
|
const NEVER_ABORT = new AbortController().signal;
|
|
73
77
|
async function chatCompletionTextForIndex(signal, params) {
|
|
@@ -111,134 +115,8 @@ async function pathExists(abs) {
|
|
|
111
115
|
return false;
|
|
112
116
|
}
|
|
113
117
|
}
|
|
114
|
-
function
|
|
115
|
-
|
|
116
|
-
? `
|
|
117
|
-
|
|
118
|
-
【简体中文硬性要求 — 纲要步骤】凡是给人看的文字(仓库级 <title>/ <description>、每个 <section> 的 <title>、每个 <page> 的 <title> 与 <description>)必须全部是简体中文(zh-CN)。禁止使用英文句子或段落;仅路径、文件名、代码标识符/API 符号可保留英文。`
|
|
119
|
-
: "";
|
|
120
|
-
const enOutlineExtra = structureLang.folder === "en"
|
|
121
|
-
? `
|
|
122
|
-
|
|
123
|
-
【English hard requirement — outline step】All human-readable text in this XML (repo-level <title>/<description>, each <section>'s <title>, each <page>'s <title> and <description>) MUST be fluent English. Do not write Chinese, Japanese, or other non-English prose for those fields. Only code identifiers, filenames, paths, API symbols, and unavoidable proper nouns may stay non-English where appropriate.`
|
|
124
|
-
: "";
|
|
125
|
-
const sectionBlock = comprehensive
|
|
126
|
-
? `Use **multiple** top-level \`<section>\` blocks under \`<sections>\`: **between 2 and 7** (inclusive). **Never** return only **one** section when the wiki has **two or more** pages — split topics into **distinct** sections (do **not** collapse everything into a single bucket named after the wiki title).
|
|
127
|
-
Use **at most 7** sections total. For very small repos with only **one** page, **one** section is acceptable.
|
|
128
|
-
Each section MUST have a **unique** \`id\` attribute (letters, digits, hyphens only — stable identifier).
|
|
129
|
-
Each section's \`<title>\` MUST be **in the outline language** (${structureLang.label}), **repo-specific**, and suitable as a section heading (this becomes the subdirectory name under each language folder).
|
|
130
|
-
**Filesystem folders** under the language directory are derived from each section \`<title>\` (slugified), **not** from \`id\`.
|
|
131
|
-
Distribute pages across sections: each section's \`<pages>\` lists \`<page_ref>\` ids; use **at most ${wikiStructureXml_1.REPOWIKI_MAX_PAGES}** pages **total** across all sections.
|
|
132
|
-
|
|
133
|
-
Return ONLY valid XML in this shape:
|
|
134
|
-
|
|
135
|
-
<wiki_structure>
|
|
136
|
-
<title>[Overall title]</title>
|
|
137
|
-
<description>[Brief]</description>
|
|
138
|
-
<sections>
|
|
139
|
-
<section id="getting-started">
|
|
140
|
-
<title>[Section title in outline language]</title>
|
|
141
|
-
<pages>
|
|
142
|
-
<page_ref>page-1</page_ref>
|
|
143
|
-
</pages>
|
|
144
|
-
<subsections/>
|
|
145
|
-
</section>
|
|
146
|
-
<!-- more sections with unique ids -->
|
|
147
|
-
</sections>
|
|
148
|
-
<pages>
|
|
149
|
-
<page id="page-1">
|
|
150
|
-
<title>[Title]</title>
|
|
151
|
-
<description>[What this covers]</description>
|
|
152
|
-
<importance>high</importance>
|
|
153
|
-
<relevant_files>
|
|
154
|
-
<file_path>[repo-relative/path]</file_path>
|
|
155
|
-
</relevant_files>
|
|
156
|
-
<related_pages/>
|
|
157
|
-
<parent_section>getting-started</parent_section>
|
|
158
|
-
</page>
|
|
159
|
-
</pages>
|
|
160
|
-
</wiki_structure>`
|
|
161
|
-
: `<wiki_structure>
|
|
162
|
-
<title>[Overall title]</title>
|
|
163
|
-
<description>[Brief]</description>
|
|
164
|
-
<pages>
|
|
165
|
-
<page id="page-1">
|
|
166
|
-
<title>[Title]</title>
|
|
167
|
-
<description>[What]</description>
|
|
168
|
-
<importance>high</importance>
|
|
169
|
-
<relevant_files>
|
|
170
|
-
<file_path>[path]</file_path>
|
|
171
|
-
</relevant_files>
|
|
172
|
-
<related_pages/>
|
|
173
|
-
</page>
|
|
174
|
-
</pages>
|
|
175
|
-
</wiki_structure>`;
|
|
176
|
-
return `Analyze the repository "${repoName}" and propose a concise developer wiki outline.
|
|
177
|
-
|
|
178
|
-
<file_tree>
|
|
179
|
-
${treeText}
|
|
180
|
-
</file_tree>
|
|
181
|
-
|
|
182
|
-
<readme_excerpt>
|
|
183
|
-
${readmeChunk.slice(0, 12_000)}
|
|
184
|
-
</readme_excerpt>
|
|
185
|
-
|
|
186
|
-
Target language for human-readable titles/descriptions ONLY in this outline step: ${structureLang.label}.${zhOutlineExtra}${enOutlineExtra}
|
|
187
|
-
|
|
188
|
-
${sectionBlock}
|
|
189
|
-
|
|
190
|
-
Rules:
|
|
191
|
-
- Produce **at most ${wikiStructureXml_1.REPOWIKI_MAX_PAGES}** wiki pages total with **stable** ids \`page-1\`, \`page-2\`, …, \`page-${wikiStructureXml_1.REPOWIKI_MAX_PAGES}\` (use consecutive ids; fewer pages is OK).
|
|
192
|
-
${comprehensive ? `- Every \`<page>\` MUST include \`<parent_section>\` with the **exact** \`id\` of the section that owns this page (the section whose \`<page_ref>\` lists this page id).\n- Each page id must appear in exactly one section's \`page_ref\` list.` : `- Without a \`<sections>\` block, every page is stored under **one** folder derived from the wiki \`<title>\`; omit \`<parent_section>\` or ignore it for paths.`}
|
|
193
|
-
${comprehensive ? `- Each section \`<title>\` becomes a subdirectory name (slugified); keep titles concise and filesystem-friendly where possible.` : `- The wiki \`<title>\` alone determines that single subdirectory name (slugified).`}
|
|
194
|
-
- Ensure \`relevant_files\` cite real paths from file_tree where possible (skip generated/vendor dirs).
|
|
195
|
-
${comprehensive ? `- CRITICAL: Every tag must be closed. After \`<sections>\`, you MUST include one final \`<pages>...</pages>\` block containing every full \`<page id="...">...</page>\` with title, description, parent_section, and relevant_files. Section-level \`<pages>\` may only list \`<page_ref>\` — never omit the outer \`<page>\` definitions.` : `- CRITICAL: Every tag must be closed. Include a \`<pages>\` block listing every full \`<page id="...">...</page>\` with title, description, and relevant_files.`}
|
|
196
|
-
- Return ONLY XML. No markdown fences. No HTML. Start with <wiki_structure> end </wiki_structure>.`;
|
|
197
|
-
}
|
|
198
|
-
function pageMarkdownPrompt(langFolder, langDescriptor, pageTopic, ctx) {
|
|
199
|
-
const zhExtra = langFolder === "zh"
|
|
200
|
-
? `
|
|
201
|
-
|
|
202
|
-
【简体中文硬性要求 — 正文】全部正文、各级标题(# / ## / ###)、表格单元格、Mermaid 与其它图中的说明文字一律使用简体中文(zh-CN)。禁止英文句子,除非直接引用代码、路径、标识符或 API 名称。`
|
|
203
|
-
: "";
|
|
204
|
-
const enExtra = langFolder === "en"
|
|
205
|
-
? `
|
|
206
|
-
|
|
207
|
-
【English hard requirement — body】All prose, headings (# / ## / ###), table cell text, and explanatory labels inside Mermaid/diagrams MUST be English. Do not write Chinese prose (or mixed-language explanations) unless you are quoting literal content from repo files/strings. Preserve non-English only in fenced code excerpts, paths, identifiers, and API symbols as they appear in the repo.`
|
|
208
|
-
: "";
|
|
209
|
-
const h1Rule = langFolder === "zh"
|
|
210
|
-
? `2. Start with '# [title]' (the H1 must match the topic; for a zh-CN wiki, use Simplified Chinese for that title line).`
|
|
211
|
-
: langFolder === "en"
|
|
212
|
-
? `2. Start with '# [title]' (the H1 must match the topic in English prose).`
|
|
213
|
-
: `2. Start with '# [title]' (the H1 must match the topic).`;
|
|
214
|
-
return `You write accurate technical Markdown documentation for developers.
|
|
215
|
-
|
|
216
|
-
Output language: ${langDescriptor}.${zhExtra}${enExtra}
|
|
217
|
-
|
|
218
|
-
Repository context bundled as tagged files:
|
|
219
|
-
|
|
220
|
-
${ctx}
|
|
221
|
-
|
|
222
|
-
Write ONE wiki page for topic: "${pageTopic}".
|
|
223
|
-
|
|
224
|
-
Strict rules:
|
|
225
|
-
1. Ground claims only in supplied files.
|
|
226
|
-
${h1Rule}
|
|
227
|
-
3. After the introduction (first paragraph or short opener) and **before** the first \`##\`, add a concise **table of contents**: a bullet or numbered list of links to the \`##\` sections that follow (use markdown links with anchors, e.g. \`[Section](#section-slug)\`, matching your real headings). **Omit this TOC** if the page is very short or only has a single \`##\` section (avoid a redundant mini-TOC).
|
|
228
|
-
4. Use '##','###', tables, fenced code from files when helpful.
|
|
229
|
-
5. Prefer Mermaid with \`\`\`mermaid diagrams using TOP-DOWN flow (\`graph TD\`, not LR).
|
|
230
|
-
6. Where useful cite repository files on one line: \`Sources: path/to/file:line-range\` (comma-separated if multiple). Paths are repo-relative with \`/\` separators.
|
|
231
|
-
|
|
232
|
-
If bundled files lack coverage, acknowledge gaps briefly — do not invent APIs.`;
|
|
233
|
-
}
|
|
234
|
-
function pageGenerationSystemPrompt(langFolder) {
|
|
235
|
-
if (langFolder === "zh") {
|
|
236
|
-
return "你是技术文档撰写者,只根据提供的 <file path=…> 摘录作答。Wiki 页的各级标题、正文、表格文字、图中的文字说明必须全部是简体中文(zh-CN)。除代码摘录、仓库路径与标识符/API 英文名外禁止使用英文 prose。";
|
|
237
|
-
}
|
|
238
|
-
if (langFolder === "en") {
|
|
239
|
-
return "You are a technical writer. Answer ONLY from bundled <file path=…> excerpts. The entire Markdown page MUST be English: headings, body, table text, diagram labels/explanations. Use non-English prose only inside literal code fences or when verbatim-quoting user-facing strings from the repository; identifiers, paths, and API symbols follow the codebase.";
|
|
240
|
-
}
|
|
241
|
-
return "You write factual Markdown grounded strictly in bundled <file path=…> excerpts.";
|
|
118
|
+
async function mkdirp(p) {
|
|
119
|
+
await fs.mkdir(p, { recursive: true });
|
|
242
120
|
}
|
|
243
121
|
function normalizeLeadingH1(md, canonicalTitle) {
|
|
244
122
|
const t = canonicalTitle.trim();
|
|
@@ -255,9 +133,6 @@ function normalizeLeadingH1(md, canonicalTitle) {
|
|
|
255
133
|
}
|
|
256
134
|
return md;
|
|
257
135
|
}
|
|
258
|
-
async function mkdirp(p) {
|
|
259
|
-
await fs.mkdir(p, { recursive: true });
|
|
260
|
-
}
|
|
261
136
|
function bucketAndStemFromRel(relPosix) {
|
|
262
137
|
const n = relPosix.replace(/\\/g, "/");
|
|
263
138
|
const slash = n.lastIndexOf("/");
|
|
@@ -314,6 +189,7 @@ async function runRepowikiIndex(opts) {
|
|
|
314
189
|
const readme = await (0, repowikiScanner_1.tryReadFirstReadme)(opts.repoRootFs);
|
|
315
190
|
const structureLang = langs[0] ?? exports.REPOWIKI_LANG_ZH;
|
|
316
191
|
const langFolders = langs.map((l) => l.folder);
|
|
192
|
+
const wikiAudience = resolveWikiAudience(opts.wikiAudience);
|
|
317
193
|
let existingCp = forceFull ? null : await (0, repowikiCheckpoint_1.readRepowikiCheckpoint)(wikiBase);
|
|
318
194
|
if (forceFull && existingCp) {
|
|
319
195
|
await (0, repowikiCheckpoint_1.clearRepowikiCheckpoint)(wikiBase);
|
|
@@ -364,11 +240,7 @@ async function runRepowikiIndex(opts) {
|
|
|
364
240
|
if (!resumed) {
|
|
365
241
|
report?.({ done: 0, total: 0, detail: "Requesting wiki outline from model…" });
|
|
366
242
|
log("[repowiki] Requesting wiki structure…");
|
|
367
|
-
const structureSystem = structureLang.folder
|
|
368
|
-
? "你只输出格式正确的 wiki_structure XML(符合用户给定模板);不要使用 markdown 代码围栏。纲要中凡是给人阅读的标题与描述必须使用简体中文(zh-CN)。"
|
|
369
|
-
: structureLang.folder === "en"
|
|
370
|
-
? "You output ONLY well-formed wiki_structure XML matching the user's template. Never use markdown fences. Every repo title, wiki title/description, section titles, page titles, and page descriptions meant for humans must be fluent English (no Chinese prose in those strings unless it is unavoidable quoted content from the repository)."
|
|
371
|
-
: "You output ONLY well-formed wiki_structure XML matching the user's template. Never use markdown fences.";
|
|
243
|
+
const structureSystem = (0, repowikiPrompts_1.structureSystemPrompt)(wikiAudience, structureLang.folder);
|
|
372
244
|
const comprehensive = opts.comprehensiveSections ?? false;
|
|
373
245
|
let structureRaw = await chatCompletionTextForIndex(signal, {
|
|
374
246
|
baseUrl: opts.baseUrl,
|
|
@@ -379,7 +251,7 @@ async function runRepowikiIndex(opts) {
|
|
|
379
251
|
{ role: "system", content: structureSystem },
|
|
380
252
|
{
|
|
381
253
|
role: "user",
|
|
382
|
-
content: structurePrompt(repoName, treeText, readme, structureLang, comprehensive),
|
|
254
|
+
content: (0, repowikiPrompts_1.structurePrompt)(wikiAudience, repoName, treeText, readme, structureLang, comprehensive),
|
|
383
255
|
},
|
|
384
256
|
],
|
|
385
257
|
});
|
|
@@ -407,8 +279,8 @@ async function runRepowikiIndex(opts) {
|
|
|
407
279
|
{ role: "system", content: structureSystem },
|
|
408
280
|
{
|
|
409
281
|
role: "user",
|
|
410
|
-
content: structurePrompt(repoName, treeText, readme, structureLang, comprehensive) +
|
|
411
|
-
(0, repowikiStructureNormalize_1.structureRepairUserAppendix)(structureRaw, structureLang.folder),
|
|
282
|
+
content: (0, repowikiPrompts_1.structurePrompt)(wikiAudience, repoName, treeText, readme, structureLang, comprehensive) +
|
|
283
|
+
(0, repowikiStructureNormalize_1.structureRepairUserAppendix)(structureRaw, structureLang.folder, wikiAudience),
|
|
412
284
|
},
|
|
413
285
|
],
|
|
414
286
|
});
|
|
@@ -586,10 +458,10 @@ async function runRepowikiIndex(opts) {
|
|
|
586
458
|
model: opts.model,
|
|
587
459
|
temperature: 0.25,
|
|
588
460
|
messages: [
|
|
589
|
-
{ role: "system", content: pageGenerationSystemPrompt(lg.folder) },
|
|
461
|
+
{ role: "system", content: (0, repowikiPrompts_1.pageGenerationSystemPrompt)(wikiAudience, lg.folder) },
|
|
590
462
|
{
|
|
591
463
|
role: "user",
|
|
592
|
-
content: pageMarkdownPrompt(lg.folder, lg.label, `${page.title}\n\n${page.description}`, ctxBundle),
|
|
464
|
+
content: (0, repowikiPrompts_1.pageMarkdownPrompt)(wikiAudience, lg.folder, lg.label, `${page.title}\n\n${page.description}`, ctxBundle),
|
|
593
465
|
},
|
|
594
466
|
],
|
|
595
467
|
});
|
|
@@ -706,13 +578,10 @@ async function runRepowikiOutlineOnly(opts) {
|
|
|
706
578
|
const treeText = (0, repowikiScanner_1.summarizeTreeLines)(fileList, 260);
|
|
707
579
|
const readme = await (0, repowikiScanner_1.tryReadFirstReadme)(opts.repoRootFs);
|
|
708
580
|
const structureLang = langs[0] ?? exports.REPOWIKI_LANG_ZH;
|
|
581
|
+
const wikiAudience = resolveWikiAudience(opts.wikiAudience);
|
|
709
582
|
report?.({ done: 0, total: 0, detail: "Requesting wiki outline from model…" });
|
|
710
583
|
log("[repowiki] Requesting wiki structure…");
|
|
711
|
-
const structureSystem = structureLang.folder
|
|
712
|
-
? "你只输出格式正确的 wiki_structure XML(符合用户给定模板);不要使用 markdown 代码围栏。纲要中凡是给人阅读的标题与描述必须使用简体中文(zh-CN)。"
|
|
713
|
-
: structureLang.folder === "en"
|
|
714
|
-
? "You output ONLY well-formed wiki_structure XML matching the user's template. Never use markdown fences. Every repo title, wiki title/description, section titles, page titles, and page descriptions meant for humans must be fluent English (no Chinese prose in those strings unless it is unavoidable quoted content from the repository)."
|
|
715
|
-
: "You output ONLY well-formed wiki_structure XML matching the user's template. Never use markdown fences.";
|
|
584
|
+
const structureSystem = (0, repowikiPrompts_1.structureSystemPrompt)(wikiAudience, structureLang.folder);
|
|
716
585
|
const comprehensive = opts.comprehensiveSections ?? false;
|
|
717
586
|
let structureRaw = await chatCompletionTextForIndex(signal, {
|
|
718
587
|
baseUrl: opts.baseUrl,
|
|
@@ -723,7 +592,7 @@ async function runRepowikiOutlineOnly(opts) {
|
|
|
723
592
|
{ role: "system", content: structureSystem },
|
|
724
593
|
{
|
|
725
594
|
role: "user",
|
|
726
|
-
content: structurePrompt(repoName, treeText, readme, structureLang, comprehensive),
|
|
595
|
+
content: (0, repowikiPrompts_1.structurePrompt)(wikiAudience, repoName, treeText, readme, structureLang, comprehensive),
|
|
727
596
|
},
|
|
728
597
|
],
|
|
729
598
|
});
|
|
@@ -751,8 +620,8 @@ async function runRepowikiOutlineOnly(opts) {
|
|
|
751
620
|
{ role: "system", content: structureSystem },
|
|
752
621
|
{
|
|
753
622
|
role: "user",
|
|
754
|
-
content: structurePrompt(repoName, treeText, readme, structureLang, comprehensive) +
|
|
755
|
-
(0, repowikiStructureNormalize_1.structureRepairUserAppendix)(structureRaw, structureLang.folder),
|
|
623
|
+
content: (0, repowikiPrompts_1.structurePrompt)(wikiAudience, repoName, treeText, readme, structureLang, comprehensive) +
|
|
624
|
+
(0, repowikiStructureNormalize_1.structureRepairUserAppendix)(structureRaw, structureLang.folder, wikiAudience),
|
|
756
625
|
},
|
|
757
626
|
],
|
|
758
627
|
});
|