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
+43
View File
@@ -516,6 +516,49 @@ func (c *Client) findProjectViaIssue(ctx context.Context, shortName string) (str
return issues[0].Project.ID, nil
}
// Project is a YouTrack project summary for the register/import UI.
type Project struct {
ID string
ShortName string
Name string
}
// ListProjects lists admin-accessible projects (requires sufficient token scope).
func (c *Client) ListProjects(ctx context.Context) ([]Project, error) {
if err := c.ensureAuth(); err != nil {
return nil, err
}
var all []Project
for page := 0; page < maxPages; page++ {
skip := page * defaultPageSize
u, err := url.Parse(c.base() + "/api/admin/projects")
if err != nil {
return nil, err
}
q := u.Query()
q.Set("fields", "id,shortName,name")
q.Set("$top", fmt.Sprintf("%d", defaultPageSize))
q.Set("$skip", fmt.Sprintf("%d", skip))
u.RawQuery = q.Encode()
var raw []struct {
ID string `json:"id"`
ShortName string `json:"shortName"`
Name string `json:"name"`
}
if err := c.doJSON(ctx, http.MethodGet, u.String(), nil, &raw); err != nil {
return nil, err
}
for _, p := range raw {
all = append(all, Project{ID: p.ID, ShortName: p.ShortName, Name: p.Name})
}
if len(raw) < defaultPageSize {
break
}
}
return all, nil
}
// IssueURL builds the browser URL for an issue.
func (c *Client) IssueURL(idReadable string) string {
return c.base() + "/issue/" + idReadable