@goodandready/dsh-moa 0.2.16 → 0.2.18
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 +190 -9
- package/lib/file-workspace.js +25 -5
- package/lib/index.js +1 -0
- package/lib/moa-parser.js +6 -0
- package/lib/moa-runner.js +17 -3
- package/lib/routes.js +4 -0
- package/lib/updater.js +5 -3
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -18,6 +18,10 @@ window.__ModuleLoader__.load({
|
|
|
18
18
|
var exports = module.exports
|
|
19
19
|
const React = require('react')
|
|
20
20
|
const NS = 'dsh-moa'
|
|
21
|
+
// Plugins page row seat (DSH 0.1.6-alpha.2): key = '<package name>#<row id>'.
|
|
22
|
+
const PKG = '@goodandready/dsh-moa'
|
|
23
|
+
const ROW_ID = 'dsh-moa'
|
|
24
|
+
const ROW_CONFIG_KEY = PKG + '#' + ROW_ID
|
|
21
25
|
const TITLE = 'Mixture of Agents (MoA)'
|
|
22
26
|
const SUBTITLE = 'Ensemble parallel candidate generation with judge synthesis via /moa.'
|
|
23
27
|
|
|
@@ -113,6 +117,17 @@ window.__ModuleLoader__.load({
|
|
|
113
117
|
'badge.disabled': 'MoA Disabled',
|
|
114
118
|
'config.enabled_label': 'Enable MoA (slash command and turn routing)',
|
|
115
119
|
'slash.desc': 'Run turn with Mixture of Agents ensemble synthesis (/moa [preset] <prompt>)',
|
|
120
|
+
'updater.title': 'Plugin Updates',
|
|
121
|
+
'updater.desc': 'Check npm registry for new versions and update with one click.',
|
|
122
|
+
'updater.btnCheck': 'Check Updates',
|
|
123
|
+
'updater.btnUpdate': 'Update to v{version}',
|
|
124
|
+
'updater.checking': 'Checking registry...',
|
|
125
|
+
'updater.updating': 'Updating plugin...',
|
|
126
|
+
'updater.current': 'Current version: v{version}',
|
|
127
|
+
'updater.available': 'Update available: v{version}',
|
|
128
|
+
'updater.upToDate': 'Up to date',
|
|
129
|
+
'updater.checkFailed': 'Registry check failed',
|
|
130
|
+
'updater.success': 'Successfully updated to v{version}. Restart DSH to apply.',
|
|
116
131
|
}
|
|
117
132
|
|
|
118
133
|
const zh = {
|
|
@@ -205,6 +220,17 @@ window.__ModuleLoader__.load({
|
|
|
205
220
|
'badge.disabled': 'MoA 已禁用',
|
|
206
221
|
'config.enabled_label': '启用 MoA(斜杠命令与轮次拦截路由)',
|
|
207
222
|
'slash.desc': '使用智能体混合 (MoA) 协同综合运行此轮次 (/moa [预设] <提示词>)',
|
|
223
|
+
'updater.title': '插件在线更新',
|
|
224
|
+
'updater.desc': '检查 npm 镜像源上的最新版本并支持一键无感升级。',
|
|
225
|
+
'updater.btnCheck': '检查更新',
|
|
226
|
+
'updater.btnUpdate': '升级至 v{version}',
|
|
227
|
+
'updater.checking': '正在检查版本...',
|
|
228
|
+
'updater.updating': '正在执行更新...',
|
|
229
|
+
'updater.current': '当前版本:v{version}',
|
|
230
|
+
'updater.available': '发现新版本:v{version}',
|
|
231
|
+
'updater.upToDate': '已是最新版本',
|
|
232
|
+
'updater.checkFailed': '检查版本失败',
|
|
233
|
+
'updater.success': '成功更新至 v{version},请重启 DSH 使其生效。',
|
|
208
234
|
}
|
|
209
235
|
|
|
210
236
|
|
|
@@ -572,6 +598,9 @@ window.__ModuleLoader__.load({
|
|
|
572
598
|
handleSave,
|
|
573
599
|
saveStatus,
|
|
574
600
|
reload,
|
|
601
|
+
updateState,
|
|
602
|
+
checkUpdates,
|
|
603
|
+
runUpdate,
|
|
575
604
|
}) {
|
|
576
605
|
const [selectedPresetName, setSelectedPresetName] = React.useState(defaultPreset || (presets[0] && presets[0].name) || 'default')
|
|
577
606
|
const [isCreating, setIsCreating] = React.useState(false)
|
|
@@ -1381,6 +1410,84 @@ window.__ModuleLoader__.load({
|
|
|
1381
1410
|
)
|
|
1382
1411
|
),
|
|
1383
1412
|
|
|
1413
|
+
/* ── PLUGIN UPDATES ── */
|
|
1414
|
+
React.createElement(
|
|
1415
|
+
'div',
|
|
1416
|
+
{ className: 'moa-section-card' },
|
|
1417
|
+
React.createElement(
|
|
1418
|
+
'div',
|
|
1419
|
+
{ style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 6 } },
|
|
1420
|
+
React.createElement('div', { className: 'moa-sec-title' }, '✨ ' + (t('updater.title') || 'Plugin Updates')),
|
|
1421
|
+
React.createElement(
|
|
1422
|
+
'div',
|
|
1423
|
+
{ style: { display: 'flex', gap: 8 } },
|
|
1424
|
+
React.createElement(
|
|
1425
|
+
'button',
|
|
1426
|
+
{
|
|
1427
|
+
type: 'button',
|
|
1428
|
+
className: 'moa-btn moa-btn-sub',
|
|
1429
|
+
disabled: updateState?.checking || updateState?.updating,
|
|
1430
|
+
onClick: checkUpdates,
|
|
1431
|
+
},
|
|
1432
|
+
updateState?.checking ? (t('updater.checking') || 'Checking...') : (t('updater.btnCheck') || 'Check Updates')
|
|
1433
|
+
),
|
|
1434
|
+
updateState?.updateAvailable
|
|
1435
|
+
? React.createElement(
|
|
1436
|
+
'button',
|
|
1437
|
+
{
|
|
1438
|
+
type: 'button',
|
|
1439
|
+
className: 'moa-btn moa-btn-sub moa-btn-primary',
|
|
1440
|
+
disabled: updateState?.updating,
|
|
1441
|
+
onClick: runUpdate,
|
|
1442
|
+
},
|
|
1443
|
+
updateState?.updating
|
|
1444
|
+
? (t('updater.updating') || 'Updating...')
|
|
1445
|
+
: (t('updater.btnUpdate') || 'Update to v{version}').replace('{version}', updateState.latestVersion || '')
|
|
1446
|
+
)
|
|
1447
|
+
: null
|
|
1448
|
+
)
|
|
1449
|
+
),
|
|
1450
|
+
React.createElement(
|
|
1451
|
+
'div',
|
|
1452
|
+
{ className: 'moa-sec-desc', style: { marginBottom: 8 } },
|
|
1453
|
+
t('updater.desc') || 'Check npm registry for new versions and update with one click.'
|
|
1454
|
+
),
|
|
1455
|
+
React.createElement(
|
|
1456
|
+
'div',
|
|
1457
|
+
{ style: { display: 'flex', alignItems: 'center', gap: 10, fontSize: 12 } },
|
|
1458
|
+
React.createElement(
|
|
1459
|
+
'span',
|
|
1460
|
+
{ style: { color: 'var(--dsw-alias-label-secondary)' } },
|
|
1461
|
+
(t('updater.current') || 'Current version: v{version}').replace('{version}', updateState?.currentVersion || '0.2.16')
|
|
1462
|
+
),
|
|
1463
|
+
updateState?.checking
|
|
1464
|
+
? React.createElement('span', { style: { color: 'var(--dsw-alias-state-brand-primary, var(--dsw-alias-label-primary))' } }, t('updater.checking'))
|
|
1465
|
+
: updateState?.updateAvailable
|
|
1466
|
+
? React.createElement(
|
|
1467
|
+
'span',
|
|
1468
|
+
{ style: { color: 'var(--dsw-alias-state-error-primary)', fontWeight: 600 } },
|
|
1469
|
+
(t('updater.available') || 'Update available: v{version}').replace('{version}', updateState?.latestVersion || '')
|
|
1470
|
+
)
|
|
1471
|
+
: updateState?.currentVersion && !updateState?.error
|
|
1472
|
+
? React.createElement('span', { style: { color: 'var(--dsw-alias-state-success-primary)' } }, '✓ ' + (t('updater.upToDate') || 'Up to date'))
|
|
1473
|
+
: null
|
|
1474
|
+
),
|
|
1475
|
+
updateState?.notice
|
|
1476
|
+
? React.createElement(
|
|
1477
|
+
'div',
|
|
1478
|
+
{ className: 'moa-alert-ok', style: { marginTop: 8 } },
|
|
1479
|
+
updateState.notice
|
|
1480
|
+
)
|
|
1481
|
+
: null,
|
|
1482
|
+
updateState?.error
|
|
1483
|
+
? React.createElement(
|
|
1484
|
+
'div',
|
|
1485
|
+
{ className: 'moa-alert-err', style: { marginTop: 8 } },
|
|
1486
|
+
updateState.error
|
|
1487
|
+
)
|
|
1488
|
+
: null
|
|
1489
|
+
),
|
|
1490
|
+
|
|
1384
1491
|
/* ── ENABLED TOGGLE ── */
|
|
1385
1492
|
React.createElement(
|
|
1386
1493
|
'label',
|
|
@@ -1454,6 +1561,65 @@ window.__ModuleLoader__.load({
|
|
|
1454
1561
|
const [defaultPreset, setDefaultPreset] = React.useState('default')
|
|
1455
1562
|
const [availableModels, setAvailableModels] = React.useState([])
|
|
1456
1563
|
const [saveStatus, setSaveStatus] = React.useState('')
|
|
1564
|
+
const [updateState, setUpdateState] = React.useState({
|
|
1565
|
+
checking: false,
|
|
1566
|
+
updating: false,
|
|
1567
|
+
currentVersion: '0.2.16',
|
|
1568
|
+
latestVersion: undefined,
|
|
1569
|
+
updateAvailable: false,
|
|
1570
|
+
notice: null,
|
|
1571
|
+
error: null,
|
|
1572
|
+
})
|
|
1573
|
+
|
|
1574
|
+
const checkUpdates = async () => {
|
|
1575
|
+
setUpdateState((prev) => ({ ...prev, checking: true, error: null, notice: null }))
|
|
1576
|
+
try {
|
|
1577
|
+
const res = await fetch('/api/dsh-moa/update', { cache: 'no-store' })
|
|
1578
|
+
const data = await res.json()
|
|
1579
|
+
if (data && data.currentVersion) {
|
|
1580
|
+
setUpdateState((prev) => ({
|
|
1581
|
+
...prev,
|
|
1582
|
+
checking: false,
|
|
1583
|
+
currentVersion: data.currentVersion,
|
|
1584
|
+
latestVersion: data.latestVersion,
|
|
1585
|
+
updateAvailable: Boolean(data.updateAvailable),
|
|
1586
|
+
error: data.latestCheckFailed ? (t('updater.checkFailed') || 'Registry check failed') : null,
|
|
1587
|
+
}))
|
|
1588
|
+
} else {
|
|
1589
|
+
setUpdateState((prev) => ({ ...prev, checking: false, error: data.error || 'Check failed' }))
|
|
1590
|
+
}
|
|
1591
|
+
} catch (err) {
|
|
1592
|
+
setUpdateState((prev) => ({ ...prev, checking: false, error: String(err?.message || err) }))
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
const runUpdate = async () => {
|
|
1597
|
+
setUpdateState((prev) => ({ ...prev, updating: true, error: null, notice: null }))
|
|
1598
|
+
try {
|
|
1599
|
+
const res = await fetch('/api/dsh-moa/update', {
|
|
1600
|
+
method: 'POST',
|
|
1601
|
+
headers: { 'Content-Type': 'application/json', 'x-dsh-plugin-update': '1' },
|
|
1602
|
+
})
|
|
1603
|
+
const data = await res.json()
|
|
1604
|
+
if (data && data.updated) {
|
|
1605
|
+
setUpdateState((prev) => ({
|
|
1606
|
+
...prev,
|
|
1607
|
+
updating: false,
|
|
1608
|
+
updateAvailable: false,
|
|
1609
|
+
currentVersion: data.updatedVersion || data.latestVersion,
|
|
1610
|
+
notice: (t('updater.success') || 'Successfully updated to v{version}. Restart DSH to apply.').replace('{version}', data.updatedVersion || data.latestVersion),
|
|
1611
|
+
}))
|
|
1612
|
+
} else {
|
|
1613
|
+
setUpdateState((prev) => ({
|
|
1614
|
+
...prev,
|
|
1615
|
+
updating: false,
|
|
1616
|
+
error: data.error || data.message || 'Update failed',
|
|
1617
|
+
}))
|
|
1618
|
+
}
|
|
1619
|
+
} catch (err) {
|
|
1620
|
+
setUpdateState((prev) => ({ ...prev, updating: false, error: String(err?.message || err) }))
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1457
1623
|
const [enabled, setEnabled] = React.useState(true)
|
|
1458
1624
|
const [hostStatus, setHostStatus] = React.useState('connecting')
|
|
1459
1625
|
const [stats, setStats] = React.useState({ totalRuns: null, avgCostUsd: null })
|
|
@@ -1619,6 +1785,9 @@ window.__ModuleLoader__.load({
|
|
|
1619
1785
|
handleSave,
|
|
1620
1786
|
saveStatus,
|
|
1621
1787
|
reload,
|
|
1788
|
+
updateState,
|
|
1789
|
+
checkUpdates,
|
|
1790
|
+
runUpdate,
|
|
1622
1791
|
}
|
|
1623
1792
|
}
|
|
1624
1793
|
|
|
@@ -1662,16 +1831,24 @@ window.__ModuleLoader__.load({
|
|
|
1662
1831
|
function MoACard(props) {
|
|
1663
1832
|
ensureStyles()
|
|
1664
1833
|
const state = useMoASettings(props)
|
|
1665
|
-
const
|
|
1834
|
+
const page = !!(props && props.view === 'page')
|
|
1835
|
+
const [open, setOpen] = React.useState(!!page)
|
|
1836
|
+
|
|
1837
|
+
// Row seat (plugins.row.config): the host page draws title/icon/crumb and the
|
|
1838
|
+
// padding, so the summary is a one-liner and the page drops our card chrome.
|
|
1839
|
+
if (props && props.view === 'summary') {
|
|
1840
|
+
return React.createElement('div', { className: 'moa-sub' }, state.t('description') || SUBTITLE)
|
|
1841
|
+
}
|
|
1666
1842
|
|
|
1667
1843
|
return React.createElement(
|
|
1668
|
-
'li',
|
|
1669
|
-
{ className: 'moa-card' },
|
|
1844
|
+
page ? 'div' : 'li',
|
|
1845
|
+
{ className: page ? 'moa-page' : 'moa-card' },
|
|
1670
1846
|
React.createElement(
|
|
1671
1847
|
'button',
|
|
1672
1848
|
{
|
|
1673
1849
|
type: 'button',
|
|
1674
1850
|
className: 'moa-head',
|
|
1851
|
+
style: page ? { display: 'none' } : undefined,
|
|
1675
1852
|
'aria-expanded': open,
|
|
1676
1853
|
onClick: () => setOpen(!open),
|
|
1677
1854
|
},
|
|
@@ -1743,12 +1920,12 @@ window.__ModuleLoader__.load({
|
|
|
1743
1920
|
}
|
|
1744
1921
|
|
|
1745
1922
|
if (ctx.slots) {
|
|
1746
|
-
const registerCard = () => {
|
|
1923
|
+
const registerCard = (slotName, key) => () => {
|
|
1747
1924
|
try {
|
|
1748
1925
|
ctx.slots.register(
|
|
1749
1926
|
{
|
|
1750
|
-
name:
|
|
1751
|
-
key
|
|
1927
|
+
name: slotName,
|
|
1928
|
+
key,
|
|
1752
1929
|
order: 35,
|
|
1753
1930
|
locale: NS,
|
|
1754
1931
|
inject: () => ({ ctx }),
|
|
@@ -1756,14 +1933,18 @@ window.__ModuleLoader__.load({
|
|
|
1756
1933
|
(props) => React.createElement(MoAErrorBoundary, null, React.createElement(MoACard, props))
|
|
1757
1934
|
)
|
|
1758
1935
|
} catch (err) {
|
|
1759
|
-
console.warn('[dsh-moa] Failed to register
|
|
1936
|
+
console.warn('[dsh-moa] Failed to register ' + slotName + ':', err)
|
|
1760
1937
|
}
|
|
1761
1938
|
}
|
|
1762
1939
|
|
|
1763
1940
|
if (typeof ctx.slots.inject === 'function') {
|
|
1764
|
-
|
|
1941
|
+
// Row seat first (the seat the current core renders), legacy seat kept as a
|
|
1942
|
+
// fallback for older cores.
|
|
1943
|
+
ctx.slots.inject('plugins.row.config', registerCard('plugins.row.config', ROW_CONFIG_KEY))
|
|
1944
|
+
ctx.slots.inject('settings.plugin.item', registerCard('settings.plugin.item', NS))
|
|
1765
1945
|
} else {
|
|
1766
|
-
registerCard()
|
|
1946
|
+
registerCard('plugins.row.config', ROW_CONFIG_KEY)()
|
|
1947
|
+
registerCard('settings.plugin.item', NS)()
|
|
1767
1948
|
}
|
|
1768
1949
|
}
|
|
1769
1950
|
|
package/lib/file-workspace.js
CHANGED
|
@@ -95,16 +95,25 @@ function sanitizePath(filePath) {
|
|
|
95
95
|
* Formats collected project files into structured Markdown code blocks
|
|
96
96
|
* suitable for inclusion in candidate system prompts.
|
|
97
97
|
*/
|
|
98
|
-
export function formatProjectContext(projectFiles = []) {
|
|
98
|
+
export function formatProjectContext(projectFiles = [], options = {}) {
|
|
99
99
|
if (!Array.isArray(projectFiles) || projectFiles.length === 0) return ''
|
|
100
|
+
const { skippedFiles = 0, skippedList = [] } = options
|
|
100
101
|
const fence = '```'
|
|
101
|
-
|
|
102
|
+
let formatted = projectFiles
|
|
102
103
|
.map((f) => `### File: ${f.relativePath}\n${fence}\n${f.content}\n${fence}`)
|
|
103
104
|
.join('\n\n')
|
|
105
|
+
|
|
106
|
+
if (skippedFiles > 0) {
|
|
107
|
+
const preview = skippedList.slice(0, 5).join(', ')
|
|
108
|
+
const more = skippedList.length > 5 ? ` and ${skippedList.length - 5} more` : ''
|
|
109
|
+
const warning = `> ⚠️ **Workspace Scan Notice:** ${skippedFiles} workspace file(s) were skipped or truncated due to size/budget limits or read errors (${preview}${more}). The workspace context below is partial.`
|
|
110
|
+
formatted = `${warning}\n\n${formatted}`
|
|
111
|
+
}
|
|
112
|
+
return formatted
|
|
104
113
|
}
|
|
105
114
|
|
|
106
115
|
export async function collectProjectContext(baseDir, maxCharBudget = 16000) {
|
|
107
|
-
if (!baseDir) return { files: [], totalChars: 0 }
|
|
116
|
+
if (!baseDir) return { files: [], totalChars: 0, skippedFiles: 0, skippedList: [] }
|
|
108
117
|
|
|
109
118
|
const ignoreDirs = new Set(['node_modules', '.git', '.moa', '.worktrees', 'dist', 'build', '.dsh', '.next', '.nuxt', '.cache', 'coverage', '.turbo', '.idea', '.vscode'])
|
|
110
119
|
const codeExts = new Set([
|
|
@@ -130,7 +139,6 @@ export async function collectProjectContext(baseDir, maxCharBudget = 16000) {
|
|
|
130
139
|
}
|
|
131
140
|
|
|
132
141
|
for (const item of list) {
|
|
133
|
-
if (totalChars >= maxCharBudget) break
|
|
134
142
|
// Skip all dotfiles, including .env and .env.* variants: their
|
|
135
143
|
// contents must never be shipped to third-party model providers.
|
|
136
144
|
if (item.name.startsWith('.')) continue
|
|
@@ -138,6 +146,14 @@ export async function collectProjectContext(baseDir, maxCharBudget = 16000) {
|
|
|
138
146
|
const rel = relPrefix ? `${relPrefix}/${item.name}` : item.name
|
|
139
147
|
const full = path.join(currentDir, item.name)
|
|
140
148
|
|
|
149
|
+
if (totalChars >= maxCharBudget) {
|
|
150
|
+
if (item.isFile() && codeExts.has(path.extname(item.name).toLowerCase())) {
|
|
151
|
+
skippedFiles++
|
|
152
|
+
skippedList.push(`${rel} (budget limit)`)
|
|
153
|
+
}
|
|
154
|
+
continue
|
|
155
|
+
}
|
|
156
|
+
|
|
141
157
|
if (item.isDirectory()) {
|
|
142
158
|
if (!ignoreDirs.has(item.name)) {
|
|
143
159
|
await scan(full, rel)
|
|
@@ -147,7 +163,11 @@ export async function collectProjectContext(baseDir, maxCharBudget = 16000) {
|
|
|
147
163
|
if (codeExts.has(ext)) {
|
|
148
164
|
try {
|
|
149
165
|
const stat = await fs.stat(full)
|
|
150
|
-
if (stat.size > 100000)
|
|
166
|
+
if (stat.size > 100000) {
|
|
167
|
+
skippedFiles++
|
|
168
|
+
skippedList.push(`${rel} (>100KB)`)
|
|
169
|
+
continue
|
|
170
|
+
}
|
|
151
171
|
const content = await fs.readFile(full, 'utf8')
|
|
152
172
|
const budgetRemaining = maxCharBudget - totalChars
|
|
153
173
|
const truncated = content.length > budgetRemaining ? content.slice(0, budgetRemaining) + '\n... [truncated]' : content
|
package/lib/index.js
CHANGED
|
@@ -25,6 +25,7 @@ import { createLiveCanvasClient } from './live-canvas.js'
|
|
|
25
25
|
import { registerPluginUpdater, isSafeWriteRequest } from './updater.js'
|
|
26
26
|
|
|
27
27
|
export const name = '@goodandready/dsh-moa'
|
|
28
|
+
export { collectProjectContext, formatProjectContext } from './file-workspace.js'
|
|
28
29
|
export const inject = ['webServer', 'llm', 'settings', 'sessions', 'tools']
|
|
29
30
|
|
|
30
31
|
export const NS = 'dsh-moa'
|
package/lib/moa-parser.js
CHANGED
|
@@ -138,6 +138,12 @@ export function formatMoAResponse({ moaResult, presetName }) {
|
|
|
138
138
|
parts.push('> 🔄 **Mode**: Iterative project refinement (Refinement)')
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
if (moaResult?.skippedFiles > 0) {
|
|
142
|
+
const preview = moaResult.skippedList?.slice(0, 3)?.join(', ') || ''
|
|
143
|
+
const more = (moaResult.skippedList?.length || 0) > 3 ? ` and ${(moaResult.skippedList?.length || 0) - 3} more` : ''
|
|
144
|
+
parts.push(`> ⚠️ **Workspace Notice**: ${moaResult.skippedFiles} file(s) skipped during workspace scan (${preview}${more}). Context representation may be partial.`)
|
|
145
|
+
}
|
|
146
|
+
|
|
141
147
|
const hasPromoted = moaResult?.promotedFiles && moaResult.promotedFiles.length > 0
|
|
142
148
|
if (hasPromoted) {
|
|
143
149
|
parts.push(`> 📦 **Files created in the project**: \`${moaResult.promotedFiles.join('`, `')}\``)
|
package/lib/moa-runner.js
CHANGED
|
@@ -18,8 +18,6 @@ export { slotLabel, cleanAdvisoryMessages, isBroadPromptRequiringQuestions, buil
|
|
|
18
18
|
export { parseWinnerIndex, parseRecommendedAssembler, parseMoACommand, stripOrSummarizeCode, formatMoAResponse } from './moa-parser.js'
|
|
19
19
|
export { estimateTokenCost, summarizeMoAUsage } from './pricing.js'
|
|
20
20
|
|
|
21
|
-
const DEFAULT_PROMPT = 'Please propose an optimal, well-structured, production-ready solution with full code and explanations.'
|
|
22
|
-
|
|
23
21
|
/**
|
|
24
22
|
* Invokes LLM call with transient retry for recoverable network/rate-limit errors.
|
|
25
23
|
*/
|
|
@@ -78,11 +76,19 @@ export async function runMoAPipeline({
|
|
|
78
76
|
const collectedCtx = await collectProjectContext(cwd, 16000)
|
|
79
77
|
const isRefinement = Boolean(collectedCtx?.files?.length > 0 && isRefinementTask(userPrompt, collectedCtx.files))
|
|
80
78
|
let projectContext = ''
|
|
79
|
+
if (collectedCtx?.skippedFiles > 0 && typeof onProgress === 'function') {
|
|
80
|
+
const preview = collectedCtx.skippedList.slice(0, 3).join(', ')
|
|
81
|
+
const more = collectedCtx.skippedList.length > 3 ? ` (+${collectedCtx.skippedList.length - 3})` : ''
|
|
82
|
+
onProgress(`⚠️ *Workspace scan note: ${collectedCtx.skippedFiles} file(s) skipped (${preview}${more})*\n`)
|
|
83
|
+
}
|
|
81
84
|
if (isRefinement) {
|
|
82
85
|
if (typeof onProgress === 'function') {
|
|
83
86
|
onProgress('🔍 *Reading project files for refinement context...*\n')
|
|
84
87
|
}
|
|
85
|
-
projectContext = formatProjectContext(collectedCtx.files
|
|
88
|
+
projectContext = formatProjectContext(collectedCtx.files, {
|
|
89
|
+
skippedFiles: collectedCtx.skippedFiles,
|
|
90
|
+
skippedList: collectedCtx.skippedList,
|
|
91
|
+
})
|
|
86
92
|
}
|
|
87
93
|
|
|
88
94
|
// 3. Build prompts & evaluate broad questionnaire needs
|
|
@@ -140,6 +146,8 @@ export async function runMoAPipeline({
|
|
|
140
146
|
candidates: referenceOutputs.map((r) => ({ label: r.label, usage: r.usage, costUsd: r.costUsd })),
|
|
141
147
|
aggregator: { inputTokens: 0, outputTokens: 0, totalTokens: 0, costUsd: 0 },
|
|
142
148
|
},
|
|
149
|
+
skippedFiles: collectedCtx?.skippedFiles || 0,
|
|
150
|
+
skippedList: collectedCtx?.skippedList || [],
|
|
143
151
|
durationMs: Date.now() - startTime,
|
|
144
152
|
}
|
|
145
153
|
}
|
|
@@ -227,6 +235,8 @@ export async function runMoAPipeline({
|
|
|
227
235
|
candidates: referenceOutputs.map((r) => ({ label: r.label, usage: r.usage, costUsd: r.costUsd })),
|
|
228
236
|
aggregator: qUsage,
|
|
229
237
|
},
|
|
238
|
+
skippedFiles: collectedCtx?.skippedFiles || 0,
|
|
239
|
+
skippedList: collectedCtx?.skippedList || [],
|
|
230
240
|
durationMs,
|
|
231
241
|
}
|
|
232
242
|
}
|
|
@@ -283,6 +293,8 @@ export async function runMoAPipeline({
|
|
|
283
293
|
candidates: referenceOutputs.map((r) => ({ label: r.label, usage: r.usage, costUsd: r.costUsd })),
|
|
284
294
|
aggregator: { inputTokens: 0, outputTokens: 0, totalTokens: 0, costUsd: 0 },
|
|
285
295
|
},
|
|
296
|
+
skippedFiles: collectedCtx?.skippedFiles || 0,
|
|
297
|
+
skippedList: collectedCtx?.skippedList || [],
|
|
286
298
|
durationMs,
|
|
287
299
|
}
|
|
288
300
|
}
|
|
@@ -461,6 +473,8 @@ export async function runMoAPipeline({
|
|
|
461
473
|
allowCandidateOverride,
|
|
462
474
|
...(livePreview ? { liveCanvas: livePreview } : {}),
|
|
463
475
|
usage: usageSummary,
|
|
476
|
+
skippedFiles: collectedCtx?.skippedFiles || 0,
|
|
477
|
+
skippedList: collectedCtx?.skippedList || [],
|
|
464
478
|
durationMs,
|
|
465
479
|
}
|
|
466
480
|
}
|
package/lib/routes.js
CHANGED
|
@@ -398,6 +398,10 @@ ctx.effect(() => {
|
|
|
398
398
|
liveCanvas,
|
|
399
399
|
})
|
|
400
400
|
|
|
401
|
+
if (result?.skippedFiles > 0) {
|
|
402
|
+
ctx.logger?.warn?.(`[dsh-moa] Workspace scan skipped ${result.skippedFiles} file(s): ${result.skippedList.join(', ')}`)
|
|
403
|
+
}
|
|
404
|
+
|
|
401
405
|
writeJson(res, 200, { ok: true, ...result })
|
|
402
406
|
} catch (err) {
|
|
403
407
|
writeJson(res, 500, { ok: false, error: err?.message || String(err) })
|
package/lib/updater.js
CHANGED
|
@@ -186,11 +186,13 @@ export async function getUpdateStatus(options, target = runtime()) {
|
|
|
186
186
|
async function installExact(target, packageSpec, options) {
|
|
187
187
|
if (target.cliEntry === undefined) throw new Error('Automatic update is unavailable in this runtime.');
|
|
188
188
|
await new Promise((resolvePromise, reject) => {
|
|
189
|
-
|
|
189
|
+
// Note: Respect strict ecosystem quarantine policy without age bypass
|
|
190
|
+
const args = [
|
|
190
191
|
target.cliEntry, 'plugin', '--profile', target.profileName, 'add',
|
|
191
|
-
|
|
192
|
+
packageSpec,
|
|
192
193
|
`--registry=${options.registry ?? 'https://registry.npmjs.org/'}`,
|
|
193
|
-
]
|
|
194
|
+
];
|
|
195
|
+
const child = spawn(process.execPath, args, {
|
|
194
196
|
cwd: target.profileDir,
|
|
195
197
|
windowsHide: true,
|
|
196
198
|
stdio: ['ignore', 'pipe', 'pipe'],
|