Phase 002: rebrand to hermes-ui and consolidate i18n to zh/en
Build / build (push) Canceled after 0s
NPM Lockfile Check / npm ci --ignore-scripts (push) Canceled after 0s
Playwright / e2e (push) Canceled after 0s

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:
2026-10-16 11:11:29 +08:00
parent 1e9ea89d86
commit c93e1fe1bd
70 changed files with 1305 additions and 17856 deletions
+7 -3
View File
@@ -26,7 +26,7 @@ interface JwtPayload {
username: string
role: UserRole
type: 'access'
aud: 'hermes-web-ui'
aud: string
iat: number
exp: number
}
@@ -39,7 +39,10 @@ declare module 'koa' {
}
}
const JWT_AUDIENCE = 'hermes-web-ui'
const JWT_AUDIENCE = 'hermes-ui'
// Tokens signed before the hermes-web-ui -> hermes-ui rename still carry the old
// audience. Keep accepting them so upgrades do not force a re-login.
const LEGACY_JWT_AUDIENCES = new Set(['hermes-web-ui'])
const DEFAULT_EXPIRES_SECONDS = 60 * 60 * 24 * 30
const MIN_EXPIRES_SECONDS = 1
const MAX_EXPIRES_SECONDS = 60 * 60 * 24 * 365
@@ -167,7 +170,8 @@ export function verifyUserJwt(token: string, secret: string, now = Date.now()):
try {
const payload = JSON.parse(Buffer.from(body, 'base64url').toString('utf-8')) as Partial<JwtPayload>
if (payload.type !== 'access' || payload.aud !== JWT_AUDIENCE) return null
if (payload.type !== 'access') return null
if (payload.aud !== JWT_AUDIENCE && !LEGACY_JWT_AUDIENCES.has(String(payload.aud))) return null
if (!payload.sub || !payload.username || !payload.role || !payload.exp) return null
if (Math.floor(now / 1000) >= payload.exp) return null
return payload as JwtPayload