Compare commits

...

14 Commits

Author SHA1 Message Date
forbes
fe50b1595e art: update kindred icon set
Some checks failed
Build and Test / build (pull_request) Has been cancelled
Update Document, DrawStyle, Link, PartDesign, and document-* SVGs.
Remove DrawStyleHiddenLine.svg.
2026-02-07 10:44:24 -06:00
forbes
7bec3d5c3b fix(ci): fix release creation and artifact collection
All checks were successful
Build and Test / build (push) Successful in 1h5m11s
- Exclude appimagetool from artifact upload (FreeCAD_*.AppImage glob)
- Build release JSON payload in Python to fix false/False type error
  (shell 'false' is not valid Python; use bool with re.search instead)
2026-02-07 08:20:24 -06:00
forbes
145c29d7d6 fix(build): pin icu<76 in build deps to match host
The build environment (via qt6-main) was pulling ICU 78 headers while
the host/runtime environment had ICU 75 pinned. The compiled binary
contained icu_78 mangled symbols that fail to resolve against ICU 75
shared libs at runtime. Pin icu>=75,<76 in build deps to match.
2026-02-07 08:18:46 -06:00
forbes
8ba7b73aa8 fix(ci): fix ccache strategy and add runner cleanup
- Cache key: replace run_id (unique per build) with date-based key
  so entries are reused within the same day and rotate daily
- Skip cache save on exact hit (act_runner can't overwrite keys)
- build.sh: set CCACHE_DIR/CCACHE_BASEDIR inside rattler-build's
  isolated env so release builds actually use the cached directory
- build.sh: print ccache stats at end for diagnostics
- Add disk space cleanup step to build.yml (matching release.yml)
- Remove cross-build cache fallback in release.yml (different -O flags)
- Add runner cleanup daemon (.gitea/runner/) with systemd timer
  to purge stale cache entries, Docker data, and old workspaces
2026-02-07 08:18:00 -06:00
forbes
1e4deea130 fix(ci): add disk space cleanup steps to release workflow
Some checks failed
Build and Test / build (push) Failing after 15m24s
The runner host disk is at 95% capacity. Add cleanup steps:
- Remove pre-installed bloat (dotnet, android, boost) at start
- Clear rattler package cache and pixi build dirs between
  AppImage and .deb build steps
2026-02-06 20:01:33 -06:00
forbes
3923e2e4b9 fix(ci): replace release-action with direct Gitea API calls
Some checks failed
Build and Test / build (push) Has been cancelled
Release Build / build-linux (push) Failing after 1h25m19s
Release Build / publish-release (push) Has been skipped
The gitea.com/actions/release-action is archived and requires go to
build from source, which isn't available in the ubuntu-latest runner.
Replace with curl calls to the Gitea release API: create release,
upload assets. Handles existing releases by deleting and recreating.
2026-02-06 18:22:23 -06:00
forbes
9e29b76fbc fix(build): pin icu >=75,<76 to prevent header/lib version mismatch
All checks were successful
Build and Test / build (push) Successful in 1h18m21s
The build environment resolved ICU 78 headers while the host environment
had ICU 75 libraries (constrained by xerces-c, qt6-main, etc.). This
caused libFreeCADBase.so to contain icu_78 mangled symbols that couldn't
be found in the bundled ICU 75 libs at runtime:

  undefined symbol: _ZN6icu_7813UnicodeString8fromUTF8ENS_11StringPieceE

Pin ICU explicitly in both recipe.yaml host deps and pixi.toml to ensure
headers and libs always match.
2026-02-06 16:48:03 -06:00
forbes
88e025f1c6 docs: update stale silo/pkg/freecad paths to silo-mod layout
Some checks failed
Build and Test / build (push) Successful in 1h24m15s
Release Build / build-linux (push) Successful in 2h8m56s
Release Build / publish-release (push) Failing after 11m58s
2026-02-06 12:43:04 -06:00
forbes
772d3b3288 fix(build): update CMake install paths for silo-mod repo layout
Some checks failed
Build and Test / build (push) Has been cancelled
The silo submodule now uses silo-mod layout where the FreeCAD workbench
is at freecad/ (not pkg/freecad/). Also install the silo-client
submodule directory.
2026-02-06 12:42:02 -06:00
forbes
dfa2b73966 fix(ci): extract appimagetool for FUSE-less containers
Some checks failed
Build and Test / build (push) Has been cancelled
appimagetool is an AppImage itself and requires FUSE to self-mount.
CI containers typically don't have FUSE. Extract it with
--appimage-extract and run squashfs-root/AppRun instead.
2026-02-06 11:33:33 -06:00
forbes
056b015e78 chore: update mods/silo submodule to silo-mod initial commit
Some checks failed
Build and Test / build (push) Has been cancelled
2026-02-06 11:25:15 -06:00
6649372f7b Merge pull request 'refactor: rewire silo submodule for monorepo split' (#19) from refactor/silo-split into main
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #19
2026-02-06 17:23:08 +00:00
5db68dab25 Merge pull request 'docs: split REPOSITORY_STATE.md into topic files' (#18) from docs/split-repository-state into main
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #18
2026-02-06 17:22:42 +00:00
forbes
c59c704da3 refactor: rewire silo submodule for silo-mod split
Some checks failed
Build and Test / build (pull_request) Has been cancelled
- .gitmodules: silo.git -> silo-mod.git (FreeCAD workbench only)
- Init.py: silo/pkg/freecad -> silo/freecad (new repo layout)
- InitGui.py: same path update

The silo monorepo has been split into:
- silo-client: shared Python API client (submodule of silo-mod)
- silo-mod: FreeCAD workbench (this submodule)
- silo-calc: LibreOffice Calc extension (separate repo)
- silo: server only (no longer a Create submodule)
2026-02-06 11:15:30 -06:00
39 changed files with 1248 additions and 177 deletions

View File

@@ -0,0 +1,11 @@
[Unit]
Description=Kindred Create CI runner disk cleanup
After=docker.service
[Service]
Type=oneshot
ExecStart=/opt/runner/cleanup.sh
Environment=CLEANUP_THRESHOLD=85
Environment=CACHE_MAX_AGE_DAYS=7
StandardOutput=append:/var/log/runner-cleanup.log
StandardError=append:/var/log/runner-cleanup.log

220
.gitea/runner/cleanup.sh Executable file
View File

@@ -0,0 +1,220 @@
#!/usr/bin/env bash
# Runner disk cleanup script for Kindred Create CI/CD
#
# Designed to run as a cron job on the pubworker host:
# */30 * * * * /path/to/cleanup.sh >> /var/log/runner-cleanup.log 2>&1
#
# Or install the systemd timer (see cleanup.timer / cleanup.service).
#
# What it cleans:
# 1. Docker: stopped containers, dangling images, build cache
# 2. act_runner action cache: keeps only the newest entry per key prefix
# 3. act_runner workspaces: removes leftover build workspaces
# 4. System: apt cache, old logs
#
# What it preserves:
# - The current runner container and its image
# - The most recent cache entry per prefix (so ccache hits still work)
# - Everything outside of known CI paths
set -euo pipefail
# ---------------------------------------------------------------------------
# Configuration -- adjust these to match your runner setup
# ---------------------------------------------------------------------------
# Disk usage threshold (percent) -- only run aggressive cleanup above this
THRESHOLD=${CLEANUP_THRESHOLD:-85}
# act_runner cache directory (default location)
CACHE_DIR=${CACHE_DIR:-/root/.cache/actcache}
# act_runner workspace directories
WORKSPACES=(
"/root/.cache/act"
"/workspace"
)
# Maximum age (days) for cache entries before unconditional deletion
CACHE_MAX_AGE_DAYS=${CACHE_MAX_AGE_DAYS:-7}
# Maximum age (days) for Docker images not used by running containers
DOCKER_IMAGE_MAX_AGE=${DOCKER_IMAGE_MAX_AGE:-48h}
# Log prefix
LOG_PREFIX="[runner-cleanup]"
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
log() { echo "$(date '+%Y-%m-%d %H:%M:%S') ${LOG_PREFIX} $*"; }
disk_usage_pct() {
df --output=pcent / | tail -1 | tr -dc '0-9'
}
bytes_to_human() {
numfmt --to=iec-i --suffix=B "$1" 2>/dev/null || echo "${1}B"
}
# ---------------------------------------------------------------------------
# Phase 1: Check if cleanup is needed
# ---------------------------------------------------------------------------
usage=$(disk_usage_pct)
log "Disk usage: ${usage}% (threshold: ${THRESHOLD}%)"
if [ "$usage" -lt "$THRESHOLD" ]; then
log "Below threshold, running light cleanup only"
AGGRESSIVE=false
else
log "Above threshold, running aggressive cleanup"
AGGRESSIVE=true
fi
# ---------------------------------------------------------------------------
# Phase 2: Docker cleanup (always runs, safe)
# ---------------------------------------------------------------------------
log "--- Docker cleanup ---"
# Remove stopped containers
stopped=$(docker ps -aq --filter status=exited --filter status=dead 2>/dev/null | wc -l)
if [ "$stopped" -gt 0 ]; then
docker rm $(docker ps -aq --filter status=exited --filter status=dead) 2>/dev/null || true
log "Removed ${stopped} stopped containers"
fi
# Remove dangling images (untagged layers)
dangling=$(docker images -q --filter dangling=true 2>/dev/null | wc -l)
if [ "$dangling" -gt 0 ]; then
docker rmi $(docker images -q --filter dangling=true) 2>/dev/null || true
log "Removed ${dangling} dangling images"
fi
# Prune build cache
docker builder prune -f --filter "until=${DOCKER_IMAGE_MAX_AGE}" 2>/dev/null || true
log "Pruned Docker build cache older than ${DOCKER_IMAGE_MAX_AGE}"
if [ "$AGGRESSIVE" = true ]; then
# Remove all images not used by running containers
running_images=$(docker ps -q 2>/dev/null | xargs -r docker inspect --format='{{.Image}}' | sort -u)
all_images=$(docker images -q 2>/dev/null | sort -u)
for img in $all_images; do
if ! echo "$running_images" | grep -q "$img"; then
docker rmi -f "$img" 2>/dev/null || true
fi
done
log "Removed unused Docker images (aggressive)"
# Prune volumes
docker volume prune -f 2>/dev/null || true
log "Pruned unused Docker volumes"
fi
# ---------------------------------------------------------------------------
# Phase 3: act_runner action cache cleanup
# ---------------------------------------------------------------------------
log "--- Action cache cleanup ---"
if [ -d "$CACHE_DIR" ]; then
before=$(du -sb "$CACHE_DIR" 2>/dev/null | cut -f1)
# Delete cache entries older than max age
find "$CACHE_DIR" -type f -mtime "+${CACHE_MAX_AGE_DAYS}" -delete 2>/dev/null || true
find "$CACHE_DIR" -type d -empty -delete 2>/dev/null || true
after=$(du -sb "$CACHE_DIR" 2>/dev/null | cut -f1)
freed=$((before - after))
log "Cache cleanup freed $(bytes_to_human $freed) (entries older than ${CACHE_MAX_AGE_DAYS}d)"
else
log "Cache directory not found: ${CACHE_DIR}"
# Try common alternative locations
for alt in /var/lib/act_runner/.cache/actcache /home/*/.cache/actcache; do
if [ -d "$alt" ]; then
log "Found cache at: $alt (update CACHE_DIR config)"
CACHE_DIR="$alt"
find "$CACHE_DIR" -type f -mtime "+${CACHE_MAX_AGE_DAYS}" -delete 2>/dev/null || true
find "$CACHE_DIR" -type d -empty -delete 2>/dev/null || true
break
fi
done
fi
# ---------------------------------------------------------------------------
# Phase 4: Workspace cleanup
# ---------------------------------------------------------------------------
log "--- Workspace cleanup ---"
for ws in "${WORKSPACES[@]}"; do
if [ -d "$ws" ]; then
# Remove workspace dirs not modified in the last 2 hours
# (active builds should be touching files continuously)
before=$(du -sb "$ws" 2>/dev/null | cut -f1)
find "$ws" -mindepth 1 -maxdepth 1 -type d -mmin +120 -exec rm -rf {} + 2>/dev/null || true
after=$(du -sb "$ws" 2>/dev/null | cut -f1)
freed=$((before - after))
if [ "$freed" -gt 0 ]; then
log "Workspace $ws: freed $(bytes_to_human $freed)"
fi
fi
done
# ---------------------------------------------------------------------------
# Phase 5: System cleanup
# ---------------------------------------------------------------------------
log "--- System cleanup ---"
# apt cache
apt-get clean 2>/dev/null || true
# Truncate large log files (keep last 1000 lines)
for logfile in /var/log/syslog /var/log/daemon.log /var/log/kern.log; do
if [ -f "$logfile" ] && [ "$(stat -c%s "$logfile" 2>/dev/null)" -gt 104857600 ]; then
tail -1000 "$logfile" > "${logfile}.tmp" && mv "${logfile}.tmp" "$logfile"
log "Truncated $logfile (was >100MB)"
fi
done
# Journal logs older than 3 days
journalctl --vacuum-time=3d 2>/dev/null || true
# ---------------------------------------------------------------------------
# Phase 6: Emergency cleanup (only if still critical)
# ---------------------------------------------------------------------------
usage=$(disk_usage_pct)
if [ "$usage" -gt 95 ]; then
log "CRITICAL: Still at ${usage}% after cleanup"
# Nuclear option: remove ALL docker data except running containers
docker system prune -af --volumes 2>/dev/null || true
log "Ran docker system prune -af --volumes"
# Clear entire action cache
if [ -d "$CACHE_DIR" ]; then
rm -rf "${CACHE_DIR:?}/"*
log "Cleared entire action cache"
fi
usage=$(disk_usage_pct)
log "After emergency cleanup: ${usage}%"
fi
# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------
usage=$(disk_usage_pct)
log "Cleanup complete. Disk usage: ${usage}%"
# Report top space consumers for diagnostics
log "Top 10 directories under /var:"
du -sh /var/*/ 2>/dev/null | sort -rh | head -10 | while read -r line; do
log " $line"
done

View File

@@ -0,0 +1,10 @@
[Unit]
Description=Run CI runner cleanup every 30 minutes
[Timer]
OnBootSec=5min
OnUnitActiveSec=30min
Persistent=true
[Install]
WantedBy=timers.target

View File

@@ -22,6 +22,17 @@ jobs:
DEBIAN_FRONTEND: noninteractive
steps:
- name: Free disk space
run: |
echo "=== Disk usage before cleanup ==="
df -h /
rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache 2>/dev/null || true
rm -rf /usr/local/share/boost /usr/share/swift 2>/dev/null || true
apt-get autoremove -y 2>/dev/null || true
apt-get clean 2>/dev/null || true
echo "=== Disk usage after cleanup ==="
df -h /
- name: Install system prerequisites
run: |
apt-get update -qq
@@ -46,12 +57,16 @@ jobs:
export PATH="$HOME/.pixi/bin:$PATH"
pixi --version
- name: Compute cache date key
id: cache-date
run: echo "date=$(date -u +%Y%m%d)" >> $GITHUB_OUTPUT
- name: Restore ccache
id: ccache-restore
uses: https://github.com/actions/cache/restore@v4
with:
path: /tmp/ccache-kindred-create
key: ccache-build-${{ github.ref_name }}-${{ github.run_id }}
key: ccache-build-${{ github.ref_name }}-${{ steps.cache-date.outputs.date }}
restore-keys: |
ccache-build-${{ github.ref_name }}-
ccache-build-main-
@@ -60,6 +75,7 @@ jobs:
run: |
mkdir -p $CCACHE_DIR
pixi run ccache -z
pixi run ccache -p
- name: Configure (CMake)
run: pixi run cmake --preset conda-linux-release
@@ -71,11 +87,11 @@ jobs:
run: pixi run ccache -s
- name: Save ccache
if: always()
if: always() && steps.ccache-restore.outputs.cache-hit != 'true'
uses: https://github.com/actions/cache/save@v4
with:
path: /tmp/ccache-kindred-create
key: ccache-build-${{ github.ref_name }}-${{ github.run_id }}
key: ccache-build-${{ github.ref_name }}-${{ steps.cache-date.outputs.date }}
- name: Run C++ unit tests
continue-on-error: true

View File

@@ -31,6 +31,18 @@ jobs:
DEBIAN_FRONTEND: noninteractive
steps:
- name: Free disk space
run: |
echo "=== Disk usage before cleanup ==="
df -h /
# Remove pre-installed bloat common in runner images
rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache 2>/dev/null || true
rm -rf /usr/local/share/boost /usr/share/swift 2>/dev/null || true
apt-get autoremove -y 2>/dev/null || true
apt-get clean 2>/dev/null || true
echo "=== Disk usage after cleanup ==="
df -h /
- name: Install system prerequisites
run: |
apt-get update -qq
@@ -55,20 +67,26 @@ jobs:
export PATH="$HOME/.pixi/bin:$PATH"
pixi --version
- name: Compute cache date key
id: cache-date
run: echo "date=$(date -u +%Y%m%d)" >> $GITHUB_OUTPUT
- name: Restore ccache
id: ccache-restore
uses: https://github.com/actions/cache/restore@v4
with:
path: /tmp/ccache-kindred-create
key: ccache-release-linux-${{ github.run_id }}
key: ccache-release-linux-${{ steps.cache-date.outputs.date }}
restore-keys: |
ccache-release-linux-
ccache-build-main-
- name: Prepare ccache
run: |
mkdir -p $CCACHE_DIR
# Ensure ccache is accessible to rattler-build's subprocess
export PATH="$(pixi run bash -c 'echo $PATH')"
pixi run ccache -z
pixi run ccache -p
- name: Build release package (AppImage)
working-directory: package/rattler-build
@@ -80,11 +98,19 @@ jobs:
run: pixi run ccache -s
- name: Save ccache
if: always()
if: always() && steps.ccache-restore.outputs.cache-hit != 'true'
uses: https://github.com/actions/cache/save@v4
with:
path: /tmp/ccache-kindred-create
key: ccache-release-linux-${{ github.run_id }}
key: ccache-release-linux-${{ steps.cache-date.outputs.date }}
- name: Clean up intermediate build files
run: |
# Remove pixi package cache and build work dirs to free space for .deb
rm -rf package/rattler-build/.pixi/build 2>/dev/null || true
find /root/.cache/rattler -type f -delete 2>/dev/null || true
echo "=== Disk usage after cleanup ==="
df -h /
- name: Build .deb package
run: |
@@ -105,7 +131,7 @@ jobs:
with:
name: release-linux
path: |
package/rattler-build/linux/*.AppImage
package/rattler-build/linux/FreeCAD_*.AppImage
package/rattler-build/linux/*.deb
package/rattler-build/linux/*-SHA256.txt
package/rattler-build/linux/*.sha256
@@ -315,22 +341,69 @@ jobs:
ls -lah release/
- name: Create release
uses: https://gitea.com/actions/release-action@main
with:
files: release/*
title: "Kindred Create ${{ env.BUILD_TAG }}"
body: |
## Kindred Create ${{ env.BUILD_TAG }}
env:
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
GITEA_URL: ${{ github.server_url }}
REPO: ${{ github.repository }}
run: |
TAG="${BUILD_TAG}"
### Downloads
# Build JSON payload entirely in Python to avoid shell/Python type mismatches
PAYLOAD=$(python3 -c "
import json, re
tag = '${TAG}'
prerelease = bool(re.search(r'(rc|beta|alpha)', tag))
body = '''## Kindred Create {tag}
| Platform | File |
|----------|------|
| Linux (AppImage) | `KindredCreate-*-Linux-x86_64.AppImage` |
| Linux (Debian/Ubuntu) | `kindred-create_*.deb` |
### Downloads
*macOS and Windows builds are not yet available.*
| Platform | File |
|----------|------|
| Linux (AppImage) | \`KindredCreate-*-Linux-x86_64.AppImage\` |
| Linux (Debian/Ubuntu) | \`kindred-create_*.deb\` |
SHA256 checksums are provided alongside each artifact.
prerelease: ${{ contains(github.ref_name, 'rc') || contains(github.ref_name, 'beta') || contains(github.ref_name, 'alpha') }}
api_key: ${{ secrets.RELEASE_TOKEN }}
*macOS and Windows builds are not yet available.*
SHA256 checksums are provided alongside each artifact.'''.format(tag=tag)
print(json.dumps({
'tag_name': tag,
'name': f'Kindred Create {tag}',
'body': body,
'prerelease': prerelease,
}))
")
# Delete existing release for this tag (if any) so we can recreate
existing=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: token ${GITEA_TOKEN}" \
"${GITEA_URL}/api/v1/repos/${REPO}/releases/tags/${TAG}")
if [ "$existing" = "200" ]; then
release_id=$(curl -s \
-H "Authorization: token ${GITEA_TOKEN}" \
"${GITEA_URL}/api/v1/repos/${REPO}/releases/tags/${TAG}" | \
python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
curl -s -X DELETE \
-H "Authorization: token ${GITEA_TOKEN}" \
"${GITEA_URL}/api/v1/repos/${REPO}/releases/${release_id}"
echo "Deleted existing release ${release_id} for tag ${TAG}"
fi
# Create release
release_id=$(curl -s -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d "$PAYLOAD" \
"${GITEA_URL}/api/v1/repos/${REPO}/releases" | \
python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
echo "Created release ${release_id}"
# Upload assets
for file in release/*; do
filename=$(basename "$file")
echo "Uploading ${filename}..."
curl -s -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-F "attachment=@${file}" \
"${GITEA_URL}/api/v1/repos/${REPO}/releases/${release_id}/assets?name=${filename}"
echo " done."
done

2
.gitmodules vendored
View File

@@ -15,4 +15,4 @@
url = https://git.kindred-systems.com/forbes/ztools.git
[submodule "mods/silo"]
path = mods/silo
url = https://git.kindred-systems.com/kindred/silo.git
url = https://git.kindred-systems.com/kindred/silo-mod.git

View File

@@ -7,14 +7,14 @@ FreeCAD startup
└─ src/Mod/Create/Init.py
└─ setup_kindred_addons()
├─ exec(mods/ztools/ztools/Init.py)
└─ exec(mods/silo/pkg/freecad/Init.py)
└─ exec(mods/silo/freecad/Init.py)
└─ src/Mod/Create/InitGui.py
├─ setup_kindred_workbenches()
│ ├─ exec(mods/ztools/ztools/InitGui.py)
│ │ ├─ registers ZToolsWorkbench
│ │ └─ installs _ZToolsPartDesignManipulator (global)
│ └─ exec(mods/silo/pkg/freecad/InitGui.py)
│ └─ exec(mods/silo/freecad/InitGui.py)
│ └─ registers SiloWorkbench
└─ Deferred setup (QTimer):
├─ 1500ms: _setup_silo_auth_panel() → "Database Auth" dock
@@ -43,16 +43,13 @@ mods/ztools/ [submodule] ztools workbench
│ └── resources/ Icons, theme utilities
└── CatppuccinMocha/ Theme preference pack (QSS)
mods/silo/ [submodule] Silo parts database
├── cmd/ Go server entry points
├── internal/ Go API, database, auth, storage packages
── pkg/freecad/ FreeCAD workbench (Python)
├── InitGui.py SiloWorkbench
├── silo_commands.py Commands + SiloClient API
└── silo_origin.py FileOrigin backend for Silo
├── pkg/calc/ LibreOffice Calc extension (Python)
├── deployments/ Docker compose configuration
└── migrations/ PostgreSQL schema migrations (001010)
mods/silo/ [submodule -> silo-mod.git] FreeCAD workbench
├── silo-client/ [submodule -> silo-client.git] shared API client
│ └── silo_client/ SiloClient, SiloSettings, CATEGORY_NAMES
── freecad/ FreeCAD workbench (Python)
├── InitGui.py SiloWorkbench
├── silo_commands.py Commands + FreeCADSiloSettings adapter
└── silo_origin.py FileOrigin backend for Silo
src/Gui/Stylesheets/ QSS themes and SVG assets
resources/preferences/ Canonical preference pack (KindredCreate)

View File

@@ -28,7 +28,7 @@
## Origin commands (C++)
The Origin abstraction (`src/Gui/FileOrigin.h`) provides a backend-agnostic interface for document storage. Commands delegate to the active `FileOrigin` implementation (currently `LocalFileOrigin` for local files, `SiloOrigin` via `mods/silo/pkg/freecad/silo_origin.py` for Silo-tracked documents).
The Origin abstraction (`src/Gui/FileOrigin.h`) provides a backend-agnostic interface for document storage. Commands delegate to the active `FileOrigin` implementation (currently `LocalFileOrigin` for local files, `SiloOrigin` via `mods/silo/freecad/silo_origin.py` for Silo-tracked documents).
**Registered commands (5):**
@@ -71,7 +71,7 @@ These appear in the File menu and "Origin Tools" toolbar across all workbenches
**Server architecture:** Go REST API (38+ routes) + PostgreSQL + MinIO S3. Authentication via local (bcrypt), LDAP, or OIDC backends. See `mods/silo/docs/` for server documentation.
**LibreOffice Calc extension** (`mods/silo/pkg/calc/`): BOM management, item creation, and AI-assisted descriptions via OpenRouter API. Shares the same Silo REST API and auth token system.
**LibreOffice Calc extension** ([silo-calc](https://git.kindred-systems.com/kindred/silo-calc.git)): BOM management, item creation, and AI-assisted descriptions via OpenRouter API. Shares the same Silo REST API and auth token system via the shared [silo-client](https://git.kindred-systems.com/kindred/silo-client.git) package.
---
@@ -95,7 +95,7 @@ Four copies must stay in sync:
`silo-bom.svg`, `silo-commit.svg`, `silo-info.svg`, `silo-pull.svg`, `silo-push.svg`
### Silo module icons (`mods/silo/pkg/freecad/resources/icons/`)
### Silo module icons (`mods/silo/freecad/resources/icons/`)
10 SVGs loaded at runtime by the `_icon()` function in `silo_commands.py`:

View File

@@ -134,8 +134,10 @@ install(DIRECTORY ${CMAKE_SOURCE_DIR}/mods/ztools/ztools
install(DIRECTORY ${CMAKE_SOURCE_DIR}/mods/ztools/CatppuccinMocha
DESTINATION ${CMAKE_INSTALL_DATADIR}/Mod/ztools)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/mods/silo/pkg/freecad/
install(DIRECTORY ${CMAKE_SOURCE_DIR}/mods/silo/freecad/
DESTINATION ${CMAKE_INSTALL_DATADIR}/Mod/Silo)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/mods/silo/silo-client/
DESTINATION ${CMAKE_INSTALL_DATADIR}/Mod/silo-client)
```
---

View File

@@ -1,8 +1,117 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="4" fill="#313244"/>
<path d="M8 6 L20 6 L24 10 L24 26 L8 26 Z" fill="none" stroke="#89b4fa" stroke-width="1.5"/>
<path d="M20 6 L20 10 L24 10" fill="none" stroke="#74c7ec" stroke-width="1.5"/>
<line x1="11" y1="14" x2="21" y2="14" stroke="#74c7ec" stroke-width="1.5"/>
<line x1="11" y1="18" x2="21" y2="18" stroke="#74c7ec" stroke-width="1.5"/>
<line x1="11" y1="22" x2="17" y2="22" stroke="#74c7ec" stroke-width="1.5"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 32 32"
version="1.1"
id="svg4"
sodipodi:docname="Document.svg"
inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs4">
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect5"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.8970359,0,1 @ F,0,0,1,0,0,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect4"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,2.25625,0,1 @ F,0,0,1,0,1.411235,0,1 @ F,0,0,1,0,1.2732549,0,1 @ F,0,0,1,0,2.25625,0,1 @ F,0,0,1,0,1.875,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
</defs>
<sodipodi:namedview
id="namedview4"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="32"
inkscape:cx="10.90625"
inkscape:cy="12.21875"
inkscape:window-width="2560"
inkscape:window-height="1371"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<rect
width="32"
height="32"
rx="4"
fill="#313244"
id="rect1" />
<path
d="m 10.246497,6 h 8.332515 a 3.4070227,3.4070227 22.5 0 1 2.409129,0.9978938 l 2.101779,2.101779 a 3.0739092,3.0739092 67.5 0 1 0.900327,2.1735822 l 0,12.470495 A 2.25625,2.25625 135 0 1 21.733997,26 H 9.8652468 a 1.875,1.875 45 0 1 -1.875,-1.875 V 8.25625 A 2.25625,2.25625 135 0 1 10.246497,6 Z"
fill="none"
stroke="#89b4fa"
stroke-width="1.5"
id="path1"
inkscape:path-effect="#path-effect4"
inkscape:original-d="M 7.9902468,6 H 19.990247 l 4,4 V 26 H 7.9902468 Z" />
<path
d="m 19.707388,5.8623613 v 3.4443418 a 0.8970359,0.8970359 45 0 0 0.897036,0.8970359 h 3.385823"
fill="none"
stroke="#74c7ec"
stroke-width="1.61701"
id="path2"
style="stroke:#89b4fa;stroke-width:1.5;stroke-dasharray:none;stroke-opacity:1"
inkscape:path-effect="#path-effect5"
inkscape:original-d="m 19.707388,5.8623613 v 4.3413777 h 4.282859" />
<line
x1="11"
y1="14"
x2="21"
y2="14"
stroke="#74c7ec"
stroke-width="1.5"
id="line2"
style="stroke-linecap:round" />
<line
x1="11"
y1="18"
x2="21"
y2="18"
stroke="#74c7ec"
stroke-width="1.5"
id="line3"
style="stroke-linecap:round" />
<line
x1="11"
y1="22"
x2="17"
y2="22"
stroke="#74c7ec"
stroke-width="1.5"
id="line4"
style="stroke-linecap:round" />
</svg>

Before

Width:  |  Height:  |  Size: 534 B

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -1,5 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="4" fill="#313244"/>
<ellipse cx="16" cy="16" rx="10" ry="6" fill="none" stroke="#f9e2af" stroke-width="2"/>
<circle cx="16" cy="16" r="3" fill="#fab387"/>
<ellipse cx="16" cy="16" rx="10" ry="6" fill="none" stroke="#cdd6f4" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="16" cy="16" r="3" fill="none" stroke="#cdd6f4" stroke-width="1.5"/>
</svg>

Before

Width:  |  Height:  |  Size: 262 B

After

Width:  |  Height:  |  Size: 344 B

View File

@@ -1,5 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="4" fill="#313244"/>
<path d="M8 12 L16 8 L24 12 L24 22 L16 26 L8 22 Z" fill="#f9e2af" fill-opacity="0.6" stroke="#fab387" stroke-width="1.5"/>
<path d="M8 12 L16 16 L24 12 M16 16 L16 26" fill="none" stroke="#fab387" stroke-width="1.5"/>
<path d="M5.5 9.5 16 4l10.5 5.5v13L16 28 5.5 22.5z" fill="#45475a" stroke="#89b4fa" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.5 9.5 16 15l10.5-5.5M16 15v13" fill="none" stroke="#89b4fa" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 344 B

After

Width:  |  Height:  |  Size: 419 B

View File

@@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="4" fill="#313244"/>
<path d="M8 12 L16 8 L24 12 L24 22 L16 26 L8 22 Z" fill="none" stroke="#f9e2af" stroke-width="1.5"/>
<path d="M8 12 L16 16 L24 12 M16 16 L16 26" fill="none" stroke="#fab387" stroke-width="1.5" stroke-dasharray="2,2"/>
</svg>

Before

Width:  |  Height:  |  Size: 345 B

View File

@@ -1,7 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="4" fill="#313244"/>
<rect x="8" y="10" width="16" height="12" fill="none" stroke="#f9e2af" stroke-width="2"/>
<line x1="8" y1="10" x2="12" y2="6" stroke="#fab387" stroke-width="1.5"/>
<line x1="24" y1="10" x2="28" y2="6" stroke="#fab387" stroke-width="1.5"/>
<line x1="12" y1="6" x2="28" y2="6" stroke="#fab387" stroke-width="1.5"/>
<path d="M5.5 9.5 16 4l10.5 5.5v13L16 28 5.5 22.5z" fill="#585b70" stroke="#cdd6f4" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.5 9.5 16 15l10.5-5.5M16 15v13" fill="none" stroke="#cdd6f4" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 444 B

After

Width:  |  Height:  |  Size: 419 B

View File

@@ -1,10 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="4" fill="#313244"/>
<circle cx="8" cy="12" r="2" fill="#f9e2af"/>
<circle cx="16" cy="8" r="2" fill="#f9e2af"/>
<circle cx="24" cy="12" r="2" fill="#f9e2af"/>
<circle cx="8" cy="22" r="2" fill="#fab387"/>
<circle cx="16" cy="26" r="2" fill="#fab387"/>
<circle cx="24" cy="22" r="2" fill="#fab387"/>
<circle cx="16" cy="16" r="2" fill="#f9e2af"/>
<circle cx="16" cy="4" r="1.5" fill="#cdd6f4"/>
<circle cx="5.5" cy="9.5" r="1.5" fill="#cdd6f4"/>
<circle cx="26.5" cy="9.5" r="1.5" fill="#cdd6f4"/>
<circle cx="16" cy="15" r="1.5" fill="#cdd6f4"/>
<circle cx="5.5" cy="22.5" r="1.5" fill="#cdd6f4"/>
<circle cx="26.5" cy="22.5" r="1.5" fill="#cdd6f4"/>
<circle cx="16" cy="28" r="1.5" fill="#cdd6f4"/>
</svg>

Before

Width:  |  Height:  |  Size: 463 B

After

Width:  |  Height:  |  Size: 491 B

View File

@@ -1,5 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="4" fill="#313244"/>
<path d="M8 12 L16 8 L24 12 L24 22 L16 26 L8 22 Z" fill="#f9e2af" stroke="#fab387" stroke-width="1.5"/>
<path d="M8 12 L16 16 L24 12 M16 16 L16 26" fill="none" stroke="#313244" stroke-width="1"/>
<path d="M5.5 9.5 16 4l10.5 5.5v13L16 28 5.5 22.5z" fill="#45475a" stroke="#cdd6f4" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.5 9.5 16 15l10.5-5.5M16 15v13" fill="none" stroke="#cdd6f4" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 323 B

After

Width:  |  Height:  |  Size: 419 B

View File

@@ -1,5 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="4" fill="#313244"/>
<path d="M8 12 L16 8 L24 12 L24 22 L16 26 L8 22 Z" fill="none" stroke="#f9e2af" stroke-width="1.5"/>
<path d="M8 12 L16 16 L24 12 M16 16 L16 26" fill="none" stroke="#fab387" stroke-width="1.5"/>
<path d="M5.5 9.5 16 4l10.5 5.5v13L16 28 5.5 22.5z" fill="none" stroke="#cdd6f4" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.5 9.5 16 15l10.5-5.5M16 15v13" fill="none" stroke="#cdd6f4" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 322 B

After

Width:  |  Height:  |  Size: 416 B

View File

@@ -1,9 +1,62 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="4" fill="#313244"/>
<circle cx="10" cy="10" r="4" fill="none" stroke="#89b4fa" stroke-width="1.5"/>
<circle cx="22" cy="10" r="4" fill="none" stroke="#74c7ec" stroke-width="1.5"/>
<circle cx="10" cy="22" r="4" fill="none" stroke="#74c7ec" stroke-width="1.5"/>
<circle cx="22" cy="22" r="4" fill="none" stroke="#89b4fa" stroke-width="1.5"/>
<line x1="14" y1="10" x2="18" y2="10" stroke="#89b4fa" stroke-width="1.5"/>
<line x1="10" y1="14" x2="10" y2="18" stroke="#74c7ec" stroke-width="1.5"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 32 32"
version="1.1"
id="svg3"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<rect
width="32"
height="32"
rx="4"
fill="#313244"
id="rect1" />
<circle
cx="10"
cy="10"
r="4"
fill="none"
stroke="#89b4fa"
stroke-width="1.5"
id="circle1" />
<circle
cx="22"
cy="10"
r="4"
fill="none"
stroke="#89b4fa"
stroke-width="1.5"
id="circle2" />
<circle
cx="10"
cy="22"
r="4"
fill="none"
stroke="#89b4fa"
stroke-width="1.5"
id="circle3" />
<circle
cx="22"
cy="22"
r="4"
fill="none"
stroke="#89b4fa"
stroke-width="1.5"
id="circle4" />
<line
x1="14"
y1="10"
x2="18"
y2="10"
stroke="#cba6f7"
stroke-width="1.5"
id="line1" />
<line
x1="10"
y1="14"
x2="10"
y2="18"
stroke="#cba6f7"
stroke-width="1.5"
id="line2" />
</svg>

Before

Width:  |  Height:  |  Size: 607 B

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1,7 +1,52 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="4" fill="#313244"/>
<rect x="6" y="6" width="10" height="10" rx="1" fill="none" stroke="#89b4fa" stroke-width="1.5"/>
<rect x="10" y="10" width="10" height="10" rx="1" fill="#313244" stroke="#74c7ec" stroke-width="1.5"/>
<rect x="14" y="14" width="10" height="10" rx="1" fill="#313244" stroke="#89b4fa" stroke-width="1.5"/>
<circle cx="24" cy="8" r="4" fill="none" stroke="#a6e3a1" stroke-width="1.5"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 32 32"
version="1.1"
id="svg3"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<rect
width="32"
height="32"
rx="4"
fill="#313244"
id="rect1" />
<rect
x="6"
y="6"
width="10"
height="10"
rx="1.5"
fill="none"
stroke="#89b4fa"
stroke-width="1.5"
id="rect2" />
<rect
x="10"
y="10"
width="10"
height="10"
rx="1.5"
fill="#313244"
stroke="#cba6f7"
stroke-width="1.5"
id="rect3" />
<rect
x="14"
y="14"
width="10"
height="10"
rx="1.5"
fill="#313244"
stroke="#89b4fa"
stroke-width="1.5"
id="rect4" />
<circle
cx="24"
cy="8"
r="4"
fill="none"
stroke="#a6e3a1"
stroke-width="1.5"
id="circle1" />
</svg>

Before

Width:  |  Height:  |  Size: 514 B

After

Width:  |  Height:  |  Size: 910 B

View File

@@ -1,6 +1,35 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="4" fill="#313244"/>
<rect x="8" y="8" width="10" height="10" rx="1" fill="none" stroke="#89b4fa" stroke-width="1.5"/>
<path d="M18 18 L24 24" stroke="#74c7ec" stroke-width="2"/>
<circle cx="24" cy="24" r="3" fill="#74c7ec"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 32 32"
version="1.1"
id="svg3"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<rect
width="32"
height="32"
rx="4"
fill="#313244"
id="rect1" />
<rect
x="8"
y="8"
width="10"
height="10"
rx="1.5"
fill="none"
stroke="#89b4fa"
stroke-width="1.5"
id="rect2" />
<path
d="M 18,18 24,24"
stroke="#89b4fa"
stroke-width="1.5"
id="path1" />
<circle
cx="24"
cy="24"
r="3"
fill="#cba6f7"
id="circle1" />
</svg>

Before

Width:  |  Height:  |  Size: 334 B

After

Width:  |  Height:  |  Size: 636 B

View File

@@ -1,7 +1,48 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="4" fill="#313244"/>
<rect x="6" y="10" width="20" height="14" rx="2" fill="none" stroke="#89b4fa" stroke-width="1.5"/>
<circle cx="12" cy="17" r="3" fill="none" stroke="#74c7ec" stroke-width="1.5"/>
<circle cx="20" cy="17" r="3" fill="none" stroke="#74c7ec" stroke-width="1.5"/>
<line x1="15" y1="17" x2="17" y2="17" stroke="#89b4fa" stroke-width="1.5"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 32 32"
version="1.1"
id="svg3"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<rect
width="32"
height="32"
rx="4"
fill="#313244"
id="rect1" />
<rect
x="6"
y="10"
width="20"
height="14"
rx="2"
fill="none"
stroke="#89b4fa"
stroke-width="1.5"
id="rect2" />
<circle
cx="12"
cy="17"
r="3"
fill="none"
stroke="#cba6f7"
stroke-width="1.5"
id="circle1" />
<circle
cx="20"
cy="17"
r="3"
fill="none"
stroke="#cba6f7"
stroke-width="1.5"
id="circle2" />
<line
x1="15"
y1="17"
x2="17"
y2="17"
stroke="#89b4fa"
stroke-width="1.5"
id="line1" />
</svg>

Before

Width:  |  Height:  |  Size: 466 B

After

Width:  |  Height:  |  Size: 838 B

View File

@@ -1,7 +1,42 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="4" fill="#313244"/>
<circle cx="10" cy="10" r="3" fill="none" stroke="#89b4fa" stroke-width="1.5"/>
<circle cx="22" cy="10" r="3" fill="none" stroke="#74c7ec" stroke-width="1.5"/>
<circle cx="10" cy="20" r="3" fill="none" stroke="#74c7ec" stroke-width="1.5"/>
<path d="M24 18 L24 26 L18 22 Z" fill="#a6e3a1"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 32 32"
version="1.1"
id="svg3"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<rect
width="32"
height="32"
rx="4"
fill="#313244"
id="rect1" />
<circle
cx="10"
cy="10"
r="3"
fill="none"
stroke="#89b4fa"
stroke-width="1.5"
id="circle1" />
<circle
cx="22"
cy="10"
r="3"
fill="none"
stroke="#89b4fa"
stroke-width="1.5"
id="circle2" />
<circle
cx="10"
cy="20"
r="3"
fill="none"
stroke="#89b4fa"
stroke-width="1.5"
id="circle3" />
<path
d="M 24,18 24,26 18,22 Z"
fill="#a6e3a1"
id="path1" />
</svg>

Before

Width:  |  Height:  |  Size: 421 B

After

Width:  |  Height:  |  Size: 764 B

View File

@@ -1,5 +1,34 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="4" fill="#313244"/>
<rect x="6" y="6" width="12" height="12" rx="1" fill="none" stroke="#89b4fa" stroke-width="1.5"/>
<rect x="14" y="14" width="12" height="12" rx="1" fill="#313244" stroke="#74c7ec" stroke-width="1.5"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 32 32"
version="1.1"
id="svg3"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<rect
width="32"
height="32"
rx="4"
fill="#313244"
id="rect1" />
<rect
x="6"
y="6"
width="12"
height="12"
rx="1.5"
fill="none"
stroke="#89b4fa"
stroke-width="1.5"
id="rect2" />
<rect
x="14"
y="14"
width="12"
height="12"
rx="1.5"
fill="#313244"
stroke="#cba6f7"
stroke-width="1.5"
id="rect3" />
</svg>

Before

Width:  |  Height:  |  Size: 328 B

After

Width:  |  Height:  |  Size: 616 B

View File

@@ -1,7 +1,42 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="4" fill="#313244"/>
<circle cx="10" cy="16" r="5" fill="none" stroke="#89b4fa" stroke-width="1.5"/>
<circle cx="22" cy="16" r="5" fill="none" stroke="#74c7ec" stroke-width="1.5"/>
<path d="M13 12 L19 12 M19 12 L17 10 M19 12 L17 14" stroke="#a6e3a1" stroke-width="1.5"/>
<path d="M19 20 L13 20 M13 20 L15 18 M13 20 L15 22" stroke="#f38ba8" stroke-width="1.5"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 32 32"
version="1.1"
id="svg3"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<rect
width="32"
height="32"
rx="4"
fill="#313244"
id="rect1" />
<circle
cx="10"
cy="16"
r="5"
fill="none"
stroke="#89b4fa"
stroke-width="1.5"
id="circle1" />
<circle
cx="22"
cy="16"
r="5"
fill="none"
stroke="#89b4fa"
stroke-width="1.5"
id="circle2" />
<path
d="M 13,12 19,12 M 19,12 17,10 M 19,12 17,14"
stroke="#a6e3a1"
stroke-width="1.5"
fill="none"
id="path1" />
<path
d="M 19,20 13,20 M 13,20 15,18 M 13,20 15,22"
stroke="#f38ba8"
stroke-width="1.5"
fill="none"
id="path2" />
</svg>

Before

Width:  |  Height:  |  Size: 471 B

After

Width:  |  Height:  |  Size: 837 B

View File

@@ -1,14 +1,62 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect x="2" y="2" width="28" height="28" rx="4" fill="#313244"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 32 32"
version="1.1"
id="svg5"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<rect
x="2"
y="2"
width="28"
height="28"
rx="4"
fill="#313244"
id="rect1" />
<!-- Base sketch profile -->
<path d="M6 24 L6 20 L14 18 L26 20 L26 24 L14 26 Z" fill="#45475a" stroke="#6c7086" stroke-width="1"/>
<path
d="M 6,24 6,20 14,18 26,20 26,24 14,26 Z"
fill="#45475a"
stroke="#6c7086"
stroke-width="1"
id="path1" />
<!-- Extruded body -->
<path d="M6 20 L6 10 L14 8 L26 10 L26 20 L14 22 Z" fill="#45475a" stroke="#89b4fa" stroke-width="1.5"/>
<path d="M6 10 L14 12 L26 10" stroke="#89b4fa" stroke-width="1.5" fill="none"/>
<path d="M14 12 L14 22" stroke="#89b4fa" stroke-width="1.5"/>
<path
d="M 6,20 6,10 14,8 26,10 26,20 14,22 Z"
fill="#45475a"
stroke="#89b4fa"
stroke-width="1.5"
id="path2" />
<path
d="M 6,10 14,12 26,10"
stroke="#89b4fa"
stroke-width="1.5"
fill="none"
id="path3" />
<path
d="M 14,12 V 22"
stroke="#89b4fa"
stroke-width="1.5"
id="path4" />
<!-- Top face -->
<path d="M6 10 L14 8 L26 10 L14 12 Z" fill="#74c7ec" fill-opacity="0.4"/>
<path
d="M 6,10 14,8 26,10 14,12 Z"
fill="#74c7ec"
fill-opacity="0.4"
id="path5" />
<!-- Extrude arrow -->
<path d="M20 18 L20 6" stroke="#a6e3a1" stroke-width="2" stroke-linecap="round"/>
<path d="M17 9 L20 5 L23 9" stroke="#a6e3a1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
<path
d="M 20,18 V 6"
stroke="#a6e3a1"
stroke-width="2"
stroke-linecap="round"
id="path6" />
<path
d="M 17,9 20,5 23,9"
stroke="#a6e3a1"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
fill="none"
id="path7" />
</svg>

Before

Width:  |  Height:  |  Size: 878 B

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,14 +1,67 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect x="2" y="2" width="28" height="28" rx="4" fill="#313244"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 32 32"
version="1.1"
id="svg5"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<rect
x="2"
y="2"
width="28"
height="28"
rx="4"
fill="#313244"
id="rect1" />
<!-- Solid block -->
<path d="M4 22 L4 10 L16 6 L28 10 L28 22 L16 26 Z" fill="#45475a" stroke="#89b4fa" stroke-width="1.5"/>
<path d="M4 10 L16 14 L28 10" stroke="#89b4fa" stroke-width="1.5" fill="none"/>
<path d="M16 14 L16 26" stroke="#89b4fa" stroke-width="1.5"/>
<path
d="M 4,22 4,10 16,6 28,10 28,22 16,26 Z"
fill="#45475a"
stroke="#89b4fa"
stroke-width="1.5"
id="path1" />
<path
d="M 4,10 16,14 28,10"
stroke="#89b4fa"
stroke-width="1.5"
fill="none"
id="path2" />
<path
d="M 16,14 V 26"
stroke="#89b4fa"
stroke-width="1.5"
id="path3" />
<!-- Pocket cut-out -->
<path d="M10 12 L16 10 L22 12 L22 18 L16 20 L10 18 Z" fill="#1e1e2e" stroke="#f38ba8" stroke-width="1.5"/>
<path d="M10 12 L16 14 L22 12" stroke="#f38ba8" stroke-width="1" fill="none"/>
<path d="M16 14 L16 20" stroke="#f38ba8" stroke-width="1"/>
<path
d="M 10,12 16,10 22,12 22,18 16,20 10,18 Z"
fill="#1e1e2e"
stroke="#f38ba8"
stroke-width="1.5"
id="path4" />
<path
d="M 10,12 16,14 22,12"
stroke="#f38ba8"
stroke-width="1"
fill="none"
id="path5" />
<path
d="M 16,14 V 20"
stroke="#f38ba8"
stroke-width="1"
id="path6" />
<!-- Cut arrow -->
<path d="M16 8 L16 16" stroke="#f38ba8" stroke-width="1.5" stroke-linecap="round"/>
<path d="M14 13 L16 17 L18 13" stroke="#f38ba8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
<path
d="M 16,8 V 16"
stroke="#f38ba8"
stroke-width="1.5"
stroke-linecap="round"
id="path7" />
<path
d="M 14,13 16,17 18,13"
stroke="#f38ba8"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
fill="none"
id="path8" />
</svg>

Before

Width:  |  Height:  |  Size: 925 B

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,6 +1,34 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="4" fill="#313244"/>
<path d="M12 20 L8 20 A4 4 0 0 1 8 12 L12 12" fill="none" stroke="#585b70" stroke-width="2"/>
<path d="M20 12 L24 12 A4 4 0 0 1 24 20 L20 20" fill="none" stroke="#585b70" stroke-width="2"/>
<line x1="6" y1="26" x2="26" y2="6" stroke="#f38ba8" stroke-width="2"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 32 32"
version="1.1"
id="svg3"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<rect
width="32"
height="32"
rx="4"
fill="#313244"
id="rect1" />
<path
d="M 12,20 H 8 A 4,4 0 0 1 8,12 h 4"
fill="none"
stroke="#585b70"
stroke-width="1.5"
id="path1" />
<path
d="M 20,12 h 4 A 4,4 0 0 1 24,20 h -4"
fill="none"
stroke="#585b70"
stroke-width="1.5"
id="path2" />
<line
x1="6"
y1="26"
x2="26"
y2="6"
stroke="#f38ba8"
stroke-width="2"
id="line1" />
</svg>

Before

Width:  |  Height:  |  Size: 391 B

After

Width:  |  Height:  |  Size: 680 B

View File

@@ -1,10 +1,60 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect x="2" y="2" width="28" height="28" rx="4" fill="#313244"/>
<!-- Document shape -->
<path d="M9 5 L9 27 L23 27 L23 11 L17 5 Z" fill="#45475a" stroke="#89b4fa" stroke-width="1.5"/>
<!-- Folded corner -->
<path d="M17 5 L17 11 L23 11" fill="#313244" stroke="#89b4fa" stroke-width="1.5" stroke-linejoin="round"/>
<!-- Plus sign for "new" -->
<circle cx="22" cy="22" r="6" fill="#a6e3a1"/>
<path d="M22 19 L22 25 M19 22 L25 22" stroke="#1e1e2e" stroke-width="2" stroke-linecap="round"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 32 32"
version="1.1"
id="svg4"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<rect
x="2"
y="2"
width="28"
height="28"
rx="4"
fill="#313244"
id="rect1" />
<path
d="M 10,6 H 18 L 24,12 V 26 H 10 Z"
fill="none"
stroke="#89b4fa"
stroke-width="1.5"
id="path1"
style="stroke-linejoin:round" />
<path
d="M 18,6 V 12 H 24"
fill="none"
stroke="#89b4fa"
stroke-width="1.5"
id="path2"
style="stroke-linejoin:round" />
<line
x1="12"
y1="16"
x2="20"
y2="16"
stroke="#74c7ec"
stroke-width="1.5"
id="line1"
style="stroke-linecap:round" />
<line
x1="12"
y1="20"
x2="20"
y2="20"
stroke="#74c7ec"
stroke-width="1.5"
id="line2"
style="stroke-linecap:round" />
<circle
cx="24"
cy="24"
r="5"
fill="#a6e3a1"
id="circle1" />
<path
d="M 24,21.5 V 26.5 M 21.5,24 H 26.5"
stroke="#1e1e2e"
stroke-width="1.5"
stroke-linecap="round"
id="path3" />
</svg>

Before

Width:  |  Height:  |  Size: 572 B

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,14 +1,75 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect x="2" y="2" width="28" height="28" rx="4" fill="#313244"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 32 32"
version="1.1"
id="svg4"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<rect
x="2"
y="2"
width="28"
height="28"
rx="4"
fill="#313244"
id="rect1" />
<!-- Printer body -->
<rect x="5" y="12" width="22" height="10" rx="2" fill="#45475a" stroke="#89b4fa" stroke-width="1.5"/>
<rect
x="5"
y="12"
width="22"
height="10"
rx="2"
fill="#45475a"
stroke="#89b4fa"
stroke-width="1.5"
id="rect2" />
<!-- Paper input (top) -->
<rect x="9" y="6" width="14" height="8" rx="1" fill="#cdd6f4" stroke="#6c7086" stroke-width="1"/>
<rect
x="9"
y="6"
width="14"
height="8"
rx="1"
fill="#cdd6f4"
stroke="#6c7086"
stroke-width="1"
id="rect3" />
<!-- Paper output (bottom) -->
<rect x="9" y="20" width="14" height="8" rx="1" fill="#cdd6f4" stroke="#6c7086" stroke-width="1"/>
<rect
x="9"
y="20"
width="14"
height="8"
rx="1"
fill="#cdd6f4"
stroke="#6c7086"
stroke-width="1"
id="rect4" />
<!-- Paper lines -->
<line x1="11" y1="23" x2="21" y2="23" stroke="#585b70" stroke-width="1" stroke-linecap="round"/>
<line x1="11" y1="25" x2="18" y2="25" stroke="#585b70" stroke-width="1" stroke-linecap="round"/>
<line
x1="11"
y1="23"
x2="21"
y2="23"
stroke="#585b70"
stroke-width="1"
stroke-linecap="round"
id="line1" />
<line
x1="11"
y1="25.5"
x2="18"
y2="25.5"
stroke="#585b70"
stroke-width="1"
stroke-linecap="round"
id="line2" />
<!-- Printer status light -->
<circle cx="23" cy="15" r="1.5" fill="#a6e3a1"/>
<circle
cx="23"
cy="15"
r="1.5"
fill="#a6e3a1"
id="circle1" />
</svg>

Before

Width:  |  Height:  |  Size: 830 B

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,15 +1,63 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect x="2" y="2" width="28" height="28" rx="4" fill="#313244"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 32 32"
version="1.1"
id="svg4"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<rect
x="2"
y="2"
width="28"
height="28"
rx="4"
fill="#313244"
id="rect1" />
<!-- Floppy disk body -->
<path d="M7 6 L7 26 L25 26 L25 10 L21 6 Z" fill="#45475a" stroke="#89b4fa" stroke-width="1.5"/>
<path
d="M 7,6 H 21 L 25,10 V 26 H 7 Z"
fill="#45475a"
stroke="#89b4fa"
stroke-width="1.5"
id="path1"
style="stroke-linejoin:round" />
<!-- Metal slider -->
<rect x="10" y="6" width="10" height="8" rx="1" fill="#1e1e2e" stroke="#6c7086" stroke-width="1"/>
<rect
x="10"
y="6"
width="10"
height="8"
rx="1"
fill="#1e1e2e"
stroke="#6c7086"
stroke-width="1"
id="rect2" />
<!-- Slider notch -->
<rect x="17" y="7" width="2" height="6" fill="#313244"/>
<rect
x="17"
y="7"
width="2"
height="6"
fill="#313244"
id="rect3" />
<!-- Label area -->
<rect x="9" y="17" width="14" height="7" rx="1" fill="#cdd6f4"/>
<!-- Pencil icon for "save as" -->
<g transform="translate(18, 14)">
<path d="M6 2 L8 0 L10 2 L4 8 L2 8 L2 6 Z" fill="#f9e2af" stroke="#fab387" stroke-width="0.5"/>
</g>
<rect
x="9"
y="17"
width="14"
height="7"
rx="1"
fill="#cdd6f4"
id="rect4" />
<!-- Pencil badge for "save as" -->
<circle
cx="24"
cy="24"
r="5"
fill="#f9e2af"
id="circle1" />
<path
d="M 22,26 22,24 26,20 28,22 24,26 Z"
fill="#1e1e2e"
id="path2" />
</svg>

Before

Width:  |  Height:  |  Size: 738 B

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,14 +1,71 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect x="2" y="2" width="28" height="28" rx="4" fill="#313244"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 32 32"
version="1.1"
id="svg4"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<rect
x="2"
y="2"
width="28"
height="28"
rx="4"
fill="#313244"
id="rect1" />
<!-- Floppy disk body -->
<path d="M7 6 L7 26 L25 26 L25 10 L21 6 Z" fill="#45475a" stroke="#89b4fa" stroke-width="1.5"/>
<path
d="M 7,6 H 21 L 25,10 V 26 H 7 Z"
fill="#45475a"
stroke="#89b4fa"
stroke-width="1.5"
id="path1"
style="stroke-linejoin:round" />
<!-- Metal slider -->
<rect x="10" y="6" width="10" height="8" rx="1" fill="#1e1e2e" stroke="#6c7086" stroke-width="1"/>
<rect
x="10"
y="6"
width="10"
height="8"
rx="1"
fill="#1e1e2e"
stroke="#6c7086"
stroke-width="1"
id="rect2" />
<!-- Slider notch -->
<rect x="17" y="7" width="2" height="6" fill="#313244"/>
<rect
x="17"
y="7"
width="2"
height="6"
fill="#313244"
id="rect3" />
<!-- Label area -->
<rect x="9" y="17" width="14" height="7" rx="1" fill="#cdd6f4"/>
<rect
x="9"
y="17"
width="14"
height="7"
rx="1"
fill="#cdd6f4"
id="rect4" />
<!-- Label lines -->
<line x1="11" y1="19" x2="21" y2="19" stroke="#313244" stroke-width="1" stroke-linecap="round"/>
<line x1="11" y1="22" x2="17" y2="22" stroke="#313244" stroke-width="1" stroke-linecap="round"/>
<line
x1="11"
y1="19.5"
x2="21"
y2="19.5"
stroke="#313244"
stroke-width="1"
stroke-linecap="round"
id="line1" />
<line
x1="11"
y1="22"
x2="17"
y2="22"
stroke="#313244"
stroke-width="1"
stroke-linecap="round"
id="line2" />
</svg>

Before

Width:  |  Height:  |  Size: 779 B

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,3 +1,15 @@
# Configure ccache to use a shared cache directory that persists across CI runs.
# The workflow caches /tmp/ccache-kindred-create between builds.
export CCACHE_DIR="${CCACHE_DIR:-/tmp/ccache-kindred-create}"
export CCACHE_BASEDIR="${SRC_DIR:-$(pwd)}"
export CCACHE_COMPRESS="${CCACHE_COMPRESS:-true}"
export CCACHE_COMPRESSLEVEL="${CCACHE_COMPRESSLEVEL:-6}"
export CCACHE_MAXSIZE="${CCACHE_MAXSIZE:-4G}"
export CCACHE_SLOPPINESS="${CCACHE_SLOPPINESS:-include_file_ctime,include_file_mtime,pch_defines,time_macros}"
mkdir -p "$CCACHE_DIR"
echo "ccache config: CCACHE_DIR=$CCACHE_DIR CCACHE_BASEDIR=$CCACHE_BASEDIR"
ccache -z || true
if [[ ${HOST} =~ .*linux.* ]]; then
CMAKE_PRESET=conda-linux-release
fi
@@ -46,3 +58,6 @@ cmake --install build
mv ${PREFIX}/bin/FreeCAD ${PREFIX}/bin/freecad || true
mv ${PREFIX}/bin/FreeCADCmd ${PREFIX}/bin/freecadcmd || true
echo "=== ccache statistics ==="
ccache -s || true

View File

@@ -59,6 +59,10 @@ sed -i "1s/.*/\nLIST OF PACKAGES:/" AppDir/packages.txt
curl -LO https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-$(uname -m).AppImage
chmod a+x appimagetool-$(uname -m).AppImage
# Extract appimagetool so it works in containers without FUSE
./appimagetool-$(uname -m).AppImage --appimage-extract > /dev/null 2>&1
APPIMAGETOOL=squashfs-root/AppRun
if [ "${UPLOAD_RELEASE}" == "true" ]; then
case "${BUILD_TAG}" in
*weekly*)
@@ -76,7 +80,7 @@ fi
echo -e "\nCreate the appimage"
# export GPG_TTY=$(tty)
chmod a+x ./AppDir/AppRun
./appimagetool-$(uname -m).AppImage \
${APPIMAGETOOL} \
--comp zstd \
--mksquashfs-opt -Xcompression-level \
--mksquashfs-opt 22 \

View File

@@ -18,6 +18,7 @@ requirements:
- cmake
- compilers>=1.10,<1.11
- doxygen
- icu>=75,<76
- ninja
- noqt5
- python>=3.11,<3.12
@@ -102,6 +103,7 @@ requirements:
- fmt
- freetype
- hdf5
- icu>=75,<76
- lark
- libboost-devel
- matplotlib-base

View File

@@ -25,6 +25,7 @@ freetype = "*"
git = "*"
graphviz = "*"
hdf5 = "*"
icu = ">=75,<76"
ifcopenshell = "*"
lark = "*"
libboost-devel = "*"

View File

@@ -33,7 +33,13 @@ install(
# Install Silo addon
install(
DIRECTORY
${CMAKE_SOURCE_DIR}/mods/silo/pkg/freecad/
${CMAKE_SOURCE_DIR}/mods/silo/freecad/
DESTINATION
mods/silo/pkg/freecad
mods/silo/freecad
)
install(
DIRECTORY
${CMAKE_SOURCE_DIR}/mods/silo/silo-client/
DESTINATION
mods/silo/silo-client
)

View File

@@ -16,7 +16,7 @@ def setup_kindred_addons():
# Define built-in addons with their paths relative to mods/
addons = [
("ztools", "ztools/ztools"), # mods/ztools/ztools/
("silo", "silo/pkg/freecad"), # mods/silo/pkg/freecad/
("silo", "silo/freecad"), # mods/silo/freecad/
]
for name, subpath in addons:

View File

@@ -15,7 +15,7 @@ def setup_kindred_workbenches():
addons = [
("ztools", "ztools/ztools"),
("silo", "silo/pkg/freecad"),
("silo", "silo/freecad"),
]
for name, subpath in addons: