Phase 002: rebrand to hermes-ui and consolidate i18n to zh/en
Removes the ekko / hermes-web-ui branding from the whole tree and drops eight locale files, so the project presents one name and one language pair. Data compatibility is deliberate, not accidental: DB filenames, the JWT audience, and skill manifest ownership all still recognise their pre-rename values so existing deployments under ~/.hermes-web-ui keep working without a re-login or a re-injection. scripts/harness-check.mjs now scans for the legacy strings and fails the build on any new occurrence, with an explicit allow-list (and reasons) for the compatibility paths that must keep them.
This commit is contained in:
@@ -820,9 +820,9 @@ function isDesktopRuntime(): boolean {
|
||||
function candidateBundledMcpScripts(): string[] {
|
||||
return [
|
||||
process.env.HERMES_WEB_UI_MCP_BIN,
|
||||
join(process.cwd(), 'bin/hermes-studio-mcp.mjs'),
|
||||
join(__dirname, '../../bin/hermes-studio-mcp.mjs'),
|
||||
join(__dirname, '../../../../../bin/hermes-studio-mcp.mjs'),
|
||||
join(process.cwd(), 'bin/hermes-ui-mcp.mjs'),
|
||||
join(__dirname, '../../bin/hermes-ui-mcp.mjs'),
|
||||
join(__dirname, '../../../../../bin/hermes-ui-mcp.mjs'),
|
||||
join(process.cwd(), 'bin/hermes-web-ui-mcp.mjs'),
|
||||
join(__dirname, '../../bin/hermes-web-ui-mcp.mjs'),
|
||||
join(__dirname, '../../../../../bin/hermes-web-ui-mcp.mjs'),
|
||||
|
||||
@@ -44,6 +44,9 @@ function shouldIncludeManagedMcpServers(): boolean {
|
||||
function candidateBundledMcpScripts(): string[] {
|
||||
return [
|
||||
process.env.HERMES_WEB_UI_MCP_BIN,
|
||||
join(process.cwd(), 'bin/hermes-ui-mcp.mjs'),
|
||||
join(__dirname, '../../bin/hermes-ui-mcp.mjs'),
|
||||
join(__dirname, '../../../../../bin/hermes-ui-mcp.mjs'),
|
||||
join(process.cwd(), 'bin/hermes-studio-mcp.mjs'),
|
||||
join(__dirname, '../../bin/hermes-studio-mcp.mjs'),
|
||||
join(__dirname, '../../../../../bin/hermes-studio-mcp.mjs'),
|
||||
|
||||
@@ -91,7 +91,7 @@ export async function fetchPetdexManifest(options: { force?: boolean } = {}): Pr
|
||||
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS)
|
||||
try {
|
||||
const response = await fetch(PETDEX_MANIFEST_URL, {
|
||||
headers: { 'User-Agent': 'hermes-web-ui-petdex' },
|
||||
headers: { 'User-Agent': 'hermes-ui-petdex' },
|
||||
signal: controller.signal,
|
||||
})
|
||||
if (!response.ok) {
|
||||
@@ -111,7 +111,7 @@ export async function fetchPetdexAsset(urlValue: string): Promise<{ buffer: Buff
|
||||
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS)
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
headers: { 'User-Agent': 'hermes-web-ui-petdex' },
|
||||
headers: { 'User-Agent': 'hermes-ui-petdex' },
|
||||
signal: controller.signal,
|
||||
})
|
||||
if (!response.ok) throw new Error(`petdex asset request failed: ${response.status}`)
|
||||
|
||||
@@ -133,7 +133,7 @@ async function fetchBytes(urlValue: string, maxBytes: number): Promise<{ buffer:
|
||||
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS)
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
headers: { 'User-Agent': 'hermes-web-ui-pets' },
|
||||
headers: { 'User-Agent': 'hermes-ui-pets' },
|
||||
signal: controller.signal,
|
||||
})
|
||||
if (!response.ok) throw new Error(`Pet asset request failed: ${response.status}`)
|
||||
|
||||
@@ -6,7 +6,13 @@ import { detectHermesRootHome } from './hermes-path'
|
||||
import { logger } from '../logger'
|
||||
|
||||
const MANIFEST_FILENAME = '.webui-managed-skills.json'
|
||||
const MANIFEST_OWNER = 'hermes-web-ui'
|
||||
const MANIFEST_OWNER = 'hermes-ui'
|
||||
// Manifests written before the hermes-web-ui -> hermes-ui rename still carry the old
|
||||
// owner. Recognising them keeps managed skills managed instead of re-injecting them.
|
||||
const LEGACY_MANIFEST_OWNERS = new Set(['hermes-web-ui'])
|
||||
function isManagedOwner(owner: string | undefined): boolean {
|
||||
return owner === MANIFEST_OWNER || LEGACY_MANIFEST_OWNERS.has(String(owner))
|
||||
}
|
||||
const HASH_IGNORED_FILENAMES = new Set([
|
||||
'.DS_Store',
|
||||
'Thumbs.db',
|
||||
@@ -177,7 +183,7 @@ export class HermesSkillInjector {
|
||||
|
||||
const currentHash = await this.hashDir(targetSkillDir)
|
||||
const manifestEntry = manifest[entry.name]
|
||||
const isManaged = manifestEntry?.owner === MANIFEST_OWNER
|
||||
const isManaged = isManagedOwner(manifestEntry?.owner)
|
||||
const isUnchangedManagedCopy = isManaged && manifestEntry?.installed_hash === currentHash
|
||||
const isExistingBundledCopy = !manifestEntry && currentHash === sourceHash
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { SttNoSpeechDetectedError, type SttTranscribeInput, type SttTranscribeRe
|
||||
|
||||
const DEFAULT_BASE_URL = 'https://openspeech.bytedance.com/api/v3/auc/bigmodel'
|
||||
const DEFAULT_RESOURCE_ID = 'volc.seedasr.auc'
|
||||
const DEFAULT_USER_ID = 'hermes-web-ui'
|
||||
const DEFAULT_USER_ID = 'hermes-ui'
|
||||
const DONE_STATUS = '20000000'
|
||||
const RUNNING_STATUSES = new Set(['20000001', '20000002'])
|
||||
const STATUS_MESSAGES: Record<string, string> = {
|
||||
|
||||
@@ -75,9 +75,9 @@ function isDesktopRuntime(): boolean {
|
||||
function candidateBundledMcpScripts(): string[] {
|
||||
return [
|
||||
process.env.HERMES_WEB_UI_MCP_BIN,
|
||||
join(process.cwd(), 'bin/hermes-studio-mcp.mjs'),
|
||||
join(__dirname, '../../bin/hermes-studio-mcp.mjs'),
|
||||
join(__dirname, '../../../../../bin/hermes-studio-mcp.mjs'),
|
||||
join(process.cwd(), 'bin/hermes-ui-mcp.mjs'),
|
||||
join(__dirname, '../../bin/hermes-ui-mcp.mjs'),
|
||||
join(__dirname, '../../../../../bin/hermes-ui-mcp.mjs'),
|
||||
join(process.cwd(), 'bin/hermes-web-ui-mcp.mjs'),
|
||||
join(__dirname, '../../bin/hermes-web-ui-mcp.mjs'),
|
||||
join(__dirname, '../../../../../bin/hermes-web-ui-mcp.mjs'),
|
||||
|
||||
@@ -6,7 +6,7 @@ import { assertSafeTtsBaseUrl } from './url-safety'
|
||||
const DEFAULT_BASE_URL = 'https://openspeech.bytedance.com/api/v3/tts/unidirectional'
|
||||
const DEFAULT_RESOURCE_ID = 'seed-tts-2.0'
|
||||
const DEFAULT_SPEAKER = 'zh_female_xiaohe_uranus_bigtts'
|
||||
const DEFAULT_USER_ID = 'hermes-web-ui'
|
||||
const DEFAULT_USER_ID = 'hermes-ui'
|
||||
const MAX_ERROR_DETAIL_LENGTH = 500
|
||||
const DEFAULT_FORMAT = 'mp3'
|
||||
const DEFAULT_SAMPLE_RATE = 24000
|
||||
|
||||
@@ -8,7 +8,7 @@ const MAX_LOG_SIZE = 3 * 1024 * 1024 // 3MB
|
||||
const CHECK_INTERVAL = 60_000 // Check every minute
|
||||
|
||||
const logDir = process.env.VITEST
|
||||
? resolve(tmpdir(), 'hermes-web-ui-test-logs', String(process.pid))
|
||||
? resolve(tmpdir(), 'hermes-ui-test-logs', String(process.pid))
|
||||
: resolve(config.appHome, 'logs')
|
||||
mkdirSync(logDir, { recursive: true })
|
||||
|
||||
|
||||
@@ -400,8 +400,8 @@ export async function downloadWebUiVersion(version: string, source: VersionDownl
|
||||
if (!cleanVersion) throw new Error('Web UI version is required')
|
||||
|
||||
const releaseTag = `v${cleanVersion}`
|
||||
const assetName = `hermes-web-ui-${cleanVersion}.tar.gz`
|
||||
const manifestName = `hermes-web-ui-${cleanVersion}.json`
|
||||
const assetName = `hermes-ui-${cleanVersion}.tar.gz`
|
||||
const manifestName = `hermes-ui-${cleanVersion}.json`
|
||||
const manifestUrl = downloadAssetUrl(manifestName, releaseTag, source)
|
||||
onProgress?.({ stage: 'resolve', message: 'runtimeVersions.jobStage.resolveWebUi' })
|
||||
const manifest = await fetchJson<{ asset?: { sha256?: string; size?: number } }>(manifestUrl)
|
||||
@@ -424,7 +424,7 @@ export async function downloadWebUiVersion(version: string, source: VersionDownl
|
||||
onProgress?.({ stage: 'extract', message: 'runtimeVersions.jobStage.extractWebUi' })
|
||||
await extractTarGzip(archive, tempRoot)
|
||||
const extractedRoot = join(tempRoot, 'webui')
|
||||
for (const required of ['package.json', 'bin/hermes-web-ui.mjs', 'dist/server/index.js']) {
|
||||
for (const required of ['package.json', 'bin/hermes-ui.mjs', 'dist/server/index.js']) {
|
||||
if (!existsSync(join(extractedRoot, required))) throw new Error(`Web UI archive is missing required file: ${required}`)
|
||||
}
|
||||
onProgress?.({ stage: 'install', message: 'runtimeVersions.jobStage.installWebUi' })
|
||||
|
||||
Reference in New Issue
Block a user