Files
ProjectStructure/.specstory/history/2025-12-19_18-52Z-texture-commonality-folder-structure.md

194 KiB
Raw Blame History

Texture commonality folder structure (2025-12-19 18:52Z)

User

context:@.specstory/history/2025-12-19_17-59Z-texture-folder-commonality-script.md

next issue: let's make sure it scans each folder separately. it goes \textures[Blendfile][Material]

Intra-blendfile commonalities should go to \\textures\[blendfile]\common Inter-blendfile commonalities should go to \\textures\common

sound good?


Agent (model default, mode Plan)

Reviewing the specstory and current implementation to understand the context.


Tool use: **read_file_v2** • Read file: a:\1 Amazon_Active_Projects\3 ProjectStructure\.specstory\history\2025-12-19_17-59Z-texture-folder-commonality-script.md

Tool use: **read_file_v2** • Read file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.bat

Tool use: **read_file_v2** • Read file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1

Reading the specstory file in sections to understand the context:


Tool use: **read_file_v2** • Read file: a:\1 Amazon_Active_Projects\3 ProjectStructure\.specstory\history\2025-12-19_17-59Z-texture-folder-commonality-script.md

Checking the folder structure to understand the layout:


Tool use: **semantic_search_full**

Parameters:

{
  "query": "What is the folder structure for textures with blendfile and material subdirectories?",
  "topK": 10,
  "explanation": ""
}

Result:

{
  "codeResults": [
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\components\\gitignore",
        "range": {
          "startPosition": {},
          "endPosition": {
            "line": 125,
            "column": 7
          }
        },
        "contents": "# Blender Studio Git Management - .gitignore\n\n# Blender auto-save files\n*.blend1\n*.blend2\n*.blend3\n*.blend4\n*.blend5\n*.blend6\n*.blend7\n*.blend8\n*.blend9\n*.blend10\n*.blend11\n*.blend12\n*.blend13\n*.blend14\n*.blend15\n*.blend16\n*.blend17\n*.blend18\n*.blend19\n*.blend20\n*.blend21\n*.blend22\n*.blend23\n*.blend24\n*.blend25\n*.blend26\n*.blend27\n*.blend28\n*.blend29\n*.blend30\n*.blend31\n*.blend32\n\n# Blender cache and temporary files\n*.swp\n*.swo\n*~\n*.tmp\n*.temp\n\n# OS generated files\n.DS_Store\n.DS_Store?\n._*\n.Spotlight-V100\n.Trashes\nehthumbs.db\nThumbs.db\ndesktop.ini\n\n# Editor files\n.vscode/\n.idea/\n*.swp\n*.swo\n*~\n\n# Large media files (uncomment if you want to exclude rendered outputs)\n# *.mp4\n# *.avi\n# *.mov\n# *.png\n# *.jpg\n# *.jpeg\n# *.exr\n# *.hdr\n# *.tiff\n# *.tga\n\n# Audio files (uncomment if excluding)\n# *.wav\n# *.mp3\n# *.aac\n# *.ogg\n\n# Log files\n*.log\n\n# Python cache\n__pycache__/\n*.pyc\n*.pyo\n*.pyd\n.Python\n\n# Node modules (if using any web tools)\nnode_modules/\n\n# Environment files\n.env\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\n# Backup files\n*.bak\n*.backup\n*.old\n\n# Temporary files\ntemp/\ntmp/\ncache/ \n\nRenders/**\n!Renders/_zipped/\n!Renders/_zipped/**\n!Renders/**/\n!Renders/**/*.bat\n!Renders/**/*.log\nseq/\n\n# Premiere\n*.prlock\nAdobe Premiere Pro Video Previews/\nAdobe Premiere Pro Audio Previews/\nAdobe Premiere Pro (Beta) Video Previews/\nAdobe Premiere Pro (Beta) Audio Previews/\nfootage/\nplates/\n\nPr/RnR/",
        "signatures": {},
        "detailedLines": [
          {
            "text": "# Blender Studio Git Management - .gitignore",
            "lineNumber": 1
          },
          {
            "lineNumber": 2
          },
          {
            "text": "# Blender auto-save files",
            "lineNumber": 3
          },
          {
            "text": "*.blend1",
            "lineNumber": 4
          },
          {
            "text": "*.blend2",
            "lineNumber": 5
          },
          {
            "text": "*.blend3",
            "lineNumber": 6
          },
          {
            "text": "*.blend4",
            "lineNumber": 7
          },
          {
            "text": "*.blend5",
            "lineNumber": 8
          },
          {
            "text": "*.blend6",
            "lineNumber": 9
          },
          {
            "text": "*.blend7",
            "lineNumber": 10
          },
          {
            "text": "*.blend8",
            "lineNumber": 11
          },
          {
            "text": "*.blend9",
            "lineNumber": 12
          },
          {
            "text": "*.blend10",
            "lineNumber": 13
          },
          {
            "text": "*.blend11",
            "lineNumber": 14
          },
          {
            "text": "*.blend12",
            "lineNumber": 15
          },
          {
            "text": "*.blend13",
            "lineNumber": 16
          },
          {
            "text": "*.blend14",
            "lineNumber": 17
          },
          {
            "text": "*.blend15",
            "lineNumber": 18
          },
          {
            "text": "*.blend16",
            "lineNumber": 19
          },
          {
            "text": "*.blend17",
            "lineNumber": 20
          },
          {
            "text": "*.blend18",
            "lineNumber": 21
          },
          {
            "text": "*.blend19",
            "lineNumber": 22
          },
          {
            "text": "*.blend20",
            "lineNumber": 23
          },
          {
            "text": "*.blend21",
            "lineNumber": 24
          },
          {
            "text": "*.blend22",
            "lineNumber": 25
          },
          {
            "text": "*.blend23",
            "lineNumber": 26
          },
          {
            "text": "*.blend24",
            "lineNumber": 27
          },
          {
            "text": "*.blend25",
            "lineNumber": 28
          },
          {
            "text": "*.blend26",
            "lineNumber": 29
          },
          {
            "text": "*.blend27",
            "lineNumber": 30
          },
          {
            "text": "*.blend28",
            "lineNumber": 31
          },
          {
            "text": "*.blend29",
            "lineNumber": 32
          },
          {
            "text": "*.blend30",
            "lineNumber": 33
          },
          {
            "text": "*.blend31",
            "lineNumber": 34
          },
          {
            "text": "*.blend32",
            "lineNumber": 35
          },
          {
            "lineNumber": 36
          },
          {
            "text": "# Blender cache and temporary files",
            "lineNumber": 37
          },
          {
            "text": "*.swp",
            "lineNumber": 38
          },
          {
            "text": "*.swo",
            "lineNumber": 39
          },
          {
            "text": "*~",
            "lineNumber": 40
          },
          {
            "text": "*.tmp",
            "lineNumber": 41
          },
          {
            "text": "*.temp",
            "lineNumber": 42
          },
          {
            "lineNumber": 43
          },
          {
            "text": "# OS generated files",
            "lineNumber": 44
          },
          {
            "text": ".DS_Store",
            "lineNumber": 45
          },
          {
            "text": ".DS_Store?",
            "lineNumber": 46
          },
          {
            "text": "._*",
            "lineNumber": 47
          },
          {
            "text": ".Spotlight-V100",
            "lineNumber": 48
          },
          {
            "text": ".Trashes",
            "lineNumber": 49
          },
          {
            "text": "ehthumbs.db",
            "lineNumber": 50
          },
          {
            "text": "Thumbs.db",
            "lineNumber": 51
          },
          {
            "text": "desktop.ini",
            "lineNumber": 52
          },
          {
            "lineNumber": 53
          },
          {
            "text": "# Editor files",
            "lineNumber": 54
          },
          {
            "text": ".vscode/",
            "lineNumber": 55
          },
          {
            "text": ".idea/",
            "lineNumber": 56
          },
          {
            "text": "*.swp",
            "lineNumber": 57
          },
          {
            "text": "*.swo",
            "lineNumber": 58
          },
          {
            "text": "*~",
            "lineNumber": 59
          },
          {
            "lineNumber": 60
          },
          {
            "text": "# Large media files (uncomment if you want to exclude rendered outputs)",
            "lineNumber": 61
          },
          {
            "text": "# *.mp4",
            "lineNumber": 62
          },
          {
            "text": "# *.avi",
            "lineNumber": 63
          },
          {
            "text": "# *.mov",
            "lineNumber": 64
          },
          {
            "text": "# *.png",
            "lineNumber": 65
          },
          {
            "text": "# *.jpg",
            "lineNumber": 66
          },
          {
            "text": "# *.jpeg",
            "lineNumber": 67
          },
          {
            "text": "# *.exr",
            "lineNumber": 68
          },
          {
            "text": "# *.hdr",
            "lineNumber": 69
          },
          {
            "text": "# *.tiff",
            "lineNumber": 70
          },
          {
            "text": "# *.tga",
            "lineNumber": 71
          },
          {
            "lineNumber": 72
          },
          {
            "text": "# Audio files (uncomment if excluding)",
            "lineNumber": 73
          },
          {
            "text": "# *.wav",
            "lineNumber": 74
          },
          {
            "text": "# *.mp3",
            "lineNumber": 75
          },
          {
            "text": "# *.aac",
            "lineNumber": 76
          },
          {
            "text": "# *.ogg",
            "lineNumber": 77
          },
          {
            "lineNumber": 78
          },
          {
            "text": "# Log files",
            "lineNumber": 79
          },
          {
            "text": "*.log",
            "lineNumber": 80
          },
          {
            "lineNumber": 81
          },
          {
            "text": "# Python cache",
            "lineNumber": 82
          },
          {
            "text": "__pycache__/",
            "lineNumber": 83
          },
          {
            "text": "*.pyc",
            "lineNumber": 84
          },
          {
            "text": "*.pyo",
            "lineNumber": 85
          },
          {
            "text": "*.pyd",
            "lineNumber": 86
          },
          {
            "text": ".Python",
            "lineNumber": 87
          },
          {
            "lineNumber": 88
          },
          {
            "text": "# Node modules (if using any web tools)",
            "lineNumber": 89
          },
          {
            "text": "node_modules/",
            "lineNumber": 90
          },
          {
            "lineNumber": 91
          },
          {
            "text": "# Environment files",
            "lineNumber": 92
          },
          {
            "text": ".env",
            "lineNumber": 93
          },
          {
            "text": ".env.local",
            "lineNumber": 94
          },
          {
            "text": ".env.development.local",
            "lineNumber": 95
          },
          {
            "text": ".env.test.local",
            "lineNumber": 96
          },
          {
            "text": ".env.production.local",
            "lineNumber": 97
          },
          {
            "lineNumber": 98
          },
          {
            "text": "# Backup files",
            "lineNumber": 99
          },
          {
            "text": "*.bak",
            "lineNumber": 100
          },
          {
            "text": "*.backup",
            "lineNumber": 101
          },
          {
            "text": "*.old",
            "lineNumber": 102
          },
          {
            "lineNumber": 103
          },
          {
            "text": "# Temporary files",
            "lineNumber": 104
          },
          {
            "text": "temp/",
            "lineNumber": 105
          },
          {
            "text": "tmp/",
            "lineNumber": 106
          },
          {
            "text": "cache/ ",
            "lineNumber": 107
          },
          {
            "lineNumber": 108
          },
          {
            "text": "Renders/**",
            "lineNumber": 109
          },
          {
            "text": "!Renders/_zipped/",
            "lineNumber": 110
          },
          {
            "text": "!Renders/_zipped/**",
            "lineNumber": 111
          },
          {
            "text": "!Renders/**/",
            "lineNumber": 112
          },
          {
            "text": "!Renders/**/*.bat",
            "lineNumber": 113
          },
          {
            "text": "!Renders/**/*.log",
            "lineNumber": 114
          },
          {
            "text": "seq/",
            "lineNumber": 115
          },
          {
            "lineNumber": 116
          },
          {
            "text": "# Premiere",
            "lineNumber": 117
          },
          {
            "text": "*.prlock",
            "lineNumber": 118
          },
          {
            "text": "Adobe Premiere Pro Video Previews/",
            "lineNumber": 119
          },
          {
            "text": "Adobe Premiere Pro Audio Previews/",
            "lineNumber": 120
          },
          {
            "text": "Adobe Premiere Pro (Beta) Video Previews/",
            "lineNumber": 121
          },
          {
            "text": "Adobe Premiere Pro (Beta) Audio Previews/",
            "lineNumber": 122
          },
          {
            "text": "footage/",
            "lineNumber": 123
          },
          {
            "text": "plates/",
            "lineNumber": 124
          },
          {
            "lineNumber": 125
          },
          {
            "text": "Pr/RnR/",
            "lineNumber": 126
          }
        ]
      },
      "score": 0.354219913482666
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\NewProject.bat",
        "range": {
          "startPosition": {},
          "endPosition": {
            "line": 63
          }
        },
        "contents": "@echo off\nsetlocal EnableExtensions\n\nset \"SCRIPT_DIR=%~dp0\"\nset \"CONFIG_LOADER=%SCRIPT_DIR%ConfigLoader.ps1\"\nset \"CONFIG_PATH=%SCRIPT_DIR%config.json\"\n\nif not exist \"%CONFIG_LOADER%\" (\n    echo [ERROR] ConfigLoader.ps1 not found next to NewProject.bat.\n    exit /b 1\n)\n\nif not exist \"%CONFIG_PATH%\" (\n    echo [ERROR] config.json not found next to NewProject.bat.\n    exit /b 1\n)\n\nfor /f \"usebackq delims=\" %%I in (`powershell -NoProfile -ExecutionPolicy Bypass -Command ^\n    \"Set-StrictMode -Version Latest; $loader = Resolve-Path -LiteralPath '%CONFIG_LOADER%' -ErrorAction Stop; . $loader.Path; Write-Output (Get-StructDirectory)\"`) do set \"STRUCT_DIR=%%I\"\n\nif not defined STRUCT_DIR (\n    echo [ERROR] Unable to resolve ProjectStructure directory from config.\n    exit /b 1\n)\n\n:: Get current date in YYYY-MM-DD format\nfor /f \"tokens=2-4 delims=/ \" %%a in ('date /t') do (\n    set mm=%%a\n    set dd=%%b\n    set yy=%%c\n)\nset yyyy=20%yy:~-2%\nset yymmdd=%yy:~-2%%mm%%dd%\n\n:: Ask for project name\nset /p projectName=\"Enter project name (press Enter for default 'NewProject'): \"\nif \"%projectName%\"==\"\" set projectName=NewProject\nset projectRoot=%yymmdd%_%projectName%\n\n:: Create main project directory\nmkdir \"%projectRoot%\"\n\n:: Create Assets structure\nmkdir \"%projectRoot%\\Assets\\ElevenLabs\"\nif exist \"%STRUCT_DIR%\\NewDaily.bat\" copy /Y \"%STRUCT_DIR%\\NewDaily.bat\" \"%projectRoot%\\Assets\\ElevenLabs\\NewDaily.bat\" >nul\nmkdir \"%projectRoot%\\Assets\\Blends\"\nmkdir \"%projectRoot%\\Assets\\Mocap\"\nmkdir \"%projectRoot%\\Assets\\VO\"\nif exist \"%~dp0NewDaily.bat\" copy /Y \"%~dp0NewDaily.bat\" \"%projectRoot%\\Assets\\VO\\NewDaily.bat\" >nul\n\n:: Create Blends structure\nmkdir \"%projectRoot%\\Blends\\animations\\\"\nmkdir \"%projectRoot%\\Blends\\stills\\img-BG\"\n\n:: Create Deliverable structure\nmkdir \"%projectRoot%\\Deliverable\\\"\n\n:: Create Pr structure\nmkdir \"%projectRoot%\\Pr\\RnR\\RIFE\"\n\n:: Add project root additions\nif not exist \"%projectRoot%\\Renders\" mkdir \"%projectRoot%\\Renders\"",
        "signatures": {},
        "detailedLines": [
          {
            "text": "@echo off",
            "lineNumber": 1
          },
          {
            "text": "setlocal EnableExtensions",
            "lineNumber": 2
          },
          {
            "lineNumber": 3
          },
          {
            "text": "set \"SCRIPT_DIR=%~dp0\"",
            "lineNumber": 4
          },
          {
            "text": "set \"CONFIG_LOADER=%SCRIPT_DIR%ConfigLoader.ps1\"",
            "lineNumber": 5
          },
          {
            "text": "set \"CONFIG_PATH=%SCRIPT_DIR%config.json\"",
            "lineNumber": 6
          },
          {
            "lineNumber": 7
          },
          {
            "text": "if not exist \"%CONFIG_LOADER%\" (",
            "lineNumber": 8
          },
          {
            "text": "    echo [ERROR] ConfigLoader.ps1 not found next to NewProject.bat.",
            "lineNumber": 9
          },
          {
            "text": "    exit /b 1",
            "lineNumber": 10
          },
          {
            "text": ")",
            "lineNumber": 11
          },
          {
            "lineNumber": 12
          },
          {
            "text": "if not exist \"%CONFIG_PATH%\" (",
            "lineNumber": 13
          },
          {
            "text": "    echo [ERROR] config.json not found next to NewProject.bat.",
            "lineNumber": 14
          },
          {
            "text": "    exit /b 1",
            "lineNumber": 15
          },
          {
            "text": ")",
            "lineNumber": 16
          },
          {
            "lineNumber": 17
          },
          {
            "text": "for /f \"usebackq delims=\" %%I in (`powershell -NoProfile -ExecutionPolicy Bypass -Command ^",
            "lineNumber": 18
          },
          {
            "text": "    \"Set-StrictMode -Version Latest; $loader = Resolve-Path -LiteralPath '%CONFIG_LOADER%' -ErrorAction Stop; . $loader.Path; Write-Output (Get-StructDirectory)\"`) do set \"STRUCT_DIR=%%I\"",
            "lineNumber": 19
          },
          {
            "lineNumber": 20
          },
          {
            "text": "if not defined STRUCT_DIR (",
            "lineNumber": 21
          },
          {
            "text": "    echo [ERROR] Unable to resolve ProjectStructure directory from config.",
            "lineNumber": 22
          },
          {
            "text": "    exit /b 1",
            "lineNumber": 23
          },
          {
            "text": ")",
            "lineNumber": 24
          },
          {
            "lineNumber": 25
          },
          {
            "text": ":: Get current date in YYYY-MM-DD format",
            "lineNumber": 26
          },
          {
            "text": "for /f \"tokens=2-4 delims=/ \" %%a in ('date /t') do (",
            "lineNumber": 27
          },
          {
            "text": "    set mm=%%a",
            "lineNumber": 28
          },
          {
            "text": "    set dd=%%b",
            "lineNumber": 29
          },
          {
            "text": "    set yy=%%c",
            "lineNumber": 30
          },
          {
            "text": ")",
            "lineNumber": 31
          },
          {
            "text": "set yyyy=20%yy:~-2%",
            "lineNumber": 32
          },
          {
            "text": "set yymmdd=%yy:~-2%%mm%%dd%",
            "lineNumber": 33
          },
          {
            "lineNumber": 34
          },
          {
            "text": ":: Ask for project name",
            "lineNumber": 35
          },
          {
            "text": "set /p projectName=\"Enter project name (press Enter for default 'NewProject'): \"",
            "lineNumber": 36
          },
          {
            "text": "if \"%projectName%\"==\"\" set projectName=NewProject",
            "lineNumber": 37
          },
          {
            "text": "set projectRoot=%yymmdd%_%projectName%",
            "lineNumber": 38
          },
          {
            "lineNumber": 39
          },
          {
            "text": ":: Create main project directory",
            "lineNumber": 40
          },
          {
            "text": "mkdir \"%projectRoot%\"",
            "lineNumber": 41
          },
          {
            "lineNumber": 42
          },
          {
            "text": ":: Create Assets structure",
            "lineNumber": 43
          },
          {
            "text": "mkdir \"%projectRoot%\\Assets\\ElevenLabs\"",
            "lineNumber": 44
          },
          {
            "text": "if exist \"%STRUCT_DIR%\\NewDaily.bat\" copy /Y \"%STRUCT_DIR%\\NewDaily.bat\" \"%projectRoot%\\Assets\\ElevenLabs\\NewDaily.bat\" >nul",
            "lineNumber": 45
          },
          {
            "text": "mkdir \"%projectRoot%\\Assets\\Blends\"",
            "lineNumber": 46
          },
          {
            "text": "mkdir \"%projectRoot%\\Assets\\Mocap\"",
            "lineNumber": 47
          },
          {
            "text": "mkdir \"%projectRoot%\\Assets\\VO\"",
            "lineNumber": 48
          },
          {
            "text": "if exist \"%~dp0NewDaily.bat\" copy /Y \"%~dp0NewDaily.bat\" \"%projectRoot%\\Assets\\VO\\NewDaily.bat\" >nul",
            "lineNumber": 49
          },
          {
            "lineNumber": 50
          },
          {
            "text": ":: Create Blends structure",
            "lineNumber": 51
          },
          {
            "text": "mkdir \"%projectRoot%\\Blends\\animations\\\"",
            "lineNumber": 52
          },
          {
            "text": "mkdir \"%projectRoot%\\Blends\\stills\\img-BG\"",
            "lineNumber": 53
          },
          {
            "lineNumber": 54
          },
          {
            "text": ":: Create Deliverable structure",
            "lineNumber": 55
          },
          {
            "text": "mkdir \"%projectRoot%\\Deliverable\\\"",
            "lineNumber": 56
          },
          {
            "lineNumber": 57
          },
          {
            "text": ":: Create Pr structure",
            "lineNumber": 58
          },
          {
            "text": "mkdir \"%projectRoot%\\Pr\\RnR\\RIFE\"",
            "lineNumber": 59
          },
          {
            "lineNumber": 60
          },
          {
            "text": ":: Add project root additions",
            "lineNumber": 61
          },
          {
            "text": "if not exist \"%projectRoot%\\Renders\" mkdir \"%projectRoot%\\Renders\"",
            "lineNumber": 62
          }
        ]
      },
      "score": 0.3472631871700287
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\components\\gitattributes",
        "range": {
          "startPosition": {},
          "endPosition": {
            "line": 53
          }
        },
        "contents": "# Git LFS attributes configuration\n# All listed file types will be tracked by Git LFS\n\n# Video files\n*.avi filter=lfs diff=lfs merge=lfs -text\n*.mkv filter=lfs diff=lfs merge=lfs -text\n*.mov filter=lfs diff=lfs merge=lfs -text\n*.MOV filter=lfs diff=lfs merge=lfs -text\n*.mp4 filter=lfs diff=lfs merge=lfs -text\n*.webm filter=lfs diff=lfs merge=lfs -text\n\n# Image files\n*.bmp filter=lfs diff=lfs merge=lfs -text\n*.exr filter=lfs diff=lfs merge=lfs -text\n*.gif filter=lfs diff=lfs merge=lfs -text\n*.hdr filter=lfs diff=lfs merge=lfs -text\n*.jpg filter=lfs diff=lfs merge=lfs -text\n*.jpeg filter=lfs diff=lfs merge=lfs -text\n*.png filter=lfs diff=lfs merge=lfs -text\n*.tga filter=lfs diff=lfs merge=lfs -text\n*.tif filter=lfs diff=lfs merge=lfs -text\n*.tiff filter=lfs diff=lfs merge=lfs -text\n*.webp filter=lfs diff=lfs merge=lfs -text\n\n# 3D/CG files\n*.3ds filter=lfs diff=lfs merge=lfs -text\n*.abc filter=lfs diff=lfs merge=lfs -text\n*.blend filter=lfs diff=lfs merge=lfs -text\n*.blend1 filter=lfs diff=lfs merge=lfs -text\n*.blend2 filter=lfs diff=lfs merge=lfs -text\n*.bvh filter=lfs diff=lfs merge=lfs -text\n*.bvh.gz filter=lfs diff=lfs merge=lfs -text\n*.c4d filter=lfs diff=lfs merge=lfs -text\n*.dae filter=lfs diff=lfs merge=lfs -text\n*.fbx filter=lfs diff=lfs merge=lfs -text\n*.fbxkey filter=lfs diff=lfs merge=lfs -text\n*.ma filter=lfs diff=lfs merge=lfs -text\n*.max filter=lfs diff=lfs merge=lfs -text\n*.mb filter=lfs diff=lfs merge=lfs -text\n*.obj filter=lfs diff=lfs merge=lfs -text\n*.usd filter=lfs diff=lfs merge=lfs -text\n*.usdz filter=lfs diff=lfs merge=lfs -text\n*.vdb filter=lfs diff=lfs merge=lfs -text\n*.bphys filter=lfs diff=lfs merge=lfs -text\n*.bobj filter=lfs diff=lfs merge=lfs -text\n*.bvel filter=lfs diff=lfs merge=lfs -text\n*.bpointcache filter=lfs diff=lfs merge=lfs -text\n*.blob filter=lfs diff=lfs merge=lfs -text\n*.unitypackage filter=lfs diff=lfs merge=lfs -text\n\n# Houdini files\n*.hiplc filter=lfs diff=lfs merge=lfs -text\n*.bgeo filter=lfs diff=lfs merge=lfs -text",
        "signatures": {},
        "detailedLines": [
          {
            "text": "# Git LFS attributes configuration",
            "lineNumber": 1
          },
          {
            "text": "# All listed file types will be tracked by Git LFS",
            "lineNumber": 2
          },
          {
            "lineNumber": 3
          },
          {
            "text": "# Video files",
            "lineNumber": 4
          },
          {
            "text": "*.avi filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 5
          },
          {
            "text": "*.mkv filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 6
          },
          {
            "text": "*.mov filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 7
          },
          {
            "text": "*.MOV filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 8
          },
          {
            "text": "*.mp4 filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 9
          },
          {
            "text": "*.webm filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 10
          },
          {
            "lineNumber": 11
          },
          {
            "text": "# Image files",
            "lineNumber": 12
          },
          {
            "text": "*.bmp filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 13
          },
          {
            "text": "*.exr filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 14
          },
          {
            "text": "*.gif filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 15
          },
          {
            "text": "*.hdr filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 16
          },
          {
            "text": "*.jpg filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 17
          },
          {
            "text": "*.jpeg filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 18
          },
          {
            "text": "*.png filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 19
          },
          {
            "text": "*.tga filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 20
          },
          {
            "text": "*.tif filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 21
          },
          {
            "text": "*.tiff filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 22
          },
          {
            "text": "*.webp filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 23
          },
          {
            "lineNumber": 24
          },
          {
            "text": "# 3D/CG files",
            "lineNumber": 25
          },
          {
            "text": "*.3ds filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 26
          },
          {
            "text": "*.abc filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 27
          },
          {
            "text": "*.blend filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 28
          },
          {
            "text": "*.blend1 filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 29
          },
          {
            "text": "*.blend2 filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 30
          },
          {
            "text": "*.bvh filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 31
          },
          {
            "text": "*.bvh.gz filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 32
          },
          {
            "text": "*.c4d filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 33
          },
          {
            "text": "*.dae filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 34
          },
          {
            "text": "*.fbx filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 35
          },
          {
            "text": "*.fbxkey filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 36
          },
          {
            "text": "*.ma filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 37
          },
          {
            "text": "*.max filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 38
          },
          {
            "text": "*.mb filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 39
          },
          {
            "text": "*.obj filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 40
          },
          {
            "text": "*.usd filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 41
          },
          {
            "text": "*.usdz filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 42
          },
          {
            "text": "*.vdb filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 43
          },
          {
            "text": "*.bphys filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 44
          },
          {
            "text": "*.bobj filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 45
          },
          {
            "text": "*.bvel filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 46
          },
          {
            "text": "*.bpointcache filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 47
          },
          {
            "text": "*.blob filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 48
          },
          {
            "text": "*.unitypackage filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 49
          },
          {
            "lineNumber": 50
          },
          {
            "text": "# Houdini files",
            "lineNumber": 51
          },
          {
            "text": "*.hiplc filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 52
          },
          {
            "text": "*.bgeo filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 53
          }
        ]
      },
      "score": 0.3170698881149292
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\organize_textures.ps1",
        "range": {
          "startPosition": {},
          "endPosition": {
            "line": 51
          }
        },
        "contents": "# Script to organize texture files by checksum, moving all files to \\common and duplicates to \\common\\duplicates\n# Usage: .\\organize_textures.ps1\n\n# Prompt user for texture folder path\n$textureFolderPath = Read-Host \"Enter texture folder path\"\n\n# Validate the input path\nif ([string]::IsNullOrWhiteSpace($textureFolderPath)) {\n    Write-Host \"Error: No path provided.\" -ForegroundColor Red\n    exit\n}\n\nif (-not (Test-Path -Path $textureFolderPath -PathType Container)) {\n    Write-Host \"Error: Path does not exist or is not a directory: $textureFolderPath\" -ForegroundColor Red\n    exit\n}\n\n# Resolve the full path\n$textureFolderPath = (Resolve-Path $textureFolderPath).ProviderPath\nWrite-Host \"Processing texture folder: $textureFolderPath\" -ForegroundColor Cyan\n\n# Get all files recursively, excluding the \\common folder to avoid processing already-moved files\nWrite-Host \"Collecting files...\" -ForegroundColor Yellow\n$allFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { $_.FullName -notlike \"*\\common\\*\" }\n\nif ($null -eq $allFiles -or $allFiles.Count -eq 0) {\n    Write-Host \"No files found to process (excluding \\common folder).\" -ForegroundColor Yellow\n    exit\n}\n\nWrite-Host \"Found $($allFiles.Count) files to process.\" -ForegroundColor Green\n\n# Calculate checksums for all files using parallel processing\nWrite-Host \"Calculating checksums using parallel processing (this may take a while)...\" -ForegroundColor Yellow\n$throttleLimit = [Math]::Max(1, [Environment]::ProcessorCount)\n$parallelScriptBlock = {\n    try {\n        $hash = Get-FileHash -Path $_.FullName -Algorithm SHA256\n        [PSCustomObject]@{\n            File = $_\n            Hash = $hash.Hash\n        }\n    } catch {\n        Write-Warning \"Failed to calculate checksum for: $($_.FullName) - $($_.Exception.Message)\"\n        $null\n    }\n}\n$filesWithChecksums = $allFiles | ForEach-Object -Parallel $parallelScriptBlock -ThrottleLimit $throttleLimit | Where-Object { $null -ne $_ }\n\nWrite-Host \"Checksum calculation complete.\" -ForegroundColor Green",
        "signatures": {},
        "detailedLines": [
          {
            "text": "# Script to organize texture files by checksum, moving all files to \\common and duplicates to \\common\\duplicates",
            "lineNumber": 1
          },
          {
            "text": "# Usage: .\\organize_textures.ps1",
            "lineNumber": 2
          },
          {
            "lineNumber": 3
          },
          {
            "text": "# Prompt user for texture folder path",
            "lineNumber": 4
          },
          {
            "text": "$textureFolderPath = Read-Host \"Enter texture folder path\"",
            "lineNumber": 5
          },
          {
            "lineNumber": 6
          },
          {
            "text": "# Validate the input path",
            "lineNumber": 7
          },
          {
            "text": "if ([string]::IsNullOrWhiteSpace($textureFolderPath)) {",
            "lineNumber": 8
          },
          {
            "text": "    Write-Host \"Error: No path provided.\" -ForegroundColor Red",
            "lineNumber": 9
          },
          {
            "text": "    exit",
            "lineNumber": 10
          },
          {
            "text": "}",
            "lineNumber": 11
          },
          {
            "lineNumber": 12
          },
          {
            "text": "if (-not (Test-Path -Path $textureFolderPath -PathType Container)) {",
            "lineNumber": 13
          },
          {
            "text": "    Write-Host \"Error: Path does not exist or is not a directory: $textureFolderPath\" -ForegroundColor Red",
            "lineNumber": 14
          },
          {
            "text": "    exit",
            "lineNumber": 15
          },
          {
            "text": "}",
            "lineNumber": 16
          },
          {
            "lineNumber": 17
          },
          {
            "text": "# Resolve the full path",
            "lineNumber": 18
          },
          {
            "text": "$textureFolderPath = (Resolve-Path $textureFolderPath).ProviderPath",
            "lineNumber": 19
          },
          {
            "text": "Write-Host \"Processing texture folder: $textureFolderPath\" -ForegroundColor Cyan",
            "lineNumber": 20
          },
          {
            "lineNumber": 21
          },
          {
            "text": "# Get all files recursively, excluding the \\common folder to avoid processing already-moved files",
            "lineNumber": 22
          },
          {
            "text": "Write-Host \"Collecting files...\" -ForegroundColor Yellow",
            "lineNumber": 23
          },
          {
            "text": "$allFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { $_.FullName -notlike \"*\\common\\*\" }",
            "lineNumber": 24
          },
          {
            "lineNumber": 25
          },
          {
            "text": "if ($null -eq $allFiles -or $allFiles.Count -eq 0) {",
            "lineNumber": 26
          },
          {
            "text": "    Write-Host \"No files found to process (excluding \\common folder).\" -ForegroundColor Yellow",
            "lineNumber": 27
          },
          {
            "text": "    exit",
            "lineNumber": 28
          },
          {
            "text": "}",
            "lineNumber": 29
          },
          {
            "lineNumber": 30
          },
          {
            "text": "Write-Host \"Found $($allFiles.Count) files to process.\" -ForegroundColor Green",
            "lineNumber": 31
          },
          {
            "lineNumber": 32
          },
          {
            "text": "# Calculate checksums for all files using parallel processing",
            "lineNumber": 33
          },
          {
            "text": "Write-Host \"Calculating checksums using parallel processing (this may take a while)...\" -ForegroundColor Yellow",
            "lineNumber": 34
          },
          {
            "text": "$throttleLimit = [Math]::Max(1, [Environment]::ProcessorCount)",
            "lineNumber": 35
          },
          {
            "text": "$parallelScriptBlock = {",
            "lineNumber": 36
          },
          {
            "text": "    try {",
            "lineNumber": 37
          },
          {
            "text": "        $hash = Get-FileHash -Path $_.FullName -Algorithm SHA256",
            "lineNumber": 38
          },
          {
            "text": "        [PSCustomObject]@{",
            "lineNumber": 39
          },
          {
            "text": "            File = $_",
            "lineNumber": 40
          },
          {
            "text": "            Hash = $hash.Hash",
            "lineNumber": 41
          },
          {
            "text": "        }",
            "lineNumber": 42
          },
          {
            "text": "    } catch {",
            "lineNumber": 43
          },
          {
            "text": "        Write-Warning \"Failed to calculate checksum for: $($_.FullName) - $($_.Exception.Message)\"",
            "lineNumber": 44
          },
          {
            "text": "        $null",
            "lineNumber": 45
          },
          {
            "text": "    }",
            "lineNumber": 46
          },
          {
            "text": "}",
            "lineNumber": 47
          },
          {
            "text": "$filesWithChecksums = $allFiles | ForEach-Object -Parallel $parallelScriptBlock -ThrottleLimit $throttleLimit | Where-Object { $null -ne $_ }",
            "lineNumber": 48
          },
          {
            "lineNumber": 49
          },
          {
            "text": "Write-Host \"Checksum calculation complete.\" -ForegroundColor Green",
            "lineNumber": 50
          }
        ]
      },
      "score": 0.3156466484069824
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\replace_cel_with_bsdf.py",
        "range": {
          "startPosition": {},
          "endPosition": {
            "line": 106
          }
        },
        "contents": "import bpy\nimport re\nimport os\n\ndef link_bsdf_materials():\n    \"\"\"Link all materials from the BSDF library file\"\"\"\n    \n    library_path = r\"R:\\Creative\\artsy\\maya\\0 ProjectStructure\\1 BlenderAssets\\Amazon\\MATERIALS_BSDF_pallette_v1.0.blend\"\n    \n    if not os.path.exists(library_path):\n        print(f\"Warning: Library file not found at {library_path}\")\n        return []\n    \n    print(f\"Linking materials from: {library_path}\")\n    \n    # Get list of materials before linking\n    materials_before = set(bpy.data.materials.keys())\n    \n    # Link all materials from the library file\n    with bpy.data.libraries.load(library_path, link=True) as (data_from, data_to):\n        # Link all materials\n        data_to.materials = data_from.materials\n    \n    # Get list of newly linked materials\n    materials_after = set(bpy.data.materials.keys())\n    newly_linked = materials_after - materials_before\n    \n    print(f\"Linked {len(newly_linked)} materials from library\")\n    for mat_name in sorted(newly_linked):\n        print(f\"  - {mat_name}\")\n    \n    return list(newly_linked)\n\ndef remap_appended_to_linked():\n    \"\"\"Remap any appended BSDF materials to their linked counterparts\"\"\"",
        "signatures": {},
        "detailedLines": [
          {
            "text": "import bpy",
            "lineNumber": 1
          },
          {
            "text": "import re",
            "lineNumber": 2
          },
          {
            "text": "import os",
            "lineNumber": 3
          },
          {
            "lineNumber": 4
          },
          {
            "text": "def link_bsdf_materials():",
            "lineNumber": 5,
            "isSignature": true
          },
          {
            "text": "    \"\"\"Link all materials from the BSDF library file\"\"\"",
            "lineNumber": 6
          },
          {
            "text": "    ",
            "lineNumber": 7
          },
          {
            "text": "    library_path = r\"R:\\Creative\\artsy\\maya\\0 ProjectStructure\\1 BlenderAssets\\Amazon\\MATERIALS_BSDF_pallette_v1.0.blend\"",
            "lineNumber": 8
          },
          {
            "text": "    ",
            "lineNumber": 9
          },
          {
            "text": "    if not os.path.exists(library_path):",
            "lineNumber": 10
          },
          {
            "text": "        print(f\"Warning: Library file not found at {library_path}\")",
            "lineNumber": 11
          },
          {
            "text": "        return []",
            "lineNumber": 12
          },
          {
            "text": "    ",
            "lineNumber": 13
          },
          {
            "text": "    print(f\"Linking materials from: {library_path}\")",
            "lineNumber": 14
          },
          {
            "text": "    ",
            "lineNumber": 15
          },
          {
            "text": "    # Get list of materials before linking",
            "lineNumber": 16
          },
          {
            "text": "    materials_before = set(bpy.data.materials.keys())",
            "lineNumber": 17
          },
          {
            "text": "    ",
            "lineNumber": 18
          },
          {
            "text": "    # Link all materials from the library file",
            "lineNumber": 19
          },
          {
            "text": "    with bpy.data.libraries.load(library_path, link=True) as (data_from, data_to):",
            "lineNumber": 20
          },
          {
            "text": "        # Link all materials",
            "lineNumber": 21
          },
          {
            "text": "        data_to.materials = data_from.materials",
            "lineNumber": 22
          },
          {
            "text": "    ",
            "lineNumber": 23
          },
          {
            "text": "    # Get list of newly linked materials",
            "lineNumber": 24
          },
          {
            "text": "    materials_after = set(bpy.data.materials.keys())",
            "lineNumber": 25
          },
          {
            "text": "    newly_linked = materials_after - materials_before",
            "lineNumber": 26
          },
          {
            "text": "    ",
            "lineNumber": 27
          },
          {
            "text": "    print(f\"Linked {len(newly_linked)} materials from library\")",
            "lineNumber": 28
          },
          {
            "text": "    for mat_name in sorted(newly_linked):",
            "lineNumber": 29
          },
          {
            "text": "        print(f\"  - {mat_name}\")",
            "lineNumber": 30
          },
          {
            "text": "    ",
            "lineNumber": 31
          },
          {
            "text": "    return list(newly_linked)",
            "lineNumber": 32,
            "isSignature": true
          },
          {
            "lineNumber": 33
          },
          {
            "text": "def remap_appended_to_linked():",
            "lineNumber": 34,
            "isSignature": true
          },
          {
            "text": "    \"\"\"Remap any appended BSDF materials to their linked counterparts\"\"\"",
            "lineNumber": 35
          }
        ]
      },
      "score": 0.30952730774879456
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\UpgradeToGitProj.bat",
        "range": {
          "startPosition": {
            "line": 121
          },
          "endPosition": {
            "line": 166
          }
        },
        "contents": "      )\n    )\n  )\n\n  if \"!foundSubmodules!\"==\"1\" (\n    if \"%DRY%\"==\"1\" echo [DRY] Using submodules under Blends\\animations\n    for /d %%S in (\"%animDir%\\*\") do (\n      set \"name=%%~nS\"\n      set \"prefix=!name:~0,6!\"\n      if /I not \"!prefix!\"==\"daily_\" (\n        set \"submodName=%%~nS\"\n        set \"_subdir=%rendersDir%\\!submodName!\"\n        rem Ensure submodule dir exists and place helper scripts there\n        if \"%DRY%\"==\"1\" (\n          if not exist \"!_subdir!\" echo [DRY] mkdir \"!_subdir!\"\n          if exist \"%scriptDir%UpdateSequences.bat\" echo [DRY] copy \"%scriptDir%UpdateSequences.bat\" \"!_subdir!\\UpdateSequences.bat\"\n          if exist \"%scriptDir%ZipSeqArchv.bat\" echo [DRY] copy \"%scriptDir%ZipSeqArchv.bat\" \"!_subdir!\\ZipSeqArchv.bat\"\n          if exist \"%scriptDir%UnzipSeqArchv.bat\" echo [DRY] copy \"%scriptDir%UnzipSeqArchv.bat\" \"!_subdir!\\UnzipSeqArchv.bat\"\n        ) else (\n          if not exist \"!_subdir!\" mkdir \"!_subdir!\" >nul 2>&1\n          if exist \"%scriptDir%UpdateSequences.bat\" copy /Y \"%scriptDir%UpdateSequences.bat\" \"!_subdir!\\UpdateSequences.bat\" >nul\n          if exist \"%scriptDir%ZipSeqArchv.bat\" copy /Y \"%scriptDir%ZipSeqArchv.bat\" \"!_subdir!\\ZipSeqArchv.bat\" >nul\n          if exist \"%scriptDir%UnzipSeqArchv.bat\" copy /Y \"%scriptDir%UnzipSeqArchv.bat\" \"!_subdir!\\UnzipSeqArchv.bat\" >nul\n        )\n        for /d %%D in (\"%%S\\daily_*\") do (\n          set \"dailyName=%%~nD\"\n          set \"_src=%%D\\seq\"\n          set \"_dst=%rendersDir%\\!submodName!\\!dailyName!\"\n          set /a debugTotal+=1\n          if \"%DRY%\"==\"1\" (\n            if exist \"!_src!\" (\n              echo [DRY] WOULD copy \"!_src!\" -^> \"!_dst!\"\n              set /a debugPlanned+=1\n            ) else (\n              echo [DRY] Skip: missing \"!_src!\"\n              set /a debugMissing+=1\n            )\n          )\n          call :CopySeqToRenders \"!_src!\" \"!_dst!\"\n        )\n      )\n    )\n    set \"foundAny=1\"\n  ) else (\n    if \"%DRY%\"==\"1\" echo [DRY] No submodules found; using direct daily_* under animations",
        "signatures": {},
        "detailedLines": [
          {
            "text": "      )",
            "lineNumber": 122
          },
          {
            "text": "    )",
            "lineNumber": 123
          },
          {
            "text": "  )",
            "lineNumber": 124
          },
          {
            "lineNumber": 125
          },
          {
            "text": "  if \"!foundSubmodules!\"==\"1\" (",
            "lineNumber": 126
          },
          {
            "text": "    if \"%DRY%\"==\"1\" echo [DRY] Using submodules under Blends\\animations",
            "lineNumber": 127
          },
          {
            "text": "    for /d %%S in (\"%animDir%\\*\") do (",
            "lineNumber": 128
          },
          {
            "text": "      set \"name=%%~nS\"",
            "lineNumber": 129
          },
          {
            "text": "      set \"prefix=!name:~0,6!\"",
            "lineNumber": 130
          },
          {
            "text": "      if /I not \"!prefix!\"==\"daily_\" (",
            "lineNumber": 131
          },
          {
            "text": "        set \"submodName=%%~nS\"",
            "lineNumber": 132
          },
          {
            "text": "        set \"_subdir=%rendersDir%\\!submodName!\"",
            "lineNumber": 133
          },
          {
            "text": "        rem Ensure submodule dir exists and place helper scripts there",
            "lineNumber": 134
          },
          {
            "text": "        if \"%DRY%\"==\"1\" (",
            "lineNumber": 135
          },
          {
            "text": "          if not exist \"!_subdir!\" echo [DRY] mkdir \"!_subdir!\"",
            "lineNumber": 136
          },
          {
            "text": "          if exist \"%scriptDir%UpdateSequences.bat\" echo [DRY] copy \"%scriptDir%UpdateSequences.bat\" \"!_subdir!\\UpdateSequences.bat\"",
            "lineNumber": 137
          },
          {
            "text": "          if exist \"%scriptDir%ZipSeqArchv.bat\" echo [DRY] copy \"%scriptDir%ZipSeqArchv.bat\" \"!_subdir!\\ZipSeqArchv.bat\"",
            "lineNumber": 138
          },
          {
            "text": "          if exist \"%scriptDir%UnzipSeqArchv.bat\" echo [DRY] copy \"%scriptDir%UnzipSeqArchv.bat\" \"!_subdir!\\UnzipSeqArchv.bat\"",
            "lineNumber": 139
          },
          {
            "text": "        ) else (",
            "lineNumber": 140
          },
          {
            "text": "          if not exist \"!_subdir!\" mkdir \"!_subdir!\" >nul 2>&1",
            "lineNumber": 141
          },
          {
            "text": "          if exist \"%scriptDir%UpdateSequences.bat\" copy /Y \"%scriptDir%UpdateSequences.bat\" \"!_subdir!\\UpdateSequences.bat\" >nul",
            "lineNumber": 142
          },
          {
            "text": "          if exist \"%scriptDir%ZipSeqArchv.bat\" copy /Y \"%scriptDir%ZipSeqArchv.bat\" \"!_subdir!\\ZipSeqArchv.bat\" >nul",
            "lineNumber": 143
          },
          {
            "text": "          if exist \"%scriptDir%UnzipSeqArchv.bat\" copy /Y \"%scriptDir%UnzipSeqArchv.bat\" \"!_subdir!\\UnzipSeqArchv.bat\" >nul",
            "lineNumber": 144
          },
          {
            "text": "        )",
            "lineNumber": 145
          },
          {
            "text": "        for /d %%D in (\"%%S\\daily_*\") do (",
            "lineNumber": 146
          },
          {
            "text": "          set \"dailyName=%%~nD\"",
            "lineNumber": 147
          },
          {
            "text": "          set \"_src=%%D\\seq\"",
            "lineNumber": 148
          },
          {
            "text": "          set \"_dst=%rendersDir%\\!submodName!\\!dailyName!\"",
            "lineNumber": 149
          },
          {
            "text": "          set /a debugTotal+=1",
            "lineNumber": 150
          },
          {
            "text": "          if \"%DRY%\"==\"1\" (",
            "lineNumber": 151
          },
          {
            "text": "            if exist \"!_src!\" (",
            "lineNumber": 152
          },
          {
            "text": "              echo [DRY] WOULD copy \"!_src!\" -^> \"!_dst!\"",
            "lineNumber": 153
          },
          {
            "text": "              set /a debugPlanned+=1",
            "lineNumber": 154
          },
          {
            "text": "            ) else (",
            "lineNumber": 155
          },
          {
            "text": "              echo [DRY] Skip: missing \"!_src!\"",
            "lineNumber": 156
          },
          {
            "text": "              set /a debugMissing+=1",
            "lineNumber": 157
          },
          {
            "text": "            )",
            "lineNumber": 158
          },
          {
            "text": "          )",
            "lineNumber": 159
          },
          {
            "text": "          call :CopySeqToRenders \"!_src!\" \"!_dst!\"",
            "lineNumber": 160
          },
          {
            "text": "        )",
            "lineNumber": 161
          },
          {
            "text": "      )",
            "lineNumber": 162
          },
          {
            "text": "    )",
            "lineNumber": 163
          },
          {
            "text": "    set \"foundAny=1\"",
            "lineNumber": 164
          },
          {
            "text": "  ) else (",
            "lineNumber": 165
          },
          {
            "text": "    if \"%DRY%\"==\"1\" echo [DRY] No submodules found; using direct daily_* under animations",
            "lineNumber": 166
          }
        ]
      },
      "score": 0.2996269464492798
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\UpgradeToGitProj.bat",
        "range": {
          "startPosition": {
            "line": 58
          },
          "endPosition": {
            "line": 126,
            "column": 4
          }
        },
        "contents": "for %%F in (ConfigLoader.ps1 config.json) do (\n  if exist \"%scriptDir%%%F\" (\n    if \"%DRY%\"==\"1\" (\n      echo [DRY] copy \"%scriptDir%%%F\" \"%rendersDir%\\%%F\"\n    ) else (\n      copy /Y \"%scriptDir%%%F\" \"%rendersDir%\\%%F\" >nul\n    )\n  ) else (\n    echo [WARN] Missing template: \"%scriptDir%%%F\"\n  )\n)\n\n:: -----------------------------\n:: Merge .gitignore and .gitattributes from templates\n:: -----------------------------\nset \"tplGitIgnore=%scriptDir%components\\gitignore\"\nset \"dstGitIgnore=%projectDir%\\.gitignore\"\nset \"tplGitAttr=%scriptDir%components\\gitattributes\"\nset \"dstGitAttr=%projectDir%\\.gitattributes\"\n\ncall :MergeTemplate \"%tplGitIgnore%\" \"%dstGitIgnore%\"\ncall :MergeTemplate \"%tplGitAttr%\"   \"%dstGitAttr%\"\n\n:: -----------------------------\n:: Initialize git and Git LFS\n:: -----------------------------\nif not exist \"%projectDir%\\.git\" (\n  if \"%DRY%\"==\"1\" (\n    echo [DRY] git init\n  ) else (\n    pushd \"%projectDir%\" >nul\n    git init\n    popd >nul\n  )\n)\n\nif \"%DRY%\"==\"1\" (\n  echo [DRY] git lfs install\n) else (\n  pushd \"%projectDir%\" >nul\n  git lfs install\n  popd >nul\n)\n\n:: -----------------------------\n:: Collect seq outputs from daily_* into Renders\n:: -----------------------------\nset \"animDir=%projectDir%\\Blends\\animations\"\nset \"foundAny=0\"\nset \"foundSubmodules=0\"\n\nif exist \"%animDir%\" (\n  if \"%DRY%\"==\"1\" echo [DRY] Scanning animations dir: \"%animDir%\"\n  :: Detect submodules: first-level folders under animations that contain daily_*\n  for /d %%S in (\"%animDir%\\*\") do (\n    set \"name=%%~nS\"\n    set \"prefix=!name:~0,6!\"\n    if /I not \"!prefix!\"==\"daily_\" (\n      for /d %%D in (\"%%S\\daily_*\") do (\n        set \"foundSubmodules=1\"\n      )\n      if \"%DRY%\"==\"1\" (\n        if exist \"%%S\\daily_*\" echo [DRY] Detected submodule: \"%%~nS\"\n      )\n    )\n  )\n\n  if \"!foundSubmodules!\"==\"1\" (\n    ",
        "signatures": {},
        "detailedLines": [
          {
            "text": "for %%F in (ConfigLoader.ps1 config.json) do (",
            "lineNumber": 59
          },
          {
            "text": "  if exist \"%scriptDir%%%F\" (",
            "lineNumber": 60
          },
          {
            "text": "    if \"%DRY%\"==\"1\" (",
            "lineNumber": 61
          },
          {
            "text": "      echo [DRY] copy \"%scriptDir%%%F\" \"%rendersDir%\\%%F\"",
            "lineNumber": 62
          },
          {
            "text": "    ) else (",
            "lineNumber": 63
          },
          {
            "text": "      copy /Y \"%scriptDir%%%F\" \"%rendersDir%\\%%F\" >nul",
            "lineNumber": 64
          },
          {
            "text": "    )",
            "lineNumber": 65
          },
          {
            "text": "  ) else (",
            "lineNumber": 66
          },
          {
            "text": "    echo [WARN] Missing template: \"%scriptDir%%%F\"",
            "lineNumber": 67
          },
          {
            "text": "  )",
            "lineNumber": 68
          },
          {
            "text": ")",
            "lineNumber": 69
          },
          {
            "lineNumber": 70
          },
          {
            "text": ":: -----------------------------",
            "lineNumber": 71
          },
          {
            "text": ":: Merge .gitignore and .gitattributes from templates",
            "lineNumber": 72
          },
          {
            "text": ":: -----------------------------",
            "lineNumber": 73
          },
          {
            "text": "set \"tplGitIgnore=%scriptDir%components\\gitignore\"",
            "lineNumber": 74
          },
          {
            "text": "set \"dstGitIgnore=%projectDir%\\.gitignore\"",
            "lineNumber": 75
          },
          {
            "text": "set \"tplGitAttr=%scriptDir%components\\gitattributes\"",
            "lineNumber": 76
          },
          {
            "text": "set \"dstGitAttr=%projectDir%\\.gitattributes\"",
            "lineNumber": 77
          },
          {
            "lineNumber": 78
          },
          {
            "text": "call :MergeTemplate \"%tplGitIgnore%\" \"%dstGitIgnore%\"",
            "lineNumber": 79
          },
          {
            "text": "call :MergeTemplate \"%tplGitAttr%\"   \"%dstGitAttr%\"",
            "lineNumber": 80
          },
          {
            "lineNumber": 81
          },
          {
            "text": ":: -----------------------------",
            "lineNumber": 82
          },
          {
            "text": ":: Initialize git and Git LFS",
            "lineNumber": 83
          },
          {
            "text": ":: -----------------------------",
            "lineNumber": 84
          },
          {
            "text": "if not exist \"%projectDir%\\.git\" (",
            "lineNumber": 85
          },
          {
            "text": "  if \"%DRY%\"==\"1\" (",
            "lineNumber": 86
          },
          {
            "text": "    echo [DRY] git init",
            "lineNumber": 87
          },
          {
            "text": "  ) else (",
            "lineNumber": 88
          },
          {
            "text": "    pushd \"%projectDir%\" >nul",
            "lineNumber": 89
          },
          {
            "text": "    git init",
            "lineNumber": 90
          },
          {
            "text": "    popd >nul",
            "lineNumber": 91
          },
          {
            "text": "  )",
            "lineNumber": 92
          },
          {
            "text": ")",
            "lineNumber": 93
          },
          {
            "lineNumber": 94
          },
          {
            "text": "if \"%DRY%\"==\"1\" (",
            "lineNumber": 95
          },
          {
            "text": "  echo [DRY] git lfs install",
            "lineNumber": 96
          },
          {
            "text": ") else (",
            "lineNumber": 97
          },
          {
            "text": "  pushd \"%projectDir%\" >nul",
            "lineNumber": 98
          },
          {
            "text": "  git lfs install",
            "lineNumber": 99
          },
          {
            "text": "  popd >nul",
            "lineNumber": 100
          },
          {
            "text": ")",
            "lineNumber": 101
          },
          {
            "lineNumber": 102
          },
          {
            "text": ":: -----------------------------",
            "lineNumber": 103
          },
          {
            "text": ":: Collect seq outputs from daily_* into Renders",
            "lineNumber": 104
          },
          {
            "text": ":: -----------------------------",
            "lineNumber": 105
          },
          {
            "text": "set \"animDir=%projectDir%\\Blends\\animations\"",
            "lineNumber": 106
          },
          {
            "text": "set \"foundAny=0\"",
            "lineNumber": 107
          },
          {
            "text": "set \"foundSubmodules=0\"",
            "lineNumber": 108
          },
          {
            "lineNumber": 109
          },
          {
            "text": "if exist \"%animDir%\" (",
            "lineNumber": 110
          },
          {
            "text": "  if \"%DRY%\"==\"1\" echo [DRY] Scanning animations dir: \"%animDir%\"",
            "lineNumber": 111
          },
          {
            "text": "  :: Detect submodules: first-level folders under animations that contain daily_*",
            "lineNumber": 112
          },
          {
            "text": "  for /d %%S in (\"%animDir%\\*\") do (",
            "lineNumber": 113
          },
          {
            "text": "    set \"name=%%~nS\"",
            "lineNumber": 114
          },
          {
            "text": "    set \"prefix=!name:~0,6!\"",
            "lineNumber": 115
          },
          {
            "text": "    if /I not \"!prefix!\"==\"daily_\" (",
            "lineNumber": 116
          },
          {
            "text": "      for /d %%D in (\"%%S\\daily_*\") do (",
            "lineNumber": 117
          },
          {
            "text": "        set \"foundSubmodules=1\"",
            "lineNumber": 118
          },
          {
            "text": "      )",
            "lineNumber": 119
          },
          {
            "text": "      if \"%DRY%\"==\"1\" (",
            "lineNumber": 120
          },
          {
            "text": "        if exist \"%%S\\daily_*\" echo [DRY] Detected submodule: \"%%~nS\"",
            "lineNumber": 121
          },
          {
            "text": "      )",
            "lineNumber": 122
          },
          {
            "text": "    )",
            "lineNumber": 123
          },
          {
            "text": "  )",
            "lineNumber": 124
          },
          {
            "lineNumber": 125
          },
          {
            "text": "  if \"!foundSubmodules!\"==\"1\" (",
            "lineNumber": 126
          },
          {
            "text": "    ",
            "lineNumber": 127
          }
        ]
      },
      "score": 0.29278281331062317
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\replace_cel_with_bsdf.py",
        "range": {
          "startPosition": {
            "line": 186,
            "column": 26
          },
          "endPosition": {
            "line": 355
          }
        },
        "contents": "def replace_cel_materials():\n    \"\"\"Replace all CEL materials with their BSDF counterparts using Blender's user remapping\"\"\"\n    \n    # First, link BSDF materials from library\n    linked_materials = link_bsdf_materials()\n    \n    # Then, remap any missing datablocks\n    missing_remaps = remap_missing_datablocks()\n    \n    # Then, remap any appended BSDF materials to linked versions\n    appended_remaps = remap_appended_to_linked()\n    \n    print(f\"\\n=== STARTING MATERIAL REPLACEMENT ===\")\n    \n    # Custom material mappings (source -> target)\n    custom_mappings = {\n        \"bag BLACK (squid ink)\": \"BSDF_black_SQUID-INK\",\n        \"bag WHITE\": \"BSDF_WHITE\",\n        \"Wheel-White\": \"BSDF_WHITE\",\n        \"Bag Colors\": \"BSDF_Bag Colors\",\n        \"cardboard\": \"Package_Cardboard\",\n        \"blue (triton)\": \"BSDF_blue-2_TRITON\",\n        \"gray (snow)\": \"BSDF_gray-6_SNOW\",\n        \"gray (storm)\": \"BSDF_gray-2_STORM\",\n        \"gray (summit)\": \"BSDF_gray-5_SUMMIT\",\n        \"light blue (prime)\": \"BSDF_blue-4_PRIME\",\n        \"yellow (summer)\": \"BSDF_orange-5_SUMMER\",\n        \"Accessory_CEL_gray-6_SNOW\": \"BSDF_gray-6_SNOW\",\n        \"Accessory_CEL_SquidInk\": \"BSDF_black_SQUID-INK\",\n        \"FingerScanner\": \"BSDF_black_SQUID-INK\",\n        \"cel BLACK (squid ink)\": \"BSDF_black_SQUID-INK\",\n        \"cel WHITE\": \"BSDF_WHITE\",\n        \"gray (stone)\": \"BSDF_gray-3_STONE\",\n        \"green (oxygen)\": \"BSDF_green-3_OXYGEN\",\n        \"orange (smile)\": \"BSDF_orange-3_SMILE\",\n        \"orange (blaze)\": \"BSDF_orange-1_BLAZE\"\n    }\n    \n    # Get all materials in the scene\n    materials = bpy.data.materials\n    \n    # Dictionary to store source -> target material mapping\n    material_mapping = {}\n    \n    # Replace all CEL materials with their BSDF counterparts, ignoring numeric suffixes\n    cel_pattern = re.compile(r\"^(CEL_.+?)(\\.\\d{3})?$\")\n    bsdf_pattern = re.compile(r\"^(BSDF_.+?)(\\.\\d{3})?$\")\n    \n    # Build a mapping from base BSDF name to BSDF material (without suffix)",
        "signatures": {},
        "detailedLines": [
          {
            "text": "def replace_cel_materials():",
            "lineNumber": 189,
            "isSignature": true
          },
          {
            "text": "    \"\"\"Replace all CEL materials with their BSDF counterparts using Blender's user remapping\"\"\"",
            "lineNumber": 190
          },
          {
            "text": "    ",
            "lineNumber": 191
          },
          {
            "text": "    # First, link BSDF materials from library",
            "lineNumber": 192
          },
          {
            "text": "    linked_materials = link_bsdf_materials()",
            "lineNumber": 193
          },
          {
            "text": "    ",
            "lineNumber": 194
          },
          {
            "text": "    # Then, remap any missing datablocks",
            "lineNumber": 195
          },
          {
            "text": "    missing_remaps = remap_missing_datablocks()",
            "lineNumber": 196
          },
          {
            "text": "    ",
            "lineNumber": 197
          },
          {
            "text": "    # Then, remap any appended BSDF materials to linked versions",
            "lineNumber": 198
          },
          {
            "text": "    appended_remaps = remap_appended_to_linked()",
            "lineNumber": 199
          },
          {
            "text": "    ",
            "lineNumber": 200
          },
          {
            "text": "    print(f\"\\n=== STARTING MATERIAL REPLACEMENT ===\")",
            "lineNumber": 201
          },
          {
            "text": "    ",
            "lineNumber": 202
          },
          {
            "text": "    # Custom material mappings (source -> target)",
            "lineNumber": 203
          },
          {
            "text": "    custom_mappings = {",
            "lineNumber": 204
          },
          {
            "text": "        \"bag BLACK (squid ink)\": \"BSDF_black_SQUID-INK\",",
            "lineNumber": 205
          },
          {
            "text": "        \"bag WHITE\": \"BSDF_WHITE\",",
            "lineNumber": 206
          },
          {
            "text": "        \"Wheel-White\": \"BSDF_WHITE\",",
            "lineNumber": 207
          },
          {
            "text": "        \"Bag Colors\": \"BSDF_Bag Colors\",",
            "lineNumber": 208
          },
          {
            "text": "        \"cardboard\": \"Package_Cardboard\",",
            "lineNumber": 209
          },
          {
            "text": "        \"blue (triton)\": \"BSDF_blue-2_TRITON\",",
            "lineNumber": 210
          },
          {
            "text": "        \"gray (snow)\": \"BSDF_gray-6_SNOW\",",
            "lineNumber": 211
          },
          {
            "text": "        \"gray (storm)\": \"BSDF_gray-2_STORM\",",
            "lineNumber": 212
          },
          {
            "text": "        \"gray (summit)\": \"BSDF_gray-5_SUMMIT\",",
            "lineNumber": 213
          },
          {
            "text": "        \"light blue (prime)\": \"BSDF_blue-4_PRIME\",",
            "lineNumber": 214
          },
          {
            "text": "        \"yellow (summer)\": \"BSDF_orange-5_SUMMER\",",
            "lineNumber": 215
          },
          {
            "text": "        \"Accessory_CEL_gray-6_SNOW\": \"BSDF_gray-6_SNOW\",",
            "lineNumber": 216
          },
          {
            "text": "        \"Accessory_CEL_SquidInk\": \"BSDF_black_SQUID-INK\",",
            "lineNumber": 217
          },
          {
            "text": "        \"FingerScanner\": \"BSDF_black_SQUID-INK\",",
            "lineNumber": 218
          },
          {
            "text": "        \"cel BLACK (squid ink)\": \"BSDF_black_SQUID-INK\",",
            "lineNumber": 219
          },
          {
            "text": "        \"cel WHITE\": \"BSDF_WHITE\",",
            "lineNumber": 220
          },
          {
            "text": "        \"gray (stone)\": \"BSDF_gray-3_STONE\",",
            "lineNumber": 221
          },
          {
            "text": "        \"green (oxygen)\": \"BSDF_green-3_OXYGEN\",",
            "lineNumber": 222
          },
          {
            "text": "        \"orange (smile)\": \"BSDF_orange-3_SMILE\",",
            "lineNumber": 223
          },
          {
            "text": "        \"orange (blaze)\": \"BSDF_orange-1_BLAZE\"",
            "lineNumber": 224
          },
          {
            "text": "    }",
            "lineNumber": 225
          },
          {
            "text": "    ",
            "lineNumber": 226
          },
          {
            "text": "    # Get all materials in the scene",
            "lineNumber": 227
          },
          {
            "text": "    materials = bpy.data.materials",
            "lineNumber": 228
          },
          {
            "text": "    ",
            "lineNumber": 229
          },
          {
            "text": "    # Dictionary to store source -> target material mapping",
            "lineNumber": 230
          },
          {
            "text": "    material_mapping = {}",
            "lineNumber": 231
          },
          {
            "text": "    ",
            "lineNumber": 232
          },
          {
            "text": "    # Replace all CEL materials with their BSDF counterparts, ignoring numeric suffixes",
            "lineNumber": 233
          },
          {
            "text": "    cel_pattern = re.compile(r\"^(CEL_.+?)(\\.\\d{3})?$\")",
            "lineNumber": 234
          },
          {
            "text": "    bsdf_pattern = re.compile(r\"^(BSDF_.+?)(\\.\\d{3})?$\")",
            "lineNumber": 235
          },
          {
            "text": "    ",
            "lineNumber": 236
          },
          {
            "text": "    # Build a mapping from base BSDF name to BSDF material (without suffix)",
            "lineNumber": 237
          }
        ]
      },
      "score": 0.2842274010181427
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\CONFIG.md",
        "range": {
          "startPosition": {},
          "endPosition": {
            "line": 24
          }
        },
        "contents": "# ProjectStructure Configuration\n\nThe repository reads user preferences from `config.json` in the ProjectStructure\nroot (copied alongside helper batches when they are deployed to projects).\n\n## Keys\n\n| Key | Type | Meaning |\n| --- | --- | --- |\n| `dailyFormat` | bool | `true` → daily folders named `YYYY-MM-DD`; `false` → `daily_*` style. |\n| `structDir` | string | Absolute or relative path to the canonical ProjectStructure directory. Blank values default to the folder containing `config.json`. |\n| `projectsRoot` | string (optional) | Override for the root directory scanned by `UpgradeSeqBatches.ps1`. Defaults to the parent of `structDir`. |\n| `zipper` | bool | `true` → use 7Zip (if available); `false` → use Pythons built-in zipfile module. |\n| `compression` | int | Compression level `0-9` (0 = store only, 9 = max). Applies to both zipfile and 7Zip. |\n\n## Notes\n\n- `UpdateProjectBatches.ps1` copies `config.json` and `ConfigLoader.ps1` to the\n  target project so the helper `.bat` launchers can resolve script locations.\n- When `zipper` is `true`, the tool searches for `7z`/`7za` on `PATH`. If neither\n  is found it logs a warning and falls back to `zipfile`.\n- Leaving `structDir` empty is safe—the scripts fall back to the directory that\n  contains `config.json`.",
        "signatures": {},
        "detailedLines": [
          {
            "text": "# ProjectStructure Configuration",
            "lineNumber": 1
          },
          {
            "lineNumber": 2
          },
          {
            "text": "The repository reads user preferences from `config.json` in the ProjectStructure",
            "lineNumber": 3
          },
          {
            "text": "root (copied alongside helper batches when they are deployed to projects).",
            "lineNumber": 4
          },
          {
            "lineNumber": 5
          },
          {
            "text": "## Keys",
            "lineNumber": 6
          },
          {
            "lineNumber": 7
          },
          {
            "text": "| Key | Type | Meaning |",
            "lineNumber": 8
          },
          {
            "text": "| --- | --- | --- |",
            "lineNumber": 9
          },
          {
            "text": "| `dailyFormat` | bool | `true` → daily folders named `YYYY-MM-DD`; `false` → `daily_*` style. |",
            "lineNumber": 10
          },
          {
            "text": "| `structDir` | string | Absolute or relative path to the canonical ProjectStructure directory. Blank values default to the folder containing `config.json`. |",
            "lineNumber": 11
          },
          {
            "text": "| `projectsRoot` | string (optional) | Override for the root directory scanned by `UpgradeSeqBatches.ps1`. Defaults to the parent of `structDir`. |",
            "lineNumber": 12
          },
          {
            "text": "| `zipper` | bool | `true` → use 7Zip (if available); `false` → use Pythons built-in zipfile module. |",
            "lineNumber": 13
          },
          {
            "text": "| `compression` | int | Compression level `0-9` (0 = store only, 9 = max). Applies to both zipfile and 7Zip. |",
            "lineNumber": 14
          },
          {
            "lineNumber": 15
          },
          {
            "text": "## Notes",
            "lineNumber": 16
          },
          {
            "lineNumber": 17
          },
          {
            "text": "- `UpdateProjectBatches.ps1` copies `config.json` and `ConfigLoader.ps1` to the",
            "lineNumber": 18
          },
          {
            "text": "  target project so the helper `.bat` launchers can resolve script locations.",
            "lineNumber": 19
          },
          {
            "text": "- When `zipper` is `true`, the tool searches for `7z`/`7za` on `PATH`. If neither",
            "lineNumber": 20
          },
          {
            "text": "  is found it logs a warning and falls back to `zipfile`.",
            "lineNumber": 21
          },
          {
            "text": "- Leaving `structDir` empty is safe—the scripts fall back to the directory that",
            "lineNumber": 22
          },
          {
            "text": "  contains `config.json`.",
            "lineNumber": 23
          }
        ]
      },
      "score": 0.2787865400314331
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\components\\gitattributes",
        "range": {
          "startPosition": {
            "line": 51
          },
          "endPosition": {
            "line": 111,
            "column": 40
          }
        },
        "contents": "*.hiplc filter=lfs diff=lfs merge=lfs -text\n*.bgeo filter=lfs diff=lfs merge=lfs -text\n*.bgeo.sc filter=lfs diff=lfs merge=lfs -text\n\n# Flip Fluids cache files\n*.data filter=lfs diff=lfs merge=lfs -text\n*.sqlite3 filter=lfs diff=lfs merge=lfs -text\n*.ffp3 filter=lfs diff=lfs merge=lfs -text\n\n# Substance files\n*.sbs filter=lfs diff=lfs merge=lfs -text\n*.sbsar filter=lfs diff=lfs merge=lfs -text\n*.spp filter=lfs diff=lfs merge=lfs -text\n\n# Audio files\n*.mp3 filter=lfs diff=lfs merge=lfs -text\n*.wav filter=lfs diff=lfs merge=lfs -text\n\n# Archive/Compression files\n*.7z filter=lfs diff=lfs merge=lfs -text\n*.bz2 filter=lfs diff=lfs merge=lfs -text\n*.gz filter=lfs diff=lfs merge=lfs -text\n*.rar filter=lfs diff=lfs merge=lfs -text\n*.tar filter=lfs diff=lfs merge=lfs -text\n*.zip filter=lfs diff=lfs merge=lfs -text\n\n# Documents\n*.docx filter=lfs diff=lfs merge=lfs -text\n*.xlsx filter=lfs diff=lfs merge=lfs -text\n*.eps filter=lfs diff=lfs merge=lfs -text\n*.pdf filter=lfs diff=lfs merge=lfs -text\n\n# Adobe files\n*.aegraphic filter=lfs diff=lfs merge=lfs -text\n*.aep filter=lfs diff=lfs merge=lfs -text\n*.prel filter=lfs diff=lfs merge=lfs -text\n*.prin filter=lfs diff=lfs merge=lfs -text\n*.prmf filter=lfs diff=lfs merge=lfs -text\n*.prproj filter=lfs diff=lfs merge=lfs -text\n*.ai filter=lfs diff=lfs merge=lfs -text\n*.psd filter=lfs diff=lfs merge=lfs -text\n\n# Davinci Resolve files\n*.dpx filter=lfs diff=lfs merge=lfs -text\n*.drp filter=lfs diff=lfs merge=lfs -text\n\n# Data files\n*.h5 filter=lfs diff=lfs merge=lfs -text\n*.hdf5 filter=lfs diff=lfs merge=lfs -text\n\n# Other\n*.uni filter=lfs diff=lfs merge=lfs -text\n*.pdn filter=lfs diff=lfs merge=lfs -text\n*.pur filter=lfs diff=lfs merge=lfs -text\n\n# Python files\n*.npz filter=lfs diff=lfs merge=lfs -text\n\n# Adobe Alternatives\n*.xcf filter=lfs diff=lfs merge=lfs -text\n*.af filter=lfs diff=lfs merge=lfs -text",
        "signatures": {},
        "detailedLines": [
          {
            "text": "*.hiplc filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 52
          },
          {
            "text": "*.bgeo filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 53
          },
          {
            "text": "*.bgeo.sc filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 54
          },
          {
            "lineNumber": 55
          },
          {
            "text": "# Flip Fluids cache files",
            "lineNumber": 56
          },
          {
            "text": "*.data filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 57
          },
          {
            "text": "*.sqlite3 filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 58
          },
          {
            "text": "*.ffp3 filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 59
          },
          {
            "lineNumber": 60
          },
          {
            "text": "# Substance files",
            "lineNumber": 61
          },
          {
            "text": "*.sbs filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 62
          },
          {
            "text": "*.sbsar filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 63
          },
          {
            "text": "*.spp filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 64
          },
          {
            "lineNumber": 65
          },
          {
            "text": "# Audio files",
            "lineNumber": 66
          },
          {
            "text": "*.mp3 filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 67
          },
          {
            "text": "*.wav filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 68
          },
          {
            "lineNumber": 69
          },
          {
            "text": "# Archive/Compression files",
            "lineNumber": 70
          },
          {
            "text": "*.7z filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 71
          },
          {
            "text": "*.bz2 filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 72
          },
          {
            "text": "*.gz filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 73
          },
          {
            "text": "*.rar filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 74
          },
          {
            "text": "*.tar filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 75
          },
          {
            "text": "*.zip filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 76
          },
          {
            "lineNumber": 77
          },
          {
            "text": "# Documents",
            "lineNumber": 78
          },
          {
            "text": "*.docx filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 79
          },
          {
            "text": "*.xlsx filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 80
          },
          {
            "text": "*.eps filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 81
          },
          {
            "text": "*.pdf filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 82
          },
          {
            "lineNumber": 83
          },
          {
            "text": "# Adobe files",
            "lineNumber": 84
          },
          {
            "text": "*.aegraphic filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 85
          },
          {
            "text": "*.aep filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 86
          },
          {
            "text": "*.prel filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 87
          },
          {
            "text": "*.prin filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 88
          },
          {
            "text": "*.prmf filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 89
          },
          {
            "text": "*.prproj filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 90
          },
          {
            "text": "*.ai filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 91
          },
          {
            "text": "*.psd filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 92
          },
          {
            "lineNumber": 93
          },
          {
            "text": "# Davinci Resolve files",
            "lineNumber": 94
          },
          {
            "text": "*.dpx filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 95
          },
          {
            "text": "*.drp filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 96
          },
          {
            "lineNumber": 97
          },
          {
            "text": "# Data files",
            "lineNumber": 98
          },
          {
            "text": "*.h5 filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 99
          },
          {
            "text": "*.hdf5 filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 100
          },
          {
            "lineNumber": 101
          },
          {
            "text": "# Other",
            "lineNumber": 102
          },
          {
            "text": "*.uni filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 103
          },
          {
            "text": "*.pdn filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 104
          },
          {
            "text": "*.pur filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 105
          },
          {
            "lineNumber": 106
          },
          {
            "text": "# Python files",
            "lineNumber": 107
          },
          {
            "text": "*.npz filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 108
          },
          {
            "lineNumber": 109
          },
          {
            "text": "# Adobe Alternatives",
            "lineNumber": 110
          },
          {
            "text": "*.xcf filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 111
          },
          {
            "text": "*.af filter=lfs diff=lfs merge=lfs -text",
            "lineNumber": 112
          }
        ]
      },
      "score": 0.27743393182754517
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\compress_blend_files.bat",
        "range": {
          "startPosition": {},
          "endPosition": {
            "line": 66
          }
        },
        "contents": "@echo off\nsetlocal enabledelayedexpansion\n\necho Starting Blender file compression...\n\nREM Check if files were dragged onto the batch file\nif \"%~1\"==\"\" (\n    echo.\n    echo Usage: Drag .blend files onto this batch file to compress them.\n    echo Output will be saved to the \\output folder.\n    echo.\n    pause\n    exit /b 1\n)\n\nREM Create output directory if it doesn't exist\nif not exist \"output\" mkdir \"output\"\n\nREM Initialize counters and tracking\nset \"processed=0\"\nset \"crashed=0\"\nset \"skipped=0\"\nset \"deleted_similar=0\"\nset \"threshold_percent=10\"\n\nREM Create a temporary Python script for compression\nset \"TEMP_SCRIPT=compress_blend_temp.py\"\necho Creating Python script: !TEMP_SCRIPT!\n\n(\necho import bpy\necho import os\necho import sys\necho.\necho # Enable compression globally\necho bpy.context.preferences.filepaths.save_version = 0\necho bpy.context.preferences.filepaths.use_file_compression = True\necho.\necho # Create output directory if it doesn't exist\necho if not os.path.exists^(\"output\"^):\necho     os.makedirs^(\"output\"^)\necho.\necho # Get command line arguments ^(the dragged files^)\necho blend_files = sys.argv[sys.argv.index^(\"--\"^) + 1:] if \"--\" in sys.argv else []\necho.\necho print^(\"Found \" + str^(len^(blend_files^)^) + \" .blend files to compress\"^)\necho.\necho def is_compressed_file^(path^):\necho     try:\necho         with open^(path, 'rb'^) as f:\necho             header = f.read^(4^)\necho             if header[:2] == b'\\x1f\\x8b':  # gzip\necho                 return True\necho             if header == b'\\x28\\xb5\\x2f\\xfd':  # zstd\necho                 return True\necho         return False\necho     except Exception:\necho         return False\necho.\necho for blend_file in blend_files:\necho     if blend_file.lower^(^).endswith^(\".blend\"^):\necho         try:\necho             # Create output path in output folder\necho             filename = os.path.basename^(blend_file^)\necho             output_file = os.path.join^(\"output\", filename^)\necho             # Check if output file already exists",
        "signatures": {},
        "detailedLines": [
          {
            "text": "@echo off",
            "lineNumber": 1
          },
          {
            "text": "setlocal enabledelayedexpansion",
            "lineNumber": 2
          },
          {
            "lineNumber": 3
          },
          {
            "text": "echo Starting Blender file compression...",
            "lineNumber": 4
          },
          {
            "lineNumber": 5
          },
          {
            "text": "REM Check if files were dragged onto the batch file",
            "lineNumber": 6
          },
          {
            "text": "if \"%~1\"==\"\" (",
            "lineNumber": 7
          },
          {
            "text": "    echo.",
            "lineNumber": 8
          },
          {
            "text": "    echo Usage: Drag .blend files onto this batch file to compress them.",
            "lineNumber": 9
          },
          {
            "text": "    echo Output will be saved to the \\output folder.",
            "lineNumber": 10
          },
          {
            "text": "    echo.",
            "lineNumber": 11
          },
          {
            "text": "    pause",
            "lineNumber": 12
          },
          {
            "text": "    exit /b 1",
            "lineNumber": 13
          },
          {
            "text": ")",
            "lineNumber": 14
          },
          {
            "lineNumber": 15
          },
          {
            "text": "REM Create output directory if it doesn't exist",
            "lineNumber": 16
          },
          {
            "text": "if not exist \"output\" mkdir \"output\"",
            "lineNumber": 17
          },
          {
            "lineNumber": 18
          },
          {
            "text": "REM Initialize counters and tracking",
            "lineNumber": 19
          },
          {
            "text": "set \"processed=0\"",
            "lineNumber": 20
          },
          {
            "text": "set \"crashed=0\"",
            "lineNumber": 21
          },
          {
            "text": "set \"skipped=0\"",
            "lineNumber": 22
          },
          {
            "text": "set \"deleted_similar=0\"",
            "lineNumber": 23
          },
          {
            "text": "set \"threshold_percent=10\"",
            "lineNumber": 24
          },
          {
            "lineNumber": 25
          },
          {
            "text": "REM Create a temporary Python script for compression",
            "lineNumber": 26
          },
          {
            "text": "set \"TEMP_SCRIPT=compress_blend_temp.py\"",
            "lineNumber": 27
          },
          {
            "text": "echo Creating Python script: !TEMP_SCRIPT!",
            "lineNumber": 28
          },
          {
            "lineNumber": 29
          },
          {
            "text": "(",
            "lineNumber": 30
          },
          {
            "text": "echo import bpy",
            "lineNumber": 31
          },
          {
            "text": "echo import os",
            "lineNumber": 32
          },
          {
            "text": "echo import sys",
            "lineNumber": 33
          },
          {
            "text": "echo.",
            "lineNumber": 34
          },
          {
            "text": "echo # Enable compression globally",
            "lineNumber": 35
          },
          {
            "text": "echo bpy.context.preferences.filepaths.save_version = 0",
            "lineNumber": 36
          },
          {
            "text": "echo bpy.context.preferences.filepaths.use_file_compression = True",
            "lineNumber": 37
          },
          {
            "text": "echo.",
            "lineNumber": 38
          },
          {
            "text": "echo # Create output directory if it doesn't exist",
            "lineNumber": 39
          },
          {
            "text": "echo if not os.path.exists^(\"output\"^):",
            "lineNumber": 40
          },
          {
            "text": "echo     os.makedirs^(\"output\"^)",
            "lineNumber": 41
          },
          {
            "text": "echo.",
            "lineNumber": 42
          },
          {
            "text": "echo # Get command line arguments ^(the dragged files^)",
            "lineNumber": 43
          },
          {
            "text": "echo blend_files = sys.argv[sys.argv.index^(\"--\"^) + 1:] if \"--\" in sys.argv else []",
            "lineNumber": 44
          },
          {
            "text": "echo.",
            "lineNumber": 45
          },
          {
            "text": "echo print^(\"Found \" + str^(len^(blend_files^)^) + \" .blend files to compress\"^)",
            "lineNumber": 46
          },
          {
            "text": "echo.",
            "lineNumber": 47
          },
          {
            "text": "echo def is_compressed_file^(path^):",
            "lineNumber": 48
          },
          {
            "text": "echo     try:",
            "lineNumber": 49
          },
          {
            "text": "echo         with open^(path, 'rb'^) as f:",
            "lineNumber": 50
          },
          {
            "text": "echo             header = f.read^(4^)",
            "lineNumber": 51
          },
          {
            "text": "echo             if header[:2] == b'\\x1f\\x8b':  # gzip",
            "lineNumber": 52
          },
          {
            "text": "echo                 return True",
            "lineNumber": 53
          },
          {
            "text": "echo             if header == b'\\x28\\xb5\\x2f\\xfd':  # zstd",
            "lineNumber": 54
          },
          {
            "text": "echo                 return True",
            "lineNumber": 55
          },
          {
            "text": "echo         return False",
            "lineNumber": 56
          },
          {
            "text": "echo     except Exception:",
            "lineNumber": 57
          },
          {
            "text": "echo         return False",
            "lineNumber": 58
          },
          {
            "text": "echo.",
            "lineNumber": 59
          },
          {
            "text": "echo for blend_file in blend_files:",
            "lineNumber": 60
          },
          {
            "text": "echo     if blend_file.lower^(^).endswith^(\".blend\"^):",
            "lineNumber": 61
          },
          {
            "text": "echo         try:",
            "lineNumber": 62
          },
          {
            "text": "echo             # Create output path in output folder",
            "lineNumber": 63
          },
          {
            "text": "echo             filename = os.path.basename^(blend_file^)",
            "lineNumber": 64
          },
          {
            "text": "echo             output_file = os.path.join^(\"output\", filename^)",
            "lineNumber": 65
          },
          {
            "text": "echo             # Check if output file already exists",
            "lineNumber": 66
          }
        ]
      },
      "score": 0.27458083629608154
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\organize_textures.ps1",
        "range": {
          "startPosition": {
            "line": 44
          },
          "endPosition": {
            "line": 83,
            "column": 8
          }
        },
        "contents": "        $null\n    }\n}\n$filesWithChecksums = $allFiles | ForEach-Object -Parallel $parallelScriptBlock -ThrottleLimit $throttleLimit | Where-Object { $null -ne $_ }\n\nWrite-Host \"Checksum calculation complete.\" -ForegroundColor Green\n\n# Group files by checksum\nWrite-Host \"Grouping files by checksum...\" -ForegroundColor Yellow\n$groupedByChecksum = $filesWithChecksums | Group-Object -Property Hash\n\nWrite-Host \"Found $($groupedByChecksum.Count) unique checksums.\" -ForegroundColor Green\n\n# Create \\common and \\common\\duplicates directories\n$commonPath = Join-Path -Path $textureFolderPath -ChildPath \"common\"\n$duplicatesPath = Join-Path -Path $commonPath -ChildPath \"duplicates\"\n\nif (-not (Test-Path -Path $commonPath -PathType Container)) {\n    New-Item -ItemType Directory -Path $commonPath | Out-Null\n    Write-Host \"Created directory: $commonPath\" -ForegroundColor Green\n}\n\nif (-not (Test-Path -Path $duplicatesPath -PathType Container)) {\n    New-Item -ItemType Directory -Path $duplicatesPath | Out-Null\n    Write-Host \"Created directory: $duplicatesPath\" -ForegroundColor Green\n}\n\n# Track filenames already in \\common to handle name conflicts\n$filesInCommon = @{}\n\n# Process each checksum group\nWrite-Host \"Moving files to \\common and \\common\\duplicates...\" -ForegroundColor Yellow\n$movedCount = 0\n$duplicateCount = 0\n\nforeach ($group in $groupedByChecksum) {\n    $files = $group.Group\n    \n    if ($files.Count -eq 1) {\n        ",
        "signatures": {},
        "detailedLines": [
          {
            "text": "        $null",
            "lineNumber": 45
          },
          {
            "text": "    }",
            "lineNumber": 46
          },
          {
            "text": "}",
            "lineNumber": 47
          },
          {
            "text": "$filesWithChecksums = $allFiles | ForEach-Object -Parallel $parallelScriptBlock -ThrottleLimit $throttleLimit | Where-Object { $null -ne $_ }",
            "lineNumber": 48
          },
          {
            "lineNumber": 49
          },
          {
            "text": "Write-Host \"Checksum calculation complete.\" -ForegroundColor Green",
            "lineNumber": 50
          },
          {
            "lineNumber": 51
          },
          {
            "text": "# Group files by checksum",
            "lineNumber": 52
          },
          {
            "text": "Write-Host \"Grouping files by checksum...\" -ForegroundColor Yellow",
            "lineNumber": 53
          },
          {
            "text": "$groupedByChecksum = $filesWithChecksums | Group-Object -Property Hash",
            "lineNumber": 54
          },
          {
            "lineNumber": 55
          },
          {
            "text": "Write-Host \"Found $($groupedByChecksum.Count) unique checksums.\" -ForegroundColor Green",
            "lineNumber": 56
          },
          {
            "lineNumber": 57
          },
          {
            "text": "# Create \\common and \\common\\duplicates directories",
            "lineNumber": 58
          },
          {
            "text": "$commonPath = Join-Path -Path $textureFolderPath -ChildPath \"common\"",
            "lineNumber": 59
          },
          {
            "text": "$duplicatesPath = Join-Path -Path $commonPath -ChildPath \"duplicates\"",
            "lineNumber": 60
          },
          {
            "lineNumber": 61
          },
          {
            "text": "if (-not (Test-Path -Path $commonPath -PathType Container)) {",
            "lineNumber": 62
          },
          {
            "text": "    New-Item -ItemType Directory -Path $commonPath | Out-Null",
            "lineNumber": 63
          },
          {
            "text": "    Write-Host \"Created directory: $commonPath\" -ForegroundColor Green",
            "lineNumber": 64
          },
          {
            "text": "}",
            "lineNumber": 65
          },
          {
            "lineNumber": 66
          },
          {
            "text": "if (-not (Test-Path -Path $duplicatesPath -PathType Container)) {",
            "lineNumber": 67
          },
          {
            "text": "    New-Item -ItemType Directory -Path $duplicatesPath | Out-Null",
            "lineNumber": 68
          },
          {
            "text": "    Write-Host \"Created directory: $duplicatesPath\" -ForegroundColor Green",
            "lineNumber": 69
          },
          {
            "text": "}",
            "lineNumber": 70
          },
          {
            "lineNumber": 71
          },
          {
            "text": "# Track filenames already in \\common to handle name conflicts",
            "lineNumber": 72
          },
          {
            "text": "$filesInCommon = @{}",
            "lineNumber": 73
          },
          {
            "lineNumber": 74
          },
          {
            "text": "# Process each checksum group",
            "lineNumber": 75
          },
          {
            "text": "Write-Host \"Moving files to \\common and \\common\\duplicates...\" -ForegroundColor Yellow",
            "lineNumber": 76
          },
          {
            "text": "$movedCount = 0",
            "lineNumber": 77
          },
          {
            "text": "$duplicateCount = 0",
            "lineNumber": 78
          },
          {
            "lineNumber": 79
          },
          {
            "text": "foreach ($group in $groupedByChecksum) {",
            "lineNumber": 80
          },
          {
            "text": "    $files = $group.Group",
            "lineNumber": 81
          },
          {
            "text": "    ",
            "lineNumber": 82
          },
          {
            "text": "    if ($files.Count -eq 1) {",
            "lineNumber": 83
          },
          {
            "text": "        ",
            "lineNumber": 84
          }
        ]
      },
      "score": 0.2703059911727905
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\NewProject.bat",
        "range": {
          "startPosition": {
            "line": 61
          },
          "endPosition": {
            "line": 83
          }
        },
        "contents": "if not exist \"%projectRoot%\\Renders\" mkdir \"%projectRoot%\\Renders\"\n\n:: Place helper scripts into Renders\nset \"templateRoot=%STRUCT_DIR%\"\nfor %%F in (UpdateSequences.bat ZipSeqArchv.bat UnzipSeqArchv.bat ConfigLoader.ps1 config.json) do (\n  if exist \"%templateRoot%\\%%F\" copy /Y \"%templateRoot%\\%%F\" \"%projectRoot%\\Renders\\%%F\" >nul\n)\n\n:: Use repo-provided templates for git config files\nif exist \"%~dp0components\\gitignore\" copy /Y \"%~dp0components\\gitignore\" \"%projectRoot%\\.gitignore\" >nul\nif exist \"%~dp0components\\gitattributes\" copy /Y \"%~dp0components\\gitattributes\" \"%projectRoot%\\.gitattributes\" >nul\n\n:: Initialize git and install Git LFS\npushd \"%projectRoot%\" >nul\ngit init\ngit lfs install\ngit add . -v\ngit commit -m \"init\"\npopd >nul\n\necho Project structure created successfully in folder: %projectRoot%\npause ",
        "signatures": {},
        "detailedLines": [
          {
            "text": "if not exist \"%projectRoot%\\Renders\" mkdir \"%projectRoot%\\Renders\"",
            "lineNumber": 62
          },
          {
            "lineNumber": 63
          },
          {
            "text": ":: Place helper scripts into Renders",
            "lineNumber": 64
          },
          {
            "text": "set \"templateRoot=%STRUCT_DIR%\"",
            "lineNumber": 65
          },
          {
            "text": "for %%F in (UpdateSequences.bat ZipSeqArchv.bat UnzipSeqArchv.bat ConfigLoader.ps1 config.json) do (",
            "lineNumber": 66
          },
          {
            "text": "  if exist \"%templateRoot%\\%%F\" copy /Y \"%templateRoot%\\%%F\" \"%projectRoot%\\Renders\\%%F\" >nul",
            "lineNumber": 67
          },
          {
            "text": ")",
            "lineNumber": 68
          },
          {
            "lineNumber": 69
          },
          {
            "text": ":: Use repo-provided templates for git config files",
            "lineNumber": 70
          },
          {
            "text": "if exist \"%~dp0components\\gitignore\" copy /Y \"%~dp0components\\gitignore\" \"%projectRoot%\\.gitignore\" >nul",
            "lineNumber": 71
          },
          {
            "text": "if exist \"%~dp0components\\gitattributes\" copy /Y \"%~dp0components\\gitattributes\" \"%projectRoot%\\.gitattributes\" >nul",
            "lineNumber": 72
          },
          {
            "lineNumber": 73
          },
          {
            "text": ":: Initialize git and install Git LFS",
            "lineNumber": 74
          },
          {
            "text": "pushd \"%projectRoot%\" >nul",
            "lineNumber": 75
          },
          {
            "text": "git init",
            "lineNumber": 76
          },
          {
            "text": "git lfs install",
            "lineNumber": 77
          },
          {
            "text": "git add . -v",
            "lineNumber": 78
          },
          {
            "text": "git commit -m \"init\"",
            "lineNumber": 79
          },
          {
            "text": "popd >nul",
            "lineNumber": 80
          },
          {
            "lineNumber": 81
          },
          {
            "text": "echo Project structure created successfully in folder: %projectRoot%",
            "lineNumber": 82
          },
          {
            "text": "pause ",
            "lineNumber": 83
          }
        ]
      },
      "score": 0.2641300559043884
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\UpdateSequences.ps1",
        "range": {
          "startPosition": {
            "line": 183
          },
          "endPosition": {
            "line": 223,
            "column": 8
          }
        },
        "contents": "function Add-SequenceFolder {\n    param(\n        [Parameter(Mandatory)] [System.IO.DirectoryInfo]$Directory,\n        [Parameter(Mandatory)] [hashtable]$Map\n    )\n    if ($Directory.Name -like '_*') { return }\n    $fullPath = $Directory.FullName\n    if ($Map.ContainsKey($fullPath)) { return }\n    \n    # Check if directory contains sequence files directly (not just subdirectories)\n    $extensions = @('.png','.jpg','.jpeg','.exr','.tif','.tiff','.bmp','.tga')\n    $hasSequenceFiles = Get-ChildItem -LiteralPath $fullPath -File -ErrorAction SilentlyContinue |\n        Where-Object { $extensions -contains $_.Extension.ToLower() } |\n        Select-Object -First 1\n    \n    # If it only has subdirectories and no sequence files, skip it\n    $hasSubdirs = Get-ChildItem -LiteralPath $fullPath -Directory -ErrorAction SilentlyContinue |\n        Select-Object -First 1\n    if ($null -eq $hasSequenceFiles -and $null -ne $hasSubdirs) {\n        return\n    }\n    \n    $Map[$fullPath] = Resolve-SequenceName -Directory $Directory\n}\n\ntry {\n    $root = (Get-Location).ProviderPath\n    $logFile = $null\n\n    if ($DebugMode) {\n        $logFile = Join-Path $root (\"UpdateSequences_{0}.log\" -f (Get-Date -Format 'yyyyMMdd_HHmmss'))\n        \"[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] === UpdateSequences started in '$root' ===\" | Out-File -LiteralPath $logFile -Encoding UTF8\n    }\n\n    $sequenceMap = @{}\n\n    $primaryPattern = if ($useIsoDailyFormat) { '????-??-??' } else { 'daily_*' }\n    $secondaryPattern = if ($useIsoDailyFormat) { 'daily_*' } else { '????-??-??' }\n\n    $primaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $primaryPattern -ErrorAction SilentlyContinue |\n        ",
        "signatures": {},
        "detailedLines": [
          {
            "text": "function Add-SequenceFolder {",
            "lineNumber": 184
          },
          {
            "text": "    param(",
            "lineNumber": 185
          },
          {
            "text": "        [Parameter(Mandatory)] [System.IO.DirectoryInfo]$Directory,",
            "lineNumber": 186
          },
          {
            "text": "        [Parameter(Mandatory)] [hashtable]$Map",
            "lineNumber": 187
          },
          {
            "text": "    )",
            "lineNumber": 188
          },
          {
            "text": "    if ($Directory.Name -like '_*') { return }",
            "lineNumber": 189
          },
          {
            "text": "    $fullPath = $Directory.FullName",
            "lineNumber": 190
          },
          {
            "text": "    if ($Map.ContainsKey($fullPath)) { return }",
            "lineNumber": 191
          },
          {
            "text": "    ",
            "lineNumber": 192
          },
          {
            "text": "    # Check if directory contains sequence files directly (not just subdirectories)",
            "lineNumber": 193
          },
          {
            "text": "    $extensions = @('.png','.jpg','.jpeg','.exr','.tif','.tiff','.bmp','.tga')",
            "lineNumber": 194
          },
          {
            "text": "    $hasSequenceFiles = Get-ChildItem -LiteralPath $fullPath -File -ErrorAction SilentlyContinue |",
            "lineNumber": 195
          },
          {
            "text": "        Where-Object { $extensions -contains $_.Extension.ToLower() } |",
            "lineNumber": 196
          },
          {
            "text": "        Select-Object -First 1",
            "lineNumber": 197
          },
          {
            "text": "    ",
            "lineNumber": 198
          },
          {
            "text": "    # If it only has subdirectories and no sequence files, skip it",
            "lineNumber": 199
          },
          {
            "text": "    $hasSubdirs = Get-ChildItem -LiteralPath $fullPath -Directory -ErrorAction SilentlyContinue |",
            "lineNumber": 200
          },
          {
            "text": "        Select-Object -First 1",
            "lineNumber": 201
          },
          {
            "text": "    if ($null -eq $hasSequenceFiles -and $null -ne $hasSubdirs) {",
            "lineNumber": 202
          },
          {
            "text": "        return",
            "lineNumber": 203
          },
          {
            "text": "    }",
            "lineNumber": 204
          },
          {
            "text": "    ",
            "lineNumber": 205
          },
          {
            "text": "    $Map[$fullPath] = Resolve-SequenceName -Directory $Directory",
            "lineNumber": 206
          },
          {
            "text": "}",
            "lineNumber": 207
          },
          {
            "lineNumber": 208
          },
          {
            "text": "try {",
            "lineNumber": 209
          },
          {
            "text": "    $root = (Get-Location).ProviderPath",
            "lineNumber": 210
          },
          {
            "text": "    $logFile = $null",
            "lineNumber": 211
          },
          {
            "lineNumber": 212
          },
          {
            "text": "    if ($DebugMode) {",
            "lineNumber": 213
          },
          {
            "text": "        $logFile = Join-Path $root (\"UpdateSequences_{0}.log\" -f (Get-Date -Format 'yyyyMMdd_HHmmss'))",
            "lineNumber": 214
          },
          {
            "text": "        \"[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] === UpdateSequences started in '$root' ===\" | Out-File -LiteralPath $logFile -Encoding UTF8",
            "lineNumber": 215
          },
          {
            "text": "    }",
            "lineNumber": 216
          },
          {
            "lineNumber": 217
          },
          {
            "text": "    $sequenceMap = @{}",
            "lineNumber": 218
          },
          {
            "lineNumber": 219
          },
          {
            "text": "    $primaryPattern = if ($useIsoDailyFormat) { '????-??-??' } else { 'daily_*' }",
            "lineNumber": 220
          },
          {
            "text": "    $secondaryPattern = if ($useIsoDailyFormat) { 'daily_*' } else { '????-??-??' }",
            "lineNumber": 221
          },
          {
            "lineNumber": 222
          },
          {
            "text": "    $primaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $primaryPattern -ErrorAction SilentlyContinue |",
            "lineNumber": 223
          },
          {
            "text": "        ",
            "lineNumber": 224
          }
        ]
      },
      "score": 0.263225793838501
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\replace_cel_with_bsdf.py",
        "range": {
          "startPosition": {
            "line": 188
          },
          "endPosition": {
            "line": 355
          }
        },
        "contents": "def replace_cel_materials():\n\n    \n    # Build a mapping from base BSDF name to BSDF material (without suffix)\n    bsdf_base_map = {bsdf_pattern.match(mat.name).group(1): mat for mat in materials if bsdf_pattern.match(mat.name)}\n    \n    # Build a mapping from exact material names to materials\n    exact_material_map = {mat.name: mat for mat in materials}\n\n    # Helpers to normalize names (case-insensitive, ignore numeric suffixes and library suffix)\n    def normalize_base(name):\n        base_name = name.split(\".blend\")[0] if \".blend\" in name else name\n        match = re.match(r\"^(.*?)(\\.\\d{3})?$\", base_name)\n        base_name = match.group(1) if match else base_name\n        return base_name.strip().casefold()\n\n    # Map normalized base name -> list of materials\n    materials_by_base = {}\n    for mat in materials:\n        base = normalize_base(mat.name)\n        materials_by_base.setdefault(base, []).append(mat)\n\n    # Normalize BSDF base name map for robust target lookups\n    bsdf_base_map_normalized = {normalize_base(base): mat for base, mat in bsdf_base_map.items()}\n    \n    replacements_made = 0\n    missing_targets = []\n    \n    # Process custom mappings first (case/suffix-insensitive)",
        "signatures": {
          "ranges": [
            {
              "startPosition": {
                "line": 189,
                "column": 1
              },
              "endPosition": {
                "line": 190,
                "column": 5
              }
            }
          ]
        },
        "detailedLines": [
          {
            "text": "def replace_cel_materials():",
            "lineNumber": 189,
            "isSignature": true
          },
          {
            "lineNumber": 235
          },
          {
            "text": "    ",
            "lineNumber": 236
          },
          {
            "text": "    # Build a mapping from base BSDF name to BSDF material (without suffix)",
            "lineNumber": 237
          },
          {
            "text": "    bsdf_base_map = {bsdf_pattern.match(mat.name).group(1): mat for mat in materials if bsdf_pattern.match(mat.name)}",
            "lineNumber": 238
          },
          {
            "text": "    ",
            "lineNumber": 239
          },
          {
            "text": "    # Build a mapping from exact material names to materials",
            "lineNumber": 240
          },
          {
            "text": "    exact_material_map = {mat.name: mat for mat in materials}",
            "lineNumber": 241
          },
          {
            "lineNumber": 242
          },
          {
            "text": "    # Helpers to normalize names (case-insensitive, ignore numeric suffixes and library suffix)",
            "lineNumber": 243
          },
          {
            "text": "    def normalize_base(name):",
            "lineNumber": 244
          },
          {
            "text": "        base_name = name.split(\".blend\")[0] if \".blend\" in name else name",
            "lineNumber": 245
          },
          {
            "text": "        match = re.match(r\"^(.*?)(\\.\\d{3})?$\", base_name)",
            "lineNumber": 246
          },
          {
            "text": "        base_name = match.group(1) if match else base_name",
            "lineNumber": 247
          },
          {
            "text": "        return base_name.strip().casefold()",
            "lineNumber": 248
          },
          {
            "lineNumber": 249
          },
          {
            "text": "    # Map normalized base name -> list of materials",
            "lineNumber": 250
          },
          {
            "text": "    materials_by_base = {}",
            "lineNumber": 251
          },
          {
            "text": "    for mat in materials:",
            "lineNumber": 252
          },
          {
            "text": "        base = normalize_base(mat.name)",
            "lineNumber": 253
          },
          {
            "text": "        materials_by_base.setdefault(base, []).append(mat)",
            "lineNumber": 254
          },
          {
            "lineNumber": 255
          },
          {
            "text": "    # Normalize BSDF base name map for robust target lookups",
            "lineNumber": 256
          },
          {
            "text": "    bsdf_base_map_normalized = {normalize_base(base): mat for base, mat in bsdf_base_map.items()}",
            "lineNumber": 257
          },
          {
            "text": "    ",
            "lineNumber": 258
          },
          {
            "text": "    replacements_made = 0",
            "lineNumber": 259
          },
          {
            "text": "    missing_targets = []",
            "lineNumber": 260
          },
          {
            "text": "    ",
            "lineNumber": 261
          },
          {
            "text": "    # Process custom mappings first (case/suffix-insensitive)",
            "lineNumber": 262
          }
        ]
      },
      "score": 0.2553691864013672
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\UpgradeToGitProj.bat",
        "range": {
          "startPosition": {},
          "endPosition": {
            "line": 61,
            "column": 6
          }
        },
        "contents": "@echo off\nsetlocal EnableExtensions EnableDelayedExpansion\n\n:: UpgradeToGitProj.bat\n:: Run this inside an existing (pre-git) project root.\n:: - Merges .gitignore and .gitattributes from components/ templates\n:: - Initializes git and installs Git LFS\n:: - Creates Renders, copies helper scripts\n:: - Collects seq/ outputs from daily_* folders under Blends\\animations (with submodule support)\n\n:: -----------------------------\n:: Arguments\n:: -----------------------------\nset \"DRY=0\"\nif /I \"%~1\"==\"/dry-run\" set \"DRY=1\"\nif /I \"%~1\"==\"--dry-run\" set \"DRY=1\"\nif /I \"%~1\"==\"-n\" set \"DRY=1\"\nif /I \"%~1\"==\"/n\" set \"DRY=1\"\n\nset \"projectDir=%CD%\"\nset \"scriptDir=%~dp0\"\nset \"RUN_ID=%RANDOM%_%RANDOM%\"\nset \"DELETE_LIST=%TEMP%\\upg_delete_%RUN_ID%.lst\"\n\nsetlocal EnableDelayedExpansion\nset /a debugTotal=0\nset /a debugPlanned=0\nset /a debugMissing=0\n\necho ==============================================\necho UpgradeToGitProj in \"%projectDir%\"\nif \"%DRY%\"==\"1\" (echo Mode: DRY-RUN) else (echo Mode: APPLY)\necho ==============================================\n\n:: -----------------------------\n:: Ensure Renders exists and copy helper scripts\n:: -----------------------------\nset \"rendersDir=%projectDir%\\Renders\"\nif not exist \"%rendersDir%\" (\n  if \"%DRY%\"==\"1\" (\n    echo [DRY] mkdir \"%rendersDir%\"\n  ) else (\n    mkdir \"%rendersDir%\" >nul 2>&1\n  )\n)\n\nfor %%F in (UpdateSequences.bat ZipSeqArchv.bat UnzipSeqArchv.bat) do (\n  if exist \"%scriptDir%%%F\" (\n    if \"%DRY%\"==\"1\" (\n      echo [DRY] copy \"%scriptDir%%%F\" \"%rendersDir%\\%%F\"\n    ) else (\n      copy /Y \"%scriptDir%%%F\" \"%rendersDir%\\%%F\" >nul\n    )\n  ) else (\n    echo [WARN] Missing template: \"%scriptDir%%%F\"\n  )\n)\n\nfor %%F in (ConfigLoader.ps1 config.json) do (\n  if exist \"%scriptDir%%%F\" (\n    if \"%DRY%\"==\"1\" (\n      ",
        "signatures": {},
        "detailedLines": [
          {
            "text": "@echo off",
            "lineNumber": 1
          },
          {
            "text": "setlocal EnableExtensions EnableDelayedExpansion",
            "lineNumber": 2
          },
          {
            "lineNumber": 3
          },
          {
            "text": ":: UpgradeToGitProj.bat",
            "lineNumber": 4
          },
          {
            "text": ":: Run this inside an existing (pre-git) project root.",
            "lineNumber": 5
          },
          {
            "text": ":: - Merges .gitignore and .gitattributes from components/ templates",
            "lineNumber": 6
          },
          {
            "text": ":: - Initializes git and installs Git LFS",
            "lineNumber": 7
          },
          {
            "text": ":: - Creates Renders, copies helper scripts",
            "lineNumber": 8
          },
          {
            "text": ":: - Collects seq/ outputs from daily_* folders under Blends\\animations (with submodule support)",
            "lineNumber": 9
          },
          {
            "lineNumber": 10
          },
          {
            "text": ":: -----------------------------",
            "lineNumber": 11
          },
          {
            "text": ":: Arguments",
            "lineNumber": 12
          },
          {
            "text": ":: -----------------------------",
            "lineNumber": 13
          },
          {
            "text": "set \"DRY=0\"",
            "lineNumber": 14
          },
          {
            "text": "if /I \"%~1\"==\"/dry-run\" set \"DRY=1\"",
            "lineNumber": 15
          },
          {
            "text": "if /I \"%~1\"==\"--dry-run\" set \"DRY=1\"",
            "lineNumber": 16
          },
          {
            "text": "if /I \"%~1\"==\"-n\" set \"DRY=1\"",
            "lineNumber": 17
          },
          {
            "text": "if /I \"%~1\"==\"/n\" set \"DRY=1\"",
            "lineNumber": 18
          },
          {
            "lineNumber": 19
          },
          {
            "text": "set \"projectDir=%CD%\"",
            "lineNumber": 20
          },
          {
            "text": "set \"scriptDir=%~dp0\"",
            "lineNumber": 21
          },
          {
            "text": "set \"RUN_ID=%RANDOM%_%RANDOM%\"",
            "lineNumber": 22
          },
          {
            "text": "set \"DELETE_LIST=%TEMP%\\upg_delete_%RUN_ID%.lst\"",
            "lineNumber": 23
          },
          {
            "lineNumber": 24
          },
          {
            "text": "setlocal EnableDelayedExpansion",
            "lineNumber": 25
          },
          {
            "text": "set /a debugTotal=0",
            "lineNumber": 26
          },
          {
            "text": "set /a debugPlanned=0",
            "lineNumber": 27
          },
          {
            "text": "set /a debugMissing=0",
            "lineNumber": 28
          },
          {
            "lineNumber": 29
          },
          {
            "text": "echo ==============================================",
            "lineNumber": 30
          },
          {
            "text": "echo UpgradeToGitProj in \"%projectDir%\"",
            "lineNumber": 31
          },
          {
            "text": "if \"%DRY%\"==\"1\" (echo Mode: DRY-RUN) else (echo Mode: APPLY)",
            "lineNumber": 32
          },
          {
            "text": "echo ==============================================",
            "lineNumber": 33
          },
          {
            "lineNumber": 34
          },
          {
            "text": ":: -----------------------------",
            "lineNumber": 35
          },
          {
            "text": ":: Ensure Renders exists and copy helper scripts",
            "lineNumber": 36
          },
          {
            "text": ":: -----------------------------",
            "lineNumber": 37
          },
          {
            "text": "set \"rendersDir=%projectDir%\\Renders\"",
            "lineNumber": 38
          },
          {
            "text": "if not exist \"%rendersDir%\" (",
            "lineNumber": 39
          },
          {
            "text": "  if \"%DRY%\"==\"1\" (",
            "lineNumber": 40
          },
          {
            "text": "    echo [DRY] mkdir \"%rendersDir%\"",
            "lineNumber": 41
          },
          {
            "text": "  ) else (",
            "lineNumber": 42
          },
          {
            "text": "    mkdir \"%rendersDir%\" >nul 2>&1",
            "lineNumber": 43
          },
          {
            "text": "  )",
            "lineNumber": 44
          },
          {
            "text": ")",
            "lineNumber": 45
          },
          {
            "lineNumber": 46
          },
          {
            "text": "for %%F in (UpdateSequences.bat ZipSeqArchv.bat UnzipSeqArchv.bat) do (",
            "lineNumber": 47
          },
          {
            "text": "  if exist \"%scriptDir%%%F\" (",
            "lineNumber": 48
          },
          {
            "text": "    if \"%DRY%\"==\"1\" (",
            "lineNumber": 49
          },
          {
            "text": "      echo [DRY] copy \"%scriptDir%%%F\" \"%rendersDir%\\%%F\"",
            "lineNumber": 50
          },
          {
            "text": "    ) else (",
            "lineNumber": 51
          },
          {
            "text": "      copy /Y \"%scriptDir%%%F\" \"%rendersDir%\\%%F\" >nul",
            "lineNumber": 52
          },
          {
            "text": "    )",
            "lineNumber": 53
          },
          {
            "text": "  ) else (",
            "lineNumber": 54
          },
          {
            "text": "    echo [WARN] Missing template: \"%scriptDir%%%F\"",
            "lineNumber": 55
          },
          {
            "text": "  )",
            "lineNumber": 56
          },
          {
            "text": ")",
            "lineNumber": 57
          },
          {
            "lineNumber": 58
          },
          {
            "text": "for %%F in (ConfigLoader.ps1 config.json) do (",
            "lineNumber": 59
          },
          {
            "text": "  if exist \"%scriptDir%%%F\" (",
            "lineNumber": 60
          },
          {
            "text": "    if \"%DRY%\"==\"1\" (",
            "lineNumber": 61
          },
          {
            "text": "      ",
            "lineNumber": 62
          }
        ]
      },
      "score": 0.25357121229171753
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\zip_sequences.py",
        "range": {
          "startPosition": {},
          "endPosition": {
            "line": 102
          }
        },
        "contents": "#!/usr/bin/env python3\n\"\"\"Maintain zipped render sequences for Git hooks.\n\nDefault mode scans `Renders/`, produces ZIP archives under `Renders/_zipped/`,\nand stages any updated archives so commits only track compact files. Switch to\n`--mode expand` to inflate the tracked archives back into the ignored working\ndirectories after checkouts or pulls.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport argparse\nimport json\nimport os\nimport platform\nimport shutil\nimport subprocess\nimport sys\nimport tempfile\nimport time\nimport traceback\nfrom concurrent.futures import ThreadPoolExecutor, as_completed\nfrom pathlib import Path\nfrom typing import Iterator, Sequence\n\n# Try to import psutil for cross-platform RAM detection\ntry:\n    import psutil\n    HAS_PSUTIL = True\nexcept ImportError:\n    HAS_PSUTIL = False\n    # For Windows fallback\n    if platform.system() == \"Windows\":\n        try:\n            import ctypes\n            HAS_CTYPES = True\n        except ImportError:\n            HAS_CTYPES = False\n    else:\n        HAS_CTYPES = False\n\n\nRENDER_ROOT = Path(\"Renders\")\nARCHIVE_ROOT = RENDER_ROOT / \"_zipped\"\nSEQUENCE_EXTENSIONS = {\n    \".png\",\n    \".jpg\",\n    \".jpeg\",\n    \".tif\",\n    \".tiff\",\n    \".exr\",\n}\nSTATE_SUFFIX = \".meta.json\"\nDEFAULT_CONFIG = {\n    \"zipper\": \"7z\",\n    \"compression\": 9,\n    \"compressionMethod\": \"LZMA2\",  # Compression method: LZMA2 (multi-threaded), PPMd (single-threaded), BZip2, Deflate\n    \"dailyFormat\": \"daily_YYMMDD\",\n    \"Max7zInst\": 0,  # Maximum concurrent 7z instances (0 = auto-calculate)\n}\n\n\ndef log(mode: str, message: str, *, verbose_only: bool = False, verbose: bool = False) -> None:\n    if verbose_only and not verbose:\n        return\n    print(f\"[{mode}] {message}\", flush=True)\n\n\ndef load_config() -> dict:\n    # First try to load from project's .config folder (current working directory)\n    # Then fall back to ProjectStructure repo config (next to zip_sequences.py)\n    ",
        "signatures": {},
        "detailedLines": [
          {
            "text": "#!/usr/bin/env python3",
            "lineNumber": 1
          },
          {
            "text": "\"\"\"Maintain zipped render sequences for Git hooks.",
            "lineNumber": 2
          },
          {
            "lineNumber": 3
          },
          {
            "text": "Default mode scans `Renders/`, produces ZIP archives under `Renders/_zipped/`,",
            "lineNumber": 4
          },
          {
            "text": "and stages any updated archives so commits only track compact files. Switch to",
            "lineNumber": 5
          },
          {
            "text": "`--mode expand` to inflate the tracked archives back into the ignored working",
            "lineNumber": 6
          },
          {
            "text": "directories after checkouts or pulls.",
            "lineNumber": 7
          },
          {
            "text": "\"\"\"",
            "lineNumber": 8
          },
          {
            "lineNumber": 9
          },
          {
            "text": "from __future__ import annotations",
            "lineNumber": 10
          },
          {
            "lineNumber": 11
          },
          {
            "text": "import argparse",
            "lineNumber": 12
          },
          {
            "text": "import json",
            "lineNumber": 13
          },
          {
            "text": "import os",
            "lineNumber": 14
          },
          {
            "text": "import platform",
            "lineNumber": 15
          },
          {
            "text": "import shutil",
            "lineNumber": 16
          },
          {
            "text": "import subprocess",
            "lineNumber": 17
          },
          {
            "text": "import sys",
            "lineNumber": 18
          },
          {
            "text": "import tempfile",
            "lineNumber": 19
          },
          {
            "text": "import time",
            "lineNumber": 20
          },
          {
            "text": "import traceback",
            "lineNumber": 21
          },
          {
            "text": "from concurrent.futures import ThreadPoolExecutor, as_completed",
            "lineNumber": 22
          },
          {
            "text": "from pathlib import Path",
            "lineNumber": 23
          },
          {
            "text": "from typing import Iterator, Sequence",
            "lineNumber": 24
          },
          {
            "lineNumber": 25
          },
          {
            "text": "# Try to import psutil for cross-platform RAM detection",
            "lineNumber": 26
          },
          {
            "text": "try:",
            "lineNumber": 27
          },
          {
            "text": "    import psutil",
            "lineNumber": 28
          },
          {
            "text": "    HAS_PSUTIL = True",
            "lineNumber": 29
          },
          {
            "text": "except ImportError:",
            "lineNumber": 30
          },
          {
            "text": "    HAS_PSUTIL = False",
            "lineNumber": 31
          },
          {
            "text": "    # For Windows fallback",
            "lineNumber": 32
          },
          {
            "text": "    if platform.system() == \"Windows\":",
            "lineNumber": 33
          },
          {
            "text": "        try:",
            "lineNumber": 34
          },
          {
            "text": "            import ctypes",
            "lineNumber": 35
          },
          {
            "text": "            HAS_CTYPES = True",
            "lineNumber": 36
          },
          {
            "text": "        except ImportError:",
            "lineNumber": 37
          },
          {
            "text": "            HAS_CTYPES = False",
            "lineNumber": 38
          },
          {
            "text": "    else:",
            "lineNumber": 39
          },
          {
            "text": "        HAS_CTYPES = False",
            "lineNumber": 40
          },
          {
            "lineNumber": 41
          },
          {
            "lineNumber": 42
          },
          {
            "text": "RENDER_ROOT = Path(\"Renders\")",
            "lineNumber": 43
          },
          {
            "text": "ARCHIVE_ROOT = RENDER_ROOT / \"_zipped\"",
            "lineNumber": 44
          },
          {
            "text": "SEQUENCE_EXTENSIONS = {",
            "lineNumber": 45
          },
          {
            "text": "    \".png\",",
            "lineNumber": 46
          },
          {
            "text": "    \".jpg\",",
            "lineNumber": 47
          },
          {
            "text": "    \".jpeg\",",
            "lineNumber": 48
          },
          {
            "text": "    \".tif\",",
            "lineNumber": 49
          },
          {
            "text": "    \".tiff\",",
            "lineNumber": 50
          },
          {
            "text": "    \".exr\",",
            "lineNumber": 51
          },
          {
            "text": "}",
            "lineNumber": 52
          },
          {
            "text": "STATE_SUFFIX = \".meta.json\"",
            "lineNumber": 53
          },
          {
            "text": "DEFAULT_CONFIG = {",
            "lineNumber": 54
          },
          {
            "text": "    \"zipper\": \"7z\",",
            "lineNumber": 55
          },
          {
            "text": "    \"compression\": 9,",
            "lineNumber": 56
          },
          {
            "text": "    \"compressionMethod\": \"LZMA2\",  # Compression method: LZMA2 (multi-threaded), PPMd (single-threaded), BZip2, Deflate",
            "lineNumber": 57
          },
          {
            "text": "    \"dailyFormat\": \"daily_YYMMDD\",",
            "lineNumber": 58
          },
          {
            "text": "    \"Max7zInst\": 0,  # Maximum concurrent 7z instances (0 = auto-calculate)",
            "lineNumber": 59
          },
          {
            "text": "}",
            "lineNumber": 60
          },
          {
            "lineNumber": 61
          },
          {
            "lineNumber": 62
          },
          {
            "text": "def log(mode: str, message: str, *, verbose_only: bool = False, verbose: bool = False) -> None:",
            "lineNumber": 63,
            "isSignature": true
          },
          {
            "text": "    if verbose_only and not verbose:",
            "lineNumber": 64
          },
          {
            "text": "        return",
            "lineNumber": 65
          },
          {
            "text": "    print(f\"[{mode}] {message}\", flush=True)",
            "lineNumber": 66,
            "isSignature": true
          },
          {
            "lineNumber": 67
          },
          {
            "lineNumber": 68
          },
          {
            "text": "def load_config() -> dict:",
            "lineNumber": 69,
            "isSignature": true
          },
          {
            "text": "    # First try to load from project's .config folder (current working directory)",
            "lineNumber": 70,
            "isSignature": true
          },
          {
            "text": "    # Then fall back to ProjectStructure repo config (next to zip_sequences.py)",
            "lineNumber": 71,
            "isSignature": true
          },
          {
            "text": "    ",
            "lineNumber": 72
          }
        ]
      },
      "score": 0.251534104347229
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\compress_blend_files.bat",
        "range": {
          "startPosition": {
            "line": 64
          },
          "endPosition": {
            "line": 118
          }
        },
        "contents": "echo             output_file = os.path.join^(\"output\", filename^)\necho             # Check if output file already exists\necho             if os.path.exists^(output_file^):\necho                 print^(\"SKIP_EXISTING:\" + blend_file^)\necho                 continue\necho             # Skip if source is already compressed\necho             if is_compressed_file^(blend_file^):\necho                 print^(\"SKIP_ALREADY_COMPRESSED:\" + blend_file^)\necho                 continue\necho             print^(\"PROCESSING:\" + blend_file^)\necho             # Load the blend file\necho             bpy.ops.wm.open_mainfile^(filepath=blend_file^)\necho             # Save with compression to output folder\necho             bpy.ops.wm.save_mainfile^(filepath=output_file, compress=True^)\necho             print^(\"SUCCESS:\" + blend_file + \":\" + output_file^)\necho         except Exception as e:\necho             print^(\"CRASH:\" + blend_file + \":\" + str^(e^)^)\necho     else:\necho         print^(\"SKIP_NOT_BLEND:\" + blend_file^)\necho.\necho print^(\"COMPRESSION_COMPLETE\"^)\necho bpy.ops.wm.quit_blender^(^)\n) > \"!TEMP_SCRIPT!\"\n\nREM Check if script was created successfully\nif exist \"!TEMP_SCRIPT!\" (\n    echo Script created successfully: !TEMP_SCRIPT!\n) else (\n    echo ERROR: Failed to create script file!\n    pause\n    exit /b 1\n)\n\nREM Run Blender to process the dragged files\necho Processing dragged .blend files...\necho Using script: !TEMP_SCRIPT!\ndel /f /q \"blender_output.txt\" 2>nul\nblender --background --factory-startup --python \"!TEMP_SCRIPT!\" -- %* 2^>^&1 | powershell -NoProfile -Command \"$input | Tee-Object -FilePath 'blender_output.txt'\"\n\nREM Clean up temporary script\necho Cleaning up temporary script...\ndel \"!TEMP_SCRIPT!\" 2>nul\n\nREM Parse output and generate report\necho.\necho ========================================\necho COMPRESSION REPORT\necho ========================================\necho.\n\nREM Count processed files and get file info\nfor /f \"tokens=1,2,3 delims=:\" %%a in (blender_output.txt) do (\n    if \"%%a\"==\"SUCCESS\" (\n        set /a processed+=1",
        "signatures": {},
        "detailedLines": [
          {
            "text": "echo             output_file = os.path.join^(\"output\", filename^)",
            "lineNumber": 65
          },
          {
            "text": "echo             # Check if output file already exists",
            "lineNumber": 66
          },
          {
            "text": "echo             if os.path.exists^(output_file^):",
            "lineNumber": 67
          },
          {
            "text": "echo                 print^(\"SKIP_EXISTING:\" + blend_file^)",
            "lineNumber": 68
          },
          {
            "text": "echo                 continue",
            "lineNumber": 69
          },
          {
            "text": "echo             # Skip if source is already compressed",
            "lineNumber": 70
          },
          {
            "text": "echo             if is_compressed_file^(blend_file^):",
            "lineNumber": 71
          },
          {
            "text": "echo                 print^(\"SKIP_ALREADY_COMPRESSED:\" + blend_file^)",
            "lineNumber": 72
          },
          {
            "text": "echo                 continue",
            "lineNumber": 73
          },
          {
            "text": "echo             print^(\"PROCESSING:\" + blend_file^)",
            "lineNumber": 74
          },
          {
            "text": "echo             # Load the blend file",
            "lineNumber": 75
          },
          {
            "text": "echo             bpy.ops.wm.open_mainfile^(filepath=blend_file^)",
            "lineNumber": 76
          },
          {
            "text": "echo             # Save with compression to output folder",
            "lineNumber": 77
          },
          {
            "text": "echo             bpy.ops.wm.save_mainfile^(filepath=output_file, compress=True^)",
            "lineNumber": 78
          },
          {
            "text": "echo             print^(\"SUCCESS:\" + blend_file + \":\" + output_file^)",
            "lineNumber": 79
          },
          {
            "text": "echo         except Exception as e:",
            "lineNumber": 80
          },
          {
            "text": "echo             print^(\"CRASH:\" + blend_file + \":\" + str^(e^)^)",
            "lineNumber": 81
          },
          {
            "text": "echo     else:",
            "lineNumber": 82
          },
          {
            "text": "echo         print^(\"SKIP_NOT_BLEND:\" + blend_file^)",
            "lineNumber": 83
          },
          {
            "text": "echo.",
            "lineNumber": 84
          },
          {
            "text": "echo print^(\"COMPRESSION_COMPLETE\"^)",
            "lineNumber": 85
          },
          {
            "text": "echo bpy.ops.wm.quit_blender^(^)",
            "lineNumber": 86
          },
          {
            "text": ") > \"!TEMP_SCRIPT!\"",
            "lineNumber": 87
          },
          {
            "lineNumber": 88
          },
          {
            "text": "REM Check if script was created successfully",
            "lineNumber": 89
          },
          {
            "text": "if exist \"!TEMP_SCRIPT!\" (",
            "lineNumber": 90
          },
          {
            "text": "    echo Script created successfully: !TEMP_SCRIPT!",
            "lineNumber": 91
          },
          {
            "text": ") else (",
            "lineNumber": 92
          },
          {
            "text": "    echo ERROR: Failed to create script file!",
            "lineNumber": 93
          },
          {
            "text": "    pause",
            "lineNumber": 94
          },
          {
            "text": "    exit /b 1",
            "lineNumber": 95
          },
          {
            "text": ")",
            "lineNumber": 96
          },
          {
            "lineNumber": 97
          },
          {
            "text": "REM Run Blender to process the dragged files",
            "lineNumber": 98
          },
          {
            "text": "echo Processing dragged .blend files...",
            "lineNumber": 99
          },
          {
            "text": "echo Using script: !TEMP_SCRIPT!",
            "lineNumber": 100
          },
          {
            "text": "del /f /q \"blender_output.txt\" 2>nul",
            "lineNumber": 101
          },
          {
            "text": "blender --background --factory-startup --python \"!TEMP_SCRIPT!\" -- %* 2^>^&1 | powershell -NoProfile -Command \"$input | Tee-Object -FilePath 'blender_output.txt'\"",
            "lineNumber": 102
          },
          {
            "lineNumber": 103
          },
          {
            "text": "REM Clean up temporary script",
            "lineNumber": 104
          },
          {
            "text": "echo Cleaning up temporary script...",
            "lineNumber": 105
          },
          {
            "text": "del \"!TEMP_SCRIPT!\" 2>nul",
            "lineNumber": 106
          },
          {
            "lineNumber": 107
          },
          {
            "text": "REM Parse output and generate report",
            "lineNumber": 108
          },
          {
            "text": "echo.",
            "lineNumber": 109
          },
          {
            "text": "echo ========================================",
            "lineNumber": 110
          },
          {
            "text": "echo COMPRESSION REPORT",
            "lineNumber": 111
          },
          {
            "text": "echo ========================================",
            "lineNumber": 112
          },
          {
            "text": "echo.",
            "lineNumber": 113
          },
          {
            "lineNumber": 114
          },
          {
            "text": "REM Count processed files and get file info",
            "lineNumber": 115
          },
          {
            "text": "for /f \"tokens=1,2,3 delims=:\" %%a in (blender_output.txt) do (",
            "lineNumber": 116
          },
          {
            "text": "    if \"%%a\"==\"SUCCESS\" (",
            "lineNumber": 117
          },
          {
            "text": "        set /a processed+=1",
            "lineNumber": 118
          }
        ]
      },
      "score": 0.24592049419879913
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\ConfigLoader.ps1",
        "range": {
          "startPosition": {
            "line": 226
          },
          "endPosition": {
            "line": 268
          }
        },
        "contents": "            exit 1\n        }\n\n        if (-not (Test-Path -LiteralPath $resolvedProject -PathType Container)) {\n            Write-Error \"Project path is not a directory: $resolvedProject\"\n            exit 1\n        }\n\n        Write-Host \"`nDeploying to: $resolvedProject\" -ForegroundColor Cyan\n        Write-Host \"Struct directory:  $structDir\" -ForegroundColor Cyan\n\n        $specs = @(\n            @{ Name = 'UpdateSequences.bat'; Source = Join-Path -Path $structDir -ChildPath 'UpdateSequences.bat' },\n            @{ Name = 'UpdateAllSequences.bat'; Source = Join-Path -Path $structDir -ChildPath 'UpdateAllSequences.bat' },\n            @{ Name = 'ZipSeqArchv.bat'; Source = Join-Path -Path $structDir -ChildPath 'ZipSeqArchv.bat' },\n            @{ Name = 'UnzipSeqArchv.bat'; Source = Join-Path -Path $structDir -ChildPath 'UnzipSeqArchv.bat' },\n            @{ Name = 'NewDaily.bat'; Source = Join-Path -Path $structDir -ChildPath 'NewDaily.bat' },\n            @{ Name = '.gitattributes'; Source = Join-Path -Path $structDir -ChildPath 'components\\gitattributes' },\n            @{ Name = '.gitignore'; Source = Join-Path -Path $structDir -ChildPath 'components\\gitignore' }\n        )\n\n        # Config files to deploy to projectroot\\.config\\\n        $configAssets = @(\n            @{ Name = 'config.json'; Source = Join-Path -Path $structDir -ChildPath 'config.json' },\n            @{ Name = 'GetStructDir.ps1'; Source = Join-Path -Path $structDir -ChildPath 'GetStructDir.ps1' }\n        )\n\n        foreach ($spec in $specs) {\n            if (-not (Test-Path -LiteralPath $spec.Source -PathType Leaf)) {\n                Write-Error \"Source file not found: $($spec.Source)\"\n                exit 1\n            }\n        }\n\n        foreach ($asset in $configAssets) {\n            if (-not (Test-Path -LiteralPath $asset.Source -PathType Leaf)) {\n                Write-Error \"Config asset not found: $($asset.Source)\"\n                exit 1\n            }\n        }\n\n        # Ensure .config directory exists in project root and is hidden",
        "signatures": {},
        "detailedLines": [
          {
            "text": "            exit 1",
            "lineNumber": 227
          },
          {
            "text": "        }",
            "lineNumber": 228
          },
          {
            "lineNumber": 229
          },
          {
            "text": "        if (-not (Test-Path -LiteralPath $resolvedProject -PathType Container)) {",
            "lineNumber": 230
          },
          {
            "text": "            Write-Error \"Project path is not a directory: $resolvedProject\"",
            "lineNumber": 231
          },
          {
            "text": "            exit 1",
            "lineNumber": 232
          },
          {
            "text": "        }",
            "lineNumber": 233
          },
          {
            "lineNumber": 234
          },
          {
            "text": "        Write-Host \"`nDeploying to: $resolvedProject\" -ForegroundColor Cyan",
            "lineNumber": 235
          },
          {
            "text": "        Write-Host \"Struct directory:  $structDir\" -ForegroundColor Cyan",
            "lineNumber": 236
          },
          {
            "lineNumber": 237
          },
          {
            "text": "        $specs = @(",
            "lineNumber": 238
          },
          {
            "text": "            @{ Name = 'UpdateSequences.bat'; Source = Join-Path -Path $structDir -ChildPath 'UpdateSequences.bat' },",
            "lineNumber": 239
          },
          {
            "text": "            @{ Name = 'UpdateAllSequences.bat'; Source = Join-Path -Path $structDir -ChildPath 'UpdateAllSequences.bat' },",
            "lineNumber": 240
          },
          {
            "text": "            @{ Name = 'ZipSeqArchv.bat'; Source = Join-Path -Path $structDir -ChildPath 'ZipSeqArchv.bat' },",
            "lineNumber": 241
          },
          {
            "text": "            @{ Name = 'UnzipSeqArchv.bat'; Source = Join-Path -Path $structDir -ChildPath 'UnzipSeqArchv.bat' },",
            "lineNumber": 242
          },
          {
            "text": "            @{ Name = 'NewDaily.bat'; Source = Join-Path -Path $structDir -ChildPath 'NewDaily.bat' },",
            "lineNumber": 243
          },
          {
            "text": "            @{ Name = '.gitattributes'; Source = Join-Path -Path $structDir -ChildPath 'components\\gitattributes' },",
            "lineNumber": 244
          },
          {
            "text": "            @{ Name = '.gitignore'; Source = Join-Path -Path $structDir -ChildPath 'components\\gitignore' }",
            "lineNumber": 245
          },
          {
            "text": "        )",
            "lineNumber": 246
          },
          {
            "lineNumber": 247
          },
          {
            "text": "        # Config files to deploy to projectroot\\.config\\",
            "lineNumber": 248
          },
          {
            "text": "        $configAssets = @(",
            "lineNumber": 249
          },
          {
            "text": "            @{ Name = 'config.json'; Source = Join-Path -Path $structDir -ChildPath 'config.json' },",
            "lineNumber": 250
          },
          {
            "text": "            @{ Name = 'GetStructDir.ps1'; Source = Join-Path -Path $structDir -ChildPath 'GetStructDir.ps1' }",
            "lineNumber": 251
          },
          {
            "text": "        )",
            "lineNumber": 252
          },
          {
            "lineNumber": 253
          },
          {
            "text": "        foreach ($spec in $specs) {",
            "lineNumber": 254
          },
          {
            "text": "            if (-not (Test-Path -LiteralPath $spec.Source -PathType Leaf)) {",
            "lineNumber": 255
          },
          {
            "text": "                Write-Error \"Source file not found: $($spec.Source)\"",
            "lineNumber": 256
          },
          {
            "text": "                exit 1",
            "lineNumber": 257
          },
          {
            "text": "            }",
            "lineNumber": 258
          },
          {
            "text": "        }",
            "lineNumber": 259
          },
          {
            "lineNumber": 260
          },
          {
            "text": "        foreach ($asset in $configAssets) {",
            "lineNumber": 261
          },
          {
            "text": "            if (-not (Test-Path -LiteralPath $asset.Source -PathType Leaf)) {",
            "lineNumber": 262
          },
          {
            "text": "                Write-Error \"Config asset not found: $($asset.Source)\"",
            "lineNumber": 263
          },
          {
            "text": "                exit 1",
            "lineNumber": 264
          },
          {
            "text": "            }",
            "lineNumber": 265
          },
          {
            "text": "        }",
            "lineNumber": 266
          },
          {
            "lineNumber": 267
          },
          {
            "text": "        # Ensure .config directory exists in project root and is hidden",
            "lineNumber": 268
          }
        ]
      },
      "score": 0.24059920012950897
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\UpdateSequences.ps1",
        "range": {
          "startPosition": {
            "line": 221
          },
          "endPosition": {
            "line": 266,
            "column": 8
          }
        },
        "contents": "    $primaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $primaryPattern -ErrorAction SilentlyContinue |\n        Where-Object { $_.Name -notlike '_*' }\n    foreach ($d in $primaryDirs) {\n        $seqDirs = @(Get-ChildItem -LiteralPath $d.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -notlike '_*' })\n        if ($seqDirs.Count -eq 0) {\n            Add-SequenceFolder -Directory $d -Map $sequenceMap\n        } else {\n            foreach ($s in $seqDirs) {\n                Add-SequenceFolder -Directory $s -Map $sequenceMap\n            }\n        }\n    }\n\n    $secondaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $secondaryPattern -ErrorAction SilentlyContinue |\n        Where-Object { $_.Name -notlike '_*' }\n    foreach ($d in $secondaryDirs) {\n        $seqDirs = @(Get-ChildItem -LiteralPath $d.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -notlike '_*' })\n        if ($seqDirs.Count -eq 0) {\n            Add-SequenceFolder -Directory $d -Map $sequenceMap\n        } else {\n            foreach ($s in $seqDirs) {\n                Add-SequenceFolder -Directory $s -Map $sequenceMap\n            }\n        }\n    }\n\n    $directSeqs = Get-ChildItem -LiteralPath $root -Directory -ErrorAction SilentlyContinue |\n        Where-Object {\n            $_.Name -notlike '_*' -and\n            $_.Name -notlike 'daily_*' -and\n            $_.Name -notmatch '^\\d{4}-\\d{2}-\\d{2}$'\n        }\n    foreach ($seq in $directSeqs) {\n        Add-SequenceFolder -Directory $seq -Map $sequenceMap\n    }\n\n    $sequenceFolders = $sequenceMap.GetEnumerator() | ForEach-Object {\n        [pscustomobject]@{\n            Path = $_.Key\n            Name = $_.Value\n        }\n    } | Sort-Object -Property Path\n\n    if (-not $sequenceFolders) {\n        ",
        "signatures": {},
        "detailedLines": [
          {
            "text": "    $primaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $primaryPattern -ErrorAction SilentlyContinue |",
            "lineNumber": 223
          },
          {
            "text": "        Where-Object { $_.Name -notlike '_*' }",
            "lineNumber": 224
          },
          {
            "text": "    foreach ($d in $primaryDirs) {",
            "lineNumber": 225
          },
          {
            "text": "        $seqDirs = @(Get-ChildItem -LiteralPath $d.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -notlike '_*' })",
            "lineNumber": 226
          },
          {
            "text": "        if ($seqDirs.Count -eq 0) {",
            "lineNumber": 227
          },
          {
            "text": "            Add-SequenceFolder -Directory $d -Map $sequenceMap",
            "lineNumber": 228
          },
          {
            "text": "        } else {",
            "lineNumber": 229
          },
          {
            "text": "            foreach ($s in $seqDirs) {",
            "lineNumber": 230
          },
          {
            "text": "                Add-SequenceFolder -Directory $s -Map $sequenceMap",
            "lineNumber": 231
          },
          {
            "text": "            }",
            "lineNumber": 232
          },
          {
            "text": "        }",
            "lineNumber": 233
          },
          {
            "text": "    }",
            "lineNumber": 234
          },
          {
            "lineNumber": 235
          },
          {
            "text": "    $secondaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $secondaryPattern -ErrorAction SilentlyContinue |",
            "lineNumber": 236
          },
          {
            "text": "        Where-Object { $_.Name -notlike '_*' }",
            "lineNumber": 237
          },
          {
            "text": "    foreach ($d in $secondaryDirs) {",
            "lineNumber": 238
          },
          {
            "text": "        $seqDirs = @(Get-ChildItem -LiteralPath $d.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -notlike '_*' })",
            "lineNumber": 239
          },
          {
            "text": "        if ($seqDirs.Count -eq 0) {",
            "lineNumber": 240
          },
          {
            "text": "            Add-SequenceFolder -Directory $d -Map $sequenceMap",
            "lineNumber": 241
          },
          {
            "text": "        } else {",
            "lineNumber": 242
          },
          {
            "text": "            foreach ($s in $seqDirs) {",
            "lineNumber": 243
          },
          {
            "text": "                Add-SequenceFolder -Directory $s -Map $sequenceMap",
            "lineNumber": 244
          },
          {
            "text": "            }",
            "lineNumber": 245
          },
          {
            "text": "        }",
            "lineNumber": 246
          },
          {
            "text": "    }",
            "lineNumber": 247
          },
          {
            "lineNumber": 248
          },
          {
            "text": "    $directSeqs = Get-ChildItem -LiteralPath $root -Directory -ErrorAction SilentlyContinue |",
            "lineNumber": 249
          },
          {
            "text": "        Where-Object {",
            "lineNumber": 250
          },
          {
            "text": "            $_.Name -notlike '_*' -and",
            "lineNumber": 251
          },
          {
            "text": "            $_.Name -notlike 'daily_*' -and",
            "lineNumber": 252
          },
          {
            "text": "            $_.Name -notmatch '^\\d{4}-\\d{2}-\\d{2}$'",
            "lineNumber": 253
          },
          {
            "text": "        }",
            "lineNumber": 254
          },
          {
            "text": "    foreach ($seq in $directSeqs) {",
            "lineNumber": 255
          },
          {
            "text": "        Add-SequenceFolder -Directory $seq -Map $sequenceMap",
            "lineNumber": 256
          },
          {
            "text": "    }",
            "lineNumber": 257
          },
          {
            "lineNumber": 258
          },
          {
            "text": "    $sequenceFolders = $sequenceMap.GetEnumerator() | ForEach-Object {",
            "lineNumber": 259
          },
          {
            "text": "        [pscustomobject]@{",
            "lineNumber": 260
          },
          {
            "text": "            Path = $_.Key",
            "lineNumber": 261
          },
          {
            "text": "            Name = $_.Value",
            "lineNumber": 262
          },
          {
            "text": "        }",
            "lineNumber": 263
          },
          {
            "text": "    } | Sort-Object -Property Path",
            "lineNumber": 264
          },
          {
            "lineNumber": 265
          },
          {
            "text": "    if (-not $sequenceFolders) {",
            "lineNumber": 266
          },
          {
            "text": "        ",
            "lineNumber": 267
          }
        ]
      },
      "score": 0.2402079999446869
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\zip_sequences.py",
        "range": {
          "startPosition": {
            "line": 645,
            "column": 42
          },
          "endPosition": {
            "line": 661,
            "column": 63
          }
        },
        "contents": "def sequence_dir_for(zip_path: Path) -> Path:\n    rel = zip_path.relative_to(ARCHIVE_ROOT)\n    # Remove the archive suffix (.7z or .zip) from the end\n    # Handle both .7z and .zip extensions\n    rel_str = str(rel)\n    if rel_str.endswith(\".7z\"):\n        rel_str = rel_str[:-3]\n    elif rel_str.endswith(\".zip\"):\n        rel_str = rel_str[:-4]\n    return RENDER_ROOT / rel_str\n\n\ndef state_path_for(zip_path: Path) -> Path:\n    return zip_path.with_suffix(zip_path.suffix + STATE_SUFFIX)",
        "signatures": {},
        "detailedLines": [
          {
            "text": "def sequence_dir_for(zip_path: Path) -> Path:",
            "lineNumber": 649,
            "isSignature": true
          },
          {
            "text": "    rel = zip_path.relative_to(ARCHIVE_ROOT)",
            "lineNumber": 650
          },
          {
            "text": "    # Remove the archive suffix (.7z or .zip) from the end",
            "lineNumber": 651
          },
          {
            "text": "    # Handle both .7z and .zip extensions",
            "lineNumber": 652
          },
          {
            "text": "    rel_str = str(rel)",
            "lineNumber": 653
          },
          {
            "text": "    if rel_str.endswith(\".7z\"):",
            "lineNumber": 654
          },
          {
            "text": "        rel_str = rel_str[:-3]",
            "lineNumber": 655
          },
          {
            "text": "    elif rel_str.endswith(\".zip\"):",
            "lineNumber": 656
          },
          {
            "text": "        rel_str = rel_str[:-4]",
            "lineNumber": 657
          },
          {
            "text": "    return RENDER_ROOT / rel_str",
            "lineNumber": 658,
            "isSignature": true
          },
          {
            "lineNumber": 659
          },
          {
            "lineNumber": 660
          },
          {
            "text": "def state_path_for(zip_path: Path) -> Path:",
            "lineNumber": 661,
            "isSignature": true
          },
          {
            "text": "    return zip_path.with_suffix(zip_path.suffix + STATE_SUFFIX)",
            "lineNumber": 662,
            "isSignature": true
          }
        ]
      },
      "score": 0.23667949438095093
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\organize_textures.bat",
        "range": {
          "startPosition": {},
          "endPosition": {
            "line": 22,
            "column": 12
          }
        },
        "contents": "@echo off\nsetlocal EnableExtensions\n\nset \"script_dir=%~dp0\"\nset \"ps1_path=%script_dir%organize_textures.ps1\"\n\nif not exist \"%ps1_path%\" (\n    echo [ERROR] organize_textures.ps1 not found at %ps1_path%\n    exit /b 1\n)\n\necho Running texture organizer...\npwsh -NoProfile -ExecutionPolicy Bypass -File \"%ps1_path%\"\nset \"rc=%errorlevel%\"\n\nif %rc% neq 0 (\n    echo.\n    echo Script exited with error code %rc%\n)\n\necho.\npause\nexit /b %rc%",
        "signatures": {},
        "detailedLines": [
          {
            "text": "@echo off",
            "lineNumber": 1
          },
          {
            "text": "setlocal EnableExtensions",
            "lineNumber": 2
          },
          {
            "lineNumber": 3
          },
          {
            "text": "set \"script_dir=%~dp0\"",
            "lineNumber": 4
          },
          {
            "text": "set \"ps1_path=%script_dir%organize_textures.ps1\"",
            "lineNumber": 5
          },
          {
            "lineNumber": 6
          },
          {
            "text": "if not exist \"%ps1_path%\" (",
            "lineNumber": 7
          },
          {
            "text": "    echo [ERROR] organize_textures.ps1 not found at %ps1_path%",
            "lineNumber": 8
          },
          {
            "text": "    exit /b 1",
            "lineNumber": 9
          },
          {
            "text": ")",
            "lineNumber": 10
          },
          {
            "lineNumber": 11
          },
          {
            "text": "echo Running texture organizer...",
            "lineNumber": 12
          },
          {
            "text": "pwsh -NoProfile -ExecutionPolicy Bypass -File \"%ps1_path%\"",
            "lineNumber": 13
          },
          {
            "text": "set \"rc=%errorlevel%\"",
            "lineNumber": 14
          },
          {
            "lineNumber": 15
          },
          {
            "text": "if %rc% neq 0 (",
            "lineNumber": 16
          },
          {
            "text": "    echo.",
            "lineNumber": 17
          },
          {
            "text": "    echo Script exited with error code %rc%",
            "lineNumber": 18
          },
          {
            "text": ")",
            "lineNumber": 19
          },
          {
            "lineNumber": 20
          },
          {
            "text": "echo.",
            "lineNumber": 21
          },
          {
            "text": "pause",
            "lineNumber": 22
          },
          {
            "text": "exit /b %rc%",
            "lineNumber": 23
          }
        ]
      },
      "score": 0.23035340011119843
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\UpdateProjectBatches.ps1",
        "range": {
          "startPosition": {
            "line": 55
          },
          "endPosition": {
            "line": 115
          }
        },
        "contents": ")\n\n# Config files to deploy to projectroot\\.config\\\n$configAssets = @(\n    @{ Name = 'config.json'; Source = Join-Path -Path $structDir -ChildPath 'config.json' },\n    @{ Name = 'GetStructDir.ps1'; Source = Join-Path -Path $structDir -ChildPath 'GetStructDir.ps1' }\n)\n\nforeach ($spec in $specs) {\n    if (-not (Test-Path -LiteralPath $spec.Source -PathType Leaf)) {\n        Write-Error \"Source file not found: $($spec.Source)\"\n        exit 1\n    }\n}\n\nforeach ($asset in $configAssets) {\n    if (-not (Test-Path -LiteralPath $asset.Source -PathType Leaf)) {\n        Write-Error \"Config asset not found: $($asset.Source)\"\n        exit 1\n    }\n}\n\n# Ensure .config directory exists in project root\n$projectConfigDir = Join-Path -Path $resolvedProject -ChildPath '.config'\nif (-not (Test-Path -LiteralPath $projectConfigDir -PathType Container)) {\n    New-Item -Path $projectConfigDir -ItemType Directory -Force | Out-Null\n    Write-Host \"Created .config directory: $projectConfigDir\" -ForegroundColor Cyan\n}\n\n$touchedDirs = @{}\n$summary = @()\n\nforeach ($spec in $specs) {\n    Write-Host \"`n=== Updating $($spec.Name) ===\" -ForegroundColor Magenta\n\n    $targets = Get-ChildItem -LiteralPath $resolvedProject -Recurse -Filter $spec.Name -File -ErrorAction SilentlyContinue\n    $targets = $targets | Where-Object { $_.FullName -ne $spec.Source }\n\n    if (-not $targets) {\n        Write-Host \"No targets found.\" -ForegroundColor Yellow\n        $summary += [pscustomobject]@{\n            Name     = $spec.Name\n            Updated  = 0\n            Failed   = 0\n            Skipped  = 0\n            Total    = 0\n        }\n        continue\n    }\n\n    $updated = 0\n    $failed = 0\n\n    foreach ($target in $targets) {\n        try {\n            Copy-Item -Path $spec.Source -Destination $target.FullName -Force\n            Write-Host \"[OK] $($target.FullName)\" -ForegroundColor Green\n            $updated++\n\n            $targetDir = $target.Directory.FullName",
        "signatures": {},
        "detailedLines": [
          {
            "text": ")",
            "lineNumber": 56
          },
          {
            "lineNumber": 57
          },
          {
            "text": "# Config files to deploy to projectroot\\.config\\",
            "lineNumber": 58
          },
          {
            "text": "$configAssets = @(",
            "lineNumber": 59
          },
          {
            "text": "    @{ Name = 'config.json'; Source = Join-Path -Path $structDir -ChildPath 'config.json' },",
            "lineNumber": 60
          },
          {
            "text": "    @{ Name = 'GetStructDir.ps1'; Source = Join-Path -Path $structDir -ChildPath 'GetStructDir.ps1' }",
            "lineNumber": 61
          },
          {
            "text": ")",
            "lineNumber": 62
          },
          {
            "lineNumber": 63
          },
          {
            "text": "foreach ($spec in $specs) {",
            "lineNumber": 64
          },
          {
            "text": "    if (-not (Test-Path -LiteralPath $spec.Source -PathType Leaf)) {",
            "lineNumber": 65
          },
          {
            "text": "        Write-Error \"Source file not found: $($spec.Source)\"",
            "lineNumber": 66
          },
          {
            "text": "        exit 1",
            "lineNumber": 67
          },
          {
            "text": "    }",
            "lineNumber": 68
          },
          {
            "text": "}",
            "lineNumber": 69
          },
          {
            "lineNumber": 70
          },
          {
            "text": "foreach ($asset in $configAssets) {",
            "lineNumber": 71
          },
          {
            "text": "    if (-not (Test-Path -LiteralPath $asset.Source -PathType Leaf)) {",
            "lineNumber": 72
          },
          {
            "text": "        Write-Error \"Config asset not found: $($asset.Source)\"",
            "lineNumber": 73
          },
          {
            "text": "        exit 1",
            "lineNumber": 74
          },
          {
            "text": "    }",
            "lineNumber": 75
          },
          {
            "text": "}",
            "lineNumber": 76
          },
          {
            "lineNumber": 77
          },
          {
            "text": "# Ensure .config directory exists in project root",
            "lineNumber": 78
          },
          {
            "text": "$projectConfigDir = Join-Path -Path $resolvedProject -ChildPath '.config'",
            "lineNumber": 79
          },
          {
            "text": "if (-not (Test-Path -LiteralPath $projectConfigDir -PathType Container)) {",
            "lineNumber": 80
          },
          {
            "text": "    New-Item -Path $projectConfigDir -ItemType Directory -Force | Out-Null",
            "lineNumber": 81
          },
          {
            "text": "    Write-Host \"Created .config directory: $projectConfigDir\" -ForegroundColor Cyan",
            "lineNumber": 82
          },
          {
            "text": "}",
            "lineNumber": 83
          },
          {
            "lineNumber": 84
          },
          {
            "text": "$touchedDirs = @{}",
            "lineNumber": 85
          },
          {
            "text": "$summary = @()",
            "lineNumber": 86
          },
          {
            "lineNumber": 87
          },
          {
            "text": "foreach ($spec in $specs) {",
            "lineNumber": 88
          },
          {
            "text": "    Write-Host \"`n=== Updating $($spec.Name) ===\" -ForegroundColor Magenta",
            "lineNumber": 89
          },
          {
            "lineNumber": 90
          },
          {
            "text": "    $targets = Get-ChildItem -LiteralPath $resolvedProject -Recurse -Filter $spec.Name -File -ErrorAction SilentlyContinue",
            "lineNumber": 91
          },
          {
            "text": "    $targets = $targets | Where-Object { $_.FullName -ne $spec.Source }",
            "lineNumber": 92
          },
          {
            "lineNumber": 93
          },
          {
            "text": "    if (-not $targets) {",
            "lineNumber": 94
          },
          {
            "text": "        Write-Host \"No targets found.\" -ForegroundColor Yellow",
            "lineNumber": 95
          },
          {
            "text": "        $summary += [pscustomobject]@{",
            "lineNumber": 96
          },
          {
            "text": "            Name     = $spec.Name",
            "lineNumber": 97
          },
          {
            "text": "            Updated  = 0",
            "lineNumber": 98
          },
          {
            "text": "            Failed   = 0",
            "lineNumber": 99
          },
          {
            "text": "            Skipped  = 0",
            "lineNumber": 100
          },
          {
            "text": "            Total    = 0",
            "lineNumber": 101
          },
          {
            "text": "        }",
            "lineNumber": 102
          },
          {
            "text": "        continue",
            "lineNumber": 103
          },
          {
            "text": "    }",
            "lineNumber": 104
          },
          {
            "lineNumber": 105
          },
          {
            "text": "    $updated = 0",
            "lineNumber": 106
          },
          {
            "text": "    $failed = 0",
            "lineNumber": 107
          },
          {
            "lineNumber": 108
          },
          {
            "text": "    foreach ($target in $targets) {",
            "lineNumber": 109
          },
          {
            "text": "        try {",
            "lineNumber": 110
          },
          {
            "text": "            Copy-Item -Path $spec.Source -Destination $target.FullName -Force",
            "lineNumber": 111
          },
          {
            "text": "            Write-Host \"[OK] $($target.FullName)\" -ForegroundColor Green",
            "lineNumber": 112
          },
          {
            "text": "            $updated++",
            "lineNumber": 113
          },
          {
            "lineNumber": 114
          },
          {
            "text": "            $targetDir = $target.Directory.FullName",
            "lineNumber": 115
          }
        ]
      },
      "score": 0.22555430233478546
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\remove_action_fake_users.bat",
        "range": {
          "startPosition": {},
          "endPosition": {
            "line": 66
          }
        },
        "contents": "@echo off\nsetlocal enabledelayedexpansion\n\necho Starting fake user removal for actions...\n\nREM Check if files were dragged onto the batch file\nif \"%~1\"==\"\" (\n\techo.\n\techo Usage: Drag .blend files onto this batch file to remove fake users from actions.\n\techo Output will be saved to the \\output folder.\n\techo.\n\tpause\n\texit /b 1\n)\n\nREM Create output directory if it doesn't exist\nif not exist \"output\" mkdir \"output\"\n\nREM Initialize counters and tracking\nset \"processed=0\"\nset \"crashed=0\"\nset \"skipped=0\"\nset \"deleted_similar=0\"\nset \"threshold_percent=10\"\nset \"updated_total=0\"\n\nREM Create a temporary Python script for processing\nset \"TEMP_SCRIPT=remove_action_fake_users_temp.py\"\necho Creating Python script: !TEMP_SCRIPT!\n\n(\necho import bpy\necho import os\necho import sys\necho.\necho # Create output directory if it doesn't exist\necho if not os.path.exists^(\"output\"^):\necho \tos.makedirs^(\"output\"^)\necho.\necho # Get command line arguments ^(the dragged files^)\necho blend_files = sys.argv[sys.argv.index^(\"--\"^) + 1:] if \"--\" in sys.argv else []\necho.\necho print^(\"Found \" + str^(len^(blend_files^)^) + \" .blend files to process\"^)\necho.\necho for blend_file in blend_files:\necho ^\tif blend_file.lower^(^).endswith^(\".blend\"^):\necho ^\t\ttry:\necho ^\t\t\t# Create output path in output folder\necho ^\t\t\tfilename = os.path.basename^(blend_file^)\necho ^\t\t\toutput_file = os.path.join^(\"output\", filename^)\necho ^\t\t\t# Check if output file already exists\necho ^\t\t\tif os.path.exists^(output_file^):\necho ^\t\t\t\tprint^(\"SKIP_EXISTING:\" + blend_file^)\necho ^\t\t\t\tcontinue\necho ^\t\t\tprint^(\"PROCESSING:\" + blend_file^)\necho ^\t\t\t# Load the blend file\necho ^\t\t\tbpy.ops.wm.open_mainfile^(filepath=blend_file^)\necho ^\t\t\t# Remove fake users from all actions\necho ^\t\t\tchanged = 0\necho ^\t\t\tfor action in bpy.data.actions:\necho ^\t\t\t\tif getattr^(action, \"use_fake_user\", False^):\necho ^\t\t\t\t\taction.use_fake_user = False\necho ^\t\t\t\t\tchanged += 1\necho ^\t\t\tprint^(\"UPDATED:\" + blend_file + \":\" + str^(changed^)^)\necho ^\t\t\t# Save to output folder\necho ^\t\t\tbpy.ops.wm.save_mainfile^(filepath=output_file, compress=True^)",
        "signatures": {},
        "detailedLines": [
          {
            "text": "@echo off",
            "lineNumber": 1
          },
          {
            "text": "setlocal enabledelayedexpansion",
            "lineNumber": 2
          },
          {
            "lineNumber": 3
          },
          {
            "text": "echo Starting fake user removal for actions...",
            "lineNumber": 4
          },
          {
            "lineNumber": 5
          },
          {
            "text": "REM Check if files were dragged onto the batch file",
            "lineNumber": 6
          },
          {
            "text": "if \"%~1\"==\"\" (",
            "lineNumber": 7
          },
          {
            "text": "\techo.",
            "lineNumber": 8
          },
          {
            "text": "\techo Usage: Drag .blend files onto this batch file to remove fake users from actions.",
            "lineNumber": 9
          },
          {
            "text": "\techo Output will be saved to the \\output folder.",
            "lineNumber": 10
          },
          {
            "text": "\techo.",
            "lineNumber": 11
          },
          {
            "text": "\tpause",
            "lineNumber": 12
          },
          {
            "text": "\texit /b 1",
            "lineNumber": 13
          },
          {
            "text": ")",
            "lineNumber": 14
          },
          {
            "lineNumber": 15
          },
          {
            "text": "REM Create output directory if it doesn't exist",
            "lineNumber": 16
          },
          {
            "text": "if not exist \"output\" mkdir \"output\"",
            "lineNumber": 17
          },
          {
            "lineNumber": 18
          },
          {
            "text": "REM Initialize counters and tracking",
            "lineNumber": 19
          },
          {
            "text": "set \"processed=0\"",
            "lineNumber": 20
          },
          {
            "text": "set \"crashed=0\"",
            "lineNumber": 21
          },
          {
            "text": "set \"skipped=0\"",
            "lineNumber": 22
          },
          {
            "text": "set \"deleted_similar=0\"",
            "lineNumber": 23
          },
          {
            "text": "set \"threshold_percent=10\"",
            "lineNumber": 24
          },
          {
            "text": "set \"updated_total=0\"",
            "lineNumber": 25
          },
          {
            "lineNumber": 26
          },
          {
            "text": "REM Create a temporary Python script for processing",
            "lineNumber": 27
          },
          {
            "text": "set \"TEMP_SCRIPT=remove_action_fake_users_temp.py\"",
            "lineNumber": 28
          },
          {
            "text": "echo Creating Python script: !TEMP_SCRIPT!",
            "lineNumber": 29
          },
          {
            "lineNumber": 30
          },
          {
            "text": "(",
            "lineNumber": 31
          },
          {
            "text": "echo import bpy",
            "lineNumber": 32
          },
          {
            "text": "echo import os",
            "lineNumber": 33
          },
          {
            "text": "echo import sys",
            "lineNumber": 34
          },
          {
            "text": "echo.",
            "lineNumber": 35
          },
          {
            "text": "echo # Create output directory if it doesn't exist",
            "lineNumber": 36
          },
          {
            "text": "echo if not os.path.exists^(\"output\"^):",
            "lineNumber": 37
          },
          {
            "text": "echo \tos.makedirs^(\"output\"^)",
            "lineNumber": 38
          },
          {
            "text": "echo.",
            "lineNumber": 39
          },
          {
            "text": "echo # Get command line arguments ^(the dragged files^)",
            "lineNumber": 40
          },
          {
            "text": "echo blend_files = sys.argv[sys.argv.index^(\"--\"^) + 1:] if \"--\" in sys.argv else []",
            "lineNumber": 41
          },
          {
            "text": "echo.",
            "lineNumber": 42
          },
          {
            "text": "echo print^(\"Found \" + str^(len^(blend_files^)^) + \" .blend files to process\"^)",
            "lineNumber": 43
          },
          {
            "text": "echo.",
            "lineNumber": 44
          },
          {
            "text": "echo for blend_file in blend_files:",
            "lineNumber": 45
          },
          {
            "text": "echo ^\tif blend_file.lower^(^).endswith^(\".blend\"^):",
            "lineNumber": 46
          },
          {
            "text": "echo ^\t\ttry:",
            "lineNumber": 47
          },
          {
            "text": "echo ^\t\t\t# Create output path in output folder",
            "lineNumber": 48
          },
          {
            "text": "echo ^\t\t\tfilename = os.path.basename^(blend_file^)",
            "lineNumber": 49
          },
          {
            "text": "echo ^\t\t\toutput_file = os.path.join^(\"output\", filename^)",
            "lineNumber": 50
          },
          {
            "text": "echo ^\t\t\t# Check if output file already exists",
            "lineNumber": 51
          },
          {
            "text": "echo ^\t\t\tif os.path.exists^(output_file^):",
            "lineNumber": 52
          },
          {
            "text": "echo ^\t\t\t\tprint^(\"SKIP_EXISTING:\" + blend_file^)",
            "lineNumber": 53
          },
          {
            "text": "echo ^\t\t\t\tcontinue",
            "lineNumber": 54
          },
          {
            "text": "echo ^\t\t\tprint^(\"PROCESSING:\" + blend_file^)",
            "lineNumber": 55
          },
          {
            "text": "echo ^\t\t\t# Load the blend file",
            "lineNumber": 56
          },
          {
            "text": "echo ^\t\t\tbpy.ops.wm.open_mainfile^(filepath=blend_file^)",
            "lineNumber": 57
          },
          {
            "text": "echo ^\t\t\t# Remove fake users from all actions",
            "lineNumber": 58
          },
          {
            "text": "echo ^\t\t\tchanged = 0",
            "lineNumber": 59
          },
          {
            "text": "echo ^\t\t\tfor action in bpy.data.actions:",
            "lineNumber": 60
          },
          {
            "text": "echo ^\t\t\t\tif getattr^(action, \"use_fake_user\", False^):",
            "lineNumber": 61
          },
          {
            "text": "echo ^\t\t\t\t\taction.use_fake_user = False",
            "lineNumber": 62
          },
          {
            "text": "echo ^\t\t\t\t\tchanged += 1",
            "lineNumber": 63
          },
          {
            "text": "echo ^\t\t\tprint^(\"UPDATED:\" + blend_file + \":\" + str^(changed^)^)",
            "lineNumber": 64
          },
          {
            "text": "echo ^\t\t\t# Save to output folder",
            "lineNumber": 65
          },
          {
            "text": "echo ^\t\t\tbpy.ops.wm.save_mainfile^(filepath=output_file, compress=True^)",
            "lineNumber": 66
          }
        ]
      },
      "score": 0.2200496941804886
    },
    {
      "codeBlock": {
        "relativeWorkspacePath": ".\\ConfigLoader.ps1",
        "range": {
          "startPosition": {},
          "endPosition": {
            "line": 64
          }
        },
        "contents": "Set-StrictMode -Version Latest\n$ErrorActionPreference = 'Stop'\n\n$script:LoaderRoot = Split-Path -Parent $MyInvocation.MyCommand.Path\n$script:ConfigPath = Join-Path -Path $script:LoaderRoot -ChildPath 'config.json'\n$script:ConfigCache = $null\n\nfunction Get-ProjectStructureConfig {\n    if ($null -ne $script:ConfigCache) {\n        return $script:ConfigCache\n    }\n\n    if (Test-Path -LiteralPath $script:ConfigPath) {\n        try {\n            $raw = Get-Content -LiteralPath $script:ConfigPath -Raw -ErrorAction Stop\n            if ($raw.Trim().Length -gt 0) {\n                $script:ConfigCache = $raw | ConvertFrom-Json\n                return $script:ConfigCache\n            }\n        }\n        catch {\n            Write-Warning \"Failed to parse config.json: $($_.Exception.Message)\"\n        }\n    }\n\n    $script:ConfigCache = [pscustomobject]@{}\n    return $script:ConfigCache\n}\n\nfunction Get-ConfigValue {\n    param(\n        [Parameter(Mandatory)] [string]$Name,\n        $Default = $null\n    )\n\n    $config = Get-ProjectStructureConfig\n    if ($config.PSObject.Properties.Name -contains $Name) {\n        $value = $config.$Name\n        if ($null -ne $value -and ($value -isnot [string] -or $value.Trim().Length -gt 0)) {\n            return $value\n        }\n    }\n\n    return $Default\n}\n\nfunction Get-StructDirectory {\n    # When script is run directly (not dot-sourced), always use script's directory for portability\n    if ($MyInvocation.InvocationName -ne '.') {\n        return $script:LoaderRoot\n    }\n\n    $value = Get-ConfigValue -Name 'structDir'\n    if ($null -eq $value -or [string]::IsNullOrWhiteSpace($value)) {\n        return $script:LoaderRoot\n    }\n\n    if ([System.IO.Path]::IsPathRooted($value)) {\n        $resolved = Resolve-Path -LiteralPath $value -ErrorAction SilentlyContinue\n        if ($null -ne $resolved) { return $resolved.Path }\n        return $value\n    }\n\n    $candidate = Join-Path -Path $script:LoaderRoot -ChildPath $value",
        "signatures": {},
        "detailedLines": [
          {
            "text": "Set-StrictMode -Version Latest",
            "lineNumber": 1
          },
          {
            "text": "$ErrorActionPreference = 'Stop'",
            "lineNumber": 2
          },
          {
            "lineNumber": 3
          },
          {
            "text": "$script:LoaderRoot = Split-Path -Parent $MyInvocation.MyCommand.Path",
            "lineNumber": 4
          },
          {
            "text": "$script:ConfigPath = Join-Path -Path $script:LoaderRoot -ChildPath 'config.json'",
            "lineNumber": 5
          },
          {
            "text": "$script:ConfigCache = $null",
            "lineNumber": 6
          },
          {
            "lineNumber": 7
          },
          {
            "text": "function Get-ProjectStructureConfig {",
            "lineNumber": 8
          },
          {
            "text": "    if ($null -ne $script:ConfigCache) {",
            "lineNumber": 9
          },
          {
            "text": "        return $script:ConfigCache",
            "lineNumber": 10
          },
          {
            "text": "    }",
            "lineNumber": 11
          },
          {
            "lineNumber": 12
          },
          {
            "text": "    if (Test-Path -LiteralPath $script:ConfigPath) {",
            "lineNumber": 13
          },
          {
            "text": "        try {",
            "lineNumber": 14
          },
          {
            "text": "            $raw = Get-Content -LiteralPath $script:ConfigPath -Raw -ErrorAction Stop",
            "lineNumber": 15
          },
          {
            "text": "            if ($raw.Trim().Length -gt 0) {",
            "lineNumber": 16
          },
          {
            "text": "                $script:ConfigCache = $raw | ConvertFrom-Json",
            "lineNumber": 17
          },
          {
            "text": "                return $script:ConfigCache",
            "lineNumber": 18
          },
          {
            "text": "            }",
            "lineNumber": 19
          },
          {
            "text": "        }",
            "lineNumber": 20
          },
          {
            "text": "        catch {",
            "lineNumber": 21
          },
          {
            "text": "            Write-Warning \"Failed to parse config.json: $($_.Exception.Message)\"",
            "lineNumber": 22
          },
          {
            "text": "        }",
            "lineNumber": 23
          },
          {
            "text": "    }",
            "lineNumber": 24
          },
          {
            "lineNumber": 25
          },
          {
            "text": "    $script:ConfigCache = [pscustomobject]@{}",
            "lineNumber": 26
          },
          {
            "text": "    return $script:ConfigCache",
            "lineNumber": 27
          },
          {
            "text": "}",
            "lineNumber": 28
          },
          {
            "lineNumber": 29
          },
          {
            "text": "function Get-ConfigValue {",
            "lineNumber": 30
          },
          {
            "text": "    param(",
            "lineNumber": 31
          },
          {
            "text": "        [Parameter(Mandatory)] [string]$Name,",
            "lineNumber": 32
          },
          {
            "text": "        $Default = $null",
            "lineNumber": 33
          },
          {
            "text": "    )",
            "lineNumber": 34
          },
          {
            "lineNumber": 35
          },
          {
            "text": "    $config = Get-ProjectStructureConfig",
            "lineNumber": 36
          },
          {
            "text": "    if ($config.PSObject.Properties.Name -contains $Name) {",
            "lineNumber": 37
          },
          {
            "text": "        $value = $config.$Name",
            "lineNumber": 38
          },
          {
            "text": "        if ($null -ne $value -and ($value -isnot [string] -or $value.Trim().Length -gt 0)) {",
            "lineNumber": 39
          },
          {
            "text": "            return $value",
            "lineNumber": 40
          },
          {
            "text": "        }",
            "lineNumber": 41
          },
          {
            "text": "    }",
            "lineNumber": 42
          },
          {
            "lineNumber": 43
          },
          {
            "text": "    return $Default",
            "lineNumber": 44
          },
          {
            "text": "}",
            "lineNumber": 45
          },
          {
            "lineNumber": 46
          },
          {
            "text": "function Get-StructDirectory {",
            "lineNumber": 47
          },
          {
            "text": "    # When script is run directly (not dot-sourced), always use script's directory for portability",
            "lineNumber": 48
          },
          {
            "text": "    if ($MyInvocation.InvocationName -ne '.') {",
            "lineNumber": 49
          },
          {
            "text": "        return $script:LoaderRoot",
            "lineNumber": 50
          },
          {
            "text": "    }",
            "lineNumber": 51
          },
          {
            "lineNumber": 52
          },
          {
            "text": "    $value = Get-ConfigValue -Name 'structDir'",
            "lineNumber": 53
          },
          {
            "text": "    if ($null -eq $value -or [string]::IsNullOrWhiteSpace($value)) {",
            "lineNumber": 54
          },
          {
            "text": "        return $script:LoaderRoot",
            "lineNumber": 55
          },
          {
            "text": "    }",
            "lineNumber": 56
          },
          {
            "lineNumber": 57
          },
          {
            "text": "    if ([System.IO.Path]::IsPathRooted($value)) {",
            "lineNumber": 58
          },
          {
            "text": "        $resolved = Resolve-Path -LiteralPath $value -ErrorAction SilentlyContinue",
            "lineNumber": 59
          },
          {
            "text": "        if ($null -ne $resolved) { return $resolved.Path }",
            "lineNumber": 60
          },
          {
            "text": "        return $value",
            "lineNumber": 61
          },
          {
            "text": "    }",
            "lineNumber": 62
          },
          {
            "lineNumber": 63
          },
          {
            "text": "    $candidate = Join-Path -Path $script:LoaderRoot -ChildPath $value",
            "lineNumber": 64
          }
        ]
      },
      "score": 0.21668344736099243
    }
  ]
}

Status: completed


Creating a plan to update the script for two-level duplicate detection:


Tool use: **create_plan**

Parameters:

{
  "plan": "# Two-Level Texture Organization Script\n\n## Current Behavior\nThe script currently processes all files recursively and moves everything to a single `\\common` folder at the texture root level.\n\n## New Requirements\nThe texture folder structure is: `\\\\textures\\[Blendfile]\\[Material]`\n\nThe script needs to:\n1. **Intra-blendfile commonalities**: Files that appear in multiple materials within the same blendfile → `\\\\textures\\[blendfile]\\common`\n2. **Inter-blendfile commonalities**: Files that appear across multiple blendfiles → `\\\\textures\\common`\n\n## Implementation Plan\n\n### File: `organize_textures.ps1`\n\n**Two-Pass Approach:**\n\n#### Pass 1: Intra-Blendfile Processing\n1. Get all direct subdirectories of the texture folder (these are blendfile folders)\n2. For each blendfile folder:\n   - Get all files recursively within that blendfile folder (excluding `\\common` folders)\n   - Calculate checksums for all files in that blendfile\n   - Group files by checksum\n   - For each checksum group:\n     - If multiple files (duplicates within blendfile):\n       - Move first file to `[blendfile]\\common`\n       - Move remaining files to `[blendfile]\\common\\duplicates` with numbered suffixes\n     - If single file: leave it in place (will be processed in Pass 2)\n\n#### Pass 2: Inter-Blendfile Processing\n1. After Pass 1 completes, get all remaining files (excluding all `\\common` folders)\n2. Calculate checksums for all remaining files\n3. Group files by checksum\n4. For each checksum group:\n   - If multiple files (duplicates across blendfiles):\n     - Move first file to `\\textures\\common`\n     - Move remaining files to `\\textures\\common\\duplicates` with numbered suffixes\n   - If single file: leave it in place (unique file)\n\n**Key Changes:**\n- Identify blendfile folders as direct subdirectories of the texture root\n- Process each blendfile folder independently in Pass 1\n- Exclude `\\common` folders from file collection in both passes\n- Create `[blendfile]\\common` and `[blendfile]\\common\\duplicates` directories as needed\n- Create `\\textures\\common` and `\\textures\\common\\duplicates` directories for Pass 2\n- Handle filename conflicts when moving files\n- Provide progress feedback for each blendfile and overall progress\n\n**Structure Detection:**\n- Assume texture folder structure: `[textureRoot]\\[Blendfile]\\[Material]\\...`\n- Blendfile folders are direct children of the texture root\n- Material folders are children of blendfile folders\n\n**Edge Cases:**\n- Handle blendfile folders that already have `\\common` subdirectories\n- Skip processing if a blendfile folder has no files\n- Handle files directly in blendfile folder (not in material subfolders)",
  "name": "Two-level texture organization",
  "todos": [
    {
      "content": "Add logic to identify blendfile folders as direct subdirectories of texture root",
      "status": "pending",
      "id": "identify_blendfile_folders"
    },
    {
      "content": "Implement Pass 1: Process each blendfile folder separately, finding duplicates within each blendfile and moving to [blendfile]\\common",
      "status": "pending",
      "id": "pass1_intra_blendfile"
    },
    {
      "content": "Implement Pass 2: Process remaining files across all blendfiles, finding duplicates across blendfiles and moving to \\textures\\common",
      "status": "pending",
      "id": "pass2_inter_blendfile"
    },
    {
      "content": "Update file collection to exclude all \\common folders (both blendfile-level and root-level)",
      "status": "pending",
      "id": "update_exclusions"
    },
    {
      "content": "Ensure proper directory creation for both [blendfile]\\common and \\textures\\common paths",
      "status": "pending",
      "id": "handle_directory_creation"
    }
  ],
  "overview": "Update organize_textures.ps1 to scan each blendfile folder separately, moving intra-blendfile duplicates to [blendfile]\\common and inter-blendfile duplicates to \\textures\\common"
}

Additional data:

{
  "reviewData": {
    "status": "Requested",
    "selectedOption": "none",
    "isShowingInput": false
  },
  "planUri": "c:\\Users\\Nathan\\.cursor\\plans\\two-level_texture_organization_df41b675.plan.md",
  "hasOpenedEditor": true
}

Result:

{
  "rejected": {}
}

Status: completed


User

Implement the plan as specified, it is attached for your reference. Do NOT edit the plan file itself.

To-do's from the plan have already been created. Do not create them again. Mark them as in_progress as you work, starting with the first one. Don't stop until you have completed all the to-dos.


Agent (model default, mode Agent)

Implementing the plan. Reviewing the current script, then updating it for two-level duplicate detection.


Tool use: **read_file_v2**

Status: loading