@goodandready/dsh-moa 0.2.67 → 0.2.68

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/index.js CHANGED
@@ -401,3 +401,15 @@ export {
401
401
  analyzeCandidateUncertainty,
402
402
  formatUncertaintyAnnotations,
403
403
  } from './moa-uncertainty.js'
404
+ export {
405
+ classifyPromptDomain,
406
+ assignAdaptivePersonas,
407
+ DOMAIN_PERSONA_POOLS,
408
+ } from './moa-adaptive-personas.js'
409
+ export {
410
+ isGitRepository,
411
+ createSwarmWorktree,
412
+ collectSwarmWorktreeDiff,
413
+ cleanupSwarmWorktrees,
414
+ runSubagentSwarm,
415
+ } from './moa-swarm.js'
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Prompt-Adaptive Dynamic Persona Synthesis for Reference Models (#254)
3
+ * Classifies prompt technical domain and synthesizes complementary engineering personas
4
+ * dynamically so each candidate approaches the task from a distinct expert angle.
5
+ */
6
+
7
+ export const DOMAIN_PERSONA_POOLS = {
8
+ database: [
9
+ {
10
+ id: 'dba_index_specialist',
11
+ title: 'DBA Index Specialist',
12
+ prompt: 'You are a Principal DBA Index Specialist. Focus on query execution plans, composite indexing, lock contention prevention, and optimal read/write throughput.',
13
+ },
14
+ {
15
+ id: 'zero_downtime_migration_guard',
16
+ title: 'Zero-Downtime Migration Guard',
17
+ prompt: 'You are a Zero-Downtime Migration Guard. Ensure backward-compatible schema evolutions, safe expand-and-contract patterns, and rollback safety.',
18
+ },
19
+ {
20
+ id: 'orm_query_architect',
21
+ title: 'ORM & Query Architect',
22
+ prompt: 'You are an ORM & Query Architect. Focus on eliminating N+1 queries, clean repository abstractions, transaction isolation levels, and strict data integrity.',
23
+ },
24
+ ],
25
+ frontend: [
26
+ {
27
+ id: 'a11y_ux_specialist',
28
+ title: 'Accessibility & UX Specialist',
29
+ prompt: 'You are an Accessibility & UX Specialist. Ensure WCAG 2.1 AA compliance, keyboard navigation, ARIA semantics, and responsive user feedback.',
30
+ },
31
+ {
32
+ id: 'css_design_systems_architect',
33
+ title: 'CSS & Design Systems Architect',
34
+ prompt: 'You are a CSS & Design Systems Architect. Focus on design tokens, layout resilience, fluid typography, zero layout shift, and clean component composition.',
35
+ },
36
+ {
37
+ id: 'state_rendering_optimizer',
38
+ title: 'State & Rendering Optimizer',
39
+ prompt: 'You are a Frontend State & Rendering Optimizer. Focus on minimizing unnecessary re-renders, memoization, deterministic state transitions, and bundle efficiency.',
40
+ },
41
+ ],
42
+ security: [
43
+ {
44
+ id: 'offensive_security_auditor',
45
+ title: 'Offensive Security Auditor',
46
+ prompt: 'You are an Offensive Security Auditor. Proactively hunt for injection vectors, SSRF, path traversal, auth bypass, and privilege escalation.',
47
+ },
48
+ {
49
+ id: 'defensive_hardening_specialist',
50
+ title: 'Defensive Hardening Specialist',
51
+ prompt: 'You are a Defensive Hardening Specialist. Enforce least-privilege access, strict input validation, fail-closed guards, and cryptographic best practices.',
52
+ },
53
+ {
54
+ id: 'runtime_sandbox_guardian',
55
+ title: 'Runtime & Sandbox Guardian',
56
+ prompt: 'You are a Runtime & Sandbox Guardian. Focus on resource limits, rate limiting, secret sanitization, and zero-trust boundary enforcement.',
57
+ },
58
+ ],
59
+ performance: [
60
+ {
61
+ id: 'algorithmic_optimizer',
62
+ title: 'Algorithmic Complexity Optimizer',
63
+ prompt: 'You are an Algorithmic Complexity Optimizer. Replace O(N^2) bottlenecks with optimal data structures, streaming pipelines, and bounded memory usage.',
64
+ },
65
+ {
66
+ id: 'concurrency_profiler',
67
+ title: 'Memory & Concurrency Profiler',
68
+ prompt: 'You are a Memory & Concurrency Profiler. Prevent event-loop blocking, race conditions, memory leaks, and unbounded promise queues.',
69
+ },
70
+ ],
71
+ testing: [
72
+ {
73
+ id: 'edge_case_fuzzer',
74
+ title: 'Edge-Case & Fuzzing Specialist',
75
+ prompt: 'You are an Edge-Case & Fuzzing Specialist. Target boundary conditions, malformed inputs, concurrency races, and failure recovery paths.',
76
+ },
77
+ {
78
+ id: 'contract_test_architect',
79
+ title: 'Integration & Contract Test Architect',
80
+ prompt: 'You are an Integration & Contract Test Architect. Build deterministic, isolated, fast-running test suites with zero flakiness.',
81
+ },
82
+ ],
83
+ architecture: [
84
+ {
85
+ id: 'ddd_architect',
86
+ title: 'Domain-Driven Design Architect',
87
+ prompt: 'You are a Domain-Driven Design Architect. Enforce clean module boundaries, single responsibility, explicit contracts, and low coupling.',
88
+ },
89
+ {
90
+ id: 'resilience_engineer',
91
+ title: 'Resilience & Fault-Tolerance Engineer',
92
+ prompt: 'You are a Resilience & Fault-Tolerance Engineer. Design idempotent operations, graceful degradation, circuit breakers, and clear error taxonomy.',
93
+ },
94
+ ],
95
+ }
96
+
97
+ const DOMAIN_RULES = [
98
+ { domain: 'database', pattern: /\b(sql|postgres|mysql|sqlite|prisma|drizzle|typeorm|migration|index|schema|table|query|database|db|transaction)\b/i },
99
+ { domain: 'security', pattern: /\b(security|auth|jwt|oauth|csrf|xss|ssrf|injection|traversal|permission|encrypt|hash|token|secret|vulnerability|cve)\b/i },
100
+ { domain: 'frontend', pattern: /\b(react|vue|svelte|css|tailwind|html|dom|component|ui|ux|button|modal|layout|responsive|aria|accessibility|style)\b/i },
101
+ { domain: 'performance', pattern: /\b(performance|optimize|latency|throughput|cache|memory|leak|benchmark|bottleneck|fast|profil|concurrent|parallel)\b/i },
102
+ { domain: 'testing', pattern: /\b(test|unit|integration|e2e|mock|assert|coverage|vitest|jest|playwright|tdd|regression)\b/i },
103
+ ]
104
+
105
+ /**
106
+ * Classifies a user prompt into a specialized technical domain.
107
+ *
108
+ * @param {string} prompt
109
+ * @returns {{ domain: string, confidence: number, matchedKeywords: string[] }}
110
+ */
111
+ export function classifyPromptDomain(prompt) {
112
+ const text = String(prompt || '').trim()
113
+ if (!text) return { domain: 'architecture', confidence: 0.5, matchedKeywords: [] }
114
+
115
+ let bestDomain = 'architecture'
116
+ let bestCount = 0
117
+ let bestMatches = []
118
+
119
+ for (const rule of DOMAIN_RULES) {
120
+ const matches = [...text.matchAll(new RegExp(rule.pattern.source, 'gi'))].map((m) => m[0].toLowerCase())
121
+ const unique = [...new Set(matches)]
122
+ if (unique.length > bestCount) {
123
+ bestCount = unique.length
124
+ bestDomain = rule.domain
125
+ bestMatches = unique
126
+ }
127
+ }
128
+
129
+ return {
130
+ domain: bestDomain,
131
+ confidence: bestCount > 0 ? Math.min(0.98, Number((0.6 + bestCount * 0.12).toFixed(2))) : 0.55,
132
+ matchedKeywords: bestMatches,
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Synthesizes and assigns complementary domain-specific personas to reference model slots.
138
+ *
139
+ * @param {Array<object>} references
140
+ * @param {string} prompt
141
+ * @returns {{ domain: string, references: Array<object>, personasAssigned: Array<object> }}
142
+ */
143
+ export function assignAdaptivePersonas(references, prompt) {
144
+ if (!Array.isArray(references) || references.length === 0) {
145
+ return { domain: 'architecture', references: [], personasAssigned: [] }
146
+ }
147
+
148
+ const { domain } = classifyPromptDomain(prompt)
149
+ const pool = DOMAIN_PERSONA_POOLS[domain] || DOMAIN_PERSONA_POOLS.architecture
150
+ const fallbackPool = DOMAIN_PERSONA_POOLS.architecture
151
+
152
+ const personasAssigned = []
153
+ const enrichedRefs = references.map((slot, idx) => {
154
+ const chosen = pool[idx % pool.length] || fallbackPool[idx % fallbackPool.length]
155
+ personasAssigned.push({
156
+ candidateIndex: idx + 1,
157
+ model: `${slot.provider || ''}:${slot.model || ''}`,
158
+ domain,
159
+ personaId: chosen.id,
160
+ personaTitle: chosen.title,
161
+ })
162
+ return {
163
+ ...slot,
164
+ adaptive_domain: domain,
165
+ adaptive_persona_id: chosen.id,
166
+ adaptive_persona_title: chosen.title,
167
+ adaptive_persona_prompt: `[ADAPTIVE EXPERT ROLE — ${chosen.title} (${domain.toUpperCase()})]: ${chosen.prompt}`,
168
+ }
169
+ })
170
+
171
+ return {
172
+ domain,
173
+ references: enrichedRefs,
174
+ personasAssigned,
175
+ }
176
+ }
@@ -85,9 +85,9 @@ export async function runReferencesParallel(references, messages, options = {},
85
85
  references.forEach((slot, i) => {
86
86
  const label = slotLabel(slot)
87
87
  const role = slot?.role_persona || slot?.role || 'general'
88
- const persona = (role && ROLE_PERSONA_PROMPTS[role])
89
- ? `\n\n${ROLE_PERSONA_PROMPTS[role]}`
90
- : ''
88
+ const basePersona = (role && ROLE_PERSONA_PROMPTS[role]) ? `\n\n${ROLE_PERSONA_PROMPTS[role]}` : ''
89
+ const adaptiveExtra = slot?.adaptive_persona_prompt ? `\n\n${slot.adaptive_persona_prompt}` : ''
90
+ const persona = basePersona + adaptiveExtra
91
91
  const slotMessages = [{ role: 'system', content: systemPrompt + persona }, ...advisoryMessages]
92
92
 
93
93
  // Feature 7: Per-candidate temperature or temperature gradient
@@ -140,7 +140,8 @@ export async function runReferencesParallel(references, messages, options = {},
140
140
  index: i + 1,
141
141
  slot,
142
142
  label,
143
- role_persona: role,
143
+ role_persona: slot?.adaptive_persona_title || role,
144
+ ...(slot?.adaptive_domain ? { adaptive_domain: slot.adaptive_domain } : {}),
144
145
  temperature: effectiveTemperature,
145
146
  text,
146
147
  usage: costInfo,
package/lib/moa-parser.js CHANGED
@@ -56,12 +56,18 @@ export function parseMoACommand(text, presets = [], defaultPreset = undefined) {
56
56
  }
57
57
  }
58
58
 
59
- const remainder = text.slice(4).trim()
59
+ let remainder = text.slice(4).trim()
60
+ let isSwarm = false
61
+ if (/^--swarm(?:\s+|$)/i.test(remainder)) {
62
+ isSwarm = true
63
+ remainder = remainder.replace(/^--swarm\s*/i, '').trim()
64
+ }
60
65
  if (!remainder) {
61
66
  return {
62
67
  presetName: defaultPreset,
63
68
  prompt: '',
64
69
  isExplicit: false,
70
+ ...(isSwarm ? { isSwarm: true } : {}),
65
71
  }
66
72
  }
67
73
 
@@ -71,6 +77,7 @@ export function parseMoACommand(text, presets = [], defaultPreset = undefined) {
71
77
  presetName: matchPreset[1],
72
78
  prompt: matchPreset[2] || '',
73
79
  isExplicit: true,
80
+ ...(isSwarm ? { isSwarm: true } : {}),
74
81
  }
75
82
  }
76
83
 
@@ -80,6 +87,7 @@ export function parseMoACommand(text, presets = [], defaultPreset = undefined) {
80
87
  presetName: matchShortPreset[1],
81
88
  prompt: matchShortPreset[2] || '',
82
89
  isExplicit: true,
90
+ ...(isSwarm ? { isSwarm: true } : {}),
83
91
  }
84
92
  }
85
93
 
@@ -100,6 +108,7 @@ export function parseMoACommand(text, presets = [], defaultPreset = undefined) {
100
108
  presetName: defaultPreset,
101
109
  prompt: remainder,
102
110
  isExplicit: false,
111
+ ...(isSwarm ? { isSwarm: true } : {}),
103
112
  }
104
113
  }
105
114
 
package/lib/moa-schema.js CHANGED
@@ -64,6 +64,8 @@ export const PresetSchema = z.object({
64
64
  local_fallback_models: z.array(ModelSlotSchema).default([]),
65
65
  interactive_workbench_enabled: z.boolean().default(false),
66
66
  uncertainty_scoring_enabled: z.boolean().default(false),
67
+ subagent_swarm_enabled: z.boolean().default(false),
68
+ adaptive_personas_enabled: z.boolean().default(false),
67
69
  })
68
70
 
69
71
  export const Config = z.object({
@@ -74,6 +76,8 @@ export const Config = z.object({
74
76
  ask_clarifying_questions: z.boolean().default(true).volatile(),
75
77
  test_gate_enabled: z.boolean().default(false).volatile(),
76
78
  uncertainty_scoring_enabled: z.boolean().default(false).volatile(),
79
+ subagent_swarm_enabled: z.boolean().default(false).volatile(),
80
+ adaptive_personas_enabled: z.boolean().default(false).volatile(),
77
81
  smart_routing_model: ModelSlotSchema.default({ provider: '', model: '' }).volatile(),
78
82
  prices: z.dict(PriceRow).default({}).volatile(),
79
83
  presets: z.array(PresetSchema).default([
@@ -0,0 +1,219 @@
1
+ /**
2
+ * MoA-to-Subagents Swarm with Isolated Git Worktrees (#255)
3
+ * Provisions isolated git worktrees (or workspace sandboxes) per candidate,
4
+ * dispatches autonomous subagent/candidate execution, collects git diffs,
5
+ * and guarantees worktree cleanup in finally blocks.
6
+ */
7
+
8
+ import fs from 'node:fs/promises'
9
+ import { existsSync } from 'node:fs'
10
+ import path from 'node:path'
11
+ import { execFile } from 'node:child_process'
12
+ import { promisify } from 'node:util'
13
+ import { logger } from './logger.js'
14
+ import { slotLabel } from './moa-prompts.js'
15
+ import { extractFileBlocks } from './workspace/fs.js'
16
+
17
+ const execFileAsync = promisify(execFile)
18
+
19
+ /**
20
+ * Checks if a directory is inside a valid git repository.
21
+ */
22
+ export async function isGitRepository(cwd) {
23
+ try {
24
+ const { stdout } = await execFileAsync('git', ['rev-parse', '--is-inside-work-tree'], { cwd, timeout: 5000 })
25
+ return stdout.trim() === 'true'
26
+ } catch {
27
+ return false
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Creates an isolated git worktree (or directory sandbox if not a git repo) for a swarm candidate.
33
+ *
34
+ * @param {string} cwd
35
+ * @param {string} runId
36
+ * @param {number} candidateIndex
37
+ * @returns {Promise<{ worktreePath: string, branchName: string, isGitWorktree: boolean }>}
38
+ */
39
+ export async function createSwarmWorktree(cwd, runId, candidateIndex) {
40
+ const safeRunId = String(runId || Date.now()).replace(/[^a-zA-Z0-9_-]/g, '')
41
+ const worktreePath = path.join(cwd, '.moa', `swarm-${safeRunId}`, `candidate-${candidateIndex}`)
42
+ const branchName = `moa-swarm/${safeRunId}/cand-${candidateIndex}`
43
+
44
+ await fs.mkdir(path.dirname(worktreePath), { recursive: true })
45
+
46
+ if (await isGitRepository(cwd)) {
47
+ try {
48
+ await execFileAsync('git', ['worktree', 'add', '--detach', worktreePath, 'HEAD'], { cwd, timeout: 10000 })
49
+ return { worktreePath, branchName, isGitWorktree: true }
50
+ } catch (err) {
51
+ logger.warn(`[dsh-moa] git worktree add failed for candidate-${candidateIndex}, using isolated directory sandbox: ${err?.message || err}`)
52
+ }
53
+ }
54
+
55
+ await fs.mkdir(worktreePath, { recursive: true })
56
+ return { worktreePath, branchName, isGitWorktree: false }
57
+ }
58
+
59
+ /**
60
+ * Collects git diff and modified files from a candidate's swarm worktree.
61
+ *
62
+ * @param {string} worktreePath
63
+ * @param {boolean} isGitWorktree
64
+ * @returns {Promise<{ diffText: string, modifiedFiles: string[] }>}
65
+ */
66
+ export async function collectSwarmWorktreeDiff(worktreePath, isGitWorktree = false) {
67
+ if (!existsSync(worktreePath)) {
68
+ return { diffText: '', modifiedFiles: [] }
69
+ }
70
+
71
+ if (isGitWorktree) {
72
+ try {
73
+ const { stdout: statusOut } = await execFileAsync('git', ['status', '--porcelain'], { cwd: worktreePath, timeout: 5000 })
74
+ const modifiedFiles = statusOut
75
+ .split('\n')
76
+ .map((line) => line.slice(3).trim())
77
+ .filter(Boolean)
78
+
79
+ const { stdout: diffOut } = await execFileAsync('git', ['diff', 'HEAD'], { cwd: worktreePath, timeout: 5000 })
80
+ return { diffText: diffOut.trim(), modifiedFiles }
81
+ } catch {
82
+ // Fallback to directory scan
83
+ }
84
+ }
85
+
86
+ const modifiedFiles = []
87
+ async function scanDir(dir, prefix = '') {
88
+ const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => [])
89
+ for (const entry of entries) {
90
+ if (entry.name === '.git') continue
91
+ const rel = prefix ? `${prefix}/${entry.name}` : entry.name
92
+ const full = path.join(dir, entry.name)
93
+ if (entry.isDirectory()) {
94
+ await scanDir(full, rel)
95
+ } else {
96
+ modifiedFiles.push(rel)
97
+ }
98
+ }
99
+ }
100
+ await scanDir(worktreePath)
101
+ return { diffText: '', modifiedFiles }
102
+ }
103
+
104
+ /**
105
+ * Guarantees removal of all swarm worktrees and temporary directories.
106
+ *
107
+ * @param {string} cwd
108
+ * @param {string} runId
109
+ * @param {Array<{ worktreePath: string, isGitWorktree: boolean }>} worktrees
110
+ */
111
+ export async function cleanupSwarmWorktrees(cwd, runId, worktrees = []) {
112
+ for (const wt of worktrees) {
113
+ if (!wt?.worktreePath) continue
114
+ if (wt.isGitWorktree) {
115
+ try {
116
+ await execFileAsync('git', ['worktree', 'remove', '--force', wt.worktreePath], { cwd, timeout: 8000 })
117
+ } catch {}
118
+ }
119
+ try {
120
+ await fs.rm(wt.worktreePath, { recursive: true, force: true })
121
+ } catch {}
122
+ }
123
+
124
+ if (await isGitRepository(cwd)) {
125
+ try {
126
+ await execFileAsync('git', ['worktree', 'prune'], { cwd, timeout: 5000 })
127
+ } catch {}
128
+ }
129
+
130
+ const safeRunId = String(runId || '').replace(/[^a-zA-Z0-9_-]/g, '')
131
+ if (safeRunId) {
132
+ const swarmRoot = path.join(cwd, '.moa', `swarm-${safeRunId}`)
133
+ try {
134
+ await fs.rm(swarmRoot, { recursive: true, force: true })
135
+ } catch {}
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Runs candidates as a swarm with isolated worktrees.
141
+ * Uses ctx.subagent.run if available on Cordis context, falling back to callLlm + worktree materialization.
142
+ */
143
+ export async function runSubagentSwarm(references, messages, options = {}, callLlm, onProgress) {
144
+ const cwd = options.cwd || process.cwd()
145
+ const runId = options.runId || `run-${Date.now()}`
146
+ const worktrees = []
147
+
148
+ try {
149
+ if (typeof onProgress === 'function') {
150
+ onProgress(`🐝 *Launching MoA Subagent Swarm across ${references.length} isolated worktrees...*\n`)
151
+ }
152
+
153
+ const tasks = references.map(async (slot, idx) => {
154
+ const candidateIndex = idx + 1
155
+ const label = slotLabel(slot)
156
+ const wt = await createSwarmWorktree(cwd, runId, candidateIndex)
157
+ worktrees.push(wt)
158
+
159
+ const start = Date.now()
160
+ let responseText = ''
161
+ let usage = { inputTokens: 100, outputTokens: 100, totalTokens: 200, costUsd: 0 }
162
+
163
+ if (options.ctx?.subagent && typeof options.ctx.subagent.run === 'function') {
164
+ const subRes = await options.ctx.subagent.run({
165
+ provider: slot.provider,
166
+ model: slot.model,
167
+ cwd: wt.worktreePath,
168
+ messages,
169
+ signal: options.signal,
170
+ })
171
+ responseText = typeof subRes === 'string' ? subRes : (subRes?.content || subRes?.text || '')
172
+ if (subRes?.usage) usage = subRes.usage
173
+ } else {
174
+ const llmRes = await callLlm({
175
+ provider: slot.provider,
176
+ model: slot.model,
177
+ messages,
178
+ temperature: options.temperature ?? 0.6,
179
+ maxTokens: options.maxTokens ?? 4096,
180
+ signal: options.signal,
181
+ })
182
+ responseText = typeof llmRes === 'string' ? llmRes : (llmRes?.content || llmRes?.text || '')
183
+ if (llmRes?.usage) usage = llmRes.usage
184
+ }
185
+
186
+ // Materialize any extracted file blocks inside the isolated worktree
187
+ const files = extractFileBlocks(responseText)
188
+ for (const f of files) {
189
+ const targetFile = path.join(wt.worktreePath, f.relativePath || f.path || "")
190
+ await fs.mkdir(path.dirname(targetFile), { recursive: true })
191
+ await fs.writeFile(targetFile, f.content, 'utf8')
192
+ }
193
+
194
+ const diffInfo = await collectSwarmWorktreeDiff(wt.worktreePath, wt.isGitWorktree)
195
+ const enrichedText = diffInfo.diffText
196
+ ? `${responseText}\n\n#### Git Worktree Diff (${wt.branchName}):\n\`\`\`diff\n${diffInfo.diffText}\n\`\`\``
197
+ : responseText
198
+
199
+ return {
200
+ index: candidateIndex,
201
+ slot,
202
+ label,
203
+ text: enrichedText,
204
+ files,
205
+ swarmWorktree: wt.worktreePath,
206
+ swarmBranch: wt.branchName,
207
+ modifiedFiles: diffInfo.modifiedFiles,
208
+ usage,
209
+ costUsd: usage.costUsd || 0,
210
+ durationMs: Date.now() - start,
211
+ ok: true,
212
+ }
213
+ })
214
+
215
+ return await Promise.all(tasks)
216
+ } finally {
217
+ await cleanupSwarmWorktrees(cwd, runId, worktrees)
218
+ }
219
+ }
@@ -1,3 +1,5 @@
1
+ import { assignAdaptivePersonas } from '../moa-adaptive-personas.js'
2
+ import { runSubagentSwarm } from '../moa-swarm.js'
1
3
  import { runReferencesParallel } from '../moa-candidates.js'
2
4
  import { extractFileBlocks, writeCandidateWorkspace, cleanMoaWorkspaces } from '../workspace/fs.js'
3
5
  import { verifyFileSyntax } from '../workspace/diff.js'
@@ -30,8 +32,15 @@ export async function stageCandidateRound1({
30
32
  testCommand,
31
33
  execFn,
32
34
  }) {
33
- const referenceOutputs = await runReferencesParallel(
34
- effectiveReferences,
35
+ const lastMsgText = enrichedMessages[enrichedMessages.length - 1]?.content || ''
36
+ const adaptiveRefs = preset?.adaptive_personas_enabled
37
+ ? assignAdaptivePersonas(effectiveReferences, typeof lastMsgText === 'string' ? lastMsgText : '').references
38
+ : effectiveReferences
39
+
40
+ const referenceOutputs = preset?.subagent_swarm_enabled
41
+ ? await runSubagentSwarm(adaptiveRefs, enrichedMessages, { temperature: refTemp, maxTokens, signal, cwd, runId }, callLlm, onProgress)
42
+ : await runReferencesParallel(
43
+ adaptiveRefs,
35
44
  enrichedMessages,
36
45
  {
37
46
  systemPrompt: candidateSystemPrompt,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-moa",
3
- "version": "0.2.67",
3
+ "version": "0.2.68",
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",