Полное переименование в omnichannel-configserver-mcp (имя MCP-сервера, бинарник, файл конфига, доки)
This commit is contained in:
+1
-1
@@ -1,4 +1,4 @@
|
||||
# Секреты модуля omnichannel-mcp. Реальные значения — в .env (gitignored)
|
||||
# Секреты модуля omnichannel-configserver-mcp. Реальные значения — в .env (gitignored)
|
||||
# или в config.local.json рядом с config.json.
|
||||
#
|
||||
# Основная учётная запись (право записи):
|
||||
|
||||
+1
-1
@@ -4,5 +4,5 @@ config.local.json
|
||||
.env
|
||||
|
||||
# Бинарник модуля и кэш Python.
|
||||
/omnichannel-mcp
|
||||
/omnichannel-configserver-mcp
|
||||
__pycache__/
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
### Added
|
||||
|
||||
- MCP-сервер `omnichannel-mcp` для управления платформой Omnichannel через API
|
||||
- MCP-сервер `omnichannel-configserver-mcp` для управления платформой Omnichannel через API
|
||||
`config_server` 1.1.0+ (36 инструментов: наблюдение, конфигурация, жизненный
|
||||
цикл, релиз, обслуживание).
|
||||
- Режим «только чтение» и отдельная read-only учётная запись.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# omnichannel-mcp — сборка, тесты, линт.
|
||||
# omnichannel-configserver-mcp — сборка, тесты, линт.
|
||||
GO ?= go
|
||||
GOLANGCI_LINT ?= golangci-lint
|
||||
|
||||
@@ -6,7 +6,7 @@ GOLANGCI_LINT ?= golangci-lint
|
||||
|
||||
# Бинарник модуля.
|
||||
build:
|
||||
$(GO) build -o omnichannel-mcp .
|
||||
$(GO) build -o omnichannel-configserver-mcp .
|
||||
|
||||
# Тесты с race-детектором (основной гейт).
|
||||
test:
|
||||
@@ -36,13 +36,13 @@ ci: build test lint tidy-check
|
||||
# Демо: поднять локальный стенд и прогнать сквозной сценарий.
|
||||
demo:
|
||||
docker compose -f examples/demo/docker-compose.yml up -d
|
||||
$(GO) build -o omnichannel-mcp .
|
||||
$(GO) build -o omnichannel-configserver-mcp .
|
||||
python3 examples/demo/demo.py
|
||||
|
||||
# E2E: то же плюс реальный config-agent, исполняющий задачи деплоя.
|
||||
e2e:
|
||||
docker compose -f examples/demo/docker-compose.yml up -d
|
||||
$(GO) build -o omnichannel-mcp .
|
||||
$(GO) build -o omnichannel-configserver-mcp .
|
||||
python3 examples/demo/e2e.py
|
||||
|
||||
demo-down:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# omnichannel-mcp
|
||||
# omnichannel-configserver-mcp
|
||||
|
||||
MCP-сервер для управления платформой **Omnichannel** через API
|
||||
[`config_server`](../API.md): развёртывание релизов и эксплуатация — из любого
|
||||
@@ -31,12 +31,12 @@ MCP-клиент запускает его локально, а он транс
|
||||
|
||||
```bash
|
||||
export GOPRIVATE=git.totmin.ru
|
||||
go build -o omnichannel-mcp .
|
||||
./omnichannel-mcp --health # -> ok
|
||||
go build -o omnichannel-configserver-mcp .
|
||||
./omnichannel-configserver-mcp --health # -> ok
|
||||
|
||||
cp examples/config.single-server.json config.json # укажите base_url
|
||||
export OMNI_USER=admin OMNI_PASSWORD='...'
|
||||
./omnichannel-mcp --check-config -config config.json
|
||||
./omnichannel-configserver-mcp --check-config -config config.json
|
||||
```
|
||||
|
||||
Подключение к клиенту (общий вид):
|
||||
@@ -44,9 +44,9 @@ export OMNI_USER=admin OMNI_PASSWORD='...'
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"omnichannel-mcp": {
|
||||
"command": "/opt/omnichannel-mcp/omnichannel-mcp",
|
||||
"args": ["-config", "/opt/omnichannel-mcp/config.json"],
|
||||
"omnichannel-configserver-mcp": {
|
||||
"command": "/opt/omnichannel-configserver-mcp/omnichannel-configserver-mcp",
|
||||
"args": ["-config", "/opt/omnichannel-configserver-mcp/config.json"],
|
||||
"env": { "OMNI_USER": "admin", "OMNI_PASSWORD": "СЕКРЕТ" }
|
||||
}
|
||||
}
|
||||
@@ -82,7 +82,7 @@ export OMNI_USER=admin OMNI_PASSWORD='...'
|
||||
|
||||
```bash
|
||||
docker compose -f examples/demo/docker-compose.yml up -d # локальный config_server v1.1.0
|
||||
go build -o omnichannel-mcp .
|
||||
go build -o omnichannel-configserver-mcp .
|
||||
python3 examples/demo/demo.py # сквозной сценарий через MCP
|
||||
python3 examples/demo/e2e.py # + реальный config-agent: deploy/restart/down
|
||||
docker compose -f examples/demo/docker-compose.yml down -v
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Совместимость с версиями API
|
||||
|
||||
`omnichannel-mcp` рассчитан на API **`config_server` 1.1.0** (он же `latest`).
|
||||
`omnichannel-configserver-mcp` рассчитан на API **`config_server` 1.1.0** (он же `latest`).
|
||||
Эта версия добавила JSON-эндпоинты, на которые опирается сервер.
|
||||
|
||||
## Что появилось в 1.1.0
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
```
|
||||
┌────────────────┐ MCP (stdio, JSON-RPC) ┌──────────────────┐
|
||||
│ MCP-клиент │ ◄──────────────────────► │ omnichannel-mcp │
|
||||
│ MCP-клиент │ ◄──────────────────────► │ omnichannel-configserver-mcp │
|
||||
│ (AI-ассистент)│ │ (этот сервер) │
|
||||
└────────────────┘ └────────┬─────────┘
|
||||
│ HTTP (session)
|
||||
@@ -21,7 +21,7 @@
|
||||
└───────────────────────────┘
|
||||
```
|
||||
|
||||
`omnichannel-mcp` — тонкий клиент. Он не выполняет команды сам: создаёт задачи
|
||||
`omnichannel-configserver-mcp` — тонкий клиент. Он не выполняет команды сам: создаёт задачи
|
||||
через API `config_server`, а те забирают агенты нод. Сервер без состояния — при
|
||||
перезапуске ничего не теряется.
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
1. аргумент инструмента `config_path` (для обёрток; обычно не нужен);
|
||||
2. флаг запуска `-config /path/config.json`;
|
||||
3. каталог из переменной окружения `OMNI_CONFIG_DIR` (в нём берётся
|
||||
`omnichannel-mcp.json`).
|
||||
`omnichannel-configserver-mcp.json`).
|
||||
|
||||
Обычный режим — флаг `-config`.
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
## Проверка конфига
|
||||
|
||||
```bash
|
||||
./omnichannel-mcp --check-config -config config.json
|
||||
./omnichannel-configserver-mcp --check-config -config config.json
|
||||
```
|
||||
|
||||
Печатает итоговый (слитый) конфиг с замаскированными секретами, список серверов
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Быстрый старт
|
||||
|
||||
`omnichannel-mcp` — это **MCP-сервер**: программа, которую AI-ассистент
|
||||
`omnichannel-configserver-mcp` — это **MCP-сервер**: программа, которую AI-ассистент
|
||||
(Claude Desktop, Cursor, Continue и любой другой MCP-клиент) запускает как
|
||||
локальный процесс и через которую получает доступ к платформе Omnichannel.
|
||||
Сервер не хранит состояние и не имеет UI: он лишь транслирует запросы агента в
|
||||
@@ -18,10 +18,10 @@ HTTP API `config_server`.
|
||||
## 1. Сборка
|
||||
|
||||
```bash
|
||||
cd omnichannel-mcp
|
||||
cd omnichannel-configserver-mcp
|
||||
export GOPRIVATE=git.totmin.ru
|
||||
go build -o omnichannel-mcp .
|
||||
./omnichannel-mcp --health # -> ok
|
||||
go build -o omnichannel-configserver-mcp .
|
||||
./omnichannel-configserver-mcp --health # -> ok
|
||||
```
|
||||
|
||||
## 2. Конфигурация
|
||||
@@ -54,7 +54,7 @@ cp examples/config.single-server.json config.json
|
||||
|
||||
```bash
|
||||
export OMNI_USER=admin OMNI_PASSWORD='...'
|
||||
./omnichannel-mcp --check-config -config config.json
|
||||
./omnichannel-configserver-mcp --check-config -config config.json
|
||||
```
|
||||
|
||||
## 3. Подключение к MCP-клиенту
|
||||
@@ -64,9 +64,9 @@ export OMNI_USER=admin OMNI_PASSWORD='...'
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"omnichannel-mcp": {
|
||||
"command": "/opt/omnichannel-mcp/omnichannel-mcp",
|
||||
"args": ["-config", "/opt/omnichannel-mcp/config.json"],
|
||||
"omnichannel-configserver-mcp": {
|
||||
"command": "/opt/omnichannel-configserver-mcp/omnichannel-configserver-mcp",
|
||||
"args": ["-config", "/opt/omnichannel-configserver-mcp/config.json"],
|
||||
"env": {
|
||||
"OMNI_USER": "admin",
|
||||
"OMNI_PASSWORD": "СЕКРЕТ"
|
||||
@@ -104,6 +104,6 @@ export OMNI_USER=admin OMNI_PASSWORD='...'
|
||||
|
||||
```bash
|
||||
docker compose -f examples/demo/docker-compose.yml up -d
|
||||
go build -o omnichannel-mcp .
|
||||
go build -o omnichannel-configserver-mcp .
|
||||
python3 examples/demo/demo.py
|
||||
```
|
||||
|
||||
+11
-11
@@ -1,6 +1,6 @@
|
||||
# Подключение к MCP-клиентам
|
||||
|
||||
`omnichannel-mcp` — обычный stdio-сервер. Достаточно указать команду запуска,
|
||||
`omnichannel-configserver-mcp` — обычный stdio-сервер. Достаточно указать команду запуска,
|
||||
аргумент `-config` и (при необходимости) переменные окружения с секретами.
|
||||
|
||||
## Claude Desktop
|
||||
@@ -13,9 +13,9 @@
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"omnichannel-mcp": {
|
||||
"command": "/opt/omnichannel-mcp/omnichannel-mcp",
|
||||
"args": ["-config", "/opt/omnichannel-mcp/config.json"],
|
||||
"omnichannel-configserver-mcp": {
|
||||
"command": "/opt/omnichannel-configserver-mcp/omnichannel-configserver-mcp",
|
||||
"args": ["-config", "/opt/omnichannel-configserver-mcp/config.json"],
|
||||
"env": {
|
||||
"OMNI_USER": "admin",
|
||||
"OMNI_PASSWORD": "СЕКРЕТ"
|
||||
@@ -32,9 +32,9 @@
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"omnichannel-mcp": {
|
||||
"command": "/opt/omnichannel-mcp/omnichannel-mcp",
|
||||
"args": ["-config", "/opt/omnichannel-mcp/config.json"],
|
||||
"omnichannel-configserver-mcp": {
|
||||
"command": "/opt/omnichannel-configserver-mcp/omnichannel-configserver-mcp",
|
||||
"args": ["-config", "/opt/omnichannel-configserver-mcp/config.json"],
|
||||
"env": { "OMNI_USER": "admin", "OMNI_PASSWORD": "СЕКРЕТ" }
|
||||
}
|
||||
}
|
||||
@@ -46,16 +46,16 @@
|
||||
Форма одна: `command` + `args` + `env`. Минимально достаточно:
|
||||
|
||||
```json
|
||||
{ "command": "/opt/omnichannel-mcp/omnichannel-mcp",
|
||||
"args": ["-config", "/opt/omnichannel-mcp/config.json"] }
|
||||
{ "command": "/opt/omnichannel-configserver-mcp/omnichannel-configserver-mcp",
|
||||
"args": ["-config", "/opt/omnichannel-configserver-mcp/config.json"] }
|
||||
```
|
||||
|
||||
Если секреты лежат в `config.local.json`, переменные окружения не нужны.
|
||||
|
||||
## Проверка подключения
|
||||
|
||||
- Из терминала: `./omnichannel-mcp --check-config -config config.json` и
|
||||
`./omnichannel-mcp --health`.
|
||||
- Из терминала: `./omnichannel-configserver-mcp --check-config -config config.json` и
|
||||
`./omnichannel-configserver-mcp --health`.
|
||||
- В клиенте: попросите ассистента вызвать `server_info` — он покажет версию API
|
||||
и режим. Затем `overview` — сводку по стенду.
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Эксплуатация
|
||||
|
||||
`omnichannel-mcp` работает в **плоскости управления**: он видит статусы,
|
||||
`omnichannel-configserver-mcp` работает в **плоскости управления**: он видит статусы,
|
||||
конфигурацию, задачи и историю, но не заглядывает внутрь контейнеров. Это
|
||||
разделение осознанное — так сервер остаётся безопасным и предсказуемым.
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Безопасность
|
||||
|
||||
`omnichannel-mcp` даёт ассистенту право управлять платформой, поэтому
|
||||
`omnichannel-configserver-mcp` даёт ассистенту право управлять платформой, поэтому
|
||||
безопасность строится в несколько независимых слоёв: конфигурация модуля,
|
||||
подтверждения, и ограничения на стороне `config_server`.
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
```bash
|
||||
docker compose -f examples/demo/docker-compose.yml up -d
|
||||
go build -o omnichannel-mcp .
|
||||
go build -o omnichannel-configserver-mcp .
|
||||
python3 examples/demo/demo.py
|
||||
```
|
||||
|
||||
@@ -22,7 +22,7 @@ python3 examples/demo/demo.py
|
||||
|
||||
```bash
|
||||
docker compose -f examples/demo/docker-compose.yml up -d
|
||||
go build -o omnichannel-mcp .
|
||||
go build -o omnichannel-configserver-mcp .
|
||||
python3 examples/demo/e2e.py
|
||||
```
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Сквозной демо-пример использования omnichannel-mcp.
|
||||
"""Сквозной демо-пример использования omnichannel-configserver-mcp.
|
||||
|
||||
Что делает:
|
||||
1) засевает демо-сервис в локальный config_server (агентский эндпоинт);
|
||||
2) запускает omnichannel-mcp по stdio;
|
||||
2) запускает omnichannel-configserver-mcp по stdio;
|
||||
3) выполняет типичный сценарий эксплуатации/деплоя:
|
||||
server_info -> list_applications -> get_application -> set_env ->
|
||||
set_compose -> deploy -> get_task -> overview.
|
||||
@@ -11,7 +11,7 @@
|
||||
Зависимостей нет (только stdlib). Требуется поднятый стенд:
|
||||
docker compose -f examples/demo/docker-compose.yml up -d
|
||||
и собранный бинарник:
|
||||
go build -o omnichannel-mcp .
|
||||
go build -o omnichannel-configserver-mcp .
|
||||
|
||||
Запуск: python3 examples/demo/demo.py
|
||||
"""
|
||||
@@ -24,7 +24,7 @@ import urllib.request
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
ROOT = os.path.dirname(os.path.dirname(HERE)) # корень репозитория
|
||||
BINARY = os.path.join(ROOT, "omnichannel-mcp")
|
||||
BINARY = os.path.join(ROOT, "omnichannel-configserver-mcp")
|
||||
CONFIG = os.path.join(HERE, "config.demo.json")
|
||||
|
||||
BASE_URL = "http://127.0.0.1:5005"
|
||||
@@ -155,5 +155,5 @@ def main():
|
||||
|
||||
if __name__ == "__main__":
|
||||
if not os.path.exists(BINARY):
|
||||
sys.exit(f"нет бинарника {BINARY}: сначала выполните `go build -o omnichannel-mcp .`")
|
||||
sys.exit(f"нет бинарника {BINARY}: сначала выполните `go build -o omnichannel-configserver-mcp .`")
|
||||
main()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Демонстрационный стенд config_server для локальной проверки omnichannel-mcp.
|
||||
# Демонстрационный стенд config_server для локальной проверки omnichannel-configserver-mcp.
|
||||
#
|
||||
# Поднимает config_server v1.1.0 + PostgreSQL. Данные — эфемерные.
|
||||
#
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
"""E2E-тест деплоя omnichannel-mcp с реальным config-agent.
|
||||
"""E2E-тест деплоя omnichannel-configserver-mcp с реальным config-agent.
|
||||
|
||||
Поднимает контейнер config-agent, который опрашивает config_server и реально
|
||||
выполняет задачи через docker-compose, затем гоняет жизненный цикл сервиса
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
Требуется:
|
||||
- поднятый стенд: docker compose -f examples/demo/docker-compose.yml up -d
|
||||
- собранный бинарник: go build -o omnichannel-mcp .
|
||||
- собранный бинарник: go build -o omnichannel-configserver-mcp .
|
||||
- доступ к образу config-agent (registry.devlexicom.ru).
|
||||
|
||||
Запуск: python3 examples/demo/e2e.py
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
# Примеры промптов
|
||||
|
||||
Готовые формулировки для оператора: что написать агенту, чтобы он через
|
||||
`omnichannel-mcp` выполнил типовую задачу. В скобках — инструменты, которые
|
||||
`omnichannel-configserver-mcp` выполнил типовую задачу. В скобках — инструменты, которые
|
||||
агент вызовет. Замените хост/имена/пути на свои.
|
||||
|
||||
## Наблюдение и диагностика
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Package configserver — доменный слой MCP-модуля omnichannel-mcp.
|
||||
// Package configserver — доменный слой MCP-модуля omnichannel-configserver-mcp.
|
||||
//
|
||||
// Здесь нет зависимостей от MCP: только разбор конфига, авторизованные
|
||||
// HTTP-сессии к API config_server и типизированные вызовы его эндпоинтов.
|
||||
@@ -68,7 +68,7 @@ type Server struct {
|
||||
FrontRoots []string `json:"front_roots"`
|
||||
}
|
||||
|
||||
// Config — корневой конфиг модуля (config.json или per-agent omnichannel-mcp.json).
|
||||
// Config — корневой конфиг модуля (config.json или per-agent omnichannel-configserver-mcp.json).
|
||||
type Config struct {
|
||||
Servers []Server `json:"servers"`
|
||||
Default string `json:"default"`
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
// recoverable-ответом (`errorResult`) и инфраструктурной Go-ошибкой.
|
||||
var (
|
||||
// ErrNoConfig — не найден ни один конфиг (ни `-config`, ни OMNI_CONFIG_DIR).
|
||||
ErrNoConfig = errors.New("конфиг не найден: задайте -config или per-agent omnichannel-mcp.json")
|
||||
ErrNoConfig = errors.New("конфиг не найден: задайте -config или per-agent omnichannel-configserver-mcp.json")
|
||||
// ErrReadOnly — модуль в режиме только-чтение, мутация запрещена.
|
||||
ErrReadOnly = errors.New("модуль в режиме read_only: изменяющие инструменты отключены")
|
||||
// ErrConfirmRequired — разрушительная операция без confirm=\"true\".
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
|
||||
// tenantFileName — имя файла конфига внутри каталога OMNI_CONFIG_DIR
|
||||
// (например, при постраничной/per-call передаче конфига).
|
||||
const tenantFileName = "omnichannel-mcp.json"
|
||||
const tenantFileName = "omnichannel-configserver-mcp.json"
|
||||
|
||||
// Manager — одиночный потокобезопасный диспетчер процесса (ARCHITECTURE.md §2).
|
||||
// Кэширует per-путь загрузчики конфига (live-reload по контент-хэшу), сессии
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// patterns.go — доменные эмиттеры probe-паттернов разрешений для omnichannel-mcp.
|
||||
// patterns.go — доменные эмиттеры probe-паттернов разрешений для omnichannel-configserver-mcp.
|
||||
//
|
||||
// Канонический паттерн несёт алиас сервера и ресурс, чтобы мультисерверная
|
||||
// политика оператора могла различать стенды:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Package tools реализует MCP-инструменты модуля omnichannel-mcp поверх
|
||||
// Package tools реализует MCP-инструменты модуля omnichannel-configserver-mcp поверх
|
||||
// доменного пакета configserver. Слой тонкий: разобрать аргументы, вызвать
|
||||
// домен, вернуть текст/ошибку. Бизнес-логики здесь нет.
|
||||
package tools
|
||||
@@ -35,7 +35,7 @@ func RegisterAll(s *mcp.Server, m *configserver.Manager) {
|
||||
func openAPI(ctx context.Context, args map[string]any, write bool) (*configserver.API, *mcp.CallToolResult) {
|
||||
m := manager()
|
||||
if m == nil {
|
||||
return nil, errorResult("omnichannel-mcp: manager не инициализирован")
|
||||
return nil, errorResult("omnichannel-configserver-mcp: manager не инициализирован")
|
||||
}
|
||||
alias := getString(args, "server", "")
|
||||
api, err := m.Open(ctx, configPathArg(args), alias, write)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Command omnichannel-mcp — MCP-сервер управления платформой Omnichannel через
|
||||
// Command omnichannel-configserver-mcp — MCP-сервер управления платформой Omnichannel через
|
||||
// HTTP API config_server v1.1.0+ (деплой и эксплуатация).
|
||||
//
|
||||
// Следует общим соглашениям MCP-серверов: stdio-only, один потокобезопасный
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
|
||||
// serverName — имя MCP-сервера; часть хостов добавляет префикс serverName+"__"
|
||||
// к именам инструментов.
|
||||
const serverName = "omnichannel-mcp"
|
||||
const serverName = "omnichannel-configserver-mcp"
|
||||
|
||||
func main() {
|
||||
// --health должен быть дешёвым: без чтения конфига и подключений.
|
||||
@@ -33,7 +33,7 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
configPath := flag.String("config", "", "путь к config.json (иначе ищется OMNI_CONFIG_DIR/omnichannel-mcp.json)")
|
||||
configPath := flag.String("config", "", "путь к config.json (иначе ищется OMNI_CONFIG_DIR/omnichannel-configserver-mcp.json)")
|
||||
checkConfig := flag.Bool("check-config", false, "проверить конфиг, напечатать (секреты маскируются) и выйти")
|
||||
logLevel := flag.String("log-level", envOr("OMNI_LOG_LEVEL", "info"), "уровень логов: debug|info|warn|error")
|
||||
flag.Parse()
|
||||
|
||||
Reference in New Issue
Block a user