feat: плагин-система Lua + Calendar reference plugin

- Lua VM runtime: gopher-lua с песочницей, хуки on_init/on_tick/on_shutdown
- API: verstak.node.* / verstak.db.* / verstak.config.* / verstak.state.*
- API: verstak.worklog.* / verstak.activity.* / verstak.file.*
- API: verstak.schedule.* / verstak.http.* / verstak.ui.*
- Менеджер плагинов: жизненный цикл, инициализация, шаблоны
- Scheduler: фоновые задачи с интервалами
- PluginPage.svelte: контейнер для iframe-панелей плагинов
- Calendar plugin: миграция, категории CRUD, события CRUD
- Calendar: расширенный рекарренс (daily/weekly/monthly/yearly)
- Calendar: связь с узлами Верстака, напоминания, HTTP-праздники
- Calendar: Lua-тест-сьют (15 тестов), Go-интеграционный тест
- fix: query_row использует реальные Column() вместо guessColumns
This commit is contained in:
2026-06-07 14:59:46 +08:00
parent 8cbc87cdad
commit b80941f908
40 changed files with 4366 additions and 233 deletions
+3 -3
View File
@@ -78,10 +78,10 @@ func GenerateSecret() string {
}
// NewServer creates a bridge server.
// If cfg.Secret is empty, no authentication is required.
func NewServer(cfg Config, handler EventHandler) *Server {
// If secret is empty, no authentication is required.
func NewServer(secret string, handler EventHandler) *Server {
return &Server{
secret: cfg.Secret,
secret: secret,
handler: handler,
}
}
+5 -5
View File
@@ -10,7 +10,7 @@ import (
)
func TestServer_Ping(t *testing.T) {
s := NewServer(DefaultConfig(), nil)
s := NewServer("", nil)
port, err := s.Start(DefaultConfig())
if err != nil {
t.Fatal(err)
@@ -35,7 +35,7 @@ func TestServer_Ping(t *testing.T) {
}
func TestServer_Events_AuthRequired(t *testing.T) {
s := NewServer(Config{Secret: "test-secret"}, nil)
s := NewServer("test-secret", nil)
port, err := s.Start(Config{Secret: "test-secret"})
if err != nil {
t.Fatal(err)
@@ -56,7 +56,7 @@ func TestServer_Events_AuthRequired(t *testing.T) {
func TestServer_Events_Success(t *testing.T) {
received := make(chan []Event, 1)
s := NewServer(Config{Secret: "test-secret"}, func(evts []Event) {
s := NewServer("test-secret", func(evts []Event) {
received <- evts
})
port, err := s.Start(Config{Secret: "test-secret"})
@@ -99,7 +99,7 @@ func TestServer_Events_Success(t *testing.T) {
}
func TestServer_Events_EmptyBatch(t *testing.T) {
s := NewServer(Config{Secret: "s"}, nil)
s := NewServer("s", nil)
port, err := s.Start(Config{Secret: "s"})
if err != nil {
t.Fatal(err)
@@ -135,7 +135,7 @@ func TestGenerateSecret(t *testing.T) {
func TestServer_AutoPort(t *testing.T) {
cfg := DefaultConfig()
s := NewServer(cfg, nil)
s := NewServer("", nil)
port, err := s.Start(cfg)
if err != nil {
t.Fatal(err)