merge: resolve conflicts after merging main

Adapt runtime features (usage tracking, ping, heartbeat) to main's
multi-workspace architecture. Update frontend imports from @multica/types
to @/shared/types after the package consolidation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jiayuan 2026-03-26 18:37:56 +08:00
commit 6ee034c6e9
151 changed files with 3664 additions and 6579 deletions

View file

@ -87,11 +87,7 @@ func resolveWorkspaceID(cmd *cobra.Command) string {
return val
}
cfg, _ := cli.LoadCLIConfig()
if cfg.WorkspaceID != "" {
return cfg.WorkspaceID
}
// Fallback: try daemon.json for workspace_id
return cli.LoadWorkspaceIDFromDaemonConfig()
return cfg.WorkspaceID
}
func runAgentList(cmd *cobra.Command, _ []string) error {

View file

@ -22,8 +22,6 @@ var daemonCmd = &cobra.Command{
func init() {
f := daemonCmd.Flags()
f.String("repos-root", "", "Base directory for task repositories (env: MULTICA_REPOS_ROOT)")
f.String("config-path", "", "Path to daemon config file (env: MULTICA_DAEMON_CONFIG)")
f.String("daemon-id", "", "Unique daemon identifier (env: MULTICA_DAEMON_ID)")
f.String("device-name", "", "Human-readable device name (env: MULTICA_DAEMON_DEVICE_NAME)")
f.String("runtime-name", "", "Runtime display name (env: MULTICA_AGENT_RUNTIME_NAME)")
@ -35,9 +33,6 @@ func init() {
func runDaemon(cmd *cobra.Command, _ []string) error {
overrides := daemon.Overrides{
ServerURL: cli.FlagOrEnv(cmd, "server-url", "MULTICA_SERVER_URL", ""),
WorkspaceID: cli.FlagOrEnv(cmd, "workspace-id", "MULTICA_WORKSPACE_ID", ""),
ReposRoot: flagString(cmd, "repos-root"),
ConfigPath: flagString(cmd, "config-path"),
DaemonID: flagString(cmd, "daemon-id"),
DeviceName: flagString(cmd, "device-name"),
RuntimeName: flagString(cmd, "runtime-name"),
@ -73,4 +68,3 @@ func flagString(cmd *cobra.Command, name string) string {
val, _ := cmd.Flags().GetString(name)
return val
}

View file

@ -0,0 +1,151 @@
package main
import (
"context"
"fmt"
"os"
"text/tabwriter"
"time"
"github.com/spf13/cobra"
"github.com/multica-ai/multica/server/internal/cli"
)
var workspaceCmd = &cobra.Command{
Use: "workspace",
Short: "Manage workspaces",
}
var workspaceListCmd = &cobra.Command{
Use: "list",
Short: "List all workspaces you belong to",
RunE: runWorkspaceList,
}
var workspaceWatchCmd = &cobra.Command{
Use: "watch <workspace-id>",
Short: "Add a workspace to the daemon watch list",
Args: cobra.ExactArgs(1),
RunE: runWatch,
}
var workspaceUnwatchCmd = &cobra.Command{
Use: "unwatch <workspace-id>",
Short: "Remove a workspace from the daemon watch list",
Args: cobra.ExactArgs(1),
RunE: runUnwatch,
}
func init() {
workspaceCmd.AddCommand(workspaceListCmd)
workspaceCmd.AddCommand(workspaceWatchCmd)
workspaceCmd.AddCommand(workspaceUnwatchCmd)
}
func runWorkspaceList(cmd *cobra.Command, _ []string) error {
serverURL := resolveServerURL(cmd)
token := resolveToken()
if token == "" {
return fmt.Errorf("not authenticated: run 'multica auth login' first")
}
client := cli.NewAPIClient(serverURL, "", token)
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
var workspaces []struct {
ID string `json:"id"`
Name string `json:"name"`
}
if err := client.GetJSON(ctx, "/api/workspaces", &workspaces); err != nil {
return fmt.Errorf("list workspaces: %w", err)
}
if len(workspaces) == 0 {
fmt.Fprintln(os.Stderr, "No workspaces found.")
return nil
}
// Load watched set for marking.
cfg, _ := cli.LoadCLIConfig()
watched := make(map[string]bool)
for _, w := range cfg.WatchedWorkspaces {
watched[w.ID] = true
}
w := tabwriter.NewWriter(os.Stdout, 0, 4, 2, ' ', 0)
fmt.Fprintln(w, "ID\tNAME\tWATCHING")
for _, ws := range workspaces {
mark := ""
if watched[ws.ID] {
mark = "*"
}
fmt.Fprintf(w, "%s\t%s\t%s\n", ws.ID, ws.Name, mark)
}
return w.Flush()
}
func runWatch(cmd *cobra.Command, args []string) error {
workspaceID := args[0]
serverURL := resolveServerURL(cmd)
token := resolveToken()
if token == "" {
return fmt.Errorf("not authenticated: run 'multica auth login' first")
}
client := cli.NewAPIClient(serverURL, "", token)
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
var ws struct {
ID string `json:"id"`
Name string `json:"name"`
}
if err := client.GetJSON(ctx, "/api/workspaces/"+workspaceID, &ws); err != nil {
return fmt.Errorf("workspace not found: %w", err)
}
cfg, err := cli.LoadCLIConfig()
if err != nil {
return err
}
if !cfg.AddWatchedWorkspace(ws.ID, ws.Name) {
fmt.Fprintf(os.Stderr, "Already watching workspace %s (%s)\n", ws.ID, ws.Name)
return nil
}
if cfg.WorkspaceID == "" {
cfg.WorkspaceID = ws.ID
fmt.Fprintf(os.Stderr, "Set default workspace to %s (%s)\n", ws.ID, ws.Name)
}
if err := cli.SaveCLIConfig(cfg); err != nil {
return err
}
fmt.Fprintf(os.Stderr, "Watching workspace %s (%s)\n", ws.ID, ws.Name)
return nil
}
func runUnwatch(_ *cobra.Command, args []string) error {
workspaceID := args[0]
cfg, err := cli.LoadCLIConfig()
if err != nil {
return err
}
if !cfg.RemoveWatchedWorkspace(workspaceID) {
return fmt.Errorf("workspace %s is not being watched", workspaceID)
}
if err := cli.SaveCLIConfig(cfg); err != nil {
return err
}
fmt.Fprintf(os.Stderr, "Stopped watching workspace %s\n", workspaceID)
return nil
}

View file

@ -28,6 +28,7 @@ func init() {
rootCmd.AddCommand(daemonCmd)
rootCmd.AddCommand(agentCmd)
rootCmd.AddCommand(runtimeCmd)
rootCmd.AddCommand(workspaceCmd)
rootCmd.AddCommand(configCmd)
rootCmd.AddCommand(statusCmd)
rootCmd.AddCommand(versionCmd)

View file

@ -144,6 +144,7 @@ func NewRouter(pool *pgxpool.Pool, hub *realtime.Hub, bus *events.Bus) chi.Route
r.Route("/api/skills", func(r chi.Router) {
r.Get("/", h.ListSkills)
r.Post("/", h.CreateSkill)
r.Post("/import", h.ImportSkill)
r.Route("/{id}", func(r chi.Router) {
r.Get("/", h.GetSkill)
r.Put("/", h.UpdateSkill)