@goodandready/dsh-moa 0.2.48 → 0.2.49

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/lib/history.js CHANGED
@@ -51,6 +51,14 @@ export function invalidateHistoryCache() {
51
51
  _historyCache = null
52
52
  }
53
53
 
54
+ function getOrInitCache(filePath, stat) {
55
+ if (!_historyCache || _historyCache.filePath !== filePath || _historyCache.mtimeMs !== stat.mtimeMs || _historyCache.size !== stat.size) {
56
+ _historyCache = { filePath, mtimeMs: stat.mtimeMs, size: stat.size, leaderboards: new Map(), runsById: new Map(), totalCount: null }
57
+ }
58
+ if (!_historyCache.runsById) _historyCache.runsById = new Map()
59
+ return _historyCache
60
+ }
61
+
54
62
  /**
55
63
  * Checks if the history file exceeds the size threshold and rotates it.
56
64
  * Moves current file to `${filePath}.1`, removing any older `.1` backup.
@@ -277,22 +285,8 @@ export function countFileLinesSync(filePath, stat) {
277
285
  try { fs.closeSync(fd) } catch { /* best effort */ }
278
286
  }
279
287
 
280
- if (
281
- !_historyCache ||
282
- _historyCache.filePath !== filePath ||
283
- _historyCache.mtimeMs !== stat.mtimeMs ||
284
- _historyCache.size !== stat.size
285
- ) {
286
- _historyCache = {
287
- filePath,
288
- mtimeMs: stat.mtimeMs,
289
- size: stat.size,
290
- leaderboards: new Map(),
291
- totalCount: count,
292
- }
293
- } else {
294
- _historyCache.totalCount = count
295
- }
288
+ const cache = getOrInitCache(filePath, stat)
289
+ cache.totalCount = count
296
290
  return count
297
291
  }
298
292
 
@@ -314,29 +308,17 @@ export function getMoaHistory(limit = 20, offset = 0, filePath = getDefaultHisto
314
308
  const lines = raw.trim().split('\n').filter(Boolean)
315
309
  const total = lines.length
316
310
 
317
- if (
318
- !_historyCache ||
319
- _historyCache.filePath !== filePath ||
320
- _historyCache.mtimeMs !== stat.mtimeMs ||
321
- _historyCache.size !== stat.size
322
- ) {
323
- _historyCache = {
324
- filePath,
325
- mtimeMs: stat.mtimeMs,
326
- size: stat.size,
327
- leaderboards: new Map(),
328
- totalCount: total,
329
- }
330
- } else {
331
- _historyCache.totalCount = total
332
- }
311
+ const cache = getOrInitCache(filePath, stat)
312
+ cache.totalCount = total
333
313
 
334
314
  const sliced = lines
335
315
  .slice(Math.max(0, total - offset - limit), total - offset)
336
316
  .reverse()
337
317
  .map((line) => {
338
318
  try {
339
- return JSON.parse(line)
319
+ const item = JSON.parse(line)
320
+ if (item?.id) cache.runsById.set(item.id, item)
321
+ return item
340
322
  } catch {
341
323
  return null
342
324
  }
@@ -348,24 +330,22 @@ export function getMoaHistory(limit = 20, offset = 0, filePath = getDefaultHisto
348
330
 
349
331
  // For larger files: read only tail lines backwards to avoid splitting 10MB in memory
350
332
  const tailLines = readTailLinesSync(filePath, needed)
333
+ const cache = getOrInitCache(filePath, stat)
351
334
  const pageLines = tailLines.slice(offset, offset + limit)
352
335
  const runs = pageLines
353
336
  .map((line) => {
354
337
  try {
355
- return JSON.parse(line)
338
+ const item = JSON.parse(line)
339
+ if (item?.id) cache.runsById.set(item.id, item)
340
+ return item
356
341
  } catch {
357
342
  return null
358
343
  }
359
344
  })
360
345
  .filter(Boolean)
361
346
 
362
- let total = (_historyCache &&
363
- _historyCache.filePath === filePath &&
364
- _historyCache.mtimeMs === stat.mtimeMs &&
365
- _historyCache.size === stat.size &&
366
- typeof _historyCache.totalCount === 'number')
367
- ? _historyCache.totalCount
368
- : undefined
347
+ const isCached = _historyCache && _historyCache.filePath === filePath && _historyCache.mtimeMs === stat.mtimeMs && _historyCache.size === stat.size
348
+ let total = isCached && typeof _historyCache.totalCount === 'number' ? _historyCache.totalCount : undefined
369
349
  if (typeof total !== 'number') {
370
350
  total = tailLines.length < needed ? tailLines.length : countFileLinesSync(filePath, stat)
371
351
  }
@@ -392,24 +372,9 @@ export function getMoaLeaderboard(filePath = getDefaultHistoryFile(), options =
392
372
  const presetFilter = typeof options === 'string' ? options : (options?.presetFilter || options?.preset || null)
393
373
  const filterKey = presetFilter || 'all'
394
374
 
395
- if (
396
- _historyCache &&
397
- _historyCache.filePath === filePath &&
398
- _historyCache.mtimeMs === stat.mtimeMs &&
399
- _historyCache.size === stat.size
400
- ) {
401
- if (_historyCache.leaderboards.has(filterKey)) {
402
- return _historyCache.leaderboards.get(filterKey)
403
- }
404
- } else {
405
- _historyCache = {
406
- filePath,
407
- mtimeMs: stat.mtimeMs,
408
- size: stat.size,
409
- leaderboards: new Map(),
410
- totalCount: null,
411
- }
412
- }
375
+ const isCached = _historyCache && _historyCache.filePath === filePath && _historyCache.mtimeMs === stat.mtimeMs && _historyCache.size === stat.size
376
+ if (isCached && _historyCache.leaderboards.has(filterKey)) return _historyCache.leaderboards.get(filterKey)
377
+ const cache = getOrInitCache(filePath, stat)
413
378
 
414
379
  const raw = fs.readFileSync(filePath, 'utf8')
415
380
  const lines = raw.trim().split('\n').filter(Boolean)
@@ -500,18 +465,51 @@ export function getMoaLeaderboard(filePath = getDefaultHistoryFile(), options =
500
465
  }
501
466
 
502
467
  /**
503
- * Retrieves a single history run by ID.
468
+ * Retrieves a single history run by ID using in-memory cache and tail reading (#235).
504
469
  */
505
470
  export function getMoaRunById(runId, filePath = getDefaultHistoryFile()) {
506
471
  try {
507
- if (!fs.existsSync(filePath)) return null
472
+ if (!runId || !fs.existsSync(filePath)) return null
473
+ const stat = fs.statSync(filePath)
474
+ const cache = getOrInitCache(filePath, stat)
475
+ if (cache.runsById.has(runId)) return cache.runsById.get(runId)
476
+
477
+ if (stat.size <= 65536) {
478
+ const raw = fs.readFileSync(filePath, 'utf8')
479
+ const lines = raw.trim().split('\n').filter(Boolean)
480
+ for (let i = lines.length - 1; i >= 0; i--) {
481
+ try {
482
+ const item = JSON.parse(lines[i])
483
+ if (item?.id) {
484
+ cache.runsById.set(item.id, item)
485
+ if (item.id === runId) return item
486
+ }
487
+ } catch { /* skip corrupt */ }
488
+ }
489
+ return null
490
+ }
491
+
492
+ const tailLines = readTailLinesSync(filePath, 100)
493
+ for (const line of tailLines) {
494
+ try {
495
+ const item = JSON.parse(line)
496
+ if (item?.id) {
497
+ cache.runsById.set(item.id, item)
498
+ if (item.id === runId) return item
499
+ }
500
+ } catch { /* skip corrupt */ }
501
+ }
502
+
508
503
  const raw = fs.readFileSync(filePath, 'utf8')
509
504
  const lines = raw.trim().split('\n').filter(Boolean)
510
505
  for (let i = lines.length - 1; i >= 0; i--) {
511
506
  try {
512
507
  const item = JSON.parse(lines[i])
513
- if (item && item.id === runId) return item
514
- } catch { /* corrupt line skipped */ }
508
+ if (item?.id) {
509
+ cache.runsById.set(item.id, item)
510
+ if (item.id === runId) return item
511
+ }
512
+ } catch { /* skip corrupt */ }
515
513
  }
516
514
  return null
517
515
  } catch {
package/lib/moa-runner.js CHANGED
@@ -48,7 +48,7 @@ export async function runMoAPipeline({
48
48
  const aggTemp = typeof preset?.aggregator_temperature === 'number' ? preset.aggregator_temperature : 0.4
49
49
  const maxTokens = typeof preset?.max_tokens === 'number' ? preset.max_tokens : 4096
50
50
  const judgeCriteria = preset?.judge_criteria || ''
51
- const isFastMode = referenceModels.length === 1 && !preset?.curator_synthesis
51
+ let isFastMode = referenceModels.length === 1 && !preset?.curator_synthesis
52
52
  const isCuratorSynthesis = Boolean(preset?.curator_synthesis), isStreamAggregator = preset?.stream_aggregator !== false
53
53
  const isQuorumEnabled = Boolean(preset?.quorum_enabled), gracePeriodSec = typeof preset?.grace_period_sec === 'number' ? preset.grace_period_sec : 10
54
54
  const candidateRetries = 1, refTimeoutSec = typeof preset?.reference_timeout_sec === 'number' ? preset.reference_timeout_sec : 60
@@ -93,6 +93,9 @@ export async function runMoAPipeline({
93
93
  return createBudgetAbortPayload({ reason: budgetCheck.reason, primaryJudge, referenceOutputs: [], currentSpentUsd: 0, preset, isRefinement, isFastMode, collectedCtx, startTime })
94
94
  }
95
95
  const effectiveReferences = budgetCheck.references
96
+ if (effectiveReferences.length === 1 && !preset?.curator_synthesis) {
97
+ isFastMode = true
98
+ }
96
99
  if (budgetCheck.action === 'trim' && typeof onProgress === 'function') {
97
100
  onProgress(`✂️ *${budgetCheck.reason}*\n`)
98
101
  }
package/lib/routes.js CHANGED
@@ -512,7 +512,6 @@ ctx.effect(() => {
512
512
  writeJson(res, 429, { ok: false, error: 'Rate limit exceeded: please wait before starting another run' })
513
513
  return
514
514
  }
515
- _lastRunTimestamp = now
516
515
 
517
516
  try {
518
517
  const raw = await readBody(req)
@@ -522,6 +521,7 @@ ctx.effect(() => {
522
521
  writeJson(res, 400, { ok: false, error: 'Empty prompt' })
523
522
  return
524
523
  }
524
+ _lastRunTimestamp = now
525
525
 
526
526
  const cfg = live()
527
527
  if (cfg.enabled === false) {
package/lib/updater.js CHANGED
@@ -41,10 +41,11 @@ export function isTrustedUpdateRequest(request) {
41
41
  }
42
42
  }
43
43
 
44
- /** General safe write check for plugin write endpoints (CSRF / Cross-Site protection) */
44
+ /** General safe write check for plugin write endpoints (CSRF / Cross-Site protection, #234) */
45
45
  export function isSafeWriteRequest(request) {
46
46
  const remote = request?.socket?.remoteAddress || request?.connection?.remoteAddress;
47
47
  const isLoop = !remote || isLoopback(remote);
48
+ if (!isLoop) return false;
48
49
 
49
50
  const site = header(request, 'sec-fetch-site');
50
51
  if (site === 'cross-site') return false;
@@ -52,13 +53,6 @@ export function isSafeWriteRequest(request) {
52
53
  const origin = header(request, 'origin');
53
54
  const host = header(request, 'host');
54
55
 
55
- // If non-loopback caller, require valid same-origin browser proof
56
- if (!isLoop) {
57
- if (!origin || !host) return false;
58
- if (site && site !== 'same-origin' && site !== 'none') return false;
59
- }
60
-
61
- // Same-site without matching origin is rejected regardless of remote
62
56
  if (site === 'same-site') {
63
57
  if (!origin || !host) return false;
64
58
  }
@@ -68,9 +62,7 @@ export function isSafeWriteRequest(request) {
68
62
  try {
69
63
  const url = new URL(origin);
70
64
  if (host && url.host !== host) return false;
71
- if (!isLoop) {
72
- if (url.protocol !== 'http:' && url.protocol !== 'https:') return false;
73
- }
65
+ if (url.protocol !== 'http:' && url.protocol !== 'https:') return false;
74
66
  } catch {
75
67
  return false;
76
68
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-moa",
3
- "version": "0.2.48",
3
+ "version": "0.2.49",
4
4
  "description": "Mixture of Agents (MoA) plugin for DeepSeek Harness with /moa slash command",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",