viberadar 0.3.80 → 0.3.82
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/dist/scanner/index.d.ts +37 -0
- package/dist/scanner/index.d.ts.map +1 -1
- package/dist/scanner/index.js +151 -4
- package/dist/scanner/index.js.map +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +143 -1
- package/dist/server/index.js.map +1 -1
- package/dist/ui/dashboard.html +558 -29
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -1167,6 +1167,72 @@ function buildWriteE2eTestPrompt(feat, plan, modules) {
|
|
|
1167
1167
|
`- Следуй существующим паттернам проекта`,
|
|
1168
1168
|
].filter(Boolean).join('\n');
|
|
1169
1169
|
}
|
|
1170
|
+
// ─── Documentation prompt builders ───────────────────────────────────────────
|
|
1171
|
+
function buildGenerateDocsPrompt(feat, modules, projectRoot) {
|
|
1172
|
+
const sourceFiles = modules
|
|
1173
|
+
.filter(m => m.featureKeys.includes(feat.key) && m.type !== 'test' && !m.isInfra)
|
|
1174
|
+
.map(m => '- ' + m.relativePath.replace(/\\/g, '/'));
|
|
1175
|
+
return [
|
|
1176
|
+
`Сгенерируй исчерпывающую пользовательскую документацию для фичи "${feat.label}".`,
|
|
1177
|
+
``,
|
|
1178
|
+
feat.description ? `Описание фичи: ${feat.description}` : '',
|
|
1179
|
+
``,
|
|
1180
|
+
`Файлы фичи (${sourceFiles.length}):`,
|
|
1181
|
+
...sourceFiles,
|
|
1182
|
+
``,
|
|
1183
|
+
`Задача:`,
|
|
1184
|
+
`1. Прочитай каждый файл фичи`,
|
|
1185
|
+
`2. Разберись в архитектуре: как файлы связаны, какие API/функции они экспортируют`,
|
|
1186
|
+
`3. Напиши документацию в формате Markdown`,
|
|
1187
|
+
``,
|
|
1188
|
+
`Обязательные секции документа:`,
|
|
1189
|
+
`## Overview — что делает фича, зачем нужна, какую задачу решает`,
|
|
1190
|
+
`## Architecture — ключевые компоненты, data flow, связи между файлами`,
|
|
1191
|
+
`## Usage — как использовать (API, функции, endpoints, компоненты)`,
|
|
1192
|
+
`## Configuration — конфигурация, env-переменные, настройки`,
|
|
1193
|
+
`## Key Files — список файлов с кратким описанием роли каждого`,
|
|
1194
|
+
`## Dependencies — внешние пакеты и внутренние зависимости`,
|
|
1195
|
+
``,
|
|
1196
|
+
`Требования:`,
|
|
1197
|
+
`- Документация должна быть исчерпывающей, понятной для нового разработчика`,
|
|
1198
|
+
`- Описывай каждый публичный API/экспорт`,
|
|
1199
|
+
`- Приводи примеры использования`,
|
|
1200
|
+
`- Запиши результат в файл: docs/features/${feat.key}.md`,
|
|
1201
|
+
`- Создай директорию docs/features/ если её нет`,
|
|
1202
|
+
].filter(Boolean).join('\n');
|
|
1203
|
+
}
|
|
1204
|
+
function buildUpdateDocsPrompt(feat, modules, changedFiles, currentDoc, projectRoot) {
|
|
1205
|
+
const allSourceFiles = modules
|
|
1206
|
+
.filter(m => m.featureKeys.includes(feat.key) && m.type !== 'test' && !m.isInfra)
|
|
1207
|
+
.map(m => '- ' + m.relativePath.replace(/\\/g, '/'));
|
|
1208
|
+
return [
|
|
1209
|
+
`Обнови документацию фичи "${feat.label}".`,
|
|
1210
|
+
``,
|
|
1211
|
+
`Текущая документация:`,
|
|
1212
|
+
'```markdown',
|
|
1213
|
+
currentDoc,
|
|
1214
|
+
'```',
|
|
1215
|
+
``,
|
|
1216
|
+
`Файлы, изменённые после последнего обновления документации (${changedFiles.length}):`,
|
|
1217
|
+
...changedFiles.map(f => '- ' + f.replace(/\\/g, '/')),
|
|
1218
|
+
``,
|
|
1219
|
+
`Все файлы фичи (${allSourceFiles.length}):`,
|
|
1220
|
+
...allSourceFiles,
|
|
1221
|
+
``,
|
|
1222
|
+
`Задача:`,
|
|
1223
|
+
`1. Прочитай каждый изменённый файл`,
|
|
1224
|
+
`2. Определи, что изменилось по сравнению с текущей документацией`,
|
|
1225
|
+
`3. Обнови соответствующие секции документа`,
|
|
1226
|
+
`4. Сохрани структуру и стиль существующей документации`,
|
|
1227
|
+
`5. Если добавлены новые файлы — добавь их в секцию Key Files`,
|
|
1228
|
+
`6. Если удалены файлы — убери их из документации`,
|
|
1229
|
+
``,
|
|
1230
|
+
`Требования:`,
|
|
1231
|
+
`- Не переписывай весь документ, обнови только устаревшие секции`,
|
|
1232
|
+
`- Сохрани существующие примеры, если они всё ещё валидны`,
|
|
1233
|
+
`- Запиши обновлённый результат в файл: docs/features/${feat.key}.md`,
|
|
1234
|
+
].join('\n');
|
|
1235
|
+
}
|
|
1170
1236
|
// ─── Main server ──────────────────────────────────────────────────────────────
|
|
1171
1237
|
function startServer({ data: initialData, port, projectRoot }) {
|
|
1172
1238
|
return new Promise((resolve, reject) => {
|
|
@@ -1637,6 +1703,37 @@ function startServer({ data: initialData, port, projectRoot }) {
|
|
|
1637
1703
|
return;
|
|
1638
1704
|
}
|
|
1639
1705
|
}
|
|
1706
|
+
else if (task === 'generate-docs') {
|
|
1707
|
+
if (!featureKey || !currentData.features) {
|
|
1708
|
+
failBeforeStart('Фича не найдена');
|
|
1709
|
+
return;
|
|
1710
|
+
}
|
|
1711
|
+
const feat = currentData.features.find(f => f.key === featureKey);
|
|
1712
|
+
if (!feat) {
|
|
1713
|
+
failBeforeStart(`Фича ${featureKey} не найдена`);
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1716
|
+
prompt = buildGenerateDocsPrompt(feat, currentData.modules, projectRoot);
|
|
1717
|
+
}
|
|
1718
|
+
else if (task === 'update-docs') {
|
|
1719
|
+
if (!featureKey || !currentData.features) {
|
|
1720
|
+
failBeforeStart('Фича не найдена');
|
|
1721
|
+
return;
|
|
1722
|
+
}
|
|
1723
|
+
const feat = currentData.features.find(f => f.key === featureKey);
|
|
1724
|
+
if (!feat) {
|
|
1725
|
+
failBeforeStart(`Фича ${featureKey} не найдена`);
|
|
1726
|
+
return;
|
|
1727
|
+
}
|
|
1728
|
+
const docStatus = currentData.documentation?.features.find(f => f.key === featureKey);
|
|
1729
|
+
let currentDoc = '';
|
|
1730
|
+
try {
|
|
1731
|
+
currentDoc = fs.readFileSync(path.join(projectRoot, 'docs', 'features', `${featureKey}.md`), 'utf-8');
|
|
1732
|
+
}
|
|
1733
|
+
catch { }
|
|
1734
|
+
const changedFiles = docStatus?.changedFilesSinceDoc || [];
|
|
1735
|
+
prompt = buildUpdateDocsPrompt(feat, currentData.modules, changedFiles, currentDoc, projectRoot);
|
|
1736
|
+
}
|
|
1640
1737
|
else {
|
|
1641
1738
|
prompt = buildMapUnmappedPrompt(currentData.modules, currentData.features || []);
|
|
1642
1739
|
}
|
|
@@ -2205,6 +2302,7 @@ function startServer({ data: initialData, port, projectRoot }) {
|
|
|
2205
2302
|
chokidar_1.default.watch([
|
|
2206
2303
|
'**/*.{ts,tsx,js,jsx,vue,svelte}',
|
|
2207
2304
|
'viberadar.config.json',
|
|
2305
|
+
'docs/features/*.md',
|
|
2208
2306
|
], {
|
|
2209
2307
|
cwd: projectRoot,
|
|
2210
2308
|
ignored: [
|
|
@@ -2222,7 +2320,7 @@ function startServer({ data: initialData, port, projectRoot }) {
|
|
|
2222
2320
|
const rawUrl = req.url ?? '/';
|
|
2223
2321
|
const parsedUrl = new URL(rawUrl, 'http://127.0.0.1');
|
|
2224
2322
|
const url = parsedUrl.pathname;
|
|
2225
|
-
if (url === '/' || url === '/radar/qa' || url === '/radar/observability') {
|
|
2323
|
+
if (url === '/' || url === '/radar/qa' || url === '/radar/observability' || url === '/radar/docs') {
|
|
2226
2324
|
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
2227
2325
|
res.end(DASHBOARD_HTML);
|
|
2228
2326
|
return;
|
|
@@ -2750,6 +2848,50 @@ function startServer({ data: initialData, port, projectRoot }) {
|
|
|
2750
2848
|
}
|
|
2751
2849
|
return;
|
|
2752
2850
|
}
|
|
2851
|
+
// ── Documentation API ─────────────────────────────────────────────────────
|
|
2852
|
+
if (url === '/api/docs/content' && req.method === 'GET') {
|
|
2853
|
+
const featureKey = parsedUrl.searchParams.get('feature');
|
|
2854
|
+
if (!featureKey) {
|
|
2855
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
2856
|
+
res.end(JSON.stringify({ error: 'Missing feature param' }));
|
|
2857
|
+
return;
|
|
2858
|
+
}
|
|
2859
|
+
const docPath = path.join(projectRoot, 'docs', 'features', `${featureKey}.md`);
|
|
2860
|
+
try {
|
|
2861
|
+
const content = fs.readFileSync(docPath, 'utf-8');
|
|
2862
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
2863
|
+
res.end(JSON.stringify({ content, exists: true }));
|
|
2864
|
+
}
|
|
2865
|
+
catch {
|
|
2866
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
2867
|
+
res.end(JSON.stringify({ content: null, exists: false }));
|
|
2868
|
+
}
|
|
2869
|
+
return;
|
|
2870
|
+
}
|
|
2871
|
+
if (url === '/api/docs/save' && req.method === 'POST') {
|
|
2872
|
+
let body = '';
|
|
2873
|
+
req.on('data', (chunk) => { body += chunk.toString(); });
|
|
2874
|
+
req.on('end', () => {
|
|
2875
|
+
try {
|
|
2876
|
+
const { featureKey, content } = JSON.parse(body);
|
|
2877
|
+
if (!featureKey || typeof content !== 'string') {
|
|
2878
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
2879
|
+
res.end(JSON.stringify({ error: 'Missing featureKey or content' }));
|
|
2880
|
+
return;
|
|
2881
|
+
}
|
|
2882
|
+
const docsDir = path.join(projectRoot, 'docs', 'features');
|
|
2883
|
+
fs.mkdirSync(docsDir, { recursive: true });
|
|
2884
|
+
fs.writeFileSync(path.join(docsDir, `${featureKey}.md`), content, 'utf-8');
|
|
2885
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
2886
|
+
res.end(JSON.stringify({ ok: true }));
|
|
2887
|
+
}
|
|
2888
|
+
catch (err) {
|
|
2889
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
2890
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
2891
|
+
}
|
|
2892
|
+
});
|
|
2893
|
+
return;
|
|
2894
|
+
}
|
|
2753
2895
|
res.writeHead(404);
|
|
2754
2896
|
res.end('Not found');
|
|
2755
2897
|
});
|