mirror of
https://github.com/Ryder-Sun/Meldwork.git
synced 2026-11-07 06:56:03 -10:00
Show native Agent configuration file checks
Report recognized and absent configuration alternatives for selected native directories. Verified desktop security tests, frontend tests, both frontend builds, and git diff --check.
This commit is contained in:
1 parent
fc041c6887
commit
e031f0945d
6 files changed
+49
-8
No files matched your search
@@ -439,10 +439,29 @@ function registerDesktopIpc(options) {
|
||||
throw new Error('LOCAL_NATIVE_CONFIG_INVALID')
|
||||
}
|
||||
let directoryMissing = false
|
||||
let configurationFiles = null
|
||||
if (directory) {
|
||||
try { validateNativeConfigDirectory(args[0], directory) } catch { directoryMissing = true }
|
||||
try {
|
||||
validateNativeConfigDirectory(args[0], directory)
|
||||
const spec = NATIVE_CONFIG_DIRECTORIES[args[0]]
|
||||
const entries = [...spec.files.map(name => [name, false]), ...(spec.directories || []).map(name => [name, true])]
|
||||
const present = []
|
||||
const missing = []
|
||||
for (const [name, isDirectory] of entries) {
|
||||
let exists = false
|
||||
try {
|
||||
const stat = fs.statSync(path.join(directory, name))
|
||||
exists = isDirectory ? stat.isDirectory() : stat.isFile()
|
||||
} catch { /* The entry is absent or unreadable. */ }
|
||||
if (exists) present.push(isDirectory ? `${name}/` : name)
|
||||
else missing.push(isDirectory ? `${name}/` : name)
|
||||
}
|
||||
configurationFiles = { present, missing }
|
||||
if (!present.length) directoryMissing = true
|
||||
} catch { directoryMissing = true }
|
||||
}
|
||||
return { directory, ...(directoryMissing ? { directoryMissing: true } : {}),
|
||||
...(configurationFiles ? { configurationFiles } : {}),
|
||||
...(summary && Object.hasOwn(summary, 'provider') ? { provider: summary.provider || '' } : {}),
|
||||
...(summary && Object.hasOwn(summary, 'authType') ? { authType: summary.authType || '' } : {}) }
|
||||
})
|
||||
|
||||
@@ -529,6 +529,7 @@ test('native Agent configuration selection is validated and used for execution',
|
||||
assert.equal((await get(harness.event(), 'hermes')).directory, chosen.directory)
|
||||
const summary = await get(harness.event(), 'hermes')
|
||||
assert.equal(summary.provider, 'custom:work')
|
||||
assert.deepEqual(summary.configurationFiles, { present: ['config.yaml'], missing: ['auth.json', '.env'] })
|
||||
assert.doesNotMatch(JSON.stringify(summary), /synthetic-secret/)
|
||||
await harness.installerInstances[0].input.detectAgents()
|
||||
assert.equal(detectedEnvironment.HERMES_HOME, chosen.directory)
|
||||
|
||||
@@ -33,6 +33,19 @@ it('warns when a previously selected native directory is no longer valid', async
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('shows found and absent native configuration names without treating alternatives as errors', async () => {
|
||||
window.meldworkDesktop = { localAgentNativeConfig: { get: vi.fn().mockResolvedValue({
|
||||
directory: '/native/hermes', configurationFiles: { present: ['config.yaml'], missing: ['auth.json', '.env'] },
|
||||
}) } }
|
||||
const wrapper = mount(AgentNativeConfig, { props: { kind: 'hermes' } })
|
||||
await flushPromises()
|
||||
expect(wrapper.text()).toContain('config.yaml')
|
||||
expect(wrapper.text()).toContain('auth.json')
|
||||
expect(wrapper.text()).toContain(t('nativeConfig.otherFilesMissing'))
|
||||
expect(wrapper.find('[role="alert"]').exists()).toBe(false)
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('explains the Zcode home directory used by the selected configuration', async () => {
|
||||
window.meldworkDesktop = { localAgentNativeConfig: { get: vi.fn().mockResolvedValue({ directory: '' }) } }
|
||||
const wrapper = mount(AgentNativeConfig, { props: { kind: 'zcode' } })
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
<p v-if="directory !== null">{{ directory || t('nativeConfig.automatic') }}</p>
|
||||
<p v-if="['zcode', 'qwen', 'opencodereview'].includes(kind)">{{ t(`nativeConfig.expected.${kind}`) }}</p>
|
||||
<p v-if="directoryMissing" class="form-error" role="alert">{{ t('nativeConfig.directoryMissing') }} {{ t(`nativeConfig.expected.${kind}`) }}</p>
|
||||
<p v-if="directory && !directoryMissing && configurationFiles?.present?.length">{{ t('nativeConfig.foundFiles') }}: {{ configurationFiles.present.join(', ') }}</p>
|
||||
<p v-if="directory && configurationFiles?.missing?.length">{{ t('nativeConfig.otherFilesMissing') }}: {{ configurationFiles.missing.join(', ') }}</p>
|
||||
<p v-if="kind === 'hermes' && directory !== null">{{ t('nativeConfig.configuredProvider') }}: {{ provider || t('nativeConfig.providerUnknown') }}</p>
|
||||
<p v-if="['codex', 'zcode'].includes(kind) && directory !== null">{{ t('nativeConfig.userConfiguredProvider') }}: {{ provider || t('nativeConfig.providerUnknown') }}</p>
|
||||
<p v-if="kind === 'qwen' && directory !== null">{{ t('nativeConfig.userAuthType') }}: {{ authType || t('nativeConfig.providerUnknown') }}</p>
|
||||
@@ -22,6 +24,7 @@ const props = defineProps({ kind: { type: String, required: true } })
|
||||
const api = desktopApi().localAgentNativeConfig
|
||||
const directory = ref(null)
|
||||
const directoryMissing = ref(false)
|
||||
const configurationFiles = ref(null)
|
||||
const provider = ref('')
|
||||
const authType = ref('')
|
||||
const busy = ref(true)
|
||||
@@ -32,6 +35,7 @@ async function load() {
|
||||
const result = await api.get(props.kind)
|
||||
directory.value = result.directory
|
||||
directoryMissing.value = result.directoryMissing === true
|
||||
configurationFiles.value = result.configurationFiles || null
|
||||
provider.value = result.provider || ''
|
||||
authType.value = result.authType || ''
|
||||
}
|
||||
@@ -46,15 +50,15 @@ async function update(action) {
|
||||
if (!result.canceled) {
|
||||
directory.value = result.directory
|
||||
directoryMissing.value = false
|
||||
configurationFiles.value = null
|
||||
provider.value = ''
|
||||
authType.value = ''
|
||||
if (['hermes', 'codex', 'qwen', 'zcode'].includes(props.kind)) {
|
||||
const details = await api.get(props.kind)
|
||||
if (details.directory === result.directory) {
|
||||
provider.value = details.provider || ''
|
||||
authType.value = details.authType || ''
|
||||
directoryMissing.value = details.directoryMissing === true
|
||||
}
|
||||
const details = await api.get(props.kind)
|
||||
if (details.directory === result.directory) {
|
||||
provider.value = details.provider || ''
|
||||
authType.value = details.authType || ''
|
||||
directoryMissing.value = details.directoryMissing === true
|
||||
configurationFiles.value = details.configurationFiles || null
|
||||
}
|
||||
}
|
||||
} catch (caught) {
|
||||
|
||||
@@ -6,6 +6,8 @@ export default {
|
||||
'nativeConfig.providerUnknown': 'Not specified or unavailable',
|
||||
'nativeConfig.automatic': 'No directory selected; the CLI native configuration will be discovered automatically.',
|
||||
'nativeConfig.directoryMissing': 'The selected directory is unavailable or no longer contains a recognized configuration.',
|
||||
'nativeConfig.foundFiles': 'Found',
|
||||
'nativeConfig.otherFilesMissing': 'Other configurations not found (may not be needed)',
|
||||
'nativeConfig.choose': 'Choose directory',
|
||||
'nativeConfig.clear': 'Restore automatic discovery',
|
||||
'nativeConfig.invalid': 'The selected directory does not contain this Agent’s native configuration.',
|
||||
|
||||
@@ -6,6 +6,8 @@ export default {
|
||||
'nativeConfig.providerUnknown': '未指定或无法读取',
|
||||
'nativeConfig.automatic': '未手动指定目录;将自动发现 CLI 的原生配置。',
|
||||
'nativeConfig.directoryMissing': '所选目录不可用,或其中已没有可识别的配置文件。',
|
||||
'nativeConfig.foundFiles': '已找到',
|
||||
'nativeConfig.otherFilesMissing': '未找到的其他配置(可能不需要)',
|
||||
'nativeConfig.choose': '选择目录',
|
||||
'nativeConfig.clear': '恢复自动发现',
|
||||
'nativeConfig.invalid': '所选目录没有找到此 Agent 的原生配置文件。',
|
||||
|
||||
Reference in new issue
Block a user