Add tm_server with SQLite, Svelte UI, and task-master TUI sync.

Introduces the web backend (auth, RBAC, project tokens, revisions),
YouTrack-or-taskmaster backend choice in the TUI, and a first-pass
embedded Svelte UI. The frontend is functional but needs a major rework.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-27 22:23:11 +01:00
co-authored by Cursor
parent 98d2253f44
commit 4adfcdb95a
67 changed files with 7188 additions and 129 deletions
+22 -19
View File
@@ -6,7 +6,7 @@ import (
"unicode"
)
// SyncAction is a YouTrack sync menu choice.
// SyncAction is a sync menu choice.
type SyncAction string
const (
@@ -21,27 +21,30 @@ type SyncOption struct {
Shortcut rune
}
// AllSyncOptions is the ordered sync menu.
var AllSyncOptions = []SyncOption{
{Action: SyncActionPull, Label: "Pull from YouTrack", Shortcut: 'p'},
{Action: SyncActionPush, Label: "Push to YouTrack", Shortcut: 'u'},
}
// SyncMenu renders a pull/push picker overlay.
type SyncMenu struct {
Cursor int
Width int
Styles StatusMenuStyles
Cursor int
Width int
Title string
Options []SyncOption
Styles StatusMenuStyles
}
// NewSyncMenu creates a sync action menu.
func NewSyncMenu(width int, styles StatusMenuStyles) SyncMenu {
return SyncMenu{Cursor: 0, Width: width, Styles: styles}
// NewSyncMenu creates a sync action menu for the given backend label.
func NewSyncMenu(width int, styles StatusMenuStyles, backendLabel string) SyncMenu {
if backendLabel == "" {
backendLabel = "Sync"
}
opts := []SyncOption{
{Action: SyncActionPull, Label: "Pull from " + backendLabel, Shortcut: 'p'},
{Action: SyncActionPush, Label: "Push to " + backendLabel, Shortcut: 'u'},
}
return SyncMenu{Cursor: 0, Width: width, Title: backendLabel, Options: opts, Styles: styles}
}
// MoveDown moves the selection down.
func (m *SyncMenu) MoveDown() {
if m.Cursor < len(AllSyncOptions)-1 {
if m.Cursor < len(m.Options)-1 {
m.Cursor++
}
}
@@ -56,7 +59,7 @@ func (m *SyncMenu) MoveUp() {
// JumpToShortcut selects the option whose shortcut matches r.
func (m *SyncMenu) JumpToShortcut(r rune) bool {
r = unicode.ToLower(r)
for i, opt := range AllSyncOptions {
for i, opt := range m.Options {
if opt.Shortcut == r {
m.Cursor = i
return true
@@ -67,17 +70,17 @@ func (m *SyncMenu) JumpToShortcut(r rune) bool {
// Selected returns the highlighted action.
func (m SyncMenu) Selected() SyncAction {
if m.Cursor < 0 || m.Cursor >= len(AllSyncOptions) {
if m.Cursor < 0 || m.Cursor >= len(m.Options) {
return SyncActionPull
}
return AllSyncOptions[m.Cursor].Action
return m.Options[m.Cursor].Action
}
// View renders the sync menu.
func (m SyncMenu) View() string {
var lines []string
lines = append(lines, m.Styles.Title.Render("YouTrack"))
for i, opt := range AllSyncOptions {
lines = append(lines, m.Styles.Title.Render(m.Title))
for i, opt := range m.Options {
entry := fmt.Sprintf("%c %s", opt.Shortcut, opt.Label)
if i == m.Cursor {
lines = append(lines, m.Styles.Selected.Render("▸ "+entry))