@jungtz/wiki-router 1.2.0 → 1.3.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/dist/index.cjs +38 -5
- package/dist/index.mjs +38 -5
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -282,6 +282,15 @@ function createWikiRouter(config) {
|
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
+
function formatElapsed(startMs) {
|
|
286
|
+
const ms = Date.now() - startMs;
|
|
287
|
+
if (ms < 1000) return `${ms}ms`
|
|
288
|
+
if (ms < 60000) return `${(ms / 1000).toFixed(2)}s`
|
|
289
|
+
const m = Math.floor(ms / 60000);
|
|
290
|
+
const s = ((ms % 60000) / 1000).toFixed(1);
|
|
291
|
+
return `${m}m${s}s`
|
|
292
|
+
}
|
|
293
|
+
|
|
285
294
|
function fingerprintsEqual(a, b) {
|
|
286
295
|
if (!a || !b) return false
|
|
287
296
|
const ak = Object.keys(a);
|
|
@@ -292,6 +301,7 @@ function createWikiRouter(config) {
|
|
|
292
301
|
|
|
293
302
|
async function build(options = {}) {
|
|
294
303
|
const { force = false } = options;
|
|
304
|
+
const buildStart = Date.now();
|
|
295
305
|
try {
|
|
296
306
|
const knowledgeKeys = await activeSource.list();
|
|
297
307
|
|
|
@@ -312,7 +322,7 @@ function createWikiRouter(config) {
|
|
|
312
322
|
const storedFp = await activeStore.readManifest();
|
|
313
323
|
const existingFiles = await activeStore.list();
|
|
314
324
|
if (existingFiles.length > 0 && fingerprintsEqual(currentFp, storedFp)) {
|
|
315
|
-
console.log(
|
|
325
|
+
console.log(`[Wiki] Source unchanged, skipping build (fingerprint match) — ${formatElapsed(buildStart)}`);
|
|
316
326
|
return true
|
|
317
327
|
}
|
|
318
328
|
}
|
|
@@ -321,6 +331,7 @@ function createWikiRouter(config) {
|
|
|
321
331
|
let totalFiles = 0;
|
|
322
332
|
|
|
323
333
|
for (const key of knowledgeKeys) {
|
|
334
|
+
const keyStart = Date.now();
|
|
324
335
|
const existingFiles = await activeStore.list();
|
|
325
336
|
const isFirstTime = existingFiles.length === 0;
|
|
326
337
|
const { type: fileType, content: fileContent } = await activeSource.read(key);
|
|
@@ -341,7 +352,7 @@ function createWikiRouter(config) {
|
|
|
341
352
|
|
|
342
353
|
const output = await chat([{ role: 'user', content: finalPrompt }]);
|
|
343
354
|
if (!output) {
|
|
344
|
-
console.warn(`[Wiki] No output for: ${key}`);
|
|
355
|
+
console.warn(`[Wiki] No output for: ${key} — ${formatElapsed(keyStart)}`);
|
|
345
356
|
continue
|
|
346
357
|
}
|
|
347
358
|
|
|
@@ -356,17 +367,22 @@ function createWikiRouter(config) {
|
|
|
356
367
|
console.log(`[Wiki] ${isFirstTime ? 'Generated' : 'Updated'}: ${filename}`);
|
|
357
368
|
}
|
|
358
369
|
totalFiles += parsed.length;
|
|
370
|
+
console.log(`[Wiki] Done: ${key} — ${parsed.length} file(s), ${formatElapsed(keyStart)}`);
|
|
359
371
|
}
|
|
360
372
|
|
|
361
|
-
if (totalFiles === 0)
|
|
373
|
+
if (totalFiles === 0) {
|
|
374
|
+
console.warn(`[Wiki] Build produced no files — ${formatElapsed(buildStart)}`);
|
|
375
|
+
return false
|
|
376
|
+
}
|
|
362
377
|
|
|
363
378
|
if (currentFp && storeSupportsManifest) {
|
|
364
379
|
await activeStore.writeManifest(currentFp);
|
|
365
380
|
}
|
|
366
381
|
|
|
382
|
+
console.log(`[Wiki] Build complete — ${totalFiles} file(s), ${formatElapsed(buildStart)}`);
|
|
367
383
|
return true
|
|
368
384
|
} catch (err) {
|
|
369
|
-
console.error(
|
|
385
|
+
console.error(`[Wiki Generation Error] (after ${formatElapsed(buildStart)})`, err);
|
|
370
386
|
return false
|
|
371
387
|
}
|
|
372
388
|
}
|
|
@@ -549,6 +565,15 @@ function sqliteStore(config) {
|
|
|
549
565
|
|
|
550
566
|
const DEFAULT_AUTO_INDEX_HEADER = '# 知識庫目錄';
|
|
551
567
|
|
|
568
|
+
function formatElapsed(startMs) {
|
|
569
|
+
const ms = Date.now() - startMs;
|
|
570
|
+
if (ms < 1000) return `${ms}ms`
|
|
571
|
+
if (ms < 60000) return `${(ms / 1000).toFixed(2)}s`
|
|
572
|
+
const m = Math.floor(ms / 60000);
|
|
573
|
+
const s = ((ms % 60000) / 1000).toFixed(1);
|
|
574
|
+
return `${m}m${s}s`
|
|
575
|
+
}
|
|
576
|
+
|
|
552
577
|
/**
|
|
553
578
|
* @param {import('./types').TenantManagerConfig} config
|
|
554
579
|
* @returns {import('./types').TenantManager}
|
|
@@ -610,10 +635,14 @@ function createTenantManager(config) {
|
|
|
610
635
|
const { force = false } = options;
|
|
611
636
|
if (buildPromises.has(tenantId)) return buildPromises.get(tenantId)
|
|
612
637
|
|
|
638
|
+
const tenantStart = Date.now();
|
|
613
639
|
const promise = (async () => {
|
|
614
640
|
const { wiki, store } = getWiki(tenantId);
|
|
615
641
|
const ok = await wiki.build({ force });
|
|
616
|
-
if (!ok)
|
|
642
|
+
if (!ok) {
|
|
643
|
+
logger.warn && logger.warn(`[Wiki] Tenant "${tenantId}" build failed — ${formatElapsed(tenantStart)}`);
|
|
644
|
+
return false
|
|
645
|
+
}
|
|
617
646
|
|
|
618
647
|
if (autoIndex) {
|
|
619
648
|
const hasIndex = await store.read('Index.md');
|
|
@@ -624,6 +653,7 @@ function createTenantManager(config) {
|
|
|
624
653
|
}
|
|
625
654
|
|
|
626
655
|
builtTenants.add(tenantId);
|
|
656
|
+
logger.log && logger.log(`[Wiki] Tenant "${tenantId}" ready — ${formatElapsed(tenantStart)}`);
|
|
627
657
|
return true
|
|
628
658
|
})().finally(() => {
|
|
629
659
|
buildPromises.delete(tenantId);
|
|
@@ -642,8 +672,11 @@ function createTenantManager(config) {
|
|
|
642
672
|
logger.log && logger.log('[Wiki] No tenants to build');
|
|
643
673
|
return []
|
|
644
674
|
}
|
|
675
|
+
const allStart = Date.now();
|
|
645
676
|
logger.log && logger.log(`[Wiki] Pre-building ${tenants.length} tenant(s): ${tenants.join(', ')}`);
|
|
646
677
|
const results = await Promise.allSettled(tenants.map(t => build(t)));
|
|
678
|
+
const okCount = results.filter(r => r.status === 'fulfilled' && r.value === true).length;
|
|
679
|
+
logger.log && logger.log(`[Wiki] buildAll done — ${okCount}/${tenants.length} ok, ${formatElapsed(allStart)}`);
|
|
647
680
|
results.forEach((r, i) => {
|
|
648
681
|
if (r.status === 'rejected') {
|
|
649
682
|
logger.error && logger.error(
|
package/dist/index.mjs
CHANGED
|
@@ -280,6 +280,15 @@ function createWikiRouter(config) {
|
|
|
280
280
|
}
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
+
function formatElapsed(startMs) {
|
|
284
|
+
const ms = Date.now() - startMs;
|
|
285
|
+
if (ms < 1000) return `${ms}ms`
|
|
286
|
+
if (ms < 60000) return `${(ms / 1000).toFixed(2)}s`
|
|
287
|
+
const m = Math.floor(ms / 60000);
|
|
288
|
+
const s = ((ms % 60000) / 1000).toFixed(1);
|
|
289
|
+
return `${m}m${s}s`
|
|
290
|
+
}
|
|
291
|
+
|
|
283
292
|
function fingerprintsEqual(a, b) {
|
|
284
293
|
if (!a || !b) return false
|
|
285
294
|
const ak = Object.keys(a);
|
|
@@ -290,6 +299,7 @@ function createWikiRouter(config) {
|
|
|
290
299
|
|
|
291
300
|
async function build(options = {}) {
|
|
292
301
|
const { force = false } = options;
|
|
302
|
+
const buildStart = Date.now();
|
|
293
303
|
try {
|
|
294
304
|
const knowledgeKeys = await activeSource.list();
|
|
295
305
|
|
|
@@ -310,7 +320,7 @@ function createWikiRouter(config) {
|
|
|
310
320
|
const storedFp = await activeStore.readManifest();
|
|
311
321
|
const existingFiles = await activeStore.list();
|
|
312
322
|
if (existingFiles.length > 0 && fingerprintsEqual(currentFp, storedFp)) {
|
|
313
|
-
console.log(
|
|
323
|
+
console.log(`[Wiki] Source unchanged, skipping build (fingerprint match) — ${formatElapsed(buildStart)}`);
|
|
314
324
|
return true
|
|
315
325
|
}
|
|
316
326
|
}
|
|
@@ -319,6 +329,7 @@ function createWikiRouter(config) {
|
|
|
319
329
|
let totalFiles = 0;
|
|
320
330
|
|
|
321
331
|
for (const key of knowledgeKeys) {
|
|
332
|
+
const keyStart = Date.now();
|
|
322
333
|
const existingFiles = await activeStore.list();
|
|
323
334
|
const isFirstTime = existingFiles.length === 0;
|
|
324
335
|
const { type: fileType, content: fileContent } = await activeSource.read(key);
|
|
@@ -339,7 +350,7 @@ function createWikiRouter(config) {
|
|
|
339
350
|
|
|
340
351
|
const output = await chat([{ role: 'user', content: finalPrompt }]);
|
|
341
352
|
if (!output) {
|
|
342
|
-
console.warn(`[Wiki] No output for: ${key}`);
|
|
353
|
+
console.warn(`[Wiki] No output for: ${key} — ${formatElapsed(keyStart)}`);
|
|
343
354
|
continue
|
|
344
355
|
}
|
|
345
356
|
|
|
@@ -354,17 +365,22 @@ function createWikiRouter(config) {
|
|
|
354
365
|
console.log(`[Wiki] ${isFirstTime ? 'Generated' : 'Updated'}: ${filename}`);
|
|
355
366
|
}
|
|
356
367
|
totalFiles += parsed.length;
|
|
368
|
+
console.log(`[Wiki] Done: ${key} — ${parsed.length} file(s), ${formatElapsed(keyStart)}`);
|
|
357
369
|
}
|
|
358
370
|
|
|
359
|
-
if (totalFiles === 0)
|
|
371
|
+
if (totalFiles === 0) {
|
|
372
|
+
console.warn(`[Wiki] Build produced no files — ${formatElapsed(buildStart)}`);
|
|
373
|
+
return false
|
|
374
|
+
}
|
|
360
375
|
|
|
361
376
|
if (currentFp && storeSupportsManifest) {
|
|
362
377
|
await activeStore.writeManifest(currentFp);
|
|
363
378
|
}
|
|
364
379
|
|
|
380
|
+
console.log(`[Wiki] Build complete — ${totalFiles} file(s), ${formatElapsed(buildStart)}`);
|
|
365
381
|
return true
|
|
366
382
|
} catch (err) {
|
|
367
|
-
console.error(
|
|
383
|
+
console.error(`[Wiki Generation Error] (after ${formatElapsed(buildStart)})`, err);
|
|
368
384
|
return false
|
|
369
385
|
}
|
|
370
386
|
}
|
|
@@ -547,6 +563,15 @@ function sqliteStore(config) {
|
|
|
547
563
|
|
|
548
564
|
const DEFAULT_AUTO_INDEX_HEADER = '# 知識庫目錄';
|
|
549
565
|
|
|
566
|
+
function formatElapsed(startMs) {
|
|
567
|
+
const ms = Date.now() - startMs;
|
|
568
|
+
if (ms < 1000) return `${ms}ms`
|
|
569
|
+
if (ms < 60000) return `${(ms / 1000).toFixed(2)}s`
|
|
570
|
+
const m = Math.floor(ms / 60000);
|
|
571
|
+
const s = ((ms % 60000) / 1000).toFixed(1);
|
|
572
|
+
return `${m}m${s}s`
|
|
573
|
+
}
|
|
574
|
+
|
|
550
575
|
/**
|
|
551
576
|
* @param {import('./types').TenantManagerConfig} config
|
|
552
577
|
* @returns {import('./types').TenantManager}
|
|
@@ -608,10 +633,14 @@ function createTenantManager(config) {
|
|
|
608
633
|
const { force = false } = options;
|
|
609
634
|
if (buildPromises.has(tenantId)) return buildPromises.get(tenantId)
|
|
610
635
|
|
|
636
|
+
const tenantStart = Date.now();
|
|
611
637
|
const promise = (async () => {
|
|
612
638
|
const { wiki, store } = getWiki(tenantId);
|
|
613
639
|
const ok = await wiki.build({ force });
|
|
614
|
-
if (!ok)
|
|
640
|
+
if (!ok) {
|
|
641
|
+
logger.warn && logger.warn(`[Wiki] Tenant "${tenantId}" build failed — ${formatElapsed(tenantStart)}`);
|
|
642
|
+
return false
|
|
643
|
+
}
|
|
615
644
|
|
|
616
645
|
if (autoIndex) {
|
|
617
646
|
const hasIndex = await store.read('Index.md');
|
|
@@ -622,6 +651,7 @@ function createTenantManager(config) {
|
|
|
622
651
|
}
|
|
623
652
|
|
|
624
653
|
builtTenants.add(tenantId);
|
|
654
|
+
logger.log && logger.log(`[Wiki] Tenant "${tenantId}" ready — ${formatElapsed(tenantStart)}`);
|
|
625
655
|
return true
|
|
626
656
|
})().finally(() => {
|
|
627
657
|
buildPromises.delete(tenantId);
|
|
@@ -640,8 +670,11 @@ function createTenantManager(config) {
|
|
|
640
670
|
logger.log && logger.log('[Wiki] No tenants to build');
|
|
641
671
|
return []
|
|
642
672
|
}
|
|
673
|
+
const allStart = Date.now();
|
|
643
674
|
logger.log && logger.log(`[Wiki] Pre-building ${tenants.length} tenant(s): ${tenants.join(', ')}`);
|
|
644
675
|
const results = await Promise.allSettled(tenants.map(t => build(t)));
|
|
676
|
+
const okCount = results.filter(r => r.status === 'fulfilled' && r.value === true).length;
|
|
677
|
+
logger.log && logger.log(`[Wiki] buildAll done — ${okCount}/${tenants.length} ok, ${formatElapsed(allStart)}`);
|
|
645
678
|
results.forEach((r, i) => {
|
|
646
679
|
if (r.status === 'rejected') {
|
|
647
680
|
logger.error && logger.error(
|