@@ -12,6 +12,7 @@ import (
1212 "os/signal"
1313 "path/filepath"
1414 "strings"
15+ "sync"
1516 "syscall"
1617 "time"
1718
@@ -364,16 +365,6 @@ workspace:
364365}
365366
366367func main () {
367- // AGGRESSIVE STARTUP DEBUG
368- f , _ := os .Create ("/tmp/ragcode-startup.txt" )
369- cwd , _ := os .Getwd ()
370- exe , _ := os .Executable ()
371- fmt .Fprintf (f , "Time: %s\n " , time .Now ())
372- fmt .Fprintf (f , "Exe: %s\n " , exe )
373- fmt .Fprintf (f , "CWD: %s\n " , cwd )
374- fmt .Fprintf (f , "Args: %v\n " , os .Args )
375- f .Close ()
376-
377368 // Define flags
378369 configPath := flag .String ("config" , "config.yaml" , "Path to configuration file" )
379370 ollamaBaseURLFlag := flag .String ("ollama-base-url" , "" , "Ollama base URL (overrides config/env)" )
@@ -437,7 +428,7 @@ func main() {
437428 // Handle update flag
438429 if * updateFlag {
439430 fmt .Println ("Checking for updates..." )
440- info , err := updater .CheckForUpdates (Version )
431+ info , err := updater .CheckForUpdates (context . Background (), Version , true )
441432 if err != nil {
442433 log .Fatalf ("Failed to check for updates: %v" , err )
443434 }
@@ -447,8 +438,26 @@ func main() {
447438 }
448439
449440 fmt .Printf ("Found new version: %s\n Downloading...\n " , info .LatestVersion )
450- tempFile := filepath .Join (os .TempDir (), "ragcode_update.tar.gz" )
451- if err := info .DownloadAndVerify (tempFile ); err != nil {
441+
442+ // Determine extension from asset URL
443+ ext := ".tar.gz"
444+ if strings .HasSuffix (info .AssetURL , ".zip" ) {
445+ ext = ".zip"
446+ }
447+ // Create a unique temporary file securely
448+ tmp , err := os .CreateTemp ("" , "ragcode_update_*" + ext )
449+ if err != nil {
450+ log .Fatalf ("Failed to create temporary file for update: %v" , err )
451+ }
452+ tempFile := tmp .Name ()
453+ // We only need the path; close the file descriptor
454+ if err := tmp .Close (); err != nil {
455+ log .Fatalf ("Failed to close temporary file for update: %v" , err )
456+ }
457+ // Ensure the temporary file is removed after applying the update
458+ defer os .Remove (tempFile )
459+
460+ if err := info .DownloadAndVerify (context .Background (), tempFile ); err != nil {
452461 log .Fatalf ("Update failed: %v" , err )
453462 }
454463
@@ -477,12 +486,7 @@ func main() {
477486 }
478487
479488 // Background update check
480- go func () {
481- info , err := updater .CheckForUpdates (Version )
482- if err == nil && info != nil {
483- logger .Info ("🌟 New version available: %s. Run 'rag-code-mcp --update' to upgrade." , info .LatestVersion )
484- }
485- }()
489+ triggerBackgroundUpdateCheck ()
486490
487491 // Apply logging settings from config unless env vars already override them
488492 applyLoggingConfig (cfg .Logging )
@@ -643,6 +647,11 @@ func main() {
643647
644648 indexWorkspaceTool := tools .NewIndexWorkspaceTool (workspaceManager )
645649
650+ listSkillsTool := tools .NewListSkillsTool ()
651+ installSkillTool := tools .NewInstallSkillTool (workspaceManager )
652+ checkUpdateTool := tools .NewCheckUpdateTool (Version )
653+ applyUpdateTool := tools .NewApplyUpdateTool (Version )
654+
646655 // Example: use typed ToolHandlerFor for search_code
647656 registerSearchCodeToolTyped (server , searchTool , cfg )
648657
@@ -655,6 +664,10 @@ func main() {
655664 registerAgentTool (server , searchDocsTool , cfg )
656665 registerAgentTool (server , hybridTool , cfg )
657666 registerAgentTool (server , indexWorkspaceTool , cfg )
667+ registerAgentTool (server , listSkillsTool , cfg )
668+ registerAgentTool (server , installSkillTool , cfg )
669+ registerAgentTool (server , checkUpdateTool , cfg )
670+ registerAgentTool (server , applyUpdateTool , cfg )
658671
659672 if err := registerFileResources (server ); err != nil {
660673 log .Fatalf ("Failed to register resources: %v" , err )
@@ -708,6 +721,9 @@ func registerSearchCodeToolTyped(server *mcp.Server, tool *tools.SearchLocalInde
708721
709722 logger .Info ("✅ Tool '%s' completed in %v" , tool .Name (), duration )
710723
724+ // Trigger background update check (non-blocking)
725+ triggerBackgroundUpdateCheck ()
726+
711727 return nil , SearchCodeOutput {Results : result }, nil
712728 })
713729}
@@ -751,6 +767,9 @@ func registerAgentTool(server *mcp.Server, tool MCPTool, cfg *config.Config) {
751767
752768 logger .Info ("✅ Tool '%s' completed in %v" , tool .Name (), duration )
753769
770+ // Trigger background update check (non-blocking)
771+ triggerBackgroundUpdateCheck ()
772+
754773 return & mcp.CallToolResult {
755774 Content : []mcp.Content {
756775 & mcp.TextContent {Text : result },
@@ -1097,6 +1116,54 @@ func getToolSchema(toolName string) map[string]interface{} {
10971116 "required" : []string {"query" },
10981117 }
10991118
1119+ case "list_skills" :
1120+ return map [string ]interface {}{
1121+ "type" : "object" ,
1122+ "properties" : map [string ]interface {}{},
1123+ }
1124+
1125+ case "install_skill" :
1126+ return map [string ]interface {}{
1127+ "type" : "object" ,
1128+ "properties" : map [string ]interface {}{
1129+ "skill_id" : map [string ]interface {}{
1130+ "type" : "string" ,
1131+ "description" : "The ID of the skill to install or uninstall" ,
1132+ },
1133+ "active" : map [string ]interface {}{
1134+ "type" : "boolean" ,
1135+ "description" : "True to install the skill, false to uninstall it" ,
1136+ },
1137+ "file_path" : map [string ]interface {}{
1138+ "type" : "string" ,
1139+ "description" : "Optional: file path to help detect workspace context" ,
1140+ },
1141+ },
1142+ "required" : []string {"skill_id" , "active" },
1143+ }
1144+
1145+ case "check_update" :
1146+ return map [string ]interface {}{
1147+ "type" : "object" ,
1148+ "properties" : map [string ]interface {}{
1149+ "force" : map [string ]interface {}{
1150+ "type" : "boolean" ,
1151+ "description" : "Force check ignoring cache (default: false)" ,
1152+ },
1153+ },
1154+ }
1155+
1156+ case "apply_update" :
1157+ return map [string ]interface {}{
1158+ "type" : "object" ,
1159+ "properties" : map [string ]interface {}{
1160+ "force" : map [string ]interface {}{
1161+ "type" : "boolean" ,
1162+ "description" : "Force update even if version matches (default: false)" ,
1163+ },
1164+ },
1165+ }
1166+
11001167 default :
11011168 return map [string ]interface {}{
11021169 "type" : "object" ,
@@ -1252,6 +1319,7 @@ func ensureIDERules(cfg *config.Config, filePath string) {
12521319- Always provide 'file_path' to tools to ensure they detect the correct project context.
12531320- Use 'hybrid_search' if looking for exact variable names or error messages.
12541321- If the tool says "workspace not indexed", use 'index_workspace' once.
1322+ - **Skills System**: Use 'list_skills' to see available AI behaviors and 'install_skill' to enable them in this workspace (e.g., 'ragcode-priority', 'ragcode-update').
12551323`
12561324
12571325 // 3. Define target rule files
@@ -1287,3 +1355,27 @@ func ensureIDERules(cfg *config.Config, filePath string) {
12871355 }
12881356 }
12891357}
1358+
1359+ var (
1360+ lastUpdateCheck time.Time
1361+ lastUpdateCheckMutex sync.Mutex
1362+ )
1363+
1364+ func triggerBackgroundUpdateCheck () {
1365+ lastUpdateCheckMutex .Lock ()
1366+ defer lastUpdateCheckMutex .Unlock ()
1367+
1368+ // Only check if more than 1 hour passed since last check in THIS session
1369+ // to avoid spamming go-routines, while updater.CheckForUpdates handles the 24h logic
1370+ if time .Since (lastUpdateCheck ) < 1 * time .Hour {
1371+ return
1372+ }
1373+ lastUpdateCheck = time .Now ()
1374+
1375+ go func () {
1376+ info , err := updater .CheckForUpdates (context .Background (), Version , false )
1377+ if err == nil && info != nil {
1378+ logger .Info ("🌟 New version available: %s. Run 'rag-code-mcp --update' or use the 'apply_update' tool to upgrade." , info .LatestVersion )
1379+ }
1380+ }()
1381+ }
0 commit comments