Created
February 26, 2025 11:46
-
-
Save curtis-arch/3371949e844c15df2201259c288e3d7b to your computer and use it in GitHub Desktop.
Cursor Agent Tree Generator - Zero Dependencies Project Structure Visualization
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# save to .scripts/update_structure.sh | |
# Ensure required directory exists | |
mkdir -p .cursor/rules/ | |
# Ensure we're in a git repository | |
if ! git rev-parse --is-inside-work-tree &> /dev/null; then | |
echo "Error: Not in a git repository. Please run this script from a git repository." | |
exit 1 | |
fi | |
# Function to print a tree-like structure of files and directories | |
print_git_tree() { | |
# Create temporary files for git output and processing | |
local tmp_dir="/tmp" | |
local git_files="${tmp_dir}/git_files_$$_${RANDOM}.txt" | |
# Clean up on exit | |
trap 'rm -f "$git_files"' EXIT | |
# Get all git files and write to output file | |
git ls-files --others --exclude-standard --cached | sort > "$git_files" | |
# Create the output file with header | |
echo "# Project Structure" > .cursor/rules/structure.mdc | |
echo "" >> .cursor/rules/structure.mdc | |
echo "\`\`\`" >> .cursor/rules/structure.mdc | |
echo "." >> .cursor/rules/structure.mdc | |
# Process each path from git | |
local prev_path="" | |
local prev_parts=() | |
while IFS= read -r path; do | |
# Skip if it's a directory (git usually only lists files) | |
if [[ -d "$path" && ! -L "$path" ]]; then continue; fi | |
# Split current path into components | |
IFS='/' read -ra curr_parts <<< "$path" | |
local curr_depth=${#curr_parts[@]} | |
# Build directory structure for this file | |
for ((i=0; i<curr_depth; i++)); do | |
# Skip processing the file itself, we'll handle it separately | |
if [[ $i -eq $((curr_depth-1)) ]]; then | |
continue | |
fi | |
# Construct the partial path up to this component | |
local partial_path="" | |
for ((j=0; j<=i; j++)); do | |
if [[ -n "$partial_path" ]]; then | |
partial_path="$partial_path/${curr_parts[j]}" | |
else | |
partial_path="${curr_parts[j]}" | |
fi | |
done | |
# Check if we've already processed this directory | |
if [[ "$prev_path" == "$partial_path"* ]]; then | |
# Already processed this directory in the previous iteration | |
continue | |
fi | |
# Calculate common prefix with previous path | |
local common=0 | |
if [[ ${#prev_parts[@]} -gt 0 ]]; then | |
for ((k=0; k<i && k<${#prev_parts[@]}; k++)); do | |
if [[ "${curr_parts[k]}" == "${prev_parts[k]}" ]]; then | |
((common++)) | |
else | |
break | |
fi | |
done | |
fi | |
# Determine indent based on common prefix | |
local indent="" | |
for ((k=0; k<i; k++)); do | |
if [[ $k -lt $common ]]; then | |
# Check if this level has more items | |
local has_more=0 | |
local parent_path="" | |
for ((l=0; l<k; l++)); do | |
if [[ -n "$parent_path" ]]; then | |
parent_path="$parent_path/${curr_parts[l]}" | |
else | |
parent_path="${curr_parts[l]}" | |
fi | |
done | |
# If there are more siblings at this level, add vertical line | |
if grep -q "^$parent_path/${curr_parts[k]}/" "$git_files"; then | |
has_more=1 | |
fi | |
if [[ $has_more -eq 1 ]]; then | |
indent="${indent}│ " | |
else | |
indent="${indent} " | |
fi | |
else | |
indent="${indent} " | |
fi | |
done | |
# Determine if this is the last directory at its level | |
local is_last=1 | |
local dir_path="" | |
for ((k=0; k<i; k++)); do | |
if [[ -n "$dir_path" ]]; then | |
dir_path="$dir_path/${curr_parts[k]}" | |
else | |
dir_path="${curr_parts[k]}" | |
fi | |
done | |
# Check if there are more directories at this level | |
if grep -q "^$dir_path/${curr_parts[i]}/" "$git_files"; then | |
is_last=0 | |
fi | |
# Choose connector | |
local connector="├── " | |
if [[ $is_last -eq 1 ]]; then | |
connector="└── " | |
fi | |
# Output the directory | |
echo "${indent}${connector}${curr_parts[i]}/" >> .cursor/rules/structure.mdc | |
done | |
# Now output the file itself | |
local file_indent="" | |
for ((i=0; i<curr_depth-1; i++)); do | |
file_indent="${file_indent} " | |
done | |
# Determine if this is the last file in its directory | |
local parent_dir="" | |
for ((i=0; i<curr_depth-1; i++)); do | |
if [[ -n "$parent_dir" ]]; then | |
parent_dir="$parent_dir/${curr_parts[i]}" | |
else | |
parent_dir="${curr_parts[i]}" | |
fi | |
done | |
# Check if there are more files in this directory | |
local is_last_file=1 | |
while IFS= read -r next_file; do | |
if [[ "$next_file" > "$path" && "$next_file" == "$parent_dir/"* ]]; then | |
is_last_file=0 | |
break | |
fi | |
done < "$git_files" | |
# Choose connector for file | |
local file_connector="├── " | |
if [[ $is_last_file -eq 1 ]]; then | |
file_connector="└── " | |
fi | |
# Output the file | |
echo "${file_indent}${file_connector}${curr_parts[curr_depth-1]}" >> .cursor/rules/structure.mdc | |
# Remember this path for the next iteration | |
prev_path="$path" | |
prev_parts=("${curr_parts[@]}") | |
done < "$git_files" | |
# Close the code block | |
echo "\`\`\`" >> .cursor/rules/structure.mdc | |
echo "Project structure has been updated in .cursor/rules/structure.mdc" | |
} | |
# Run the tree function | |
print_git_tree |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment