@@ -16,6 +16,8 @@ import (
1616 "github.com/codeany-ai/codeany/internal/plugins"
1717 "github.com/codeany-ai/codeany/internal/session"
1818 "github.com/codeany-ai/codeany/internal/skills"
19+ "github.com/codeany-ai/codeany/internal/team"
20+ "github.com/codeany-ai/codeany/internal/worktree"
1921 "github.com/codeany-ai/open-agent-sdk-go/mcp"
2022)
2123
@@ -1107,6 +1109,151 @@ func newRNG() *rand.Rand {
11071109 return rand .New (rand .NewSource (time .Now ().UnixNano ()))
11081110}
11091111
1112+ // ─── /team ────────────────────────────────────────
1113+
1114+ func (h * Handler ) teamCmd (args []string ) Result {
1115+ configDir := config .GlobalConfigDir ()
1116+
1117+ if len (args ) == 0 {
1118+ teams := team .ListTeams (configDir )
1119+ return Result {Message : team .FormatTeamList (teams )}
1120+ }
1121+
1122+ switch args [0 ] {
1123+ case "create" :
1124+ if len (args ) < 2 {
1125+ return Result {Message : "Usage: /team create <name> [description]" }
1126+ }
1127+ name := args [1 ]
1128+ desc := strings .Join (args [2 :], " " )
1129+ t , err := team .Create (configDir , name , desc )
1130+ if err != nil {
1131+ return Result {Message : fmt .Sprintf ("Failed to create team: %v" , err )}
1132+ }
1133+ return Result {Message : fmt .Sprintf ("✓ Team %q created with lead agent\n Dir: %s" , t .Name , filepath .Join (team .TeamsDir (configDir ), name ))}
1134+
1135+ case "add" :
1136+ if len (args ) < 3 {
1137+ return Result {Message : "Usage: /team add <team> <agent-name> [type]" }
1138+ }
1139+ t , err := team .Load (configDir , args [1 ])
1140+ if err != nil {
1141+ return Result {Message : fmt .Sprintf ("Team %q not found." , args [1 ])}
1142+ }
1143+ agentType := "general-purpose"
1144+ if len (args ) > 3 {
1145+ agentType = args [3 ]
1146+ }
1147+ t .AddMember (args [2 ], agentType , "" )
1148+ return Result {Message : fmt .Sprintf ("✓ Added %s to team %s" , args [2 ], t .Name )}
1149+
1150+ case "delete" , "remove" :
1151+ if len (args ) < 2 {
1152+ return Result {Message : "Usage: /team delete <name>" }
1153+ }
1154+ if err := team .Delete (configDir , args [1 ]); err != nil {
1155+ return Result {Message : fmt .Sprintf ("Failed to delete team: %v" , err )}
1156+ }
1157+ return Result {Message : fmt .Sprintf ("✓ Team %q deleted" , args [1 ])}
1158+
1159+ case "send" :
1160+ if len (args ) < 4 {
1161+ return Result {Message : "Usage: /team send <team> <agent> <message>" }
1162+ }
1163+ teamName := args [1 ]
1164+ agentName := args [2 ]
1165+ msg := strings .Join (args [3 :], " " )
1166+ if err := team .SendMsg (configDir , teamName , "user" , agentName , msg ); err != nil {
1167+ return Result {Message : fmt .Sprintf ("Failed to send: %v" , err )}
1168+ }
1169+ return Result {Message : fmt .Sprintf ("✓ Message sent to %s in team %s" , agentName , teamName )}
1170+
1171+ case "inbox" :
1172+ if len (args ) < 3 {
1173+ return Result {Message : "Usage: /team inbox <team> <agent>" }
1174+ }
1175+ messages := team .ReadInbox (configDir , args [1 ], args [2 ])
1176+ if len (messages ) == 0 {
1177+ return Result {Message : "No unread messages." }
1178+ }
1179+ var b strings.Builder
1180+ b .WriteString (fmt .Sprintf ("Inbox for %s (%d messages):\n \n " , args [2 ], len (messages )))
1181+ for _ , m := range messages {
1182+ b .WriteString (fmt .Sprintf (" [%s] %s: %s\n " , m .Timestamp .Format ("15:04" ), m .From , m .Text ))
1183+ }
1184+ return Result {Message : b .String ()}
1185+
1186+ default :
1187+ return Result {Message : "Usage: /team [create|add|delete|send|inbox]\n \n /team List teams\n /team create <n> Create team\n /team add <t> <a> Add agent\n /team delete <n> Delete team\n /team send <t> <a> Send message\n /team inbox <t> <a> Read inbox" }
1188+ }
1189+ }
1190+
1191+ // ─── /worktree ────────────────────────────────────
1192+
1193+ func (h * Handler ) worktreeCmd (args []string ) Result {
1194+ configDir := config .GlobalConfigDir ()
1195+
1196+ if len (args ) == 0 {
1197+ wts := worktree .ListAll (configDir )
1198+ if len (wts ) == 0 {
1199+ return Result {Message : "No worktrees.\n \n Create one with: /worktree enter <name>" }
1200+ }
1201+ var b strings.Builder
1202+ b .WriteString ("Worktrees:\n \n " )
1203+ for _ , wt := range wts {
1204+ b .WriteString (fmt .Sprintf (" %s → %s (branch: %s)\n " , wt .Name , wt .Path , wt .Branch ))
1205+ }
1206+ return Result {Message : b .String ()}
1207+ }
1208+
1209+ switch args [0 ] {
1210+ case "enter" , "create" :
1211+ name := "work"
1212+ if len (args ) > 1 {
1213+ name = args [1 ]
1214+ }
1215+ a := h .app .GetAgent ()
1216+ sessionID := "unknown"
1217+ if a != nil {
1218+ sessionID = a .SessionID ()
1219+ }
1220+ wt , err := worktree .Create (configDir , name , sessionID )
1221+ if err != nil {
1222+ return Result {Message : fmt .Sprintf ("Failed to create worktree: %v" , err )}
1223+ }
1224+ if err := wt .Enter (); err != nil {
1225+ return Result {Message : fmt .Sprintf ("Failed to enter worktree: %v" , err )}
1226+ }
1227+ return Result {Message : fmt .Sprintf ("✓ Entered worktree %q\n Branch: %s\n Path: %s\n \n Use /worktree exit to return." , name , wt .Branch , wt .Path )}
1228+
1229+ case "exit" , "leave" :
1230+ a := h .app .GetAgent ()
1231+ sessionID := "unknown"
1232+ if a != nil {
1233+ sessionID = a .SessionID ()
1234+ }
1235+ wt := worktree .LoadActive (configDir , sessionID )
1236+ if wt == nil {
1237+ return Result {Message : "Not in a worktree." }
1238+ }
1239+ remove := false
1240+ if len (args ) > 1 && (args [1 ] == "--remove" || args [1 ] == "-r" ) {
1241+ remove = true
1242+ }
1243+ if err := wt .Exit (remove ); err != nil {
1244+ return Result {Message : fmt .Sprintf ("Failed to exit worktree: %v" , err )}
1245+ }
1246+ msg := fmt .Sprintf ("✓ Returned to %s" , wt .OriginalCWD )
1247+ if remove {
1248+ msg += " (worktree removed)"
1249+ }
1250+ return Result {Message : msg }
1251+
1252+ default :
1253+ return Result {Message : "Usage: /worktree [enter|exit]\n \n /worktree List worktrees\n /worktree enter <n> Create & enter worktree\n /worktree exit [-r] Exit (--remove to delete)" }
1254+ }
1255+ }
1256+
11101257// ─── helpers ──────────────────────────────────────
11111258
11121259func min (a , b int ) int {
0 commit comments