@mfittko/repo-wiki 0.2.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/.llmwiki/schema.md +107 -0
- package/AGENTS.md +42 -0
- package/CHANGELOG.md +91 -0
- package/LICENSE +21 -0
- package/README.md +254 -0
- package/dist/bin/repo-wiki.d.ts +2 -0
- package/dist/bin/repo-wiki.js +7 -0
- package/dist/bin/repo-wiki.js.map +1 -0
- package/dist/src/cli.d.ts +1 -0
- package/dist/src/cli.js +404 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/compiler.d.ts +55 -0
- package/dist/src/compiler.js +2046 -0
- package/dist/src/compiler.js.map +1 -0
- package/dist/src/config.d.ts +63 -0
- package/dist/src/config.js +86 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/context-assembler.d.ts +68 -0
- package/dist/src/context-assembler.js +378 -0
- package/dist/src/context-assembler.js.map +1 -0
- package/dist/src/data-model-signals.d.ts +1 -0
- package/dist/src/data-model-signals.js +13 -0
- package/dist/src/data-model-signals.js.map +1 -0
- package/dist/src/docs-ingestor.d.ts +138 -0
- package/dist/src/docs-ingestor.js +844 -0
- package/dist/src/docs-ingestor.js.map +1 -0
- package/dist/src/docs-linter.d.ts +14 -0
- package/dist/src/docs-linter.js +164 -0
- package/dist/src/docs-linter.js.map +1 -0
- package/dist/src/docs-validation.d.ts +36 -0
- package/dist/src/docs-validation.js +297 -0
- package/dist/src/docs-validation.js.map +1 -0
- package/dist/src/extractors.d.ts +50 -0
- package/dist/src/extractors.js +2275 -0
- package/dist/src/extractors.js.map +1 -0
- package/dist/src/frontmatter.d.ts +46 -0
- package/dist/src/frontmatter.js +377 -0
- package/dist/src/frontmatter.js.map +1 -0
- package/dist/src/index.d.ts +26 -0
- package/dist/src/index.js +18 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/init.d.ts +12 -0
- package/dist/src/init.js +121 -0
- package/dist/src/init.js.map +1 -0
- package/dist/src/language.d.ts +2 -0
- package/dist/src/language.js +62 -0
- package/dist/src/language.js.map +1 -0
- package/dist/src/linter.d.ts +33 -0
- package/dist/src/linter.js +398 -0
- package/dist/src/linter.js.map +1 -0
- package/dist/src/llm-provider.d.ts +267 -0
- package/dist/src/llm-provider.js +474 -0
- package/dist/src/llm-provider.js.map +1 -0
- package/dist/src/page-ownership.d.ts +38 -0
- package/dist/src/page-ownership.js +96 -0
- package/dist/src/page-ownership.js.map +1 -0
- package/dist/src/planner.d.ts +55 -0
- package/dist/src/planner.js +422 -0
- package/dist/src/planner.js.map +1 -0
- package/dist/src/prompts.d.ts +103 -0
- package/dist/src/prompts.js +344 -0
- package/dist/src/prompts.js.map +1 -0
- package/dist/src/publisher.d.ts +68 -0
- package/dist/src/publisher.js +662 -0
- package/dist/src/publisher.js.map +1 -0
- package/dist/src/repository-analysis.d.ts +88 -0
- package/dist/src/repository-analysis.js +485 -0
- package/dist/src/repository-analysis.js.map +1 -0
- package/dist/src/scanner.d.ts +122 -0
- package/dist/src/scanner.js +309 -0
- package/dist/src/scanner.js.map +1 -0
- package/dist/src/search.d.ts +71 -0
- package/dist/src/search.js +410 -0
- package/dist/src/search.js.map +1 -0
- package/dist/src/secret-patterns.d.ts +3 -0
- package/dist/src/secret-patterns.js +14 -0
- package/dist/src/secret-patterns.js.map +1 -0
- package/dist/src/utils/args.d.ts +2 -0
- package/dist/src/utils/args.js +19 -0
- package/dist/src/utils/args.js.map +1 -0
- package/dist/src/utils/dotenv.d.ts +7 -0
- package/dist/src/utils/dotenv.js +73 -0
- package/dist/src/utils/dotenv.js.map +1 -0
- package/dist/src/utils/fs.d.ts +22 -0
- package/dist/src/utils/fs.js +83 -0
- package/dist/src/utils/fs.js.map +1 -0
- package/dist/src/utils/git.d.ts +13 -0
- package/dist/src/utils/git.js +39 -0
- package/dist/src/utils/git.js.map +1 -0
- package/dist/src/wiki-graph.d.ts +74 -0
- package/dist/src/wiki-graph.js +335 -0
- package/dist/src/wiki-graph.js.map +1 -0
- package/dist/src/wiki-patch.d.ts +152 -0
- package/dist/src/wiki-patch.js +489 -0
- package/dist/src/wiki-patch.js.map +1 -0
- package/dist/src/wiki-query.d.ts +63 -0
- package/dist/src/wiki-query.js +255 -0
- package/dist/src/wiki-query.js.map +1 -0
- package/dist/test/cli.test.d.ts +1 -0
- package/dist/test/cli.test.js +514 -0
- package/dist/test/cli.test.js.map +1 -0
- package/dist/test/compiler-eval.test.d.ts +1 -0
- package/dist/test/compiler-eval.test.js +234 -0
- package/dist/test/compiler-eval.test.js.map +1 -0
- package/dist/test/compiler.test.d.ts +1 -0
- package/dist/test/compiler.test.js +2537 -0
- package/dist/test/compiler.test.js.map +1 -0
- package/dist/test/context-assembler.test.d.ts +1 -0
- package/dist/test/context-assembler.test.js +379 -0
- package/dist/test/context-assembler.test.js.map +1 -0
- package/dist/test/docs-linter.test.d.ts +1 -0
- package/dist/test/docs-linter.test.js +900 -0
- package/dist/test/docs-linter.test.js.map +1 -0
- package/dist/test/dotenv.test.d.ts +1 -0
- package/dist/test/dotenv.test.js +77 -0
- package/dist/test/dotenv.test.js.map +1 -0
- package/dist/test/extractors-go.test.d.ts +1 -0
- package/dist/test/extractors-go.test.js +393 -0
- package/dist/test/extractors-go.test.js.map +1 -0
- package/dist/test/extractors-rust.test.d.ts +1 -0
- package/dist/test/extractors-rust.test.js +219 -0
- package/dist/test/extractors-rust.test.js.map +1 -0
- package/dist/test/extractors-utils.test.d.ts +1 -0
- package/dist/test/extractors-utils.test.js +786 -0
- package/dist/test/extractors-utils.test.js.map +1 -0
- package/dist/test/fixtures/compiler-e2e/basic-node-service/repo/infra/deploy.d.ts +1 -0
- package/dist/test/fixtures/compiler-e2e/basic-node-service/repo/infra/deploy.js +4 -0
- package/dist/test/fixtures/compiler-e2e/basic-node-service/repo/infra/deploy.js.map +1 -0
- package/dist/test/frontmatter.test.d.ts +1 -0
- package/dist/test/frontmatter.test.js +287 -0
- package/dist/test/frontmatter.test.js.map +1 -0
- package/dist/test/init-planner.test.d.ts +1 -0
- package/dist/test/init-planner.test.js +688 -0
- package/dist/test/init-planner.test.js.map +1 -0
- package/dist/test/linter.test.d.ts +1 -0
- package/dist/test/linter.test.js +426 -0
- package/dist/test/linter.test.js.map +1 -0
- package/dist/test/llm-provider.test.d.ts +1 -0
- package/dist/test/llm-provider.test.js +783 -0
- package/dist/test/llm-provider.test.js.map +1 -0
- package/dist/test/page-ownership.test.d.ts +1 -0
- package/dist/test/page-ownership.test.js +247 -0
- package/dist/test/page-ownership.test.js.map +1 -0
- package/dist/test/publisher.test.d.ts +1 -0
- package/dist/test/publisher.test.js +1297 -0
- package/dist/test/publisher.test.js.map +1 -0
- package/dist/test/repository-analysis.test.d.ts +1 -0
- package/dist/test/repository-analysis.test.js +182 -0
- package/dist/test/repository-analysis.test.js.map +1 -0
- package/dist/test/run-compiled-tests.d.ts +1 -0
- package/dist/test/run-compiled-tests.js +48 -0
- package/dist/test/run-compiled-tests.js.map +1 -0
- package/dist/test/scanner.test.d.ts +1 -0
- package/dist/test/scanner.test.js +551 -0
- package/dist/test/scanner.test.js.map +1 -0
- package/dist/test/search.test.d.ts +1 -0
- package/dist/test/search.test.js +92 -0
- package/dist/test/search.test.js.map +1 -0
- package/dist/test/update-changelog.test.d.ts +1 -0
- package/dist/test/update-changelog.test.js +125 -0
- package/dist/test/update-changelog.test.js.map +1 -0
- package/dist/test/wiki-graph.test.d.ts +1 -0
- package/dist/test/wiki-graph.test.js +164 -0
- package/dist/test/wiki-graph.test.js.map +1 -0
- package/dist/test/wiki-patch.test.d.ts +1 -0
- package/dist/test/wiki-patch.test.js +610 -0
- package/dist/test/wiki-patch.test.js.map +1 -0
- package/dist/test/wiki-query.test.d.ts +1 -0
- package/dist/test/wiki-query.test.js +163 -0
- package/dist/test/wiki-query.test.js.map +1 -0
- package/docs/PLAN.md +993 -0
- package/docs/WHY.md +61 -0
- package/docs/plans/agent-integration.md +85 -0
- package/docs/plans/ci-publishing.md +111 -0
- package/docs/plans/doc-validation.md +92 -0
- package/docs/plans/github-action.md +113 -0
- package/docs/plans/incremental-mode.md +98 -0
- package/docs/plans/karpathy-llm-wiki-alignment.md +84 -0
- package/docs/plans/llm-compiler.md +160 -0
- package/docs/plans/production-scanner.md +104 -0
- package/docs/plans/query-and-file-back.md +103 -0
- package/docs/plans/search-index.md +118 -0
- package/docs/plans/trust-hardening.md +74 -0
- package/docs/plans/wiki-graph.md +183 -0
- package/docs/plans/wiki-health.md +76 -0
- package/package.json +83 -0
- package/prompts/compiler.md +16 -0
- package/prompts/lint.md +18 -0
- package/prompts/page-templates.md +25 -0
- package/skills/repo-wiki-cli/SKILL.md +139 -0
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM provider boundary for wiki synthesis.
|
|
3
|
+
*
|
|
4
|
+
* Defines provider request/response interfaces, structured error handling,
|
|
5
|
+
* a deterministic mock provider for tests and local CI, and a factory that
|
|
6
|
+
* selects the correct provider from configuration.
|
|
7
|
+
*
|
|
8
|
+
* Usage (tests / CI without network):
|
|
9
|
+
* const provider = createProvider(); // defaults to mock
|
|
10
|
+
* const provider = createProvider({ provider: 'mock' });
|
|
11
|
+
*
|
|
12
|
+
* Usage (OpenAI-compatible hosted provider):
|
|
13
|
+
* const provider = createProvider({ provider: 'openai-compatible', apiKey: '...', model: '...' });
|
|
14
|
+
*/
|
|
15
|
+
import { readFileSync } from 'node:fs';
|
|
16
|
+
import { buildPrompt } from './prompts.js';
|
|
17
|
+
export const LLM_DEFAULTS = {
|
|
18
|
+
provider: 'mock',
|
|
19
|
+
hostedProvider: 'openai-compatible',
|
|
20
|
+
model: 'gpt-4.1-mini',
|
|
21
|
+
baseUrl: 'https://api.openai.com/v1',
|
|
22
|
+
apiKeyEnv: 'LLMWIKI_LLM_API_KEY',
|
|
23
|
+
systemPrompt: 'You compile source-grounded GitHub Wiki pages.',
|
|
24
|
+
temperature: 0.1,
|
|
25
|
+
maxOutputTokens: 4000,
|
|
26
|
+
timeoutMs: 60000,
|
|
27
|
+
retries: 2,
|
|
28
|
+
validationRetries: 1,
|
|
29
|
+
reasoningEffort: undefined,
|
|
30
|
+
};
|
|
31
|
+
// ── Structured error ───────────────────────────────────────────────────────
|
|
32
|
+
/**
|
|
33
|
+
* Thrown by providers and the factory for all LLM-related failures.
|
|
34
|
+
*
|
|
35
|
+
* try { … } catch (err) {
|
|
36
|
+
* if (err instanceof LLMProviderError && err.retryable) { … }
|
|
37
|
+
* }
|
|
38
|
+
*/
|
|
39
|
+
export class LLMProviderError extends Error {
|
|
40
|
+
/** Identifier of the provider that raised the error. */
|
|
41
|
+
provider;
|
|
42
|
+
/** Machine-readable code (e.g. 'MISSING_API_KEY', 'RATE_LIMIT'). */
|
|
43
|
+
code;
|
|
44
|
+
/** True when the call may be retried after a short back-off. */
|
|
45
|
+
retryable;
|
|
46
|
+
constructor(message, provider, code, retryable = false) {
|
|
47
|
+
super(message);
|
|
48
|
+
this.name = 'LLMProviderError';
|
|
49
|
+
this.provider = provider;
|
|
50
|
+
this.code = code;
|
|
51
|
+
this.retryable = retryable;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// ── Mock provider (deterministic, no network) ──────────────────────────────
|
|
55
|
+
/**
|
|
56
|
+
* Deterministic provider for tests and local CI.
|
|
57
|
+
* Returns a minimal, reproducible markdown page for any request without
|
|
58
|
+
* making network calls or requiring API credentials.
|
|
59
|
+
*/
|
|
60
|
+
export class MockLLMProvider {
|
|
61
|
+
name = 'mock';
|
|
62
|
+
async complete(request) {
|
|
63
|
+
return { content: buildMockContent(request), provider: this.name };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export class OpenAICompatibleProvider {
|
|
67
|
+
name = 'openai-compatible';
|
|
68
|
+
baseUrl;
|
|
69
|
+
model;
|
|
70
|
+
timeoutMs;
|
|
71
|
+
retries;
|
|
72
|
+
apiKey;
|
|
73
|
+
constructor(config) {
|
|
74
|
+
this.apiKey = config.apiKey;
|
|
75
|
+
this.model = config.model;
|
|
76
|
+
this.baseUrl = config.baseUrl.replace(/\/+$/, '');
|
|
77
|
+
this.timeoutMs = config.timeoutMs;
|
|
78
|
+
this.retries = config.retries;
|
|
79
|
+
}
|
|
80
|
+
async complete(request) {
|
|
81
|
+
const body = {
|
|
82
|
+
model: this.model,
|
|
83
|
+
messages: [
|
|
84
|
+
{ role: 'system', content: request.systemPrompt },
|
|
85
|
+
{ role: 'user', content: request.userPrompt }
|
|
86
|
+
],
|
|
87
|
+
...buildOpenAICompatibleTokenBudget(this.model, request.maxTokens),
|
|
88
|
+
...buildOpenAICompatibleTemperatureConfig(this.model, request.temperature),
|
|
89
|
+
...buildOpenAICompatibleReasoningConfig(this.model, request.reasoningEffort)
|
|
90
|
+
};
|
|
91
|
+
const payload = assertOpenAIChatResponse(await this.postWithRetries(body), this.name);
|
|
92
|
+
const content = payload.choices[0]?.message?.content;
|
|
93
|
+
if (typeof content !== 'string' || !content.trim()) {
|
|
94
|
+
throw new LLMProviderError('OpenAI-compatible provider returned an empty completion.', this.name, 'EMPTY_RESPONSE');
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
content,
|
|
98
|
+
provider: this.name,
|
|
99
|
+
promptTokens: numberOrUndefined(payload?.usage?.prompt_tokens),
|
|
100
|
+
completionTokens: numberOrUndefined(payload?.usage?.completion_tokens)
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
async postWithRetries(body) {
|
|
104
|
+
let lastError;
|
|
105
|
+
for (let attempt = 0; attempt <= this.retries; attempt += 1) {
|
|
106
|
+
try {
|
|
107
|
+
return await this.post(body);
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
lastError = error;
|
|
111
|
+
if (!(error instanceof LLMProviderError) || !error.retryable || attempt === this.retries) {
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
await sleep(Math.min(1000 * 2 ** attempt, 8000));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
throw lastError;
|
|
118
|
+
}
|
|
119
|
+
async post(body) {
|
|
120
|
+
const controller = new AbortController();
|
|
121
|
+
const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
122
|
+
try {
|
|
123
|
+
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
124
|
+
method: 'POST',
|
|
125
|
+
headers: {
|
|
126
|
+
authorization: `Bearer ${this.apiKey}`,
|
|
127
|
+
'content-type': 'application/json'
|
|
128
|
+
},
|
|
129
|
+
body: JSON.stringify(body),
|
|
130
|
+
signal: controller.signal
|
|
131
|
+
});
|
|
132
|
+
const text = await response.text();
|
|
133
|
+
let json = null;
|
|
134
|
+
if (text) {
|
|
135
|
+
try {
|
|
136
|
+
json = JSON.parse(text);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
throw new LLMProviderError('OpenAI-compatible provider returned non-JSON response.', this.name, 'INVALID_JSON', response.status >= 500);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (!response.ok) {
|
|
143
|
+
const retryable = response.status === 408 || response.status === 409 || response.status === 429 || response.status >= 500;
|
|
144
|
+
throw new LLMProviderError(formatOpenAICompatibleHttpError(response.status, json), this.name, `HTTP_${response.status}`, retryable);
|
|
145
|
+
}
|
|
146
|
+
return json;
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
if (error instanceof LLMProviderError)
|
|
150
|
+
throw error;
|
|
151
|
+
const retryable = error instanceof Error && error.name === 'AbortError';
|
|
152
|
+
throw new LLMProviderError(retryable ? 'OpenAI-compatible provider request timed out.' : 'OpenAI-compatible provider request failed.', this.name, retryable ? 'TIMEOUT' : 'REQUEST_FAILED', retryable);
|
|
153
|
+
}
|
|
154
|
+
finally {
|
|
155
|
+
clearTimeout(timeout);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function buildOpenAICompatibleTokenBudget(model, maxTokens) {
|
|
160
|
+
if (maxTokens === undefined) {
|
|
161
|
+
return {};
|
|
162
|
+
}
|
|
163
|
+
return usesReasoningModelChatCompat(model)
|
|
164
|
+
? { max_completion_tokens: maxTokens }
|
|
165
|
+
: { max_tokens: maxTokens };
|
|
166
|
+
}
|
|
167
|
+
function buildOpenAICompatibleTemperatureConfig(model, temperature) {
|
|
168
|
+
if (temperature === undefined || usesReasoningModelChatCompat(model)) {
|
|
169
|
+
return {};
|
|
170
|
+
}
|
|
171
|
+
return { temperature };
|
|
172
|
+
}
|
|
173
|
+
function buildOpenAICompatibleReasoningConfig(model, reasoningEffort) {
|
|
174
|
+
if (reasoningEffort === undefined || !usesReasoningModelChatCompat(model)) {
|
|
175
|
+
return {};
|
|
176
|
+
}
|
|
177
|
+
return { reasoning_effort: reasoningEffort };
|
|
178
|
+
}
|
|
179
|
+
function usesReasoningModelChatCompat(model) {
|
|
180
|
+
const normalized = model.trim().toLowerCase();
|
|
181
|
+
return /^(gpt-5|o[1-9])(?:$|[-.])/.test(normalized);
|
|
182
|
+
}
|
|
183
|
+
function formatOpenAICompatibleHttpError(status, payload) {
|
|
184
|
+
const details = describeOpenAICompatibleError(payload);
|
|
185
|
+
return details
|
|
186
|
+
? `OpenAI-compatible provider request failed with HTTP ${status}: ${details}.`
|
|
187
|
+
: `OpenAI-compatible provider request failed with HTTP ${status}.`;
|
|
188
|
+
}
|
|
189
|
+
function describeOpenAICompatibleError(payload) {
|
|
190
|
+
const error = payload?.error;
|
|
191
|
+
if (!error || typeof error !== 'object') {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
const message = typeof error.message === 'string' && error.message.trim()
|
|
195
|
+
? error.message.trim()
|
|
196
|
+
: null;
|
|
197
|
+
const extras = [
|
|
198
|
+
typeof error.type === 'string' && error.type.trim() ? `type=${error.type.trim()}` : null,
|
|
199
|
+
typeof error.code === 'string' && error.code.trim() ? `code=${error.code.trim()}` : null,
|
|
200
|
+
typeof error.param === 'string' && error.param.trim() ? `param=${error.param.trim()}` : null,
|
|
201
|
+
].filter(Boolean);
|
|
202
|
+
if (!message && extras.length === 0) {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
return extras.length > 0
|
|
206
|
+
? `${message ?? 'provider error'} (${extras.join(', ')})`
|
|
207
|
+
: message;
|
|
208
|
+
}
|
|
209
|
+
function buildMockContent(request) {
|
|
210
|
+
const lines = [
|
|
211
|
+
'---',
|
|
212
|
+
`kind: ${JSON.stringify(request.archetype)}`,
|
|
213
|
+
`page_name: ${JSON.stringify(request.pageName)}`,
|
|
214
|
+
`compiled_at: "mock"`,
|
|
215
|
+
`source_repo: ${JSON.stringify(request.sourceRepo ?? 'mock')}`,
|
|
216
|
+
`source_commit: ${JSON.stringify(request.sourceCommit ?? 'mock')}`,
|
|
217
|
+
`page_state: "generated"`,
|
|
218
|
+
`source_paths: ${JSON.stringify((request.sourcePaths?.length ? request.sourcePaths : ['mock-source']).slice(0, 20))}`,
|
|
219
|
+
'---',
|
|
220
|
+
'',
|
|
221
|
+
`# ${request.pageTitle}`,
|
|
222
|
+
'',
|
|
223
|
+
'> Generated by the mock LLM provider (deterministic, no network).',
|
|
224
|
+
'',
|
|
225
|
+
`**Archetype:** ${request.archetype}`,
|
|
226
|
+
'',
|
|
227
|
+
];
|
|
228
|
+
if (request.archetype === 'architecture') {
|
|
229
|
+
lines.splice(2, 0, 'confidence: "medium"', 'claim_status: "grounded"');
|
|
230
|
+
lines.push('## Executive Architecture Summary');
|
|
231
|
+
lines.push('');
|
|
232
|
+
lines.push('Mock architecture summary grounded in prompt source paths.');
|
|
233
|
+
lines.push('');
|
|
234
|
+
lines.push('## System and Repository Context');
|
|
235
|
+
lines.push('');
|
|
236
|
+
lines.push('Mock repository context.');
|
|
237
|
+
lines.push('');
|
|
238
|
+
lines.push('## Major Modules and Responsibilities');
|
|
239
|
+
lines.push('');
|
|
240
|
+
lines.push('Mock module responsibility summary.');
|
|
241
|
+
lines.push('');
|
|
242
|
+
lines.push('## Runtime, Data, and Control-Flow Relationships');
|
|
243
|
+
lines.push('');
|
|
244
|
+
lines.push('Mock runtime relationship summary.');
|
|
245
|
+
lines.push('');
|
|
246
|
+
lines.push('## Build, Test, Deployment, and Operational Surfaces');
|
|
247
|
+
lines.push('');
|
|
248
|
+
lines.push('Mock build and operations summary.');
|
|
249
|
+
lines.push('');
|
|
250
|
+
lines.push('## Cross-Cutting Concerns');
|
|
251
|
+
lines.push('');
|
|
252
|
+
lines.push('Mock cross-cutting concern summary.');
|
|
253
|
+
lines.push('');
|
|
254
|
+
lines.push('## Caveats and Open Questions');
|
|
255
|
+
lines.push('');
|
|
256
|
+
lines.push('Mock caveats.');
|
|
257
|
+
lines.push('');
|
|
258
|
+
}
|
|
259
|
+
if (request.archetype === 'module' || request.archetype === 'architecture') {
|
|
260
|
+
lines.push('<!-- HUMAN_NOTES_START -->');
|
|
261
|
+
lines.push('<!-- HUMAN_NOTES_END -->');
|
|
262
|
+
lines.push('');
|
|
263
|
+
}
|
|
264
|
+
return lines.join('\n');
|
|
265
|
+
}
|
|
266
|
+
// ── Factory ────────────────────────────────────────────────────────────────
|
|
267
|
+
/**
|
|
268
|
+
* Create an `LLMProvider` from configuration resolved with environment overrides.
|
|
269
|
+
*
|
|
270
|
+
* - Omitting `config` returns the mock provider unless `LLMWIKI_LLM_PROVIDER`
|
|
271
|
+
* or `LLMWIKI_COMPILER_MODE` selects a hosted provider.
|
|
272
|
+
* - Explicit `provider: "mock"` remains mock unless `LLMWIKI_LLM_PROVIDER` overrides it.
|
|
273
|
+
* - Specifying an OpenAI-compatible provider without an API key throws
|
|
274
|
+
* `LLMProviderError` with `code: "MISSING_API_KEY"`.
|
|
275
|
+
* - Specifying an unknown provider name throws
|
|
276
|
+
* `LLMProviderError` with `code: "UNKNOWN_PROVIDER"`.
|
|
277
|
+
*
|
|
278
|
+
* This makes missing configuration fail loudly rather than silently falling
|
|
279
|
+
* back to an unexpected behaviour.
|
|
280
|
+
*/
|
|
281
|
+
export function createProvider(config = {}) {
|
|
282
|
+
return createProviderFromResolvedConfig(resolveProviderConfig(config));
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Create an `LLMProvider` from an already-resolved config without re-reading
|
|
286
|
+
* environment variables. Use this when a caller has applied page/archetype
|
|
287
|
+
* overrides that must not be superseded by global env resolution a second time.
|
|
288
|
+
*/
|
|
289
|
+
export function createProviderFromResolvedConfig(resolved) {
|
|
290
|
+
const providerName = resolved.provider;
|
|
291
|
+
if (providerName === 'mock') {
|
|
292
|
+
return new MockLLMProvider();
|
|
293
|
+
}
|
|
294
|
+
if (providerName === 'openai-compatible' || providerName === 'openai') {
|
|
295
|
+
if (!resolved.apiKey) {
|
|
296
|
+
throw new LLMProviderError(`Provider "${providerName}" requires an API key. ` +
|
|
297
|
+
`Set ${resolved.apiKeyEnv}, pass apiKey, or use provider="mock" for tests and CI.`, providerName, 'MISSING_API_KEY');
|
|
298
|
+
}
|
|
299
|
+
return new OpenAICompatibleProvider({
|
|
300
|
+
apiKey: resolved.apiKey,
|
|
301
|
+
model: resolved.model,
|
|
302
|
+
baseUrl: resolved.baseUrl,
|
|
303
|
+
timeoutMs: resolved.timeoutMs,
|
|
304
|
+
retries: resolved.retries
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
throw new LLMProviderError(`Unknown provider: "${providerName}". Supported providers: mock, openai-compatible.`, providerName, 'UNKNOWN_PROVIDER');
|
|
308
|
+
}
|
|
309
|
+
/** Resolve provider configuration from defaults, explicit config, and env vars. */
|
|
310
|
+
export function resolveProviderConfig(config = {}, env = process.env) {
|
|
311
|
+
const llmConfig = config.llm ? { ...config.llm, mode: config.mode } : config;
|
|
312
|
+
const envApiKey = optionalEnv(env, 'LLMWIKI_LLM_API_KEY');
|
|
313
|
+
const apiKeyEnv = envApiKey !== undefined ? 'LLMWIKI_LLM_API_KEY' : (nonBlank(llmConfig.apiKeyEnv) ?? nonBlank(llmConfig.api_key_env) ?? LLM_DEFAULTS.apiKeyEnv);
|
|
314
|
+
const systemPromptFile = optionalEnv(env, 'LLMWIKI_LLM_SYSTEM_PROMPT_FILE') ?? nonBlank(llmConfig.systemPromptFile) ?? nonBlank(llmConfig.system_prompt_file);
|
|
315
|
+
const systemPrompt = optionalEnv(env, 'LLMWIKI_LLM_SYSTEM_PROMPT') ?? readPromptFileIfSet(systemPromptFile) ?? nonBlank(llmConfig.systemPrompt) ?? nonBlank(llmConfig.system_prompt) ?? LLM_DEFAULTS.systemPrompt;
|
|
316
|
+
const mode = optionalEnv(env, 'LLMWIKI_COMPILER_MODE') ?? nonBlank(llmConfig.mode);
|
|
317
|
+
return {
|
|
318
|
+
...llmConfig,
|
|
319
|
+
provider: optionalEnv(env, 'LLMWIKI_LLM_PROVIDER') ?? nonBlank(llmConfig.provider) ?? providerForMode(mode) ?? LLM_DEFAULTS.provider,
|
|
320
|
+
apiKey: optionalEnv(env, apiKeyEnv) ?? nonBlank(llmConfig.apiKey),
|
|
321
|
+
apiKeyEnv,
|
|
322
|
+
model: optionalEnv(env, 'LLMWIKI_LLM_MODEL') ?? nonBlank(llmConfig.model) ?? LLM_DEFAULTS.model,
|
|
323
|
+
baseUrl: optionalEnv(env, 'LLMWIKI_LLM_BASE_URL') ?? nonBlank(llmConfig.baseUrl) ?? nonBlank(llmConfig.base_url) ?? LLM_DEFAULTS.baseUrl,
|
|
324
|
+
systemPrompt,
|
|
325
|
+
systemPromptFile,
|
|
326
|
+
temperature: parseNumber(optionalEnv(env, 'LLMWIKI_LLM_TEMPERATURE'), llmConfig.temperature ?? LLM_DEFAULTS.temperature, 'temperature'),
|
|
327
|
+
maxOutputTokens: parseNonNegativeInteger(optionalEnv(env, 'LLMWIKI_LLM_MAX_OUTPUT_TOKENS'), llmConfig.maxOutputTokens ?? llmConfig.max_output_tokens ?? LLM_DEFAULTS.maxOutputTokens, 'maxOutputTokens'),
|
|
328
|
+
timeoutMs: parseNonNegativeInteger(optionalEnv(env, 'LLMWIKI_LLM_TIMEOUT_MS'), llmConfig.timeoutMs ?? llmConfig.timeout_ms ?? LLM_DEFAULTS.timeoutMs, 'timeoutMs'),
|
|
329
|
+
reasoningEffort: parseReasoningEffort(optionalEnv(env, 'LLMWIKI_LLM_REASONING_EFFORT') ?? llmConfig.reasoningEffort ?? llmConfig.reasoning_effort, 'reasoningEffort'),
|
|
330
|
+
retries: parseNonNegativeInteger(optionalEnv(env, 'LLMWIKI_LLM_RETRIES'), llmConfig.retries ?? LLM_DEFAULTS.retries, 'retries'),
|
|
331
|
+
validationRetries: parseNonNegativeInteger(optionalEnv(env, 'LLMWIKI_LLM_VALIDATION_RETRIES'), llmConfig.validationRetries ?? llmConfig.validation_retries ?? LLM_DEFAULTS.validationRetries, 'validationRetries')
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
export function buildRequest(archetype, context, maxTokensOrOptions, config = {}) {
|
|
335
|
+
const prompt = buildPrompt(archetype, context);
|
|
336
|
+
const options = maxTokensOrOptions !== null && typeof maxTokensOrOptions === 'object'
|
|
337
|
+
? maxTokensOrOptions
|
|
338
|
+
: { ...config, maxTokens: typeof maxTokensOrOptions === 'number' ? maxTokensOrOptions : undefined };
|
|
339
|
+
return {
|
|
340
|
+
archetype,
|
|
341
|
+
pageName: context.pageName,
|
|
342
|
+
pageTitle: context.pageTitle,
|
|
343
|
+
systemPrompt: options.systemPrompt ?? prompt.system,
|
|
344
|
+
userPrompt: prompt.user,
|
|
345
|
+
sourceCommit: context.repoCommit,
|
|
346
|
+
sourceRepo: context.repoRemote,
|
|
347
|
+
sourcePaths: context.sourceCards.map((card) => card.path).filter((value) => typeof value === 'string' && value.trim()),
|
|
348
|
+
maxTokens: options.maxTokens ?? options.maxOutputTokens,
|
|
349
|
+
temperature: options.temperature,
|
|
350
|
+
reasoningEffort: options.reasoningEffort,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
function providerForMode(mode) {
|
|
354
|
+
if (mode === 'llm')
|
|
355
|
+
return LLM_DEFAULTS.hostedProvider;
|
|
356
|
+
if (mode === 'deterministic')
|
|
357
|
+
return LLM_DEFAULTS.provider;
|
|
358
|
+
return undefined;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Resolve architecture-specific model, output-token, timeout, and
|
|
362
|
+
* reasoning-effort overrides.
|
|
363
|
+
*
|
|
364
|
+
* Precedence (highest to lowest):
|
|
365
|
+
* 1. Architecture-specific env vars (`LLMWIKI_LLM_ARCHITECTURE_*`)
|
|
366
|
+
* 2. Global env vars for the same setting (already applied by resolveProviderConfig)
|
|
367
|
+
* 3. `.llmwiki/config.json` `compiler.llm.page_budgets.architecture` overrides
|
|
368
|
+
* 4. Global config defaults (already applied by resolveProviderConfig)
|
|
369
|
+
* 5. Built-in defaults
|
|
370
|
+
*
|
|
371
|
+
* Returns only the fields that are explicitly overridden; callers fall back to
|
|
372
|
+
* the global resolved config for fields that are not set.
|
|
373
|
+
*/
|
|
374
|
+
export function resolveArchitectureOverrides(config = {}, env = process.env) {
|
|
375
|
+
const llmConfig = config.llm ? config.llm : config;
|
|
376
|
+
const pageBudgets = llmConfig.page_budgets?.architecture ?? {};
|
|
377
|
+
const envModel = optionalEnv(env, 'LLMWIKI_LLM_ARCHITECTURE_MODEL');
|
|
378
|
+
const envMaxOutputTokens = optionalEnv(env, 'LLMWIKI_LLM_ARCHITECTURE_MAX_OUTPUT_TOKENS');
|
|
379
|
+
const envTimeoutMs = optionalEnv(env, 'LLMWIKI_LLM_ARCHITECTURE_TIMEOUT_MS');
|
|
380
|
+
const envReasoningEffort = optionalEnv(env, 'LLMWIKI_LLM_ARCHITECTURE_REASONING_EFFORT');
|
|
381
|
+
const globalEnvModel = optionalEnv(env, 'LLMWIKI_LLM_MODEL');
|
|
382
|
+
const globalEnvMaxOutputTokens = optionalEnv(env, 'LLMWIKI_LLM_MAX_OUTPUT_TOKENS');
|
|
383
|
+
const globalEnvTimeoutMs = optionalEnv(env, 'LLMWIKI_LLM_TIMEOUT_MS');
|
|
384
|
+
const globalEnvReasoningEffort = optionalEnv(env, 'LLMWIKI_LLM_REASONING_EFFORT');
|
|
385
|
+
const model = envModel ?? (globalEnvModel !== undefined ? undefined : nonBlank(pageBudgets.model));
|
|
386
|
+
const configuredMaxOutputTokens = pageBudgets.max_output_tokens !== undefined
|
|
387
|
+
? parseOptionalNonNegativeInteger(pageBudgets.max_output_tokens, 'architecture maxOutputTokens')
|
|
388
|
+
: undefined;
|
|
389
|
+
const configuredTimeoutMs = pageBudgets.timeout_ms !== undefined
|
|
390
|
+
? parseOptionalNonNegativeInteger(pageBudgets.timeout_ms, 'architecture timeoutMs')
|
|
391
|
+
: undefined;
|
|
392
|
+
const configuredReasoningEffort = parseReasoningEffort(pageBudgets.reasoning_effort, 'architecture reasoningEffort');
|
|
393
|
+
const maxOutputTokens = envMaxOutputTokens !== undefined
|
|
394
|
+
? parseNonNegativeInteger(envMaxOutputTokens, 0, 'architecture maxOutputTokens')
|
|
395
|
+
: (globalEnvMaxOutputTokens !== undefined ? undefined : configuredMaxOutputTokens);
|
|
396
|
+
const timeoutMs = envTimeoutMs !== undefined
|
|
397
|
+
? parseNonNegativeInteger(envTimeoutMs, 0, 'architecture timeoutMs')
|
|
398
|
+
: (globalEnvTimeoutMs !== undefined ? undefined : configuredTimeoutMs);
|
|
399
|
+
const reasoningEffort = envReasoningEffort !== undefined
|
|
400
|
+
? parseReasoningEffort(envReasoningEffort, 'architecture reasoningEffort')
|
|
401
|
+
: (globalEnvReasoningEffort !== undefined ? undefined : configuredReasoningEffort);
|
|
402
|
+
return { model, maxOutputTokens, timeoutMs, reasoningEffort };
|
|
403
|
+
}
|
|
404
|
+
function parseReasoningEffort(value, field = 'reasoningEffort') {
|
|
405
|
+
if (value === undefined || value === null || value === '') {
|
|
406
|
+
return undefined;
|
|
407
|
+
}
|
|
408
|
+
const normalized = typeof value === 'string' ? value.trim() : '';
|
|
409
|
+
if (normalized === '') {
|
|
410
|
+
return undefined;
|
|
411
|
+
}
|
|
412
|
+
if (['none', 'minimal', 'low', 'medium', 'high', 'xhigh'].includes(normalized)) {
|
|
413
|
+
return normalized;
|
|
414
|
+
}
|
|
415
|
+
throw new LLMProviderError(`Invalid reasoning effort LLM config for ${field}: ${JSON.stringify(value)}.`, 'config', 'INVALID_CONFIG');
|
|
416
|
+
}
|
|
417
|
+
function parseNumber(value, fallback, field) {
|
|
418
|
+
const candidate = value === undefined ? fallback : Number(value);
|
|
419
|
+
if (!Number.isFinite(candidate)) {
|
|
420
|
+
throw new LLMProviderError(`Invalid numeric LLM config for ${field}.`, 'config', 'INVALID_CONFIG');
|
|
421
|
+
}
|
|
422
|
+
return candidate;
|
|
423
|
+
}
|
|
424
|
+
function parseNonNegativeInteger(value, fallback, field) {
|
|
425
|
+
const candidate = value === undefined ? fallback : Number(value);
|
|
426
|
+
if (!Number.isInteger(candidate) || candidate < 0) {
|
|
427
|
+
throw new LLMProviderError(`Invalid non-negative integer LLM config for ${field}.`, 'config', 'INVALID_CONFIG');
|
|
428
|
+
}
|
|
429
|
+
return candidate;
|
|
430
|
+
}
|
|
431
|
+
function parseOptionalNonNegativeInteger(value, field) {
|
|
432
|
+
const candidate = typeof value === 'number'
|
|
433
|
+
? value
|
|
434
|
+
: typeof value === 'string' && value.trim().length > 0
|
|
435
|
+
? Number(value)
|
|
436
|
+
: Number.NaN;
|
|
437
|
+
if (!Number.isInteger(candidate) || candidate < 0) {
|
|
438
|
+
throw new LLMProviderError(`Invalid non-negative integer LLM config for ${field}.`, 'config', 'INVALID_CONFIG');
|
|
439
|
+
}
|
|
440
|
+
return candidate;
|
|
441
|
+
}
|
|
442
|
+
function optionalEnv(env, key) {
|
|
443
|
+
return nonBlank(env[key]);
|
|
444
|
+
}
|
|
445
|
+
function nonBlank(value) {
|
|
446
|
+
return typeof value === 'string' && value.trim() ? value : undefined;
|
|
447
|
+
}
|
|
448
|
+
function readPromptFileIfSet(filePath) {
|
|
449
|
+
if (!filePath)
|
|
450
|
+
return undefined;
|
|
451
|
+
try {
|
|
452
|
+
return readFileSync(filePath, 'utf8');
|
|
453
|
+
}
|
|
454
|
+
catch {
|
|
455
|
+
return undefined;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
function assertOpenAIChatResponse(value, provider) {
|
|
459
|
+
if (!value || typeof value !== 'object') {
|
|
460
|
+
throw new LLMProviderError('OpenAI-compatible provider returned an invalid response object.', provider, 'INVALID_RESPONSE');
|
|
461
|
+
}
|
|
462
|
+
const response = value;
|
|
463
|
+
if (!Array.isArray(response.choices) || response.choices.length === 0) {
|
|
464
|
+
throw new LLMProviderError('OpenAI-compatible provider returned no choices.', provider, 'MISSING_CHOICES');
|
|
465
|
+
}
|
|
466
|
+
return value;
|
|
467
|
+
}
|
|
468
|
+
function numberOrUndefined(value) {
|
|
469
|
+
return typeof value === 'number' ? value : undefined;
|
|
470
|
+
}
|
|
471
|
+
function sleep(ms) {
|
|
472
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
473
|
+
}
|
|
474
|
+
//# sourceMappingURL=llm-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-provider.js","sourceRoot":"","sources":["../../src/llm-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page ownership detection and human-notes preservation for wiki pages.
|
|
3
|
+
*
|
|
4
|
+
* Four page states:
|
|
5
|
+
* - generated : produced by the compiler, no human annotations yet.
|
|
6
|
+
* - mixed : compiler-generated page that also contains non-empty HUMAN_NOTES.
|
|
7
|
+
* - human-owned : page explicitly marked as human-owned (page_state: "human-owned" in
|
|
8
|
+
* frontmatter), or carries owned_by: "human". The compiler skips it.
|
|
9
|
+
* - unmanaged : page that exists on disk but was not produced by repo-wiki
|
|
10
|
+
* (no source_commit frontmatter field).
|
|
11
|
+
*/
|
|
12
|
+
export type PageState = 'generated' | 'mixed' | 'human-owned' | 'unmanaged';
|
|
13
|
+
/**
|
|
14
|
+
* Inspect a wiki page's content and return its ownership state.
|
|
15
|
+
*
|
|
16
|
+
* Decision order:
|
|
17
|
+
* 1. Explicit `page_state: "human-owned"` or `owned_by: "human"` in frontmatter → human-owned.
|
|
18
|
+
* 2. No `source_commit:` field in frontmatter → unmanaged.
|
|
19
|
+
* 3. Non-empty content between HUMAN_NOTES markers → mixed.
|
|
20
|
+
* 4. Otherwise → generated.
|
|
21
|
+
*/
|
|
22
|
+
export declare function detectPageState(content: string): PageState;
|
|
23
|
+
/**
|
|
24
|
+
* Return the raw text between HUMAN_NOTES_START and HUMAN_NOTES_END markers.
|
|
25
|
+
* Returns an empty string when neither or only one marker is present.
|
|
26
|
+
*/
|
|
27
|
+
export declare function extractHumanNotes(content: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Replace the empty slot between HUMAN_NOTES markers in `content` with `notes`.
|
|
30
|
+
* If `content` does not contain both markers in the correct order the original
|
|
31
|
+
* content is returned unchanged.
|
|
32
|
+
*/
|
|
33
|
+
export declare function injectHumanNotes(content: string, notes: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Preserve notes in generated content. If the renderer did not include a human
|
|
36
|
+
* notes block, append one so non-module pages can still retain human content.
|
|
37
|
+
*/
|
|
38
|
+
export declare function preserveHumanNotes(content: string, notes: string): string;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page ownership detection and human-notes preservation for wiki pages.
|
|
3
|
+
*
|
|
4
|
+
* Four page states:
|
|
5
|
+
* - generated : produced by the compiler, no human annotations yet.
|
|
6
|
+
* - mixed : compiler-generated page that also contains non-empty HUMAN_NOTES.
|
|
7
|
+
* - human-owned : page explicitly marked as human-owned (page_state: "human-owned" in
|
|
8
|
+
* frontmatter), or carries owned_by: "human". The compiler skips it.
|
|
9
|
+
* - unmanaged : page that exists on disk but was not produced by repo-wiki
|
|
10
|
+
* (no source_commit frontmatter field).
|
|
11
|
+
*/
|
|
12
|
+
const HUMAN_NOTES_START = '<!-- HUMAN_NOTES_START -->';
|
|
13
|
+
const HUMAN_NOTES_END = '<!-- HUMAN_NOTES_END -->';
|
|
14
|
+
/**
|
|
15
|
+
* Inspect a wiki page's content and return its ownership state.
|
|
16
|
+
*
|
|
17
|
+
* Decision order:
|
|
18
|
+
* 1. Explicit `page_state: "human-owned"` or `owned_by: "human"` in frontmatter → human-owned.
|
|
19
|
+
* 2. No `source_commit:` field in frontmatter → unmanaged.
|
|
20
|
+
* 3. Non-empty content between HUMAN_NOTES markers → mixed.
|
|
21
|
+
* 4. Otherwise → generated.
|
|
22
|
+
*/
|
|
23
|
+
export function detectPageState(content) {
|
|
24
|
+
const frontmatter = extractFrontmatter(content);
|
|
25
|
+
// Explicit human-ownership declarations take the highest priority.
|
|
26
|
+
if (/^page_state:\s*['"]?human-owned['"]?\s*$/m.test(frontmatter) || /^owned_by:\s*['"]?human['"]?\s*$/m.test(frontmatter)) {
|
|
27
|
+
return 'human-owned';
|
|
28
|
+
}
|
|
29
|
+
// Must have a source_commit field in frontmatter to be considered a repo-wiki page.
|
|
30
|
+
if (!/^source_commit:/m.test(frontmatter)) {
|
|
31
|
+
return 'unmanaged';
|
|
32
|
+
}
|
|
33
|
+
// Has source_commit – was produced by the compiler. Check for human notes.
|
|
34
|
+
if (extractHumanNotes(content).trim().length > 0) {
|
|
35
|
+
return 'mixed';
|
|
36
|
+
}
|
|
37
|
+
return 'generated';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Return the raw text between HUMAN_NOTES_START and HUMAN_NOTES_END markers.
|
|
41
|
+
* Returns an empty string when neither or only one marker is present.
|
|
42
|
+
*/
|
|
43
|
+
export function extractHumanNotes(content) {
|
|
44
|
+
const start = content.indexOf(HUMAN_NOTES_START);
|
|
45
|
+
if (start === -1) {
|
|
46
|
+
return '';
|
|
47
|
+
}
|
|
48
|
+
const notesStart = start + HUMAN_NOTES_START.length;
|
|
49
|
+
const end = content.indexOf(HUMAN_NOTES_END, notesStart);
|
|
50
|
+
if (end === -1) {
|
|
51
|
+
return '';
|
|
52
|
+
}
|
|
53
|
+
return content.slice(notesStart, end);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Replace the empty slot between HUMAN_NOTES markers in `content` with `notes`.
|
|
57
|
+
* If `content` does not contain both markers in the correct order the original
|
|
58
|
+
* content is returned unchanged.
|
|
59
|
+
*/
|
|
60
|
+
export function injectHumanNotes(content, notes) {
|
|
61
|
+
const start = content.indexOf(HUMAN_NOTES_START);
|
|
62
|
+
if (start === -1) {
|
|
63
|
+
return content;
|
|
64
|
+
}
|
|
65
|
+
const notesStart = start + HUMAN_NOTES_START.length;
|
|
66
|
+
const end = content.indexOf(HUMAN_NOTES_END, notesStart);
|
|
67
|
+
if (end === -1) {
|
|
68
|
+
return content;
|
|
69
|
+
}
|
|
70
|
+
return (content.slice(0, notesStart) +
|
|
71
|
+
notes +
|
|
72
|
+
content.slice(end));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Preserve notes in generated content. If the renderer did not include a human
|
|
76
|
+
* notes block, append one so non-module pages can still retain human content.
|
|
77
|
+
*/
|
|
78
|
+
export function preserveHumanNotes(content, notes) {
|
|
79
|
+
if (content.includes(HUMAN_NOTES_START) && content.includes(HUMAN_NOTES_END)) {
|
|
80
|
+
return injectHumanNotes(content, notes);
|
|
81
|
+
}
|
|
82
|
+
const suffix = content.endsWith('\n') ? '' : '\n';
|
|
83
|
+
return `${content}${suffix}\n${HUMAN_NOTES_START}${notes}${HUMAN_NOTES_END}\n`;
|
|
84
|
+
}
|
|
85
|
+
function extractFrontmatter(content) {
|
|
86
|
+
const normalized = content.replace(/^\uFEFF/, '').replace(/\r\n/g, '\n');
|
|
87
|
+
if (!normalized.startsWith('---\n')) {
|
|
88
|
+
return '';
|
|
89
|
+
}
|
|
90
|
+
const end = normalized.indexOf('\n---', 4);
|
|
91
|
+
if (end === -1) {
|
|
92
|
+
return '';
|
|
93
|
+
}
|
|
94
|
+
return normalized.slice(4, end);
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=page-ownership.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-ownership.js","sourceRoot":"","sources":["../../src/page-ownership.ts"],"names":[],"mappings":"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"}
|