@goodandready/dsh-moa 0.2.43 → 0.2.44

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/client.js CHANGED
@@ -2575,7 +2575,7 @@ window.__ModuleLoader__.load({
2575
2575
  }
2576
2576
  })
2577
2577
  .catch((err) => {
2578
- setSaveStatus(`Error: ${err.message || err}`)
2578
+ setSaveStatus((t('status.error_saving') || 'Error saving: ') + (err?.message || String(err)))
2579
2579
  })
2580
2580
  }
2581
2581
 
@@ -78,16 +78,6 @@ export function resolveCandidateFolder(baseDir, candidateTarget, options = {}) {
78
78
  const sub = /^\d+$/.test(sanitizedTarget) ? `candidate-${sanitizedTarget}` : (sanitizedTarget || 'candidate-1')
79
79
  const rawRunId = typeof options === 'string' ? options : options?.runId
80
80
  const safeRunId = rawRunId ? String(rawRunId).trim().replace(/[^a-zA-Z0-9_-]/g, '') : null
81
- const moaPath = path.resolve(baseDir, '.moa')
82
- try {
83
- const lst = fsSync.lstatSync(moaPath)
84
- if (lst.isSymbolicLink()) {
85
- const realMoa = fsSync.realpathSync(moaPath), realBase = fsSync.realpathSync(path.resolve(baseDir))
86
- if (realMoa !== realBase && !realMoa.startsWith(realBase + path.sep)) fsSync.unlinkSync(moaPath)
87
- }
88
- } catch (err) {
89
- if (err?.code !== 'ENOENT') throw err
90
- }
91
81
  const moaRoot = assertPathContained(baseDir, '.moa')
92
82
  const runRoot = safeRunId ? assertPathContained(moaRoot, safeRunId) : moaRoot
93
83
  return { moaRoot, runRoot, safeRunId, sub, candidateDir: assertPathContained(runRoot, sub) }
package/lib/moa-budget.js CHANGED
@@ -40,6 +40,7 @@ export function applyBudgetGuardrails({
40
40
  action = 'trim', // 'trim' | 'abort'
41
41
  prices = {},
42
42
  promptLength = 1000,
43
+ projectContext = '',
43
44
  messages = [],
44
45
  maxTokens = 2048,
45
46
  peerCritiqueEnabled = false,
@@ -57,6 +58,9 @@ export function applyBudgetGuardrails({
57
58
 
58
59
  // Calculate full input tokens from userPrompt length + messages context
59
60
  let contextChars = Number(promptLength) || 1000
61
+ if (typeof projectContext === 'string' && projectContext.length > 0 && !String(promptLength).includes(String(projectContext.length))) {
62
+ contextChars += projectContext.length
63
+ }
60
64
  if (Array.isArray(messages) && messages.length > 0) {
61
65
  for (const m of messages) {
62
66
  if (typeof m?.content === 'string') {
@@ -122,7 +122,6 @@ export async function runReferencesParallel(references, messages, options = {},
122
122
  })
123
123
  reject(new Error(`Timeout after ${Math.round(timeoutMs / 1000)}s`))
124
124
  }, timeoutMs)
125
- candidateTimer?.unref?.()
126
125
  })
127
126
 
128
127
  const res = await Promise.race([callPromise, timeoutPromise])
package/lib/moa-llm.js CHANGED
@@ -139,3 +139,14 @@ export function createLlmCaller(ctx) {
139
139
  }
140
140
  }
141
141
  }
142
+
143
+
144
+ export function callConfigEquals(a, b) {
145
+ if (!a || !b) return false
146
+ if (a.provider !== b.provider) return false
147
+ if (a.model !== b.model) return false
148
+ if (a.temperature !== b.temperature) return false
149
+ if (a.maxTokens !== b.maxTokens) return false
150
+ if (a.reasoningEffort !== b.reasoningEffort) return false
151
+ return true
152
+ }
package/lib/moa-runner.js CHANGED
@@ -60,14 +60,33 @@ export async function runMoAPipeline({
60
60
  const aggTimeoutSec = typeof preset?.aggregator_timeout_sec === 'number' ? preset.aggregator_timeout_sec : 180
61
61
  const isBlindEvaluation = Boolean(preset?.blind_evaluation), isPeerCritiqueEnabled = Boolean(preset?.peer_critique_enabled)
62
62
  const allowCandidateOverride = Boolean(preset?.allow_candidate_override)
63
- // Feature 6: Budget Guardrail check
63
+ // 1. Collect project context for refinement tasks
64
+ const collectedCtx = await collectProjectContext(cwd, 16000)
65
+ const isRefinement = Boolean(collectedCtx?.files?.length > 0 && isRefinementTask(userPrompt, collectedCtx.files))
66
+ let projectContext = ''
67
+ if (collectedCtx?.skippedFiles > 0 && typeof onProgress === 'function') {
68
+ const preview = collectedCtx.skippedList.slice(0, 3).join(', ')
69
+ const more = collectedCtx.skippedList.length > 3 ? ` (+${collectedCtx.skippedList.length - 3})` : ''
70
+ onProgress(`⚠️ *Workspace scan note: ${collectedCtx.skippedFiles} file(s) skipped (${preview}${more})*\n`)
71
+ }
72
+ if (isRefinement) {
73
+ if (typeof onProgress === 'function') {
74
+ onProgress('🔍 *Reading project files for refinement context...*\n')
75
+ }
76
+ projectContext = formatProjectContext(collectedCtx.files, {
77
+ skippedFiles: collectedCtx.skippedFiles,
78
+ skippedList: collectedCtx.skippedList,
79
+ })
80
+ }
81
+ // 2. Budget Guardrail check
64
82
  const budgetCheck = applyBudgetGuardrails({
65
83
  references: referenceModels,
66
84
  enabled: preset?.budget_guard_enabled,
67
85
  maxBudgetUsd: preset?.max_budget_usd,
68
86
  action: preset?.budget_action || 'trim',
69
87
  prices,
70
- promptLength: userPrompt?.length || 1000,
88
+ promptLength: (userPrompt?.length || 1000) + (projectContext ? projectContext.length : 0),
89
+ projectContext,
71
90
  messages,
72
91
  maxTokens,
73
92
  peerCritiqueEnabled: isPeerCritiqueEnabled,
@@ -75,20 +94,12 @@ export async function runMoAPipeline({
75
94
  judgeModels: preset?.multi_judge_enabled ? preset?.judge_models : [],
76
95
  })
77
96
  if (!budgetCheck.allowed) {
78
- return {
79
- kind: 'failure',
80
- content: `🛑 Budget Guardrail Abort: ${budgetCheck.reason}`,
81
- aggregator: slotLabel(primaryJudge),
82
- references: [],
83
- presetName: preset?.name || 'default',
84
- isRefinement: false,
85
- isFastMode,
86
- winningIndex: 0,
87
- winnerModel: 'none',
88
- promotedFiles: [],
97
+ return { kind: 'failure', content: `🛑 Budget Guardrail Abort: ${budgetCheck.reason}`,
98
+ aggregator: slotLabel(primaryJudge), references: [], presetName: preset?.name || 'default',
99
+ isRefinement, isFastMode, winningIndex: 0, winnerModel: 'none', promotedFiles: [],
89
100
  usage: { totalTokens: 0, totalCostUsd: 0, candidates: [], aggregator: { totalTokens: 0, costUsd: 0 } },
90
- skippedFiles: 0,
91
- skippedList: [],
101
+ skippedFiles: collectedCtx?.skippedFiles || 0,
102
+ skippedList: collectedCtx?.skippedList || [],
92
103
  durationMs: Date.now() - startTime,
93
104
  }
94
105
  }
@@ -96,24 +107,6 @@ export async function runMoAPipeline({
96
107
  if (budgetCheck.action === 'trim' && typeof onProgress === 'function') {
97
108
  onProgress(`✂️ *${budgetCheck.reason}*\n`)
98
109
  }
99
- // 2. Collect project context for refinement tasks
100
- const collectedCtx = await collectProjectContext(cwd, 16000)
101
- const isRefinement = Boolean(collectedCtx?.files?.length > 0 && isRefinementTask(userPrompt, collectedCtx.files))
102
- let projectContext = ''
103
- if (collectedCtx?.skippedFiles > 0 && typeof onProgress === 'function') {
104
- const preview = collectedCtx.skippedList.slice(0, 3).join(', ')
105
- const more = collectedCtx.skippedList.length > 3 ? ` (+${collectedCtx.skippedList.length - 3})` : ''
106
- onProgress(`⚠️ *Workspace scan note: ${collectedCtx.skippedFiles} file(s) skipped (${preview}${more})*\n`)
107
- }
108
- if (isRefinement) {
109
- if (typeof onProgress === 'function') {
110
- onProgress('🔍 *Reading project files for refinement context...*\n')
111
- }
112
- projectContext = formatProjectContext(collectedCtx.files, {
113
- skippedFiles: collectedCtx.skippedFiles,
114
- skippedList: collectedCtx.skippedList,
115
- })
116
- }
117
110
  // 3. Build prompts & Feature 8 multi-turn context
118
111
  const priorTurnBaseline = preset?.multi_turn_enabled !== false ? extractPriorTurnBaseline(messages) : null
119
112
  const prunedHistory = preset?.multi_turn_enabled !== false ? pruneMultiTurnMessages(messages) : messages
@@ -284,9 +277,21 @@ export async function runMoAPipeline({
284
277
  } else if (!allowCandidateOverride) {
285
278
  await cleanMoaWorkspaces(cwd, { runId })
286
279
  }
287
- if (signal?.aborted || promoteErr?.message?.includes('aborted') || promoteErr?.name === 'AbortError') {
280
+ if (promoteErr) {
288
281
  if (!allowCandidateOverride) await cleanMoaWorkspaces(cwd, { runId })
289
- return { error: new Error('Turn aborted') }
282
+ if (signal?.aborted || promoteErr?.message?.includes('aborted') || promoteErr?.name === 'AbortError' || promoteErr?.message === 'Turn aborted') {
283
+ return { error: new Error('Turn aborted') }
284
+ }
285
+ return { kind: 'failure', error: promoteErr,
286
+ content: '🛑 Checkpoint or Promotion Failure: ' + (promoteErr?.message || String(promoteErr)),
287
+ aggregator: 'Fast Mode (Direct)', references: referenceOutputs,
288
+ presetName: preset?.name || 'default', isRefinement, isFastMode: true,
289
+ winningIndex: single.index, winnerModel: single.label, promotedFiles: [], runId,
290
+ usage: { totalTokens: 0, totalCostUsd: 0, candidates: [], aggregator: { totalTokens: 0, costUsd: 0 } },
291
+ skippedFiles: collectedCtx?.skippedFiles || 0,
292
+ skippedList: collectedCtx?.skippedList || [],
293
+ durationMs: Date.now() - startTime,
294
+ }
290
295
  }
291
296
 
292
297
  const livePreview = await createPromotedPreview(liveCanvas, cwd, promotedFiles, referenceOutputs, { winningIndex: single.index })
@@ -121,9 +121,9 @@ export async function runCandidateTestGate({
121
121
  ...(candidateDir && candidateDir !== executionDir ? [candidateDir] : []),
122
122
  ...(process.platform === 'win32'
123
123
  ? [process.env.SYSTEMROOT || 'C:\\Windows', path.dirname(process.execPath)]
124
- : ['/usr', '/lib', '/lib64', '/etc', path.resolve(path.dirname(process.execPath), '..'), process.env.HOME ? path.join(process.env.HOME, '.npmrc') : null]),
124
+ : ['/usr', '/lib', '/lib64', '/etc', path.resolve(path.dirname(process.execPath), '..')]),
125
125
  ].filter(Boolean)
126
- const permOpts = `--permission ${allowedReads.map((p) => `--allow-fs-read=${p}`).join(' ')} --allow-fs-write=${executionDir} --allow-child-process`
126
+ const permOpts = `--permission ${allowedReads.map((p) => `--allow-fs-read=${p}`).join(' ')} --allow-fs-write=${executionDir}`
127
127
 
128
128
  const env = getScrubbedEnv({
129
129
  MOA_CANDIDATE_INDEX: String(candidateIndex),
@@ -134,6 +134,31 @@ export async function runCandidateTestGate({
134
134
  NODE_OPTIONS: process.env.NODE_OPTIONS ? `${process.env.NODE_OPTIONS} ${permOpts}` : permOpts,
135
135
  })
136
136
 
137
+ const allowedRoots = [executionDir, cwd, ...(candidateDir && candidateDir !== executionDir ? [candidateDir] : [])]
138
+ const cmdTokens = resolvedCmd.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g) || []
139
+ for (const rawToken of cmdTokens) {
140
+ const token = rawToken.replace(/^["']|["']$/g, '')
141
+ if (path.isAbsolute(token)) {
142
+ if (/^\/(usr\/(bin|lib|include)|bin|lib|lib64|etc)/.test(token) && !/\.(txt|json|env|npmrc|key|ssh|md)/i.test(token)) {
143
+ continue
144
+ }
145
+ const real = path.resolve(token)
146
+ const allowed = allowedRoots.some((d) => d && (real === d || real.startsWith(d + path.sep)))
147
+ if (!allowed) {
148
+ const durationMs = Date.now() - startTime
149
+ return {
150
+ candidateIndex,
151
+ passed: false,
152
+ exitCode: 1,
153
+ durationMs,
154
+ command: resolvedCmd,
155
+ output: 'Access denied: test command specifies path outside workspace sandbox',
156
+ summary: `FAIL (code 1, ${durationMs}ms)`,
157
+ }
158
+ }
159
+ }
160
+ }
161
+
137
162
  const runPromise = new Promise((resolve) => {
138
163
  let child
139
164
  let timeoutHandle = null
package/lib/routes.js CHANGED
@@ -2,12 +2,7 @@
2
2
  * DeepSeek Harness Mixture of Agents (MoA) — HTTP Route Handlers
3
3
  */
4
4
 
5
- import {
6
- getMoaHistory,
7
- getMoaLeaderboard,
8
- getMoaRunById,
9
- exportMoaHistory,
10
- } from './history.js'
5
+ import { getMoaHistory, getMoaLeaderboard, getMoaRunById, exportMoaHistory } from './history.js'
11
6
  import { promoteCandidateWorkspace, readCandidateFiles, computeLineDiff, isSafeRelativePath } from './file-workspace.js'
12
7
  import { isSafeWriteRequest } from './updater.js'
13
8
  import { runMoAPipeline } from './moa-runner.js'
@@ -18,10 +13,7 @@ let _modelsCache = { timestamp: 0, models: [] }
18
13
  const MODELS_CACHE_TTL = 60 * 1000
19
14
 
20
15
  function writeJson(res, status, body) {
21
- res.writeHead(status, {
22
- 'Content-Type': 'application/json; charset=utf-8',
23
- 'Cache-Control': 'no-store',
24
- })
16
+ res.writeHead(status, { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-store' })
25
17
  res.end(JSON.stringify(body))
26
18
  }
27
19
 
@@ -30,10 +22,7 @@ function readBody(req) {
30
22
  let acc = ''
31
23
  req.on('data', (chunk) => {
32
24
  acc += chunk
33
- if (acc.length > 5 * 1024 * 1024) {
34
- req.destroy()
35
- reject(new Error('Payload Too Large'))
36
- }
25
+ if (acc.length > 5 * 1024 * 1024) { req.destroy(); reject(new Error('Payload Too Large')) }
37
26
  })
38
27
  req.on('end', () => resolve(acc))
39
28
  req.on('error', reject)
@@ -587,6 +576,11 @@ ctx.effect(() => {
587
576
  ctx.logger?.warn?.(`[dsh-moa] Workspace scan skipped ${result.skippedFiles} file(s): ${result.skippedList.join(', ')}`)
588
577
  }
589
578
 
579
+ if (result?.error) {
580
+ writeJson(res, 500, { ok: false, error: result.error?.message || String(result.error) })
581
+ return
582
+ }
583
+
590
584
  writeJson(res, 200, { ok: true, ...result })
591
585
  } catch (err) {
592
586
  writeJson(res, 500, { ok: false, error: err?.message || String(err) })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-moa",
3
- "version": "0.2.43",
3
+ "version": "0.2.44",
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",