smdev 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/smdev/cursor_rules/backup_manager.rb +103 -0
- data/lib/smdev/cursor_rules/config_manager.rb +60 -0
- data/lib/smdev/cursor_rules/directory_manager.rb +55 -0
- data/lib/smdev/cursor_rules/file_copier.rb +53 -0
- data/lib/smdev/cursor_rules/file_operations.rb +83 -0
- data/lib/smdev/cursor_rules/installer.rb +128 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/core-rules/readme.md +1 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/core-rules/rule-generating-agent.mdc +86 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/default.mdc +42 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/documentation/markdown-auto.mdc +59 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/documentation/readme.md +1 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/global-rules/emoji-communication-always.mdc +33 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/global-rules/performance-standards-agent.mdc +36 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/global-rules/readme.md +5 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/global-rules/tech-stack-agent.mdc +42 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/rb-rules/database-standards-agent.mdc +52 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/rb-rules/rails-conventions-agent.mdc +48 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/rb-rules/readme.md +1 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/testing-rules/rspec-standards-agent.mdc +51 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/tool-rules/gitpush.mdc +35 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/tool-rules/readme.md +1 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/ts-rules/readme.md +1 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/ui-rules/readme.md +11 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/ui-rules/ui-component-standards-agent.mdc +55 -0
- data/lib/smdev/cursor_rules/templates/.cursor/rules/workflows/workflow-agile-manual.mdc +48 -0
- data/lib/smdev/cursor_rules/templates/.cursor/templates/template-arch.md +76 -0
- data/lib/smdev/cursor_rules/templates/.cursor/templates/template-prd.md +136 -0
- data/lib/smdev/cursor_rules/templates/.cursor/templates/template-story.md +146 -0
- data/lib/smdev/cursor_rules/templates/docs/agile-readme.md +251 -0
- data/lib/smdev/cursor_rules/templates/docs/cursor_rules.md +88 -0
- data/lib/smdev/cursor_rules/user_interface.rb +27 -0
- data/lib/smdev/cursor_rules.rb +16 -0
- data/lib/smdev/ecs_exec.rb +0 -4
- data/lib/smdev.rb +86 -105
- metadata +34 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f4e2aa439eb52fe028b25c321831575d0f1a9543da3320b849f07187d66ccc8
|
4
|
+
data.tar.gz: 66f79482307a323b1c96bf2f2e6bee35ae4b700ed9fa6fa6dcff7cd9b61c7d7c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55da40456e494d693c8aeff2e47dcffb4d82731db5129f2e1a1b0a3e33050e6be7bdc1833ffbed49d514be3ac45f9182387d15ecd29f574a8d526f11efa265c1
|
7
|
+
data.tar.gz: 3577639b832c7064b7fe54a90688eba6cc1eaa72aa09757a7fb82bb5c8f4ffdeeb6133d5dd23890e73f725ecf03b1a96575a09485dcbfbfcf788dd3b7b7a14bb
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Smdev
|
4
|
+
module CursorRules
|
5
|
+
class BackupManager
|
6
|
+
def initialize(target_dir, timestamp)
|
7
|
+
@target_dir = target_dir
|
8
|
+
@timestamp = timestamp
|
9
|
+
@backup_created = false
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_backup
|
13
|
+
@backup_dir = File.join(@target_dir, '.cursor/backups', @timestamp)
|
14
|
+
FileUtils.mkdir_p(@backup_dir)
|
15
|
+
|
16
|
+
backup_cursor_directory
|
17
|
+
backup_docs
|
18
|
+
|
19
|
+
puts "📦 Created backup in: #{@backup_dir}"
|
20
|
+
@backup_created = true
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def restore
|
25
|
+
return unless backup_exists?
|
26
|
+
|
27
|
+
restore_directory('rules')
|
28
|
+
restore_directory('templates')
|
29
|
+
restore_docs
|
30
|
+
|
31
|
+
puts "♻️ Restored previous version from backup"
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
def backup_exists?
|
36
|
+
@backup_created
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def backup_cursor_directory
|
42
|
+
['rules', 'templates'].each do |dir|
|
43
|
+
backup_subdirectory(dir)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def backup_subdirectory(dir)
|
48
|
+
source_dir = File.join(@target_dir, '.cursor', dir)
|
49
|
+
return unless File.directory?(source_dir)
|
50
|
+
|
51
|
+
target_dir = File.join(@backup_dir, dir)
|
52
|
+
FileUtils.mkdir_p(target_dir)
|
53
|
+
|
54
|
+
copy_directory_contents(source_dir, target_dir)
|
55
|
+
end
|
56
|
+
|
57
|
+
def copy_directory_contents(source_dir, target_dir)
|
58
|
+
Dir.glob(File.join(source_dir, '**/*')).each do |file|
|
59
|
+
next unless File.file?(file)
|
60
|
+
copy_file(file, source_dir, target_dir)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def copy_file(file, source_dir, target_dir)
|
65
|
+
rel_path = Pathname.new(file).relative_path_from(Pathname.new(source_dir)).to_s
|
66
|
+
target_file = File.join(target_dir, rel_path)
|
67
|
+
|
68
|
+
FileUtils.mkdir_p(File.dirname(target_file))
|
69
|
+
FileUtils.cp(file, target_file)
|
70
|
+
end
|
71
|
+
|
72
|
+
def backup_docs
|
73
|
+
docs_dir = File.join(@target_dir, 'docs')
|
74
|
+
return unless File.directory?(docs_dir)
|
75
|
+
|
76
|
+
target_dir = File.join(@backup_dir, 'docs')
|
77
|
+
FileUtils.mkdir_p(target_dir)
|
78
|
+
|
79
|
+
copy_directory_contents(docs_dir, target_dir)
|
80
|
+
end
|
81
|
+
|
82
|
+
def restore_directory(dir)
|
83
|
+
source_dir = File.join(@backup_dir, dir)
|
84
|
+
return unless File.directory?(source_dir)
|
85
|
+
|
86
|
+
target_dir = File.join(@target_dir, '.cursor', dir)
|
87
|
+
FileUtils.mkdir_p(target_dir)
|
88
|
+
|
89
|
+
copy_directory_contents(source_dir, target_dir)
|
90
|
+
end
|
91
|
+
|
92
|
+
def restore_docs
|
93
|
+
source_dir = File.join(@backup_dir, 'docs')
|
94
|
+
return unless File.directory?(source_dir)
|
95
|
+
|
96
|
+
target_dir = File.join(@target_dir, 'docs')
|
97
|
+
FileUtils.mkdir_p(target_dir)
|
98
|
+
|
99
|
+
copy_directory_contents(source_dir, target_dir)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Smdev
|
2
|
+
module CursorRules
|
3
|
+
# Handles configuration file updates for cursor rules
|
4
|
+
module ConfigManager
|
5
|
+
# Updates configuration files (.gitignore, .cursorignore, .cursorindexingignore)
|
6
|
+
#
|
7
|
+
# @return [void]
|
8
|
+
def update_configuration_files
|
9
|
+
update_gitignore
|
10
|
+
update_cursorignore
|
11
|
+
update_cursorindexingignore
|
12
|
+
puts "📝 Updated configuration files"
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def update_gitignore
|
18
|
+
gitignore_path = File.join(@target_dir, '.gitignore')
|
19
|
+
gitignore_entries = [
|
20
|
+
"\n# Private individual user cursor rules",
|
21
|
+
".cursor/rules/_*.mdc"
|
22
|
+
]
|
23
|
+
|
24
|
+
update_config_file(gitignore_path, gitignore_entries)
|
25
|
+
end
|
26
|
+
|
27
|
+
def update_cursorignore
|
28
|
+
cursorignore_path = File.join(@target_dir, '.cursorignore')
|
29
|
+
cursorignore_entries = [
|
30
|
+
"\n# Project notes and templates",
|
31
|
+
"xnotes/"
|
32
|
+
]
|
33
|
+
|
34
|
+
update_config_file(cursorignore_path, cursorignore_entries)
|
35
|
+
end
|
36
|
+
|
37
|
+
def update_cursorindexingignore
|
38
|
+
indexingignore_path = File.join(@target_dir, '.cursorindexingignore')
|
39
|
+
indexingignore_entries = [
|
40
|
+
"\n# Templates - accessible but not indexed",
|
41
|
+
".cursor/templates/"
|
42
|
+
]
|
43
|
+
|
44
|
+
update_config_file(indexingignore_path, indexingignore_entries)
|
45
|
+
end
|
46
|
+
|
47
|
+
def update_config_file(file_path, entries)
|
48
|
+
content = File.exist?(file_path) ? File.read(file_path) : ""
|
49
|
+
|
50
|
+
entries.each do |entry|
|
51
|
+
unless content.include?(entry)
|
52
|
+
content += "\n#{entry}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
File.write(file_path, content.strip + "\n")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Smdev
|
2
|
+
module CursorRules
|
3
|
+
# Handles directory creation and validation operations
|
4
|
+
class DirectoryManager
|
5
|
+
# Directory containing cursor rules and templates
|
6
|
+
CURSOR_DIR = '.cursor'
|
7
|
+
# Directory for cursor rules
|
8
|
+
RULES_DIR = File.join(CURSOR_DIR, 'rules')
|
9
|
+
# Directory for cursor templates
|
10
|
+
TEMPLATES_DIR = File.join(CURSOR_DIR, 'templates')
|
11
|
+
# Directory for documentation
|
12
|
+
DOCS_DIR = 'docs'
|
13
|
+
# Directory for backups
|
14
|
+
BACKUPS_DIR = File.join(CURSOR_DIR, 'backups')
|
15
|
+
|
16
|
+
def initialize(target_dir)
|
17
|
+
@target_dir = target_dir
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_required_directories
|
21
|
+
[
|
22
|
+
CURSOR_DIR,
|
23
|
+
RULES_DIR,
|
24
|
+
TEMPLATES_DIR,
|
25
|
+
DOCS_DIR,
|
26
|
+
BACKUPS_DIR
|
27
|
+
].each do |dir|
|
28
|
+
path = File.join(@target_dir, dir)
|
29
|
+
FileUtils.mkdir_p(path)
|
30
|
+
puts "📁 Created directory: #{dir}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def cursor_rules_exist?
|
35
|
+
File.directory?(File.join(@target_dir, CURSOR_DIR))
|
36
|
+
end
|
37
|
+
|
38
|
+
def validate_target_directory
|
39
|
+
unless File.directory?(@target_dir)
|
40
|
+
raise Error, "Target directory '#{@target_dir}' does not exist"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def validate_source_directory(source_dir)
|
45
|
+
return if Dir.exist?(source_dir)
|
46
|
+
raise Error, "Source cursor directory not found in gem"
|
47
|
+
end
|
48
|
+
|
49
|
+
def validate_docs_directory(source_docs)
|
50
|
+
return if Dir.exist?(source_docs)
|
51
|
+
raise Error, "Source documentation not found in gem"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
module Smdev
|
5
|
+
module CursorRules
|
6
|
+
class FileCopier
|
7
|
+
def initialize(source_dir, target_dir)
|
8
|
+
@source_dir = source_dir
|
9
|
+
@target_dir = target_dir
|
10
|
+
end
|
11
|
+
|
12
|
+
def copy_rules(source_rules, target_rules)
|
13
|
+
FileUtils.mkdir_p(target_rules)
|
14
|
+
|
15
|
+
Dir.glob(File.join(source_rules, '**', '*.mdc')).each do |source_file|
|
16
|
+
copy_with_path(source_file, source_rules, target_rules)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def copy_templates(source_templates, target_templates)
|
21
|
+
return unless Dir.exist?(source_templates)
|
22
|
+
|
23
|
+
FileUtils.mkdir_p(target_templates)
|
24
|
+
FileUtils.cp_r(Dir.glob("#{source_templates}/*"), target_templates)
|
25
|
+
end
|
26
|
+
|
27
|
+
def copy_documentation(source_docs, target_docs)
|
28
|
+
FileUtils.mkdir_p(target_docs)
|
29
|
+
|
30
|
+
Dir.glob(File.join(source_docs, '**', '*')).each do |file|
|
31
|
+
if File.file?(file)
|
32
|
+
copy_with_path(file, source_docs, target_docs)
|
33
|
+
elsif File.directory?(file)
|
34
|
+
rel_path = Pathname.new(file).relative_path_from(Pathname.new(source_docs)).to_s
|
35
|
+
FileUtils.mkdir_p(File.join(target_docs, rel_path))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def copy_with_path(source_file, source_base, target_base)
|
43
|
+
return unless File.file?(source_file)
|
44
|
+
|
45
|
+
relative_path = Pathname.new(source_file).relative_path_from(Pathname.new(source_base)).to_s
|
46
|
+
target_file = File.join(target_base, relative_path)
|
47
|
+
|
48
|
+
FileUtils.mkdir_p(File.dirname(target_file))
|
49
|
+
FileUtils.cp(source_file, target_file)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Smdev
|
4
|
+
module CursorRules
|
5
|
+
# Handles file operations for cursor rules installation
|
6
|
+
module FileOperations
|
7
|
+
# Constants for directory paths
|
8
|
+
CURSOR_DIR = '.cursor'
|
9
|
+
DOCS_DIR = 'docs'
|
10
|
+
CURSOR_SUBDIRS = ['rules', 'templates'].freeze
|
11
|
+
|
12
|
+
# Copies cursor rules and templates from source to target
|
13
|
+
#
|
14
|
+
# @raise [Error] if source directory is not found
|
15
|
+
def copy_cursor_files
|
16
|
+
validate_source_directory(File.join(@source_dir, CURSOR_DIR))
|
17
|
+
debug("Copying cursor files from #{@source_dir} to #{File.join(@target_dir, CURSOR_DIR)}")
|
18
|
+
|
19
|
+
create_cursor_directories
|
20
|
+
copy_cursor_subdirectories
|
21
|
+
|
22
|
+
puts "📝 Copied cursor rules and templates"
|
23
|
+
end
|
24
|
+
|
25
|
+
# Copies documentation files from source to target
|
26
|
+
#
|
27
|
+
# @raise [Error] if source documentation is not found
|
28
|
+
def copy_docs
|
29
|
+
docs_source = File.join(@source_dir, DOCS_DIR)
|
30
|
+
validate_source_directory(docs_source)
|
31
|
+
|
32
|
+
debug("Copying docs from #{docs_source} to #{File.join(@target_dir, DOCS_DIR)}")
|
33
|
+
|
34
|
+
# Create target directory
|
35
|
+
FileUtils.mkdir_p(File.join(@target_dir, DOCS_DIR))
|
36
|
+
|
37
|
+
# Copy documentation files
|
38
|
+
copy_directory_contents(docs_source, File.join(@target_dir, DOCS_DIR))
|
39
|
+
|
40
|
+
puts "📚 Copied documentation files"
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def create_cursor_directories
|
46
|
+
CURSOR_SUBDIRS.each do |dir|
|
47
|
+
FileUtils.mkdir_p(File.join(@target_dir, CURSOR_DIR, dir))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def copy_cursor_subdirectories
|
52
|
+
CURSOR_SUBDIRS.each do |dir|
|
53
|
+
source = File.join(@source_dir, CURSOR_DIR, dir)
|
54
|
+
target = File.join(@target_dir, CURSOR_DIR, dir)
|
55
|
+
|
56
|
+
copy_directory_contents(source, target) if File.directory?(source)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def copy_directory_contents(source_dir, target_dir)
|
61
|
+
Dir.glob(File.join(source_dir, '**/*')).each do |file|
|
62
|
+
next unless File.file?(file)
|
63
|
+
|
64
|
+
rel_path = Pathname.new(file).relative_path_from(Pathname.new(source_dir)).to_s
|
65
|
+
target_file = File.join(target_dir, rel_path)
|
66
|
+
|
67
|
+
debug("Copying #{file} to #{target_file}")
|
68
|
+
FileUtils.mkdir_p(File.dirname(target_file))
|
69
|
+
FileUtils.cp(file, target_file)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def validate_source_directory(dir)
|
74
|
+
return if File.directory?(dir)
|
75
|
+
raise Error, "Source directory '#{dir}' does not exist"
|
76
|
+
end
|
77
|
+
|
78
|
+
def debug(message)
|
79
|
+
puts "Debug: #{message}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'time'
|
3
|
+
require_relative 'backup_manager'
|
4
|
+
require_relative 'directory_manager'
|
5
|
+
require_relative 'file_copier'
|
6
|
+
require_relative 'user_interface'
|
7
|
+
require_relative 'config_manager'
|
8
|
+
|
9
|
+
module Smdev
|
10
|
+
module CursorRules
|
11
|
+
class Installer
|
12
|
+
include ConfigManager
|
13
|
+
|
14
|
+
CURSOR_DIR = '.cursor'
|
15
|
+
RULES_DIR = File.join(CURSOR_DIR, 'rules')
|
16
|
+
TEMPLATES_DIR = File.join(CURSOR_DIR, 'templates')
|
17
|
+
DOCS_DIR = 'docs'
|
18
|
+
BACKUPS_DIR = File.join(CURSOR_DIR, 'backups')
|
19
|
+
|
20
|
+
def initialize(target_dir, ui: UserInterface.new)
|
21
|
+
@target_dir = target_dir
|
22
|
+
@source_dir = CursorRules.templates_path
|
23
|
+
@directory_manager = DirectoryManager.new(target_dir)
|
24
|
+
@file_copier = FileCopier.new(@source_dir, target_dir)
|
25
|
+
@ui = ui
|
26
|
+
@backup_manager = BackupManager.new(target_dir, Time.now.strftime('%Y%m%d_%H%M%S'))
|
27
|
+
end
|
28
|
+
|
29
|
+
def install
|
30
|
+
begin
|
31
|
+
validate_and_prepare
|
32
|
+
perform_installation
|
33
|
+
@ui.display_success_message(@target_dir)
|
34
|
+
true
|
35
|
+
rescue StandardError => e
|
36
|
+
handle_error(e)
|
37
|
+
raise
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def validate_and_prepare
|
44
|
+
@directory_manager.validate_target_directory
|
45
|
+
check_target_directory
|
46
|
+
end
|
47
|
+
|
48
|
+
def check_target_directory
|
49
|
+
if @directory_manager.cursor_rules_exist?
|
50
|
+
@ui.prompt_for_override
|
51
|
+
@backup_manager.create_backup
|
52
|
+
end
|
53
|
+
@directory_manager.create_required_directories
|
54
|
+
end
|
55
|
+
|
56
|
+
def perform_installation
|
57
|
+
copy_cursor_files
|
58
|
+
copy_docs
|
59
|
+
update_configuration_files
|
60
|
+
end
|
61
|
+
|
62
|
+
def copy_cursor_files
|
63
|
+
@directory_manager.validate_source_directory(@source_dir)
|
64
|
+
|
65
|
+
source_rules = File.join(@source_dir, DirectoryManager::CURSOR_DIR, 'rules')
|
66
|
+
target_rules = File.join(@target_dir, DirectoryManager::RULES_DIR)
|
67
|
+
@file_copier.copy_rules(source_rules, target_rules)
|
68
|
+
|
69
|
+
source_templates = File.join(@source_dir, DirectoryManager::CURSOR_DIR, 'templates')
|
70
|
+
target_templates = File.join(@target_dir, DirectoryManager::TEMPLATES_DIR)
|
71
|
+
@file_copier.copy_templates(source_templates, target_templates)
|
72
|
+
|
73
|
+
puts "📝 Copied cursor rules and templates"
|
74
|
+
end
|
75
|
+
|
76
|
+
def copy_docs
|
77
|
+
source_docs = File.join(@source_dir, DirectoryManager::DOCS_DIR)
|
78
|
+
target_docs = File.join(@target_dir, DirectoryManager::DOCS_DIR)
|
79
|
+
|
80
|
+
@directory_manager.validate_docs_directory(source_docs)
|
81
|
+
@file_copier.copy_documentation(source_docs, target_docs)
|
82
|
+
puts "📚 Copied documentation files"
|
83
|
+
end
|
84
|
+
|
85
|
+
def handle_error(error)
|
86
|
+
@ui.display_error(error)
|
87
|
+
@backup_manager.restore if @backup_manager.backup_exists?
|
88
|
+
end
|
89
|
+
|
90
|
+
def update_configuration_files
|
91
|
+
update_gitignore
|
92
|
+
update_cursorignore
|
93
|
+
update_cursorindexingignore
|
94
|
+
puts "📝 Updated configuration files"
|
95
|
+
end
|
96
|
+
|
97
|
+
def update_gitignore
|
98
|
+
gitignore_path = File.join(@target_dir, '.gitignore')
|
99
|
+
gitignore_entries = [
|
100
|
+
"\n# Private individual user cursor rules",
|
101
|
+
".cursor/rules/_*.mdc"
|
102
|
+
]
|
103
|
+
|
104
|
+
update_config_file(gitignore_path, gitignore_entries)
|
105
|
+
end
|
106
|
+
|
107
|
+
def update_cursorignore
|
108
|
+
cursorignore_path = File.join(@target_dir, '.cursorignore')
|
109
|
+
cursorignore_entries = [
|
110
|
+
"\n# Project notes and templates",
|
111
|
+
"xnotes/"
|
112
|
+
]
|
113
|
+
|
114
|
+
update_config_file(cursorignore_path, cursorignore_entries)
|
115
|
+
end
|
116
|
+
|
117
|
+
def update_cursorindexingignore
|
118
|
+
indexingignore_path = File.join(@target_dir, '.cursorindexingignore')
|
119
|
+
indexingignore_entries = [
|
120
|
+
"\n# Templates - accessible but not indexed",
|
121
|
+
".cursor/templates/"
|
122
|
+
]
|
123
|
+
|
124
|
+
update_config_file(indexingignore_path, indexingignore_entries)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Core rules related to cursor or rule generation
|
@@ -0,0 +1,86 @@
|
|
1
|
+
---
|
2
|
+
description: Always follow this when the user requests that a rule be added or modified, or asks you to remember to always do something in the future
|
3
|
+
globs:
|
4
|
+
alwaysApply: false
|
5
|
+
---
|
6
|
+
# Cursor Rules Format
|
7
|
+
|
8
|
+
## Template Structure for Rules Files
|
9
|
+
|
10
|
+
```mdc
|
11
|
+
---
|
12
|
+
description: `Explicit concise description to ensure the agent knows when to apply the rule` OR blank
|
13
|
+
globs: .cursor/rules/**/*.mdc OR blank
|
14
|
+
alwaysApply: {true or false}
|
15
|
+
---
|
16
|
+
|
17
|
+
# Rule Title
|
18
|
+
|
19
|
+
## Context
|
20
|
+
|
21
|
+
- When to apply this rule
|
22
|
+
- Prerequisites or conditions
|
23
|
+
- Why the rule was added or is needed
|
24
|
+
|
25
|
+
## Critical Rules
|
26
|
+
|
27
|
+
- Concise, bulleted list of actionable rules the agent MUST follow
|
28
|
+
|
29
|
+
## Examples
|
30
|
+
|
31
|
+
<example>
|
32
|
+
{valid rule application}
|
33
|
+
</example>
|
34
|
+
|
35
|
+
<example type="invalid">
|
36
|
+
{invalid rule application}
|
37
|
+
<example>
|
38
|
+
```
|
39
|
+
|
40
|
+
### Organizational Folders (Create if non existent)
|
41
|
+
All rules files will be under an organizational folder:
|
42
|
+
- .cursor/rules/core-rules - rules related to cursor agent behavior or rule generation specifically
|
43
|
+
- .cursor/rules/my-rules - gitignore in a shared repo, rules specifically for ME only
|
44
|
+
- .cursor/rules/global-rules - these will be rules that are ALWAYS applied to every chat and cmd/ctrl-k context
|
45
|
+
- .cursor/rules/testing-rules - rules about testing
|
46
|
+
- .cursor/rules/tool-rules - rules specific to different tools, such as git, linux commands, direction of usage of MCP tools
|
47
|
+
- .cursor/rules/ts-rules - typescript language specific rules
|
48
|
+
- .cursor/rules/rb-rules - ruby specific rules
|
49
|
+
- .cursor/rules/py-rules - python specific rules
|
50
|
+
- .cursor/rules/ui-rules - rules about html, css, react
|
51
|
+
* create new folders under .cursor/rules/ as needed following similar grouping conventions,
|
52
|
+
- for example `.cursor/rules/cs-rules` if we started using c# in a project
|
53
|
+
|
54
|
+
## Glob Pattern Examples
|
55
|
+
Common glob patterns for different rule types:
|
56
|
+
- Core standards: .cursor/rules/*.mdc
|
57
|
+
- Language rules: *.cs, *.cpp
|
58
|
+
- Testing standards: *.test.ts, *.test.js
|
59
|
+
- React components: src/components/**/*.tsx
|
60
|
+
- Documentation: docs/**/*.md, *.md
|
61
|
+
- Configuration files: *.config.js
|
62
|
+
- Build artifacts: dist/**/*
|
63
|
+
- Multiple extensions: *.js, *.ts, *.tsx, *.rb
|
64
|
+
- Multiple patterns: dist/**/*.*, docs/**/*.md, *test*.*
|
65
|
+
|
66
|
+
## Critical Rules
|
67
|
+
- Rule files will be located and named ALWAYS as: `.cursor/rules/{organizational-folder}/rule-name-{auto|agent|manual|always}.mdc`
|
68
|
+
- FrontMatter Rules Types:
|
69
|
+
- The front matter section must always start the file and include all 3 fields, even if the field value will be blank - the types are:
|
70
|
+
- Manual Rule: IF a Manual rule is requested - description and globs MUST be blank and alwaysApply: false and filename ends with -manual.mdc.
|
71
|
+
- Auto Rule: IF a rule is requested that should apply always to certain glob patterns (example all typescript files or all markdown files) - description must be blank, and alwaysApply: false and filename ends with -auto.mdc.
|
72
|
+
- Always Rule: Global Rule applies to every chat and cmd/ctrl-k - description and globs blank, and alwaysApply: true and filename ends with -always.mdc.
|
73
|
+
- Agent Select Rule: The rule does not need to be loaded into every chat thread, it serves a specific purpose. The agent can see the descriptions, and choose to load the full rule in to context on its own - description is critical, globs blank, and alwaysApply:false and filename ends with -agent.mdc
|
74
|
+
- For the Rule Context and Bullets - do not repeat yourself and do not be overly explanatory
|
75
|
+
- When a rule will only be used sometimes (useAlways: false) it is CRITICAL that the description describes when the AI will load the full rule into its context
|
76
|
+
- Use Concise Markdown Tailored to Agent Context Window usage
|
77
|
+
- Always indent content within XML Example section with 2 spaces
|
78
|
+
- Emojis and Mermaid diagrams are allowed and encouraged if it is not redundant and better explains the rule for the AI comprehension.
|
79
|
+
- TRY to keep the total rule line count under 50 lines, better under 25 lines
|
80
|
+
- Always include a valid and invalid example
|
81
|
+
- NEVER use quotes around glob patterns, NEVER group glob extensions with `{}`
|
82
|
+
- If the request for a rule or a future behavior change includes context of a mistake is made, this would be great to use in the example for the rule
|
83
|
+
- After rule is created or updated, Respond with the following:
|
84
|
+
- AutoRuleGen Success: path/rule-name.mdc
|
85
|
+
- Rule Type: {Rule Type}
|
86
|
+
- Short summary of what the rule will do
|
@@ -0,0 +1,42 @@
|
|
1
|
+
---
|
2
|
+
description:
|
3
|
+
globs:
|
4
|
+
alwaysApply: false
|
5
|
+
---
|
6
|
+
# Default Cursor Rules
|
7
|
+
|
8
|
+
## Manual Rules
|
9
|
+
These rules can be triggered manually by the user.
|
10
|
+
|
11
|
+
```cursor
|
12
|
+
# Example manual rule
|
13
|
+
@manual("Generate test file")
|
14
|
+
def generate_test():
|
15
|
+
"""Generate a new test file for the current module"""
|
16
|
+
# Your rule implementation here
|
17
|
+
pass
|
18
|
+
```
|
19
|
+
|
20
|
+
## Auto Rules
|
21
|
+
These rules are triggered automatically based on file patterns.
|
22
|
+
|
23
|
+
```cursor
|
24
|
+
# Example auto rule
|
25
|
+
@auto("*.py")
|
26
|
+
def format_python(file):
|
27
|
+
"""Format Python files on save"""
|
28
|
+
# Your rule implementation here
|
29
|
+
pass
|
30
|
+
```
|
31
|
+
|
32
|
+
## Always Rules
|
33
|
+
These rules are always active.
|
34
|
+
|
35
|
+
```cursor
|
36
|
+
# Example always rule
|
37
|
+
@always
|
38
|
+
def maintain_style():
|
39
|
+
"""Maintain code style consistency"""
|
40
|
+
# Your rule implementation here
|
41
|
+
pass
|
42
|
+
```
|
@@ -0,0 +1,59 @@
|
|
1
|
+
---
|
2
|
+
description: ALWAYS use when writing or updating Markdown files to ensure consistent formatting and readability
|
3
|
+
globs: **/*.md
|
4
|
+
alwaysApply: false
|
5
|
+
---
|
6
|
+
|
7
|
+
# Markdown Documentation Standards
|
8
|
+
|
9
|
+
## Context
|
10
|
+
|
11
|
+
- When creating or modifying any Markdown documentation
|
12
|
+
- When establishing documentation structure and style
|
13
|
+
- When including diagrams, code blocks, or special elements in documentation
|
14
|
+
|
15
|
+
## Critical Rules
|
16
|
+
|
17
|
+
- Follow Markdown best practices for formatting
|
18
|
+
- Maintain clear document structure with proper heading hierarchy
|
19
|
+
- Use Mermaid UML diagrams for documenting complex sequences or architecture
|
20
|
+
- Maximum heading depth: 4 levels
|
21
|
+
- Indent content within XML tags by 2 spaces
|
22
|
+
- Code Block need to indicate the language properly after the initial 3 backticks
|
23
|
+
- Keep tables properly aligned
|
24
|
+
|
25
|
+
## Examples
|
26
|
+
|
27
|
+
<example>
|
28
|
+
# Document Title
|
29
|
+
|
30
|
+
## Section Heading
|
31
|
+
|
32
|
+
Content with **bold text** and *italics*.
|
33
|
+
|
34
|
+
```typescript
|
35
|
+
function example(): void {
|
36
|
+
console.log('Hello, Universe!');
|
37
|
+
}
|
38
|
+
```
|
39
|
+
|
40
|
+
| Name | Type | Description |
|
41
|
+
|:-----:|:------:|:------------:|
|
42
|
+
| id | number | Primary key |
|
43
|
+
| name | string | User's name |
|
44
|
+
|
45
|
+
> 💡 **Tip:** Helpful suggestion.
|
46
|
+
</example>
|
47
|
+
|
48
|
+
<example type="invalid">
|
49
|
+
#Incorrect Heading
|
50
|
+
content without proper spacing
|
51
|
+
|
52
|
+
```
|
53
|
+
function withoutLanguageSpecified() {
|
54
|
+
}
|
55
|
+
```
|
56
|
+
|
57
|
+
|No|proper|alignment|And|invalid|table
|
58
|
+
| or | proper | formatting |||||
|
59
|
+
</example>
|
@@ -0,0 +1 @@
|
|
1
|
+
Rules related to documenting files
|