Remove the API relay link and the ESP32 device feature
Two pieces of upstream promotion came out of this deployment. The sidebar "apiRelay" tab only opened a registration page on a third-party site, so it goes with no replacement. The circuit badge next to Settings was not what it looked like. It opened an ESP32 device manager: add a device, show LAN status, remote connect/disconnect, rename, delete, backed by six REST routes and an mcu_devices table. The purchase button inside that dialog was the promotional part; the rest was real device management. Since the hardware is out of scope here, the entire feature is removed rather than just the link that pointed upstream - UI entry, client API, routes, controller, store, schema, locale strings, and the one GlobalAgentServer method that only existed to answer its status column. Table creation is dropped but no DROP TABLE was added, so an already-provisioned database keeps its rows as harmless orphans instead of losing data on upgrade. DevicesView and the hermes.devices route are untouched: that is LAN device discovery, a separate feature. AGENTS.md now records the removal so the badge does not come back.
This commit is contained in:
@@ -21,7 +21,7 @@ describe('Hermes schema initialization', () => {
|
||||
})
|
||||
|
||||
it('initializes all tables with correct schemas', async () => {
|
||||
const { initAllHermesTables, USAGE_TABLE, SESSIONS_TABLE, MESSAGES_TABLE, GC_ROOMS_TABLE, USERS_TABLE, USER_PROFILES_TABLE, DEVICES_TABLE, MCU_DEVICES_TABLE } =
|
||||
const { initAllHermesTables, USAGE_TABLE, SESSIONS_TABLE, MESSAGES_TABLE, GC_ROOMS_TABLE, USERS_TABLE, USER_PROFILES_TABLE, DEVICES_TABLE } =
|
||||
await import('../../packages/server/src/db/hermes/schemas')
|
||||
|
||||
expect(() => initAllHermesTables()).not.toThrow()
|
||||
@@ -35,7 +35,6 @@ describe('Hermes schema initialization', () => {
|
||||
expect(tables.map(t => t.name)).toContain(USERS_TABLE)
|
||||
expect(tables.map(t => t.name)).toContain(USER_PROFILES_TABLE)
|
||||
expect(tables.map(t => t.name)).toContain(DEVICES_TABLE)
|
||||
expect(tables.map(t => t.name)).toContain(MCU_DEVICES_TABLE)
|
||||
|
||||
// Verify USAGE_TABLE structure
|
||||
const usageCols = db.prepare(`PRAGMA table_info("${USAGE_TABLE}")`).all() as Array<{ name: string }>
|
||||
@@ -63,13 +62,6 @@ describe('Hermes schema initialization', () => {
|
||||
expect(deviceCols.some(c => c.name === 'id')).toBe(true)
|
||||
expect(deviceCols.some(c => c.name === 'status')).toBe(true)
|
||||
expect(deviceCols.some(c => c.name === 'device_public_key')).toBe(true)
|
||||
|
||||
const mcuDeviceCols = db.prepare(`PRAGMA table_info("${MCU_DEVICES_TABLE}")`).all() as Array<{ name: string }>
|
||||
expect(mcuDeviceCols.some(c => c.name === 'id')).toBe(true)
|
||||
expect(mcuDeviceCols.some(c => c.name === 'name')).toBe(true)
|
||||
expect(mcuDeviceCols.some(c => c.name === 'device_code')).toBe(true)
|
||||
expect(mcuDeviceCols.some(c => c.name === 'is_official')).toBe(true)
|
||||
expect(mcuDeviceCols.some(c => c.name === 'created_at')).toBe(true)
|
||||
})
|
||||
|
||||
it('preserves existing data when adding safe schema columns', async () => {
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
describe('MCU devices store', () => {
|
||||
let db: any = null
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.resetModules()
|
||||
const { DatabaseSync } = await import('node:sqlite')
|
||||
db = new DatabaseSync(':memory:')
|
||||
vi.doMock('../../packages/server/src/db/index', () => ({
|
||||
getDb: () => db,
|
||||
getStoragePath: () => ':memory:',
|
||||
}))
|
||||
const { initAllHermesTables } = await import('../../packages/server/src/db/hermes/schemas')
|
||||
initAllHermesTables()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
db?.close()
|
||||
db = null
|
||||
vi.doUnmock('../../packages/server/src/db/index')
|
||||
vi.resetModules()
|
||||
})
|
||||
|
||||
it('stores official and unofficial MCU devices', async () => {
|
||||
const { createMcuDevice, listMcuDevices } = await import('../../packages/server/src/db/hermes/mcu-devices-store')
|
||||
|
||||
const official = createMcuDevice({
|
||||
name: 'Official Box',
|
||||
deviceCode: 'official-code',
|
||||
isOfficial: true,
|
||||
})
|
||||
const unofficial = createMcuDevice({
|
||||
name: 'Unofficial Box',
|
||||
deviceCode: 'unofficial-code',
|
||||
isOfficial: false,
|
||||
})
|
||||
|
||||
expect(official.is_official).toBe(true)
|
||||
expect(unofficial.is_official).toBe(false)
|
||||
expect(listMcuDevices().map(device => device.device_code).sort()).toEqual(['official-code', 'unofficial-code'])
|
||||
})
|
||||
|
||||
it('rejects duplicate device codes', async () => {
|
||||
const { createMcuDevice } = await import('../../packages/server/src/db/hermes/mcu-devices-store')
|
||||
|
||||
createMcuDevice({
|
||||
name: 'Box',
|
||||
deviceCode: 'duplicate-code',
|
||||
isOfficial: true,
|
||||
})
|
||||
|
||||
expect(() => createMcuDevice({
|
||||
name: 'Box 2',
|
||||
deviceCode: 'duplicate-code',
|
||||
isOfficial: false,
|
||||
})).toThrow('mcu_device_exists')
|
||||
})
|
||||
|
||||
it('updates device name only', async () => {
|
||||
const { createMcuDevice, updateMcuDeviceName } = await import('../../packages/server/src/db/hermes/mcu-devices-store')
|
||||
|
||||
const created = createMcuDevice({
|
||||
name: 'Old Name',
|
||||
deviceCode: 'editable-code',
|
||||
isOfficial: true,
|
||||
})
|
||||
const updated = updateMcuDeviceName(created.id, 'New Name')
|
||||
|
||||
expect(updated.name).toBe('New Name')
|
||||
expect(updated.device_code).toBe('editable-code')
|
||||
expect(updated.is_official).toBe(true)
|
||||
})
|
||||
|
||||
it('deletes MCU devices', async () => {
|
||||
const { createMcuDevice, deleteMcuDevice, listMcuDevices } = await import('../../packages/server/src/db/hermes/mcu-devices-store')
|
||||
|
||||
const created = createMcuDevice({
|
||||
name: 'Delete Me',
|
||||
deviceCode: 'delete-code',
|
||||
isOfficial: false,
|
||||
})
|
||||
|
||||
expect(deleteMcuDevice(created.id)).toBe(true)
|
||||
expect(deleteMcuDevice(created.id)).toBe(false)
|
||||
expect(listMcuDevices()).toEqual([])
|
||||
})
|
||||
})
|
||||
@@ -109,12 +109,6 @@ const ALLOWED_LEGACY_BRAND: AllowEntry[] = [
|
||||
pattern: /href="https:\/\/hermes-studio\.ai\/"/,
|
||||
reason: 'sidebar footer links to the upstream product website',
|
||||
},
|
||||
{
|
||||
// 原因:购买徽章指向托管 ESP32 活动的上游文档站
|
||||
file: 'packages/client/src/components/layout/SettingsCircuitBadge.vue',
|
||||
pattern: /const purchaseUrl = 'https:\/\/hermes-studio\.ai\/docs\//,
|
||||
reason: 'purchase badge links to the upstream docs site hosting the ESP32 offer',
|
||||
},
|
||||
{
|
||||
// 原因:断言旧 MCP 条目会从存量磁盘配置里被清掉
|
||||
file: 'tests/server/studio-mcp-autoinject.test.ts',
|
||||
|
||||
@@ -119,8 +119,6 @@ describe('Database Schema Synchronization', () => {
|
||||
WORKFLOW_RUNS_SCHEMA,
|
||||
WORKFLOW_RUN_NODE_SESSIONS_TABLE,
|
||||
WORKFLOW_RUN_NODE_SESSIONS_SCHEMA,
|
||||
MCU_DEVICES_TABLE,
|
||||
MCU_DEVICES_SCHEMA,
|
||||
} =
|
||||
await import('../../packages/server/src/db/hermes/schemas')
|
||||
|
||||
@@ -183,22 +181,6 @@ describe('Database Schema Synchronization', () => {
|
||||
expect(workflowRunNodeSessionCols.has('session_id')).toBe(true)
|
||||
expect(workflowRunNodeSessionCols.has('status')).toBe(true)
|
||||
expect(workflowRunNodeSessionCols.has('agent')).toBe(true)
|
||||
|
||||
expect(tableExists(db, MCU_DEVICES_TABLE)).toBe(true)
|
||||
const mcuDeviceCols = getTableColumns(db, MCU_DEVICES_TABLE)
|
||||
expect(mcuDeviceCols.size).toBe(Object.keys(MCU_DEVICES_SCHEMA).length)
|
||||
expect(mcuDeviceCols.has('id')).toBe(true)
|
||||
expect(mcuDeviceCols.has('name')).toBe(true)
|
||||
expect(mcuDeviceCols.has('device_code')).toBe(true)
|
||||
expect(mcuDeviceCols.has('is_official')).toBe(true)
|
||||
expect(mcuDeviceCols.has('created_at')).toBe(true)
|
||||
|
||||
db.prepare(`INSERT INTO "${MCU_DEVICES_TABLE}" (name, device_code, is_official) VALUES (?, ?, ?)`)
|
||||
.run('MCU 1', 'device-code-1', 1)
|
||||
expect(() => {
|
||||
db.prepare(`INSERT INTO "${MCU_DEVICES_TABLE}" (name, device_code, is_official) VALUES (?, ?, ?)`)
|
||||
.run('MCU Duplicate', 'device-code-1', 0)
|
||||
}).toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user