gitea composer

This commit is contained in:
Nathan
2026-02-19 12:00:21 -07:00
parent 1f28932792
commit 6d9fb0f74d
4 changed files with 913 additions and 12 deletions
+30
View File
@@ -0,0 +1,30 @@
version: '3.8'
services:
gitea-act-runner:
image: gitea/act_runner:latest
container_name: gitea-act-runner-dlm
restart: unless-stopped
volumes:
# Update this path to your TrueNAS dataset (or local runner data path)
- /mnt/pool/gitea-runner:/data
# Docker socket - required for runner to create job containers
- /var/run/docker.sock:/var/run/docker.sock
environment:
# Update with your Gitea instance URL (accessible from this container)
- GITEA_INSTANCE_URL=http://10.1.10.3:30008/
# Get this from: Repository → Settings → Actions → Runners → New Runner
- GITEA_RUNNER_REGISTRATION_TOKEN=<your-runner-token>
# Name your runner (can be anything)
- GITEA_RUNNER_NAME=dlm-runner
# Labels: format is "label:docker-image"
# These labels will be used in your workflow's runs-on field
- GITEA_RUNNER_LABELS=ubuntu:docker://node:20-bullseye,linux:docker://node:20-bullseye
networks:
# Update to match your Gitea container's network
- gitea-network
networks:
gitea-network:
external: true # Change to false if you want to create a new network
# name: gitea # Uncomment and set if using external network
+95
View File
@@ -0,0 +1,95 @@
name: Create Release
on:
workflow_dispatch:
inputs:
release_tag:
description: 'Release tag (e.g., v0.3.0)'
required: true
type: string
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Get Version
id: get_version
run: |
python - <<'PY'
import os
import tomllib
from pathlib import Path
data = tomllib.loads(Path("blender_manifest.toml").read_text(encoding="utf-8"))
version = data["version"]
# Gitea Actions uses GITHUB_OUTPUT (compatible with GitHub Actions)
output_file = os.environ.get("GITHUB_OUTPUT", os.environ.get("GITEA_OUTPUT", "/dev/stdout"))
with open(output_file, "a", encoding="utf-8") as fh:
fh.write(f"version={version}\n")
fh.write(f"zip_name=dynamiclinkmanager_{version}.zip\n")
PY
- name: Create ZIP
run: |
ADDON_DIR=dynamiclinkmanager
mkdir -p "$ADDON_DIR"
# Copy top-level files
for file in __init__.py blender_manifest.toml; do
if [ -f "$file" ]; then
cp "$file" "$ADDON_DIR"/
else
echo "Skipping missing file: $file"
fi
done
# Copy directories
cp -r ops "$ADDON_DIR"/
cp -r ui "$ADDON_DIR"/
if [ -d "utils" ] && [ "$(ls -A utils)" ]; then
cp -r utils "$ADDON_DIR"/
fi
# Create the zip from the temporary directory
zip -r "${{ steps.get_version.outputs.zip_name }}" "$ADDON_DIR"/*
- name: Create Release
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
run: |
# Gitea Actions uses github.repository context (compatible with GitHub Actions)
API_BASE="${GITHUB_SERVER_URL}/api/v1"
curl -X POST \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"tag_name\": \"${{ inputs.release_tag }}\",
\"name\": \"${{ inputs.release_tag }}\",
\"body\": \"Release ${{ steps.get_version.outputs.version }}\",
\"draft\": true
}" \
"${API_BASE}/repos/${{ github.repository }}/releases" || true
- name: Upload Release Asset
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
run: |
API_BASE="${GITHUB_SERVER_URL}/api/v1"
# Get the release ID
RELEASE_ID=$(curl -s \
-H "Authorization: token $GITEA_TOKEN" \
"${API_BASE}/repos/${{ github.repository }}/releases/tags/${{ inputs.release_tag }}" \
| grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2)
if [ -n "$RELEASE_ID" ]; then
curl -X POST \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/zip" \
--data-binary "@${{ steps.get_version.outputs.zip_name }}" \
"${API_BASE}/repos/${{ github.repository }}/releases/$RELEASE_ID/assets?name=${{ steps.get_version.outputs.zip_name }}"
fi
@@ -11663,6 +11663,222 @@ _**User**_
_**Agent (model default, mode Agent)**_
<think><details><summary>Thought Process</summary>
The user says the action slot is still not migrating in MigNLA when there's no NLA but there is an active action. They want debug added and pointed to the Action operators docs.
From the Action operators page, I see:
- `bpy.ops.action.push_down()` - "Push action down on to the NLA stack as a new strip"
- `bpy.ops.action.unlink()` - "Unlink this action from the active action slot (and/or exit Tweak Mode)"
So "action slot" in the UI might be referring to something that requires an operator to properly assign. Let me add debug to the no-NLA path so we can see:
1. What orig.animation_data has (action, action_slot, action_slot_handle, last_slot_identifier, action_blend_type, etc.)
2. What we're setting on rep
3. Whether action_slot assignment fails or is read-only
I'll add print statements (debug) in the migrator's no-NLA branch, and also consider if we need to use an operator like `bpy.ops.action.push_down` or something else. Actually re-reading the user message - they want to "migrate" the slot, i.e. copy the original's slot to the replacement. So the issue might be:
1. action_slot might be read-only when we assign action?
2. We might need to set last_slot_identifier or action_slot_handle instead?
3. Or we need to use an operator to "assign" the action in a way that sets the slot?
Let me add debug first so we can see what's on orig and what gets set on rep, and whether any assignment fails.
</details></think>
---
Adding debug in the MigNLA no-NLA path to log the original's and replacement's animation_data (action, action_slot, action_slot_handle, last_slot_identifier) and any assignment errors.
---
<tool-use data-tool-type="read" data-tool-name="read_file_v2">
<details><summary>Tool use: **read_file_v2** • Read file: T:\Dynamic-Link-Manager\ops\migrator.py</summary>
</details>
</tool-use>
---
<think><details><summary>Thought Process</summary>
I'll add debug prints that show:
1. Orig: action name, action_slot (and identifier/handle if available), action_blend_type, action_extrapolation, action_influence, last_slot_identifier
2. Before assign: rep's state
3. After assign: rep's state
4. If we try to set action_slot and it fails, catch and print
I'll also check the API - maybe we need to set `last_slot_identifier` when assigning an action so the slot gets resolved? Or use the operator that "assigns" the action to the slot. Looking at the docs again, AnimData has:
- last_slot_identifier: "The identifier of the most recently assigned action slot..."
So when you assign an action, Blender might use last_slot_identifier to find which slot to use. So we might need to copy last_slot_identifier from orig to rep before or after setting the action.
</details></think>
---
---
<tool-use data-tool-type="write" data-tool-name="edit_file_v2">
<details><summary>Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ops\migrator.py</summary>
</details>
</tool-use>
---
<think><details><summary>Thought Process</summary>
I added:
1. _slot_debug() to print action and slot-related props for orig (before), rep (before), and rep (after).
2. Setting last_slot_identifier on rep before or after action (I did it after action; the API said "its identifier is used to find the right slot when assigning an Action" - so it might need to be set before assigning the action so that when we set rad.action, Blender knows which slot. Let me try setting last_slot_identifier *before* rad.action so the slot is selected first.
</details></think>
---
Setting `last_slot_identifier` before assigning the action so slot resolution runs when the action is set.
---
<tool-use data-tool-type="write" data-tool-name="edit_file_v2">
<details><summary>Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ops\migrator.py</summary>
</details>
</tool-use>
---
<think><details><summary>Thought Process</summary>
Good. Now when the user runs MigNLA (no NLA path), the terminal will show:
- Orig (before): action name and all slot-related props
- Rep (before): same
- Whether last_slot_identifier was set
- Whether action_slot assign was tried and if it failed
- Each prop copy (action_blend_type etc.)
- Rep (after): full state
This should reveal why the slot isn't migrating (e.g. action_slot is None on orig, or assignment raises, or last_slot_identifier is empty).
</details></think>
---
---
<tool-use data-tool-type="unknown" data-tool-name="read_lints">
<details>
<summary>Tool use: **read_lints**</summary>
Parameters:
```json
{
"paths": [
"T:\\Dynamic-Link-Manager\\ops\\migrator.py"
]
}
```
Result:
```json
{
"linterErrorsByFile": [
{
"relativeWorkspacePath": "T:\\Dynamic-Link-Manager\\ops\\migrator.py"
}
]
}
```
Status: **completed**
</details>
</tool-use>
---
<think><details><summary>Thought Process</summary>
All good. Let me give a short summary to the user.
</details></think>
---
Summary of changes:
**1. Debug logging in the no-NLA path**
- **Orig (before):** `action` name and, when present: `action_slot`, `action_slot_handle`, `last_slot_identifier`, `action_blend_type`, `action_extrapolation`, `action_influence`.
- **Rep (before):** same set of properties.
- **Rep (after):** same set after we copy action and slot-related data.
- Logs when `last_slot_identifier` is set and when each of `action_blend_type`, `action_extrapolation`, `action_influence` is set.
- If assigning `rad.action_slot = ad.action_slot` raises, the exception is caught and printed.
**2. Slot handling order**
- `last_slot_identifier` is copied from orig to rep **before** setting `rad.action`, so when the action is assigned Blender can resolve the correct slot (see [AnimData](https://docs.blender.org/api/current/bpy.types.AnimData.html): *“its identifier is used to find the right slot when assigning an Action”*).
After reloading the add-on and running MigNLA (with no NLA, only an active action), check the Blender terminal or system console for lines starting with `[DLM MigNLA]`. From that you can see:
- Whether the original has an `action_slot` / `last_slot_identifier`,
- What gets set on the replacement,
- Any error when setting `action_slot`.
If the slot still doesnt migrate, the next step is to try using [bpy.ops.action](https://docs.blender.org/api/current/bpy.ops.action.html) (e.g. a temp context override with the replacement armature selected and `action.push_down()` or the operator that assigns the action to the slot) so the UIs “assign to slot” path runs. The new debug output will show whether the problem is missing/original data or a read-only or failing assignment.
---
_**User**_
Add a gitea workflow for this project in a way that mirrors my AMZNCharTools extension that we modeled the structure after.
---
_**Agent (model default, mode Agent)**_
---
---
<tool-use data-tool-type="unknown" data-tool-name="glob_file_search">
<details>
<summary>Tool use: **glob_file_search**</summary>
Status: **loading**
</details>
</tool-use>
---
<tool-use data-tool-type="unknown" data-tool-name="glob_file_search">
<details>
<summary>Tool use: **glob_file_search**</summary>
Status: **loading**
</details>
</tool-use>
---
---
@@ -11683,22 +11899,38 @@ Status: **loading**
---
---
---
<tool-use data-tool-type="write" data-tool-name="edit_file_v2">
<details><summary>Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ops\migrator.py</summary>
<tool-use data-tool-type="unknown" data-tool-name="read_file_v2">
<details>
<summary>Tool use: **read_file_v2**</summary>
Status: **loading**
</details>
</details>
</tool-use>
---
<tool-use data-tool-type="unknown" data-tool-name="glob_file_search">
<details>
<summary>Tool use: **glob_file_search**</summary>
Status: **loading**
</details>
</tool-use>
---
<tool-use data-tool-type="unknown" data-tool-name="read_file_v2">
<details>
<summary>Tool use: **read_file_v2**</summary>
Status: **loading**
</details>
</tool-use>
---
@@ -0,0 +1,544 @@
<!-- Generated by SpecStory, Markdown v2.1.0 -->
<!-- cursor Session 3f042eb5-f457-4e06-9b56-ee14ac7afd90 (2026-02-19 18:53Z) -->
# Blendfile local datablocks analysis (2026-02-19 18:53Z)
_**User**_
Use blender mcp to view my scene. What is taking up space in the blendfile? Only count local datablocks and local override data, linked libraries are not stored in the blendfile itself.
---
_**Agent (model default, mode Agent)**_
<think><details><summary>Thought Process</summary>
The user wants me to use the Blender MCP to view their scene and find out what's taking up space in the blend file. They specifically want to count only local datablocks and local override data - not linked libraries since those are stored elsewhere.
Let me first check what MCP tools are available from the user-blender server.
</details></think>
---
---
<tool-use data-tool-type="generic" data-tool-name="glob_file_search">
<details>
<summary>Tool use: **glob_file_search** • Searched codebase "undefined" • **0** result in **1** directory</summary>
Directory: **T:\Dynamic-Link-Manager\mcps\user-blender** (0 file)
</details>
</tool-use>
---
<think><details><summary>Thought Process</summary>
Let me try listing the directory with list_dir or read the mcps folder structure.
</details></think>
---
---
File not found
---
<tool-use data-tool-type="generic" data-tool-name="glob_file_search">
<details>
<summary>Tool use: **glob_file_search** • Searched codebase "undefined" • **0** result in **1** directory</summary>
Directory: **T:\Dynamic-Link-Manager\mcps\user-blender** (0 file)
</details>
</tool-use>
---
<think><details><summary>Thought Process</summary>
The mcps folder might be in a different structure. Let me check the workspace for MCP-related files and also look for how to call Blender MCP tools.
</details></think>
---
---
<tool-use data-tool-type="unknown" data-tool-name="ripgrep_raw_search">
<details>
<summary>Tool use: **ripgrep_raw_search**</summary>
Parameters:
```json
{
"pattern": "user-blender|blender",
"path": "T:\\Dynamic-Link-Manager",
"glob": "*.json",
"caseInsensitive": false
}
```
Additional data:
```json
{
"isPruned": true,
"pattern": "user-blender|blender",
"path": "T:\\Dynamic-Link-Manager",
"outputMode": "content",
"totalFiles": 0,
"totalMatches": 0,
"topFiles": []
}
```
Status: **completed**
</details>
</tool-use>
---
File not found
---
<think><details><summary>Thought Process</summary>
The user said "Use blender mcp" - the MCP servers were listed as user-blender and cursor-ide-browser. The instructions said "Browse the MCP tool descriptors in the file system" at C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager/mcps/<server>/tools/. Let me try with the path that was in the system message - maybe the folder is there but empty or has a different structure. Let me list what's in mcps.
</details></think>
---
---
<tool-use data-tool-type="unknown" data-tool-name="ripgrep_raw_search">
<details>
<summary>Tool use: **ripgrep_raw_search**</summary>
Parameters:
```json
{
"pattern": "call_mcp_tool|mcp",
"path": "T:\\Dynamic-Link-Manager",
"outputMode": "files_with_matches",
"caseInsensitive": false
}
```
Additional data:
```json
{
"isPruned": true,
"pattern": "call_mcp_tool|mcp",
"path": "T:\\Dynamic-Link-Manager",
"outputMode": "files_with_matches",
"totalFiles": 1,
"totalMatches": 1,
"topFiles": [
{
"uri": ".specstory\\history\\2026-02-18_23-39Z-character-migrator-workflow-integration.md",
"matchCount": 1
}
]
}
```
Status: **completed**
</details>
</tool-use>
---
<tool-use data-tool-type="search" data-tool-name="web_search">
<details>
<summary>Tool use: **web_search** • Searched web `undefined`**1** results</summary>
| Title | URL | Chunk |
|-------|-----|-------|
| Web search results for query: Blender MCP server tools list datablocks scene | | Links:<br/>1. [Blender MCP Server: Headless Script Management](https://mcpmarket.com/server/blender)<br/>2. [Blender Script Manager README \| MCP Marketplace](https://ubos.tech/mcp/blender-mcp-server/)<br/>3. [poly-mcp/Blender-MCP-Server](https://github.com/llm-use/Blender-MCP-Server)<br/>4. [Blender MCP Server - poly-mcp/blender-mcp-server](https://playbooks.com/mcp/llm-use-blender)<br/>5. [cwahlfeldt/blender-mcp](https://github.com/cwahlfeldt/blender-mcp)<br/><br/># Blender MCP Server Tools Overview<br/><br/>There are two main Blender MCP server implementations with different capability levels:<br/><br/>## Basic Script Manager (cwahlfeldt/blender-mcp)[2][5]<br/><br/>**Tools:**<br/>- `add_script(name, content)` - Add new scripts<br/>- `edit_script(name, content)` - Edit existing scripts<br/>- `execute_script(name, blend_file=None)` - Execute scripts in headless Blender<br/>- `remove_script(name)` - Remove scripts<br/><br/>**Resources:**<br/>- `scripts://list` - List available scripts<br/>- `script://\{name\}` - Access specific script content<br/>- `result://\{name\}` - Get execution results<br/><br/>## Advanced Complete Server (poly-mcp/Blender-MCP-Server)[3][4]<br/><br/>**50+ Tools across multiple categories:**<br/>- Object creation, manipulation, and transformation<br/>- Material and shader system management<br/>- Animation and keyframe control<br/>- Camera and lighting setup<br/>- Modifiers and constraints<br/>- Physics simulations (rigid body, cloth, fluid)<br/>- Geometry nodes and procedural generation<br/>- File import/export operations<br/>- Scene optimization and batch operations<br/><br/>**Additional Features:**[3][4]<br/>- Thread-safe execution queue for concurrent operations<br/>- Auto-dependency installation<br/>- Real-time monitoring and statistics<br/>- Production-ready error handling and logging<br/>- Simple UI panel in Blender's N-panel for server control<br/><br/>Both servers support working with datablocks and scene data through Blender's Python API (`bpy.data` objects).[2][5] |
</details>
</tool-use>
---
<think><details><summary>Thought Process</summary>
The MCP tool descriptors were said to be in the file system at C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager/mcps/<server>/tools/. The server name is "user-blender". So the path would be C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender. The glob returned 0 files - maybe the path uses forward slashes or the folder doesn't have the tool JSON files. Let me try to list resources and call a generic tool to see what's available. I'll use list_dir on the workspace to see the mcps folder.
</details></think>
---
Checking the MCP server structure and available tools:
---
File not found
---
<tool-use data-tool-type="generic" data-tool-name="glob_file_search">
<details>
<summary>Tool use: **glob_file_search** • Searched codebase "undefined" • **59** results in **1** directory</summary>
Directory: **C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps** (59 files)
| File |
|------|
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\INSTRUCTIONS.md` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\SERVER_METADATA.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_profile_start.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_profile_stop.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_unlock.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_lock.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_search.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_tabs.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_take_screenshot.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\SERVER_METADATA.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_console_messages.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_network_requests.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\prompts\asset_creation_strategy.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_handle_dialog.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\import_generated_asset_hunyuan.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_resize.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\generate_hunyuan3d_model.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_drag.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_highlight.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\poll_hunyuan_job_status.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_hunyuan3d_status.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_get_bounding_box.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_is_checked.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_is_enabled.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\import_generated_asset.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\poll_rodin_job_status.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\generate_hyper3d_model_via_images.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_is_visible.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\generate_hyper3d_model_via_text.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_get_attribute.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_get_input_value.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\download_sketchfab_model.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_sketchfab_model_preview.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\search_sketchfab_models.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_reload.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_scroll.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_sketchfab_status.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_navigate_back.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_navigate_forward.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_hyper3d_status.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_polyhaven_status.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_press_key.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_wait_for.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\download_polyhaven_asset.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_hover.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\set_texture.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_select_option.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_fill.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_fill_form.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_polyhaven_categories.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\search_polyhaven_assets.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_click.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\execute_blender_code.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_viewport_screenshot.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_type.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_object_info.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_scene_info.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_navigate.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\cursor-ide-browser\tools\browser_snapshot.json` |
</details>
</tool-use>
---
<think><details><summary>Thought Process</summary>
The user-blender MCP has tools like import_generated_asset, generate_hunyuan3d_model, etc. - these seem to be asset-generation focused. I need to find if there's a tool to run Python in Blender or get scene/datablock info. Let me list all user-blender tools and check the server metadata.
</details></think>
---
---
<tool-use data-tool-type="generic" data-tool-name="glob_file_search">
<details>
<summary>Tool use: **glob_file_search** • Searched codebase "undefined" • **22** results in **1** directory</summary>
Directory: **C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools** (22 files)
| File |
|------|
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\import_generated_asset_hunyuan.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\generate_hunyuan3d_model.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\poll_hunyuan_job_status.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_hunyuan3d_status.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\poll_rodin_job_status.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\import_generated_asset.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\generate_hyper3d_model_via_images.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\generate_hyper3d_model_via_text.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\download_sketchfab_model.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\search_sketchfab_models.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_sketchfab_model_preview.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_sketchfab_status.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_polyhaven_status.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_hyper3d_status.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\download_polyhaven_asset.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\set_texture.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_polyhaven_categories.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\search_polyhaven_assets.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\execute_blender_code.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_viewport_screenshot.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_object_info.json` |
| `../C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_scene_info.json` |
</details>
</tool-use>
---
<tool-use data-tool-type="read" data-tool-name="read_file_v2">
<details><summary>Tool use: **read_file_v2** • Read file: C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\SERVER_METADATA.json</summary>
</details>
</tool-use>
---
<think><details><summary>Thought Process</summary>
There's `execute_blender_code.json`, `get_scene_info.json`, and `get_object_info.json`. Let me read those to see if I can get datablock counts and size info. get_scene_info might give scene overview; execute_blender_code would let me run custom Python to count local datablocks and override data.
</details></think>
---
Reading the schema for the tools that can inspect the scene and run code:
---
<tool-use data-tool-type="read" data-tool-name="read_file_v2">
<details><summary>Tool use: **read_file_v2** • Read file: C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_scene_info.json</summary>
</details>
</tool-use>
---
<tool-use data-tool-type="read" data-tool-name="read_file_v2">
<details><summary>Tool use: **read_file_v2** • Read file: C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\execute_blender_code.json</summary>
</details>
</tool-use>
---
<tool-use data-tool-type="read" data-tool-name="read_file_v2">
<details><summary>Tool use: **read_file_v2** • Read file: C:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\mcps\user-blender\tools\get_object_info.json</summary>
</details>
</tool-use>
---
<think><details><summary>Thought Process</summary>
I'll use get_scene_info first to get an overview, then execute_blender_code to run Python that:
1. Iterates bpy.data and counts only local datablocks (where .library is None)
2. Counts local override data (overrides that are stored in this file)
3. Optionally reports approximate size or counts by type
In Blender:
- A datablock is "local" if it's not from a library: `id_data.library is None`
- Override data: `bpy.data.libraries` contains linked libraries; overrides are stored in the current file. I need to count override properties - in Blender 4.0+ we have `bpy.types.ID.override_create` and overrides live in the file. Actually "local override data" might mean the override hierarchy / override properties stored in the blend file for linked data. So:
- Local datablocks: all id_data where .library is None
- Local override data: could mean the override system's storage. In Blender, when you have a linked object and you override properties, that override info is stored locally. So we need datablocks that are in the override hierarchy (they might be virtual/local overrides).
Let me first get scene info to see what we're working with, then run code to count:
1. Per-type counts of datablocks where block.library is None (or getattr(block, 'library', None) is None for types that don't have library)
2. Override: in Blender, overrides are typically ID types that have .override_library set. So we could count override data as IDs that have override_library and are stored in this file (their override is local). Actually the user said "local override data" - meaning the override data that is stored in the blend file. So we want:
- All IDs that are local (library is None)
- Among those, some might be "override" type (they override a linked datablock) - the override hierarchy and property overrides are stored locally
I'll write Python that:
1. For each bpy.data collection (objects, meshes, materials, etc.), count items where .library is None
2. For override: count IDs that have override_library (they represent local override data)
Let me get scene info first, then run the counting code.
</details></think>
---
Fetching scene info, then running Blender Python to count only local datablocks and local override data.
---
<tool-use data-tool-type="unknown" data-tool-name="mcp-blender-user-blender-get_scene_info">
<details>
<summary>Tool use: **mcp-blender-user-blender-get_scene_info**</summary>
Parameters:
```json
{
"tools": [
{
"name": "get_scene_info",
"parameters": "{\"user_prompt\":\"View scene and report what is taking up space in the blend file; only local datablocks and local override data.\"}",
"serverName": "blender"
}
]
}
```
Additional data:
```json
{
"status": "success"
}
```
Result:
```json
{
"result": "{\"content\":[{\"type\":\"text\",\"text\":\"{\\n \\\"name\\\": \\\"Scene\\\",\\n \\\"object_count\\\": 3104,\\n \\\"objects\\\": [\\n {\\n \\\"name\\\": \\\"Package\\\",\\n \\\"type\\\": \\\"MESH\\\",\\n \\\"location\\\": [\\n -0.1,\\n 0.55,\\n 0.24\\n ]\\n },\\n {\\n \\\"name\\\": \\\"Package.002\\\",\\n \\\"type\\\": \\\"MESH\\\",\\n \\\"location\\\": [\\n -0.02,\\n 0.0,\\n 0.26\\n ]\\n },\\n {\\n \\\"name\\\": \\\"Package.001\\\",\\n \\\"type\\\": \\\"MESH\\\",\\n \\\"location\\\": [\\n -0.26,\\n 0.11,\\n 0.77\\n ]\\n },\\n {\\n \\\"name\\\": \\\"Damaged-Package\\\",\\n \\\"type\\\": \\\"MESH\\\",\\n \\\"location\\\": [\\n -0.2,\\n -0.4,\\n 0.24\\n ]\\n },\\n {\\n \\\"name\\\": \\\"Damaged-Package.001\\\",\\n \\\"type\\\": \\\"MESH\\\",\\n \\\"location\\\": [\\n -0.1,\\n -0.31,\\n 0.76\\n ]\\n },\\n {\\n \\\"name\\\": \\\"Problem-solve_Rack\\\",\\n \\\"type\\\": \\\"MESH\\\",\\n \\\"location\\\": [\\n -0.21,\\n -0.08,\\n -0.0\\n ]\\n },\\n {\\n \\\"name\\\": \\\"staging tape\\\",\\n \\\"type\\\": \\\"MESH\\\",\\n \\\"location\\\": [\\n 0.12,\\n 0.02,\\n 0.0\\n ]\\n },\\n {\\n \\\"name\\\": \\\"Problem-Sovle_label\\\",\\n \\\"type\\\": \\\"MESH\\\",\\n \\\"location\\\": [\\n 0.31,\\n 0.02,\\n 0.01\\n ]\\n },\\n {\\n \\\"name\\\": \\\"problem-solve_QR\\\",\\n \\\"type\\\": \\\"MESH\\\",\\n \\\"location\\\": [\\n 0.32,\\n 0.66,\\n 0.01\\n ]\\n },\\n {\\n \\\"name\\\": \\\"Problem-Sovle_label.001\\\",\\n \\\"type\\\": \\\"MESH\\\",\\n \\\"location\\\": [\\n 0.11,\\n 0.04,\\n 1.85\\n ]\\n }\\n ],\\n \\\"materials_count\\\": 145\\n}\"}]}"
}
```
Status: **completed**
</details>
</tool-use>
---
<think><details><summary>Thought Process</summary>
Scene has 3104 objects and 145 materials. Now I need to run execute_blender_code to count local vs linked datablocks and get override counts. I'll write Python that:
1. Iterates all bpy.data.* collections
2. For each datablock, check if it's local (library is None)
3. Count overrides (id_data.override_library is not None means it's an override - but overrides can be on linked data too; the override *data* is stored locally). So: local datablocks = library is None. For "local override data" - in Blender, when you override a linked ID, the override is stored in the current file. So we want IDs that have override_library - those are the ones that have local override data (the override hierarchy). Let me count both.
</details></think>
---
Running Python in Blender to count local datablocks and local override data:
---
<tool-use data-tool-type="unknown" data-tool-name="mcp-blender-user-blender-execute_blender_code">
<details>
<summary>Tool use: **mcp-blender-user-blender-execute_blender_code**</summary>
Parameters:
```json
{
"tools": [
{
"name": "execute_blender_code",
"parameters": "{\"user_prompt\":\"Count local datablocks and override data in blend file\",\"code\":\"import bpy\\nimport collections\\n\\n# Count local datablocks only (library is None)\\nlocal_counts = collections.defaultdict(int)\\noverride_count = 0\\noverride_by_type = collections.defaultdict(int)\\n\\nfor attr in dir(bpy.data):\\n if attr.startswith('_'):\\n continue\\n coll = getattr(bpy.data, attr, None)\\n if not hasattr(coll, 'values'):\\n continue\\n try:\\n for block in coll:\\n if getattr(block, 'library', None) is not None:\\n continue # skip linked\\n local_counts[attr] += 1\\n if getattr(block, 'override_library', None) and block.override_library:\\n override_count += 1\\n override_by_type[attr] += 1\\n except (TypeError, AttributeError):\\n pass\\n\\nlines = ['=== Local datablocks (library is None) ===']\\nfor k in sorted(local_counts.keys()):\\n lines.append(f'{k}: {local_counts[k]}')\\nlines.append('')\\nlines.append(f'Total local datablocks: {sum(local_counts.values())}')\\nlines.append('')\\nlines.append('=== Local override data (IDs with override_library) ===')\\nfor k in sorted(override_by_type.keys()):\\n lines.append(f'{k}: {override_by_type[k]}')\\nlines.append(f'Total with overrides: {override_count}')\\nprint('\\\\n'.join(lines))\"}",
"serverName": "blender"
}
]
}
```
Additional data:
```json
{
"status": "success"
}
```
Result:
```json
{
"result": "{\"content\":[{\"type\":\"text\",\"text\":\"Code executed successfully: === Local datablocks (library is None) ===\\nactions: 4\\narmatures: 3\\nbrushes: 44\\ncameras: 1\\ncollections: 33\\nfonts: 1\\nimages: 9\\nlibraries: 6\\nlights: 108\\nlinestyles: 1\\nmaterials: 21\\nmeshes: 19\\nnode_groups: 8\\nobjects: 3092\\nscenes: 1\\nscreens: 18\\nshape_keys: 6\\nwindow_managers: 1\\nworkspaces: 12\\nworlds: 1\\n\\nTotal local datablocks: 3389\\n\\n=== Local override data (IDs with override_library) ===\\narmatures: 3\\ncollections: 23\\nlights: 104\\nmaterials: 1\\nmeshes: 7\\nnode_groups: 1\\nobjects: 3072\\nTotal with overrides: 3211\\n\"}]}"
}
```
Status: **completed**
</details>
</tool-use>
---
<think><details><summary>Thought Process</summary>
Good. So we have:
- 3389 total local datablocks
- 3211 of those (or overlapping) have override_library - meaning they're overriding linked data, so the override data is stored locally
The biggest contributors to local storage:
- objects: 3092 local (and 3072 have overrides)
- lights: 108 local (104 with overrides)
- brushes: 44
- collections: 33 (23 with overrides)
- materials: 21
- meshes: 19
- screens: 18
- workspaces: 12
- images: 9
- node_groups: 8
- etc.
Let me also get a sense of what might be taking the most *space* - e.g. mesh data (verts/faces), image size, etc. I'll run another snippet to summarize size-heavy items.
</details></think>
---
Gathering what's using the most space (mesh geometry, images, etc.):
---
<tool-use data-tool-type="unknown" data-tool-name="mcp--">
<details>
<summary>Tool use: **mcp--**</summary>
Status: **loading**
</details>
</tool-use>
---