mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-25 07:00:48 +09:00
feat: platform
This commit is contained in:
@@ -2,6 +2,7 @@ import { Elysia } from 'elysia'
|
||||
import { corsMiddleware, errorMiddleware } from './middlewares'
|
||||
import { agentModule, authModule, modelModule, scheduleModule, settingsModule, userModule } from './modules'
|
||||
import { memoryModule } from './modules/memory'
|
||||
import { platformModule } from './modules/platform'
|
||||
import openapi from '@elysiajs/openapi'
|
||||
|
||||
const port = process.env.API_SERVER_PORT || 7002
|
||||
@@ -17,6 +18,7 @@ export const app = new Elysia()
|
||||
.use(scheduleModule)
|
||||
.use(settingsModule)
|
||||
.use(userModule)
|
||||
.use(platformModule)
|
||||
.listen(port)
|
||||
|
||||
console.log(
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
import Elysia from 'elysia'
|
||||
import { adminMiddleware, optionalAuthMiddleware } from '../../middlewares/auth'
|
||||
import {
|
||||
CreatePlatformModel,
|
||||
UpdatePlatformModel,
|
||||
GetPlatformByIdModel,
|
||||
DeletePlatformModel,
|
||||
UpdatePlatformConfigModel,
|
||||
SetPlatformActiveModel,
|
||||
} from './model'
|
||||
import {
|
||||
getPlatforms,
|
||||
getPlatformById,
|
||||
createPlatform,
|
||||
updatePlatform,
|
||||
deletePlatform,
|
||||
updatePlatformConfig,
|
||||
getActivePlatforms,
|
||||
activePlatform,
|
||||
setActivePlatform,
|
||||
} from './service'
|
||||
import { Platform } from '@memohome/shared'
|
||||
|
||||
export const platformModule = new Elysia({
|
||||
prefix: '/platform',
|
||||
})
|
||||
// 公开的读取接口 - 用户可读
|
||||
.use(optionalAuthMiddleware)
|
||||
// Get all platforms
|
||||
.onStart(async () => {
|
||||
const platforms = await getActivePlatforms()
|
||||
for (const platform of platforms) {
|
||||
await activePlatform({
|
||||
id: platform.id,
|
||||
name: platform.name,
|
||||
endpoint: platform.endpoint,
|
||||
config: platform.config as Record<string, unknown>,
|
||||
active: platform.active,
|
||||
})
|
||||
}
|
||||
})
|
||||
.get('/', async ({ query }) => {
|
||||
try {
|
||||
const page = parseInt(query.page as string) || 1
|
||||
const limit = parseInt(query.limit as string) || 10
|
||||
const sortOrder = (query.sortOrder as string) || 'desc'
|
||||
|
||||
const result = await getPlatforms({
|
||||
page,
|
||||
limit,
|
||||
sortOrder: sortOrder as 'asc' | 'desc',
|
||||
})
|
||||
|
||||
return {
|
||||
success: true,
|
||||
...result,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to fetch platforms',
|
||||
}
|
||||
}
|
||||
})
|
||||
// Get platform by ID
|
||||
.get('/:id', async ({ params }) => {
|
||||
try {
|
||||
const { id } = params
|
||||
const platform = await getPlatformById(id)
|
||||
if (!platform) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Platform not found',
|
||||
}
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
data: platform,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to fetch platform',
|
||||
}
|
||||
}
|
||||
}, GetPlatformByIdModel)
|
||||
// 管理员权限的写入接口 - 管理员可读写
|
||||
.guard(
|
||||
{
|
||||
beforeHandle: () => {
|
||||
// This will be overridden by adminMiddleware
|
||||
},
|
||||
},
|
||||
(app) =>
|
||||
app
|
||||
.use(adminMiddleware)
|
||||
// Create new platform
|
||||
.post('/', async ({ body }) => {
|
||||
try {
|
||||
const newPlatform = await createPlatform(body as Omit<Platform, 'id'>)
|
||||
return {
|
||||
success: true,
|
||||
data: newPlatform,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to create platform',
|
||||
}
|
||||
}
|
||||
}, CreatePlatformModel)
|
||||
// Update platform
|
||||
.put('/:id', async ({ params, body }) => {
|
||||
try {
|
||||
const { id } = params
|
||||
const updatedPlatform = await updatePlatform(id, body as Partial<Omit<Platform, 'id'>>)
|
||||
if (!updatedPlatform) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Platform not found',
|
||||
}
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
data: updatedPlatform,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to update platform',
|
||||
}
|
||||
}
|
||||
}, UpdatePlatformModel)
|
||||
// Update platform config
|
||||
.put('/:id/config', async ({ params, body }) => {
|
||||
try {
|
||||
const { id } = params
|
||||
const { config } = body as { config: Record<string, unknown> }
|
||||
const updatedPlatform = await updatePlatformConfig(id, config)
|
||||
if (!updatedPlatform) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Platform not found',
|
||||
}
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
data: updatedPlatform,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to update platform config',
|
||||
}
|
||||
}
|
||||
}, UpdatePlatformConfigModel)
|
||||
// Delete platform
|
||||
.delete('/:id', async ({ params }) => {
|
||||
try {
|
||||
const { id } = params
|
||||
const deletedPlatform = await deletePlatform(id)
|
||||
if (!deletedPlatform) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Platform not found',
|
||||
}
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
data: deletedPlatform,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to delete platform',
|
||||
}
|
||||
}
|
||||
}, DeletePlatformModel)
|
||||
// Active platform
|
||||
.post('/:id/active', async ({ params }) => {
|
||||
try {
|
||||
const { id } = params
|
||||
const activatedPlatform = await setActivePlatform(id, true)
|
||||
if (!activatedPlatform) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Platform not found',
|
||||
}
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
data: activatedPlatform,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to activate platform',
|
||||
}
|
||||
}
|
||||
}, SetPlatformActiveModel)
|
||||
// Inactive platform
|
||||
.post('/:id/inactive', async ({ params }) => {
|
||||
try {
|
||||
const { id } = params
|
||||
const inactivatedPlatform = await setActivePlatform(id, false)
|
||||
if (!inactivatedPlatform) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Platform not found',
|
||||
}
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
data: inactivatedPlatform,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to inactivate platform',
|
||||
}
|
||||
}
|
||||
}, SetPlatformActiveModel)
|
||||
)
|
||||
@@ -0,0 +1,49 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
const PlatformSchema = z.object({
|
||||
name: z.string().min(1, 'Platform name is required'),
|
||||
endpoint: z.string().min(1, 'Endpoint is required'),
|
||||
config: z.record(z.string(), z.unknown()),
|
||||
active: z.boolean().optional().default(true),
|
||||
})
|
||||
|
||||
export type PlatformInput = z.infer<typeof PlatformSchema>
|
||||
|
||||
export const CreatePlatformModel = {
|
||||
body: PlatformSchema,
|
||||
}
|
||||
|
||||
export const UpdatePlatformModel = {
|
||||
params: z.object({
|
||||
id: z.string(),
|
||||
}),
|
||||
body: PlatformSchema,
|
||||
}
|
||||
|
||||
export const GetPlatformByIdModel = {
|
||||
params: z.object({
|
||||
id: z.string(),
|
||||
}),
|
||||
}
|
||||
|
||||
export const DeletePlatformModel = {
|
||||
params: z.object({
|
||||
id: z.string(),
|
||||
}),
|
||||
}
|
||||
|
||||
export const UpdatePlatformConfigModel = {
|
||||
params: z.object({
|
||||
id: z.string(),
|
||||
}),
|
||||
body: z.object({
|
||||
config: z.record(z.string(), z.unknown()),
|
||||
}),
|
||||
}
|
||||
|
||||
export const SetPlatformActiveModel = {
|
||||
params: z.object({
|
||||
id: z.string(),
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
import { db } from '@memohome/db'
|
||||
import { platform } from '@memohome/db/schema'
|
||||
import { Platform } from '@memohome/shared'
|
||||
import { eq, sql, desc, asc } from 'drizzle-orm'
|
||||
import { calculateOffset, createPaginatedResult, type PaginatedResult } from '../../utils/pagination'
|
||||
import path from 'node:path'
|
||||
|
||||
/**
|
||||
* 平台列表返回类型
|
||||
*/
|
||||
type PlatformListItem = {
|
||||
id: string
|
||||
name: string
|
||||
endpoint: string
|
||||
config: Record<string, unknown>
|
||||
active: boolean
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
}
|
||||
|
||||
export const getPlatforms = async (params?: {
|
||||
page?: number
|
||||
limit?: number
|
||||
sortOrder?: 'asc' | 'desc'
|
||||
}): Promise<PaginatedResult<PlatformListItem>> => {
|
||||
const page = params?.page || 1
|
||||
const limit = params?.limit || 10
|
||||
const sortOrder = params?.sortOrder || 'desc'
|
||||
const offset = calculateOffset(page, limit)
|
||||
|
||||
// 获取总数
|
||||
const [{ count }] = await db
|
||||
.select({ count: sql<number>`count(*)` })
|
||||
.from(platform)
|
||||
|
||||
// 获取分页数据
|
||||
const orderFn = sortOrder === 'desc' ? desc : asc
|
||||
const platforms = await db
|
||||
.select()
|
||||
.from(platform)
|
||||
.orderBy(orderFn(platform.createdAt))
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
|
||||
// Cast config to Record<string, unknown> for type safety
|
||||
const typedPlatforms = platforms.map(p => ({
|
||||
...p,
|
||||
config: p.config as Record<string, unknown>,
|
||||
}))
|
||||
|
||||
return createPaginatedResult(typedPlatforms, Number(count), page, limit)
|
||||
}
|
||||
|
||||
export const getPlatformById = async (id: string) => {
|
||||
const [result] = await db.select().from(platform).where(eq(platform.id, id))
|
||||
return result
|
||||
}
|
||||
|
||||
export const getPlatformByName = async (name: string) => {
|
||||
const [result] = await db.select().from(platform).where(eq(platform.name, name))
|
||||
return result
|
||||
}
|
||||
|
||||
export const getActivePlatforms = async () => {
|
||||
return await db.select()
|
||||
.from(platform)
|
||||
.where(eq(platform.active, true))
|
||||
}
|
||||
|
||||
export const createPlatform = async (data: Omit<Platform, 'id'>) => {
|
||||
const [newPlatform] = await db
|
||||
.insert(platform)
|
||||
.values({
|
||||
name: data.name,
|
||||
endpoint: data.endpoint,
|
||||
config: data.config,
|
||||
active: data.active ?? true,
|
||||
})
|
||||
.returning()
|
||||
if (data.active ?? true) {
|
||||
await activePlatform({
|
||||
id: newPlatform.id,
|
||||
name: newPlatform.name,
|
||||
endpoint: newPlatform.endpoint,
|
||||
config: newPlatform.config as Record<string, unknown>,
|
||||
active: newPlatform.active,
|
||||
})
|
||||
}
|
||||
return newPlatform
|
||||
}
|
||||
|
||||
export const updatePlatform = async (id: string, data: Partial<Omit<Platform, 'id'>>) => {
|
||||
const updateData: {
|
||||
name?: string
|
||||
endpoint?: string
|
||||
config?: Record<string, unknown>
|
||||
active?: boolean
|
||||
updatedAt: Date
|
||||
} = {
|
||||
updatedAt: new Date(),
|
||||
}
|
||||
|
||||
if (data.name !== undefined) updateData.name = data.name
|
||||
if (data.endpoint !== undefined) updateData.endpoint = data.endpoint
|
||||
if (data.config !== undefined) updateData.config = data.config
|
||||
if (data.active !== undefined) updateData.active = data.active
|
||||
|
||||
const [updatedPlatform] = await db
|
||||
.update(platform)
|
||||
.set(updateData)
|
||||
.where(eq(platform.id, id))
|
||||
.returning()
|
||||
return updatedPlatform
|
||||
}
|
||||
|
||||
export const deletePlatform = async (id: string) => {
|
||||
const [deletedPlatform] = await db
|
||||
.delete(platform)
|
||||
.where(eq(platform.id, id))
|
||||
.returning()
|
||||
return deletedPlatform
|
||||
}
|
||||
|
||||
export const updatePlatformConfig = async (id: string, config: Record<string, unknown>) => {
|
||||
const [updatedPlatform] = await db
|
||||
.update(platform)
|
||||
.set({
|
||||
config,
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.where(eq(platform.id, id))
|
||||
.returning()
|
||||
return updatedPlatform
|
||||
}
|
||||
|
||||
// active
|
||||
|
||||
export const activePlatform = async (platform: Platform) => {
|
||||
if (platform.active) {
|
||||
return
|
||||
}
|
||||
await fetch(path.join(platform.endpoint, '/start'), {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(platform.config),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const inactivePlatform = async (platform: Platform) => {
|
||||
if (!platform.active) {
|
||||
return
|
||||
}
|
||||
await fetch(path.join(platform.endpoint, '/stop'), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const setActivePlatform = async (id: string, active: boolean) => {
|
||||
const currentPlatform = await getPlatformById(id)
|
||||
if (!currentPlatform) {
|
||||
throw new Error('Platform not found')
|
||||
}
|
||||
const platformData: Platform = {
|
||||
id: currentPlatform.id,
|
||||
name: currentPlatform.name,
|
||||
endpoint: currentPlatform.endpoint,
|
||||
config: currentPlatform.config as Record<string, unknown>,
|
||||
active: active,
|
||||
}
|
||||
if (active) {
|
||||
await activePlatform(platformData)
|
||||
} else {
|
||||
await inactivePlatform(platformData)
|
||||
}
|
||||
const [updatedPlatform] = await db
|
||||
.update(platform)
|
||||
.set({ active })
|
||||
.where(eq(platform.id, id))
|
||||
.returning()
|
||||
return updatedPlatform
|
||||
}
|
||||
|
||||
export const sendMessageToPlatform = async (name: string, options: {
|
||||
message: string
|
||||
userId: string
|
||||
}) => {
|
||||
const currentPlatform = await getPlatformByName(name)
|
||||
if (!currentPlatform) {
|
||||
throw new Error('Platform not found')
|
||||
}
|
||||
await fetch(path.join(currentPlatform.endpoint, '/send'), {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(options),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
import type { Command } from 'commander'
|
||||
import chalk from 'chalk'
|
||||
import inquirer from 'inquirer'
|
||||
import ora from 'ora'
|
||||
import { table } from 'table'
|
||||
import * as platformCore from '../../core/platform'
|
||||
import { formatError } from '../../utils'
|
||||
import { getApiUrl } from '../../core/client'
|
||||
|
||||
export function platformCommands(program: Command) {
|
||||
program
|
||||
.command('list')
|
||||
.description('List all platform configurations')
|
||||
.action(async () => {
|
||||
const spinner = ora('Fetching platform list...').start()
|
||||
try {
|
||||
const platforms = await platformCore.listPlatforms()
|
||||
spinner.succeed(chalk.green('Platform List'))
|
||||
|
||||
if (platforms.length === 0) {
|
||||
console.log(chalk.yellow('No platform configurations found'))
|
||||
return
|
||||
}
|
||||
|
||||
const tableData = [
|
||||
['ID', 'Name', 'Endpoint', 'Active', 'Created'],
|
||||
...platforms.map((item) => [
|
||||
item.id.substring(0, 8) + '...',
|
||||
item.name,
|
||||
item.endpoint,
|
||||
item.active ? chalk.green('✓ Active') : chalk.dim('✗ Inactive'),
|
||||
new Date(item.createdAt).toLocaleDateString(),
|
||||
]),
|
||||
]
|
||||
|
||||
console.log(table(tableData))
|
||||
} catch (error) {
|
||||
spinner.fail(chalk.red('Operation failed'))
|
||||
if (error instanceof Error) {
|
||||
if (error.name === 'AbortError' || error.name === 'TimeoutError') {
|
||||
console.error(chalk.red('Connection timeout, please check:'))
|
||||
console.error(chalk.yellow(' 1. Is the API server running?'))
|
||||
console.error(chalk.yellow(' 2. Is the API URL correct?'))
|
||||
console.error(chalk.dim(` Current config: ${getApiUrl()}`))
|
||||
} else {
|
||||
console.error(chalk.red('Error:'), error.message)
|
||||
}
|
||||
} else {
|
||||
console.error(chalk.red('Error:'), String(error))
|
||||
}
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
program
|
||||
.command('create')
|
||||
.description('Create platform configuration')
|
||||
.option('-n, --name <name>', 'Platform name')
|
||||
.option('-e, --endpoint <endpoint>', 'Platform endpoint URL')
|
||||
.option('-c, --config <config>', 'Platform config (JSON string)')
|
||||
.option('-a, --active', 'Set platform as active', true)
|
||||
.action(async (options) => {
|
||||
try {
|
||||
let { name, endpoint, config, active } = options
|
||||
|
||||
if (!name || !endpoint) {
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
message: 'Platform name:',
|
||||
when: !name,
|
||||
validate: (value: string) => {
|
||||
if (value.trim()) return true
|
||||
return 'Platform name is required'
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'endpoint',
|
||||
message: 'Platform endpoint URL:',
|
||||
when: !endpoint,
|
||||
validate: (value: string) => {
|
||||
if (value.trim()) return true
|
||||
return 'Endpoint is required'
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'config',
|
||||
message: 'Platform config (JSON string):',
|
||||
default: '{}',
|
||||
when: !config,
|
||||
},
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'active',
|
||||
message: 'Set as active?',
|
||||
default: true,
|
||||
when: active === undefined,
|
||||
},
|
||||
])
|
||||
|
||||
name = name || answers.name
|
||||
endpoint = endpoint || answers.endpoint
|
||||
config = config || answers.config
|
||||
active = active ?? answers.active
|
||||
}
|
||||
|
||||
// Parse config JSON
|
||||
let configObj: Record<string, unknown> = {}
|
||||
if (config) {
|
||||
try {
|
||||
configObj = JSON.parse(config)
|
||||
} catch {
|
||||
console.error(chalk.red('Invalid JSON config'))
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
const spinner = ora('Creating platform configuration...').start()
|
||||
|
||||
const platform = await platformCore.createPlatform({
|
||||
name,
|
||||
endpoint,
|
||||
config: configObj,
|
||||
active,
|
||||
})
|
||||
|
||||
spinner.succeed(chalk.green('Platform configuration created successfully'))
|
||||
console.log(chalk.blue(`Name: ${platform.name}`))
|
||||
console.log(chalk.blue(`Endpoint: ${platform.endpoint}`))
|
||||
console.log(chalk.blue(`Active: ${platform.active ? 'Yes' : 'No'}`))
|
||||
console.log(chalk.blue(`ID: ${platform.id}`))
|
||||
} catch (error) {
|
||||
console.error(chalk.red(formatError(error)))
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
program
|
||||
.command('get <id>')
|
||||
.description('Get platform configuration details')
|
||||
.action(async (id) => {
|
||||
const spinner = ora('Fetching platform configuration...').start()
|
||||
try {
|
||||
const platform = await platformCore.getPlatform(id)
|
||||
spinner.succeed(chalk.green('Platform Configuration'))
|
||||
console.log(chalk.blue(`ID: ${platform.id}`))
|
||||
console.log(chalk.blue(`Name: ${platform.name}`))
|
||||
console.log(chalk.blue(`Endpoint: ${platform.endpoint}`))
|
||||
console.log(chalk.blue(`Active: ${platform.active ? 'Yes' : 'No'}`))
|
||||
console.log(chalk.blue(`Config: ${JSON.stringify(platform.config, null, 2)}`))
|
||||
console.log(chalk.blue(`Created At: ${new Date(platform.createdAt).toLocaleString('en-US')}`))
|
||||
console.log(chalk.blue(`Updated At: ${new Date(platform.updatedAt).toLocaleString('en-US')}`))
|
||||
} catch (error) {
|
||||
spinner.fail(chalk.red('Operation failed'))
|
||||
console.error(chalk.red(formatError(error)))
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
program
|
||||
.command('update <id>')
|
||||
.description('Update platform configuration')
|
||||
.option('-n, --name <name>', 'Platform name')
|
||||
.option('-e, --endpoint <endpoint>', 'Platform endpoint URL')
|
||||
.option('-c, --config <config>', 'Platform config (JSON string)')
|
||||
.option('-a, --active <active>', 'Set active status (true/false)')
|
||||
.action(async (id, options) => {
|
||||
try {
|
||||
const updates: Record<string, unknown> = {}
|
||||
|
||||
if (options.name) updates.name = options.name
|
||||
if (options.endpoint) updates.endpoint = options.endpoint
|
||||
if (options.config) {
|
||||
try {
|
||||
updates.config = JSON.parse(options.config)
|
||||
} catch {
|
||||
console.error(chalk.red('Invalid JSON config'))
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
if (options.active !== undefined) {
|
||||
updates.active = options.active === 'true'
|
||||
}
|
||||
|
||||
if (Object.keys(updates).length === 0) {
|
||||
console.log(chalk.yellow('No updates specified'))
|
||||
return
|
||||
}
|
||||
|
||||
const spinner = ora('Updating platform configuration...').start()
|
||||
const platform = await platformCore.updatePlatform(id, updates as any)
|
||||
spinner.succeed(chalk.green('Platform configuration updated successfully'))
|
||||
console.log(chalk.blue(`Name: ${platform.name}`))
|
||||
console.log(chalk.blue(`Endpoint: ${platform.endpoint}`))
|
||||
console.log(chalk.blue(`Active: ${platform.active ? 'Yes' : 'No'}`))
|
||||
} catch (error) {
|
||||
console.error(chalk.red(formatError(error)))
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
program
|
||||
.command('update-config <id>')
|
||||
.description('Update platform config only')
|
||||
.requiredOption('-c, --config <config>', 'Platform config (JSON string)')
|
||||
.action(async (id, options) => {
|
||||
try {
|
||||
let configObj: Record<string, unknown>
|
||||
try {
|
||||
configObj = JSON.parse(options.config)
|
||||
} catch {
|
||||
console.error(chalk.red('Invalid JSON config'))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const spinner = ora('Updating platform config...').start()
|
||||
const platform = await platformCore.updatePlatformConfig(id, configObj)
|
||||
spinner.succeed(chalk.green('Platform config updated successfully'))
|
||||
console.log(chalk.blue(`Name: ${platform.name}`))
|
||||
console.log(chalk.blue(`Config: ${JSON.stringify(platform.config, null, 2)}`))
|
||||
} catch (error) {
|
||||
console.error(chalk.red(formatError(error)))
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
program
|
||||
.command('delete <id>')
|
||||
.description('Delete platform configuration')
|
||||
.action(async (id) => {
|
||||
try {
|
||||
const { confirm } = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'confirm',
|
||||
message: chalk.yellow(`Are you sure you want to delete platform configuration ${id}?`),
|
||||
default: false,
|
||||
},
|
||||
])
|
||||
|
||||
if (!confirm) {
|
||||
console.log(chalk.yellow('Cancelled'))
|
||||
return
|
||||
}
|
||||
|
||||
const spinner = ora('Deleting platform configuration...').start()
|
||||
await platformCore.deletePlatform(id)
|
||||
spinner.succeed(chalk.green('Platform configuration deleted'))
|
||||
} catch (error) {
|
||||
console.error(chalk.red(formatError(error)))
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
program
|
||||
.command('activate <id>')
|
||||
.description('Activate platform (admin only)')
|
||||
.action(async (id) => {
|
||||
const spinner = ora('Activating platform...').start()
|
||||
try {
|
||||
const platform = await platformCore.activatePlatform(id)
|
||||
spinner.succeed(chalk.green('Platform activated successfully'))
|
||||
console.log(chalk.blue(`Name: ${platform.name}`))
|
||||
console.log(chalk.blue(`Endpoint: ${platform.endpoint}`))
|
||||
console.log(chalk.blue(`Active: ${platform.active ? chalk.green('Yes') : 'No'}`))
|
||||
} catch (error) {
|
||||
spinner.fail(chalk.red('Operation failed'))
|
||||
console.error(chalk.red(formatError(error)))
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
program
|
||||
.command('deactivate <id>')
|
||||
.description('Deactivate platform (admin only)')
|
||||
.action(async (id) => {
|
||||
const spinner = ora('Deactivating platform...').start()
|
||||
try {
|
||||
const platform = await platformCore.inactivatePlatform(id)
|
||||
spinner.succeed(chalk.green('Platform deactivated successfully'))
|
||||
console.log(chalk.blue(`Name: ${platform.name}`))
|
||||
console.log(chalk.blue(`Endpoint: ${platform.endpoint}`))
|
||||
console.log(chalk.blue(`Active: ${platform.active ? 'Yes' : chalk.dim('No')}`))
|
||||
} catch (error) {
|
||||
spinner.fail(chalk.red('Operation failed'))
|
||||
console.error(chalk.red(formatError(error)))
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import chalk from 'chalk'
|
||||
import { authCommands } from './commands/auth'
|
||||
import { userCommands } from './commands/user'
|
||||
import { modelCommands } from './commands/model'
|
||||
import { platformCommands } from './commands/platform'
|
||||
import { agentCommands, startInteractiveMode } from './commands/agent'
|
||||
import { memoryCommands } from './commands/memory'
|
||||
import { configCommands } from './commands/config'
|
||||
@@ -30,6 +31,10 @@ userCommands(user)
|
||||
const model = program.command('model').description('AI model configuration management')
|
||||
modelCommands(model)
|
||||
|
||||
// Platform management commands
|
||||
const platform = program.command('platform').description('Platform configuration management')
|
||||
platformCommands(platform)
|
||||
|
||||
// Agent conversation commands
|
||||
const agent = program.command('agent').description('Chat with AI Agent')
|
||||
agentCommands(agent)
|
||||
|
||||
@@ -54,6 +54,20 @@ export {
|
||||
type ModelListItem,
|
||||
} from './model'
|
||||
|
||||
// Platform
|
||||
export {
|
||||
listPlatforms,
|
||||
createPlatform,
|
||||
getPlatform,
|
||||
updatePlatform,
|
||||
updatePlatformConfig,
|
||||
deletePlatform,
|
||||
activatePlatform,
|
||||
inactivatePlatform,
|
||||
type CreatePlatformParams,
|
||||
type PlatformListItem,
|
||||
} from './platform'
|
||||
|
||||
// Agent
|
||||
export {
|
||||
chat,
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
import { createClient, requireAuth } from './client'
|
||||
import type { Platform, ApiResponse } from '../types'
|
||||
|
||||
export interface CreatePlatformParams {
|
||||
name: string
|
||||
endpoint: string
|
||||
config: Record<string, unknown>
|
||||
active?: boolean
|
||||
}
|
||||
|
||||
export interface PlatformListItem {
|
||||
id: string
|
||||
name: string
|
||||
endpoint: string
|
||||
config: Record<string, unknown>
|
||||
active: boolean
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
/**
|
||||
* List all platforms
|
||||
*/
|
||||
export async function listPlatforms(): Promise<PlatformListItem[]> {
|
||||
requireAuth()
|
||||
const client = createClient()
|
||||
|
||||
const response = await client.platform.get()
|
||||
|
||||
if (response.error) {
|
||||
throw new Error(response.error.value)
|
||||
}
|
||||
|
||||
const data = response.data as { success?: boolean; items?: PlatformListItem[] } | null
|
||||
if (data?.success && data?.items) {
|
||||
return data.items
|
||||
}
|
||||
|
||||
throw new Error('Failed to fetch platform list')
|
||||
}
|
||||
|
||||
/**
|
||||
* Create platform configuration
|
||||
*/
|
||||
export async function createPlatform(params: CreatePlatformParams): Promise<Platform> {
|
||||
requireAuth()
|
||||
const client = createClient()
|
||||
|
||||
const payload: Record<string, unknown> = {
|
||||
name: params.name,
|
||||
endpoint: params.endpoint,
|
||||
config: params.config,
|
||||
active: params.active ?? true,
|
||||
}
|
||||
|
||||
const response = await client.platform.post(payload)
|
||||
|
||||
if (response.error) {
|
||||
throw new Error(response.error.value)
|
||||
}
|
||||
|
||||
const data = response.data as ApiResponse<Platform> | null
|
||||
if (data?.success && data?.data) {
|
||||
return data.data
|
||||
}
|
||||
|
||||
throw new Error('Failed to create platform configuration')
|
||||
}
|
||||
|
||||
/**
|
||||
* Get platform by ID
|
||||
*/
|
||||
export async function getPlatform(id: string): Promise<Platform> {
|
||||
requireAuth()
|
||||
const client = createClient()
|
||||
|
||||
const response = await client.platform({ id }).get()
|
||||
|
||||
if (response.error) {
|
||||
throw new Error(response.error.value)
|
||||
}
|
||||
|
||||
const data = response.data as ApiResponse<Platform> | null
|
||||
if (data?.success && data?.data) {
|
||||
return data.data
|
||||
}
|
||||
|
||||
throw new Error('Failed to fetch platform configuration')
|
||||
}
|
||||
|
||||
/**
|
||||
* Update platform
|
||||
*/
|
||||
export async function updatePlatform(id: string, params: Partial<CreatePlatformParams>): Promise<Platform> {
|
||||
requireAuth()
|
||||
const client = createClient()
|
||||
|
||||
const response = await client.platform({ id }).put(params)
|
||||
|
||||
if (response.error) {
|
||||
throw new Error(response.error.value)
|
||||
}
|
||||
|
||||
const data = response.data as ApiResponse<Platform> | null
|
||||
if (data?.success && data?.data) {
|
||||
return data.data
|
||||
}
|
||||
|
||||
throw new Error('Failed to update platform configuration')
|
||||
}
|
||||
|
||||
/**
|
||||
* Update platform config
|
||||
*/
|
||||
export async function updatePlatformConfig(id: string, config: Record<string, unknown>): Promise<Platform> {
|
||||
requireAuth()
|
||||
const client = createClient()
|
||||
|
||||
const response = await client.platform({ id }).config.put({ config })
|
||||
|
||||
if (response.error) {
|
||||
throw new Error(response.error.value)
|
||||
}
|
||||
|
||||
const data = response.data as ApiResponse<Platform> | null
|
||||
if (data?.success && data?.data) {
|
||||
return data.data
|
||||
}
|
||||
|
||||
throw new Error('Failed to update platform config')
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete platform
|
||||
*/
|
||||
export async function deletePlatform(id: string): Promise<void> {
|
||||
requireAuth()
|
||||
const client = createClient()
|
||||
|
||||
const response = await client.platform({ id }).delete()
|
||||
|
||||
if (response.error) {
|
||||
throw new Error(response.error.value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate platform
|
||||
*/
|
||||
export async function activatePlatform(id: string): Promise<Platform> {
|
||||
requireAuth()
|
||||
const client = createClient()
|
||||
|
||||
const response = await client.platform({ id }).active.post()
|
||||
|
||||
if (response.error) {
|
||||
throw new Error(response.error.value)
|
||||
}
|
||||
|
||||
const data = response.data as ApiResponse<Platform> | null
|
||||
if (data?.success && data?.data) {
|
||||
return data.data
|
||||
}
|
||||
|
||||
throw new Error('Failed to activate platform')
|
||||
}
|
||||
|
||||
/**
|
||||
* Inactivate platform
|
||||
*/
|
||||
export async function inactivatePlatform(id: string): Promise<Platform> {
|
||||
requireAuth()
|
||||
const client = createClient()
|
||||
|
||||
const response = await client.platform({ id }).inactive.post()
|
||||
|
||||
if (response.error) {
|
||||
throw new Error(response.error.value)
|
||||
}
|
||||
|
||||
const data = response.data as ApiResponse<Platform> | null
|
||||
if (data?.success && data?.data) {
|
||||
return data.data
|
||||
}
|
||||
|
||||
throw new Error('Failed to inactivate platform')
|
||||
}
|
||||
|
||||
@@ -69,3 +69,13 @@ export interface Schedule {
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
export interface Platform {
|
||||
id: string
|
||||
name: string
|
||||
endpoint: string
|
||||
config: Record<string, unknown>
|
||||
active: boolean
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { boolean, jsonb, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core'
|
||||
|
||||
export const platform = pgTable('platform', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
name: text('name').notNull(),
|
||||
endpoint: text('endpoint').notNull(),
|
||||
config: jsonb('config').notNull(),
|
||||
active: boolean('active').notNull().default(true),
|
||||
createdAt: timestamp('created_at').notNull().defaultNow(),
|
||||
updatedAt: timestamp('updated_at').notNull().defaultNow(),
|
||||
})
|
||||
@@ -2,4 +2,5 @@ export * from './history'
|
||||
export * from './model'
|
||||
export * from './settings'
|
||||
export * from './schedule'
|
||||
export * from './users'
|
||||
export * from './users'
|
||||
export * from './platform'
|
||||
@@ -18,6 +18,7 @@ export class TelegramPlatform extends BasePlatform {
|
||||
config = z.object({
|
||||
botToken: z.string(),
|
||||
})
|
||||
port = 7101
|
||||
|
||||
private bot?: Telegraf
|
||||
redis = new Redis(process.env.REDIS_URL || 'redis://localhost:6379')
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './model'
|
||||
export * from './schedule'
|
||||
export * from './schedule'
|
||||
export * from './platform'
|
||||
@@ -0,0 +1,7 @@
|
||||
export interface Platform {
|
||||
id: string
|
||||
name: string
|
||||
endpoint: string
|
||||
config: Record<string, unknown>
|
||||
active: boolean
|
||||
}
|
||||
Reference in New Issue
Block a user