diff --git a/README.md b/README.md index 573a8cd5b0..ee2fc2d5f4 100644 --- a/README.md +++ b/README.md @@ -1,113 +1,250 @@ - +# Kindred Create -### Your own 3D Parametric Modeler +**An engineering-focused parametric 3D CAD platform built on FreeCAD 1.0+** -[Website](https://www.freecad.org) • -[Documentation](https://wiki.freecad.org) • -[Forum](https://forum.freecad.org/) • -[Bug tracker](https://github.com/FreeCAD/FreeCAD/issues) • -[Git repository](https://github.com/FreeCAD/FreeCAD) • -[Blog](https://blog.freecad.org) +[Website](https://www.kindred-systems.com/create) • +[FreeCAD Documentation](https://wiki.freecad.org) • +[FreeCAD Forum](https://forum.freecad.org/) - -[![Release](https://img.shields.io/github/release/freecad/freecad.svg)](https://github.com/freecad/freecad/releases/latest) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/freecad/localized.svg)](https://crowdin.com/project/freecad) - - - -Overview --------- - -* **Freedom to build what you want** FreeCAD is an open-source parametric 3D -modeler made primarily to design real-life objects of any size. -Parametric modeling allows you to easily modify your design by going back into -your model history to change its parameters. - -* **Create 3D from 2D and back** FreeCAD lets you sketch geometry-constrained - 2D shapes and use them as a base to build other objects. - It contains many components to adjust dimensions or extract design details from - 3D models to create high quality production-ready drawings. - -* **Designed for your needs** FreeCAD is designed to fit a wide range of uses -including product design, mechanical engineering and architecture, -whether you are a hobbyist, programmer, experienced CAD user, student or teacher. - -* **Cross platform** FreeCAD runs on Windows, macOS and Linux operating systems. - -* **Underlying technology** - * **OpenCASCADE** A powerful geometry kernel, the most important component of FreeCAD - * **Coin3D library** Open Inventor-compliant 3D scene representation model - * **Python** FreeCAD offers a broad Python API - * **Qt** Graphical user interface built with Qt - - -Installing ----------- - -Precompiled packages for stable releases are available for Windows, macOS and Linux on the -[latest releases page](https://github.com/FreeCAD/FreeCAD/releases/latest). - -On most Linux distributions, FreeCAD is also directly installable from the -software center application. - -For weekly development releases visit the [releases page](https://github.com/FreeCAD/FreeCAD/releases/). - -Other options are described on the [wiki Download page](https://wiki.freecad.org/Download). - -Compiling ---------- - -See the [Developers Handbook – Getting Started](https://freecad.github.io/DevelopersHandbook/gettingstarted/) -for build instructions. - - -Reporting Issues ---------- - -To report an issue please: - -- Consider posting to the [Forum](https://forum.freecad.org), [Discord](https://discord.com/invite/w2cTKGzccC) channel, or [Reddit](https://www.reddit.com/r/FreeCAD) to verify the issue; -- Search the existing [issues](https://github.com/FreeCAD/FreeCAD/issues) for potential duplicates; -- Use the most updated stable or [development versions](https://github.com/FreeCAD/FreeCAD/releases/) of FreeCAD; -- Post version info from `Help > About FreeCAD > Copy to clipboard`; -- Restart FreeCAD in safe mode `Help > Restart in safe mode` and try to reproduce the issue again. If the issue is resolved it can be fixed by deleting the FreeCAD config files. -- Start recording a macro `Macro > Macro recording...` and repeat all steps. Stop recording after the issue occurs and upload the saved macro or copy the macro code in the issue; -- Post a Step-By-Step explanation on how to recreate the issue; -- Upload an example file (FCStd as ZIP file) to demonstrate the problem; - -For more details see: - -- [Bug Tracker](https://github.com/FreeCAD/FreeCAD/issues) -- [Reporting Issues and Requesting Features](https://github.com/FreeCAD/FreeCAD/issues/new/choose) -- [Contributing](https://github.com/FreeCAD/FreeCAD/blob/main/CONTRIBUTING.md) -- [Help Forum](https://forum.freecad.org/viewforum.php?f=3) - -> [!NOTE] -The [FPA](https://fpa.freecad.org) offers developers the opportunity -to apply for a grant to work on projects of their choosing. Check -[jobs and funding](https://blog.freecad.org/jobs/) to know more. - - -Usage & Getting Help --------------------- - -The FreeCAD wiki contains documentation on -general FreeCAD usage, Python scripting, and development. -View these pages for more information: - -- [Getting started](https://wiki.freecad.org/Getting_started) -- [Features list](https://wiki.freecad.org/Feature_list) -- [Frequent questions](https://wiki.freecad.org/FAQ/en) -- [Workbenches](https://wiki.freecad.org/Workbenches) -- [Scripting](https://wiki.freecad.org/Power_users_hub) -- [Developers Handbook](https://freecad.github.io/DevelopersHandbook/) - -The [FreeCAD forum](https://forum.freecad.org) is a great place -to find help and solve specific problems when learning to use FreeCAD. +> **MVP Release** - Kindred Create is currently in active development. Features and interfaces may change. --- -

This project receives generous infrastructure support from - - - and KiCad Services Corp. -

+## Overview + +Kindred Create is a fork of FreeCAD 1.0+ that integrates custom workbenches and tooling for professional engineering workflows. It combines the power of FreeCAD's parametric modeling with purpose-built extensions for part design, assembly management, and parts database integration. + +**Key additions over base FreeCAD:** + +- **ztools Workbench** - Unified interface consolidating part design, assembly, and drawing tools with custom engineering features +- **Silo Integration** - Parts database system for tracking, versioning, and managing CAD files across teams +- **Catppuccin Mocha Theme** - Dark theme optimized for extended work sessions + +Kindred Create is maintained by [Kindred Systems LLC](https://www.kindred-systems.com). + +--- + +## Features + +### ztools Workbench + +The ztools workbench provides a unified interface that consolidates functionality from multiple FreeCAD workbenches while adding custom engineering-oriented tools. + +#### Consolidated Toolbars (17 total) + +ztools exposes commands from PartDesign, Sketcher, Assembly, and Spreadsheet workbenches through a single unified interface: + +- **Structure & Sketcher Tools** - Body/Sketch creation, editing, mapping, validation +- **PartDesign Datums** - Planes, lines, points, coordinate systems, binders, clones +- **Additive Features** - Pad, revolution, loft, pipe, helix, and primitives +- **Subtractive Features** - Pocket, hole, groove, loft, pipe, helix, and primitives +- **Transformations** - Mirror, linear pattern, polar pattern, multi-transform +- **Dress-Up Features** - Fillet, chamfer, draft, thickness +- **Boolean Operations** - Union, intersection, difference +- **Assembly Tools** - Create assembly, insert link, insert new part +- **Assembly Joints** - 13 joint types (fixed, revolute, cylindrical, slider, ball, distance, parallel, perpendicular, angle, rack-pinion, screw, gears, belt) +- **Assembly Management** - Toggle grounded, solve, create view, create BOM, export +- **Spreadsheet Tools** - Create, import, export, aliases, merge/split cells + +#### Custom Datum Tools + +ztools includes a custom datum creation system with 16 creation modes, using a purpose-built attachment system that stores geometry references for reliable parametric updates. + +**Datum Planes (7 modes):** +- Offset from Face - Distance offset perpendicular to a face +- Offset from Plane - Distance offset from an existing datum plane +- Midplane - Plane equidistant between two parallel faces +- 3 Points - Plane defined by three vertices +- Normal to Edge - Plane perpendicular to an edge at a specified parameter +- Angled - Plane rotated about an edge by a specified angle +- Tangent to Cylinder - Plane tangent to a cylindrical surface + +**Datum Axes (4 modes):** +- 2 Points - Axis through two vertices +- From Edge - Axis aligned with a linear edge +- Cylinder Center - Axis at the center of a cylindrical face +- Plane Intersection - Axis at the intersection of two planes + +**Datum Points (5 modes):** +- At Vertex - Point at a selected vertex +- XYZ Coordinates - Point at absolute coordinates +- On Edge - Point at a parameter along an edge +- Face Center - Point at the centroid of a face +- Circle Center - Point at the center of a circular edge + +#### Custom Pattern Tools + +- **Rotated Linear Pattern** - Linear pattern with incremental rotation per instance +- **Assembly Linear Pattern** - Pattern assembly components linearly with spacing control +- **Assembly Polar Pattern** - Pattern assembly components around a rotation axis + +#### Enhanced Pocket + +SOLIDWORKS-style "Flip Side to Cut" feature that removes material outside the sketch profile instead of inside, using boolean operations internally. + +#### Spreadsheet Formatting Tools + +Dark-theme compatible formatting commands for spreadsheets: +- Bold, italic, underline toggles +- Left, center, right alignment +- Background and text color pickers +- Quick alias creation from cell labels + +### Silo Parts Database + +Silo is a parts database system designed for managing CAD files, part numbers, and revision history across engineering teams. + +**Architecture:** +- **Server Daemon** - Go-based REST API server +- **PostgreSQL** - Relational data storage for part metadata, relationships, and revision history +- **MinIO** - S3-compatible object storage for CAD file versioning +- **FreeCAD Workbench** - Integrated commands for check-in, check-out, and synchronization + +**Core Capabilities:** +- Configurable part numbering schemas defined in YAML +- Full revision history with status tracking (draft, review, released, obsolete) +- Bill of materials management with relationship types and quantities +- Project-based organization and tagging +- CSV import/export for bulk operations +- Web interface for browsing and searching parts + +**FreeCAD Integration:** +- Open, save, and commit files directly to Silo +- Pull latest revisions and push changes +- View item metadata and revision history + +Silo documentation is available in the `mods/silo/` directory. + +### Catppuccin Mocha Theme + +A comprehensive dark theme using the [Catppuccin Mocha](https://github.com/catppuccin/catppuccin) color palette, applied across: + +- Main window, toolbars, and menus +- 3D viewport backgrounds and selection colors +- Sketch editor colors for edges, vertices, and constraints +- Python console and code editor syntax highlighting +- Spreadsheet backgrounds and text +- Property editor and tree view +- All dialog and widget styling + +The theme is automatically applied when using Kindred Create. + +--- + +## Installing + +### Prebuilt Binaries + +Prebuilt packages for Linux are available on the [releases page](https://github.com/anthropics/create-0070/releases). + +#### Debian/Ubuntu (.deb) + +Download the `.deb` package from the releases page and install with: + +```bash +sudo dpkg -i kindred-create_*.deb +sudo apt-get install -f # Install any missing dependencies +``` + +Or install directly with apt: + +```bash +sudo apt install ./kindred-create_*.deb +``` + +After installation, launch Kindred Create from your application menu or run `kindred-create` from the terminal. + +### Building from Source + +Kindred Create uses the same build system as FreeCAD. Build instructions for each platform: + +- [Linux](https://wiki.freecad.org/Compile_on_Linux) +- [Windows](https://wiki.freecad.org/Compile_on_Windows) +- [macOS](https://wiki.freecad.org/Compile_on_MacOS) + +--- + +## Usage + +### Getting Started + +Kindred Create is compatible with standard FreeCAD workflows. The FreeCAD wiki provides documentation on general usage: + +- [Getting started](https://wiki.freecad.org/Getting_started) +- [Features list](https://wiki.freecad.org/Feature_list) +- [Workbenches](https://wiki.freecad.org/Workbenches) +- [Scripting](https://wiki.freecad.org/Power_users_hub) + +### ztools Workbench + +The ztools workbench is available from the workbench selector. On activation, it presents consolidated toolbars and applies the Catppuccin Mocha theme to spreadsheets. + +### Silo Setup + +Silo requires a running server instance with PostgreSQL and MinIO. See `mods/silo/README.md` for server deployment instructions. + +Configure the FreeCAD workbench with environment variables: +- `SILO_API_URL` - Silo server API endpoint (default: `http://localhost:8080/api`) +- `SILO_PROJECTS_DIR` - Local projects directory (default: `~/projects`) + +--- + +## Project Structure + +``` +kindred-create/ +├── src/ # FreeCAD core source +├── Mod/ # FreeCAD modules +├── mods/ # Kindred Create addon modules (git submodules) +│ ├── ztools/ # ztools workbench +│ │ ├── ztools/ # Workbench package +│ │ │ ├── InitGui.py # Workbench registration +│ │ │ └── ztools/ # Commands and resources +│ │ └── CatppuccinMocha/ # Theme preference pack +│ └── silo/ # Silo parts database +│ ├── cmd/ # Go entry points +│ ├── internal/ # Go packages +│ ├── pkg/freecad/ # FreeCAD workbench +│ └── deployments/ # Docker configuration +└── resources/ # Branding and preferences + ├── branding/ # Splash screens and logos + └── preferences/ # Default preference packs +``` + +The `mods/ztools` and `mods/silo` directories are git submodules. After cloning, initialize them with: + +```bash +git submodule update --init --recursive +``` + +--- + +## Reporting Issues + +When reporting issues: + +1. Specify whether the issue is with Kindred Create additions (ztools, Silo, theme) or base FreeCAD functionality +2. Include version info from `Help > About FreeCAD > Copy to clipboard` +3. Provide steps to reproduce the issue +4. Attach example files if applicable (FCStd as ZIP) + +For base FreeCAD issues, consider also checking the [FreeCAD issue tracker](https://github.com/FreeCAD/FreeCAD/issues). + +--- + +## License + +Kindred Create is licensed under the [LGPL-2.1-or-later](LICENSE) license, consistent with FreeCAD. + +--- + +## Acknowledgments + +Kindred Create is built on [FreeCAD](https://www.freecad.org), an open-source parametric 3D modeler. We acknowledge the FreeCAD community and contributors for their foundational work. + +**Underlying Technology:** +- [OpenCASCADE](https://www.opencascade.com/) - Geometry kernel +- [Coin3D](https://github.com/coin3d/coin) - 3D scene representation +- [Qt](https://www.qt.io/) - GUI framework +- [Python](https://www.python.org/) - Scripting and workbench development +- [Catppuccin](https://github.com/catppuccin/catppuccin) - Color palette diff --git a/docs/BOM_MERGE.md b/docs/BOM_MERGE.md new file mode 100644 index 0000000000..4aa7bddb52 --- /dev/null +++ b/docs/BOM_MERGE.md @@ -0,0 +1,475 @@ +# Feature Spec: Auto-Populate Silo BOM from Assembly Links + +## Summary + +On `Origin_Commit`, extract cross-document `App::Link` components from the active Assembly, resolve each to a Silo part number, diff against the existing server-side BOM, and submit a merge job. The client receives merge status via SSE and surfaces it in the Database Activity pane with a link to the web UI for conflict resolution. + +--- + +## Scope + +**In scope:** +- Cross-document `App::Link` extraction with quantity counting +- Silo UUID → part number resolution +- Multi-level BOM construction (levels enumerated per nesting depth) +- Diff/merge against existing server BOM +- SSE merge status events in Activity pane +- Web UI link for merge conflict resolution +- Workflow for components without Silo part numbers +- Consolidation warnings for duplicate individual links vs arrays + +**Out of scope:** +- In-document links (treated as construction/layout geometry, not BOM items) +- Flat BOM generation (existing server endpoint handles this from the multi-level data) +- Recursive commit of sub-assemblies (each assembly commits its own BOM) + +--- + +## Architecture + +### Trigger + +Hook into `Origin_Commit` in the Silo workbench. After the file commit succeeds, the BOM sync runs as a post-commit step. This separates "save my work" from "publish BOM to server." + +### Data Flow + +``` +Origin_Commit + │ + ├─ 1. Commit file to Silo (existing flow) + │ + └─ 2. BOM sync (new) + │ + ├─ a. Walk Assembly tree, collect cross-doc App::Links + ├─ b. Count quantities (individual links + ElementCount arrays) + ├─ c. Resolve Silo UUIDs → part numbers via API + ├─ d. Build multi-level BOM structure + ├─ e. GET existing BOM from server + ├─ f. Diff local vs server BOM + └─ g. POST merge job to server + │ + └─ Server emits SSE event with merge status + │ + └─ Activity pane displays result + web UI link +``` + +--- + +## 1. Assembly Link Extraction + +### Walk Strategy + +```python +def extract_bom_links(assembly_obj, level=1): + """ + Recursively walk an Assembly container, collecting cross-document + App::Link objects. In-document links are skipped. + + Returns list of BomEntry(part_number, quantity, level, children=[]) + """ + entries = {} # linked_doc_path -> BomEntry + + for obj in assembly_obj.Group: + if not obj.isDerivedFrom("App::Link"): + continue + + linked = obj.LinkedObject + if linked is None: + continue + + # Skip in-document links (construction/layout geometry) + linked_doc = linked.Document + if linked_doc == assembly_obj.Document: + continue + + doc_path = linked_doc.FileName + + if doc_path in entries: + # Multiple individual links to same source - count and warn + entries[doc_path].quantity += _link_count(obj) + entries[doc_path].consolidation_warning = True + else: + entries[doc_path] = BomEntry( + doc_path=doc_path, + silo_uuid=_get_silo_uuid(linked_doc), + quantity=_link_count(obj), + level=level, + consolidation_warning=False, + children=[], + ) + + # Recurse into sub-assemblies + if _is_assembly(linked): + entries[doc_path].children = extract_bom_links(linked, level + 1) + + return list(entries.values()) +``` + +### Quantity Counting + +```python +def _link_count(link_obj): + """ + Count instances from a single App::Link. + ElementCount > 0 means it's a link array. + """ + element_count = getattr(link_obj, "ElementCount", 0) + return element_count if element_count > 0 else 1 +``` + +Both patterns are counted: +- **Multiple `App::Link` instances** to the same external file → summed +- **Single `App::Link` with `ElementCount > 0`** → use ElementCount value + +When both patterns exist for the same source, emit a **consolidation warning** suggesting the user convert individual links to a single link array. + +### In-Document Link Filtering + +A link is in-document if `linked.Document == assembly.Document`. These are construction references (layout sketches, datum planes used for mate positioning, etc.) and are excluded from BOM extraction. + +--- + +## 2. Silo Part Number Resolution + +### UUID Lookup + +Each document committed via Silo origin has a Silo UUID stored as a custom property. Resolve to part number: + +```python +def _get_silo_uuid(doc): + """Read the Silo UUID property from a FreeCAD document.""" + try: + return doc.getPropertyByName("SiloUUID") + except AttributeError: + return None + +def resolve_part_numbers(entries, api_client): + """ + Resolve Silo UUIDs to part numbers. + Returns (resolved_entries, unresolved_entries). + """ + resolved = [] + unresolved = [] + + for entry in entries: + if entry.silo_uuid is None: + unresolved.append(entry) + continue + + item = api_client.get_item_by_uuid(entry.silo_uuid) + if item is None: + unresolved.append(entry) + continue + + entry.part_number = item["part_number"] + entry.name = item["name"] + resolved.append(entry) + + # Recurse children + if entry.children: + child_resolved, child_unresolved = resolve_part_numbers( + entry.children, api_client + ) + entry.children = child_resolved + unresolved.extend(child_unresolved) + + return resolved, unresolved +``` + +### Components Without Part Numbers + +Unresolved components trigger the **part registration workflow**: + +1. After BOM sync, display unresolved components in a dialog +2. For each, offer to create a new Silo item: + - Auto-detect whether it's an Assembly or Part from the document type + - Pre-fill name from the document label + - Apply naming convention for the schema (e.g., `kindred-rd` schema with appropriate category) + - Open the part number registration form pre-populated +3. User confirms or skips each +4. Skipped items are excluded from the BOM (not silently dropped — they remain visible as "unregistered" in the Activity pane) +5. On next commit, re-check and prompt again + +--- + +## 3. Multi-Level BOM Construction + +The BOM preserves assembly hierarchy with enumerated levels: + +```python +@dataclass +class BomEntry: + doc_path: str + silo_uuid: Optional[str] + part_number: Optional[str] + name: Optional[str] + quantity: int + level: int + children: List["BomEntry"] + consolidation_warning: bool = False +``` + +**Example structure:** + +``` +Level 1: ASM-001 Top Assembly + Level 2: PRT-100 Base Plate qty: 1 + Level 2: ASM-200 Gearbox Sub-Assy qty: 2 + Level 3: PRT-201 Housing qty: 1 + Level 3: PRT-202 Gear qty: 4 + Level 3: PRT-203 Shaft qty: 1 + Level 2: PRT-300 Cover qty: 1 + Level 2: F01-001 M8x20 Bolt qty: 12 +``` + +Each assembly commits **only its direct children** (first-level BOM). The server's existing `GET /api/items/{partNumber}/bom/expanded` endpoint handles multi-level expansion, and `GET /api/items/{partNumber}/bom/flat` handles flattened roll-up. + +--- + +## 4. Diff/Merge Logic + +### Diff Computation + +Compare the assembly-derived BOM (local) against the existing server BOM (remote): + +```python +def diff_bom(local_entries, remote_entries): + """ + Diff local assembly BOM against server BOM. + + Returns BomDiff with categorized changes. + """ + local_map = {e.part_number: e.quantity for e in local_entries} + remote_map = {e["child_part_number"]: e["quantity"] for e in remote_entries} + + diff = BomDiff( + added=[], # In local, not in remote + removed=[], # In remote, not in local + quantity_changed=[], # In both, different quantity + unchanged=[], # In both, same quantity + ) + + for pn, qty in local_map.items(): + if pn not in remote_map: + diff.added.append({"part_number": pn, "quantity": qty}) + elif remote_map[pn] != qty: + diff.quantity_changed.append({ + "part_number": pn, + "local_quantity": qty, + "remote_quantity": remote_map[pn], + }) + else: + diff.unchanged.append({"part_number": pn, "quantity": qty}) + + for pn, qty in remote_map.items(): + if pn not in local_map: + diff.removed.append({ + "part_number": pn, + "quantity": qty, + }) + + return diff +``` + +### Merge Rules + +| Scenario | Action | +|----------|--------| +| **Added** (in assembly, not on server) | Auto-add to server BOM | +| **Quantity changed** | Auto-update to assembly quantity | +| **Removed** (on server, not in assembly) | **Do NOT delete.** Warn user that unreferenced part numbers exist in last server BOM version. | +| **Unchanged** | No action | + +**Critical rule:** The assembly is authoritative for what exists in the CAD model, but items on the server that aren't in the assembly are **never auto-deleted**. This handles: +- Purchased parts tracked in Silo but not modeled in CAD +- Parts added via web UI for BOM completeness +- Items from other engineering disciplines (electrical, software BOMs) + +Removed items trigger a warning on next BOM sync: *"N items in the Silo BOM are not referenced by components in this assembly."* This surfaces in the Activity pane with a link to the web UI where the user can review and explicitly remove them if intended. + +--- + +## 5. Server-Side Merge Job + +### New Endpoint + +``` +POST /api/items/{partNumber}/bom/merge +``` + +**Request body:** + +```json +{ + "source": "assembly", + "entries": [ + {"child_part_number": "PRT-100", "quantity": 1, "source": "assembly"}, + {"child_part_number": "ASM-200", "quantity": 2, "source": "assembly"}, + {"child_part_number": "PRT-300", "quantity": 1, "source": "assembly"}, + {"child_part_number": "F01-001", "quantity": 12, "source": "assembly"} + ] +} +``` + +**Response body:** + +```json +{ + "status": "merged", + "diff": { + "added": [ + {"part_number": "PRT-300", "quantity": 1} + ], + "removed": [ + {"part_number": "PRT-400", "quantity": 2} + ], + "quantity_changed": [ + { + "part_number": "F01-001", + "old_quantity": 8, + "new_quantity": 12 + } + ], + "unchanged": [ + {"part_number": "PRT-100", "quantity": 1}, + {"part_number": "ASM-200", "quantity": 2} + ] + }, + "warnings": [ + { + "type": "unreferenced", + "part_number": "PRT-400", + "message": "Present in server BOM but not in assembly" + } + ], + "resolve_url": "/items/ASM-001/bom" +} +``` + +The server: +1. Applies adds and quantity changes immediately +2. Flags removed items as unreferenced (does not delete) +3. Emits an SSE event on the activity stream +4. Returns the diff and a `resolve_url` for the web UI + +### SSE Event + +```json +{ + "type": "bom_merge", + "item": "ASM-001", + "user": "joseph", + "timestamp": "2026-02-08T22:15:00Z", + "summary": "BOM updated: 1 added, 1 quantity changed, 1 unreferenced", + "diff": { ... }, + "resolve_url": "/items/ASM-001/bom" +} +``` + +--- + +## 6. Client-Side UX + +### Activity Pane Display + +The Database Activity pane (already connected via SSE) renders BOM merge events: + +``` +┌─────────────────────────────────────────────┐ +│ 📋 BOM Updated: ASM-001 │ +│ +1 added ~1 qty changed ⚠1 unreferenced │ +│ [View in Silo →] │ +├─────────────────────────────────────────────┤ +│ ⚠ 2 components have no Silo part number │ +│ [Register Parts...] │ +└─────────────────────────────────────────────┘ +``` + +### Consolidation Warnings + +When multiple individual `App::Link` objects reference the same external document (instead of a single link array), show a non-blocking console warning: + +``` +[Silo BOM] PRT-100 has 4 individual links. Consider using a link array +(ElementCount) for cleaner assembly management. +``` + +### Part Registration Workflow + +For unresolved components, the dialog presents: + +``` +┌─ Register Components ──────────────────────┐ +│ │ +│ The following components have no Silo │ +│ part number and will be excluded from │ +│ the BOM until registered: │ +│ │ +│ ☑ Bracket.FCStd [Part ▾] [Register] │ +│ ☑ MotorMount.FCStd [Assembly ▾] [Reg.] │ +│ ☐ construction_ref.FCStd (skip) │ +│ │ +│ [Register Selected] [Skip All] │ +└─────────────────────────────────────────────┘ +``` + +Registration uses the existing `POST /api/items` and `POST /api/generate-part-number` endpoints. Schema and category are pre-selected based on document type (Assembly → assembly category, Part → appropriate category). Name is pre-filled from the document label following the project naming convention. + +--- + +## 7. Implementation Plan + +### Phase 1: Link Extraction + Resolution + +**silo-mod workbench** (`mods/silo/`): +- `bom_sync.py` — Assembly walker, quantity counter, UUID resolver +- Hook into `Origin_Commit` post-commit + +**Silo server** (`internal/api/`): +- `GET /api/items/by-uuid/{uuid}` — New endpoint for UUID → item lookup (or extend existing `GET /api/items/{partNumber}` to accept UUID query param) + +### Phase 2: Diff/Merge + Server Endpoint + +**Silo server:** +- `POST /api/items/{partNumber}/bom/merge` — New merge endpoint +- SSE event emission for `bom_merge` type +- `internal/db/bom.go` — Merge logic with unreferenced flagging + +**silo-mod workbench:** +- Diff computation (can be client-side or server-side; server preferred for consistency) +- Activity pane rendering for merge events + +### Phase 3: Part Registration Workflow + +**silo-mod workbench:** +- Registration dialog for unresolved components +- Part/Assembly type detection +- Schema + category pre-selection +- Name convention pre-fill + +### Phase 4: Web UI Merge Resolution + +**Silo web UI** (`web/src/`): +- BOM page shows unreferenced items with warning banner +- Action to remove unreferenced items or mark as intentional (non-CAD BOM entries) +- Distinguish between "assembly-sourced" and "manually-added" BOM entries + +--- + +## API Surface (New/Modified) + +| Method | Endpoint | Description | +|--------|----------|-------------| +| `GET` | `/api/items/by-uuid/{uuid}` | Resolve Silo UUID to item (new) | +| `POST` | `/api/items/{partNumber}/bom/merge` | Submit assembly BOM merge (new) | +| SSE | Activity stream | `bom_merge` event type (new) | + +All existing BOM endpoints (`GET .../bom`, `GET .../bom/expanded`, `GET .../bom/flat`, etc.) remain unchanged. + +--- + +## Design Decisions + +1. **Merge jobs are synchronous.** The server processes the merge inline and returns the diff in the response. Revisit if assembly sizes cause timeout issues in practice. +2. **BOM entries carry a `source` field.** Each entry includes `"source": "assembly"` or `"source": "manual"` so the web UI can distinguish assembly-derived lines from manually-added ones. Manual entries are never overwritten by assembly merges. +3. **Sub-assembly commits walk bottom-up automatically.** When a top-level assembly and its sub-assemblies are all dirty, commit traverses depth-first, committing leaf assemblies before parents. This ensures each assembly's BOM merge references already-committed children. diff --git a/docs/KC_SPECIFICATION.md b/docs/KC_SPECIFICATION.md new file mode 100644 index 0000000000..a38235ca60 --- /dev/null +++ b/docs/KC_SPECIFICATION.md @@ -0,0 +1,494 @@ +# .kc File Format Specification + +**Version:** 1.0-draft +**Date:** February 2026 +**Status:** Specification — Not Started + +The `.kc` format is Kindred Create's native file format. It is a strict superset of FreeCAD's `.fcstd` format — every `.kc` file is a valid `.fcstd` file with an additional `silo/` directory containing platform metadata. This design preserves full interoperability with vanilla FreeCAD while enabling Silo integration, version control, compute job attachment, and engineering workflow features. + +--- + +## 1. Design Principles + +**Superset, not fork.** A `.kc` file can be renamed to `.fcstd` and opened in unmodified FreeCAD. FreeCAD ignores unknown entries in the ZIP archive, so the `silo/` directory is invisible to the base document loader. This means upstream FreeCAD merges never break the format. + +**Silo metadata is a snapshot.** The `silo/` directory carries a point-in-time copy of server-side state. The Silo server is authoritative. When a `.kc` file is opened while connected to Silo, the client checks for newer revisions. Offline edits are reconciled on reconnect by comparing revision hashes in `silo/manifest.json`. + +**Incremental adoption.** Not every `silo/` file needs to be populated. The format grows as Silo modules ship. A minimal `.kc` file only requires `silo/manifest.json`. All other entries are optional and introduced by their respective modules. + +**Round-trip safety.** FreeCAD's save routine writes only the entries it knows about (`Document.xml`, `GuiDocument.xml`, `.brp` files, `thumbnails/`). It does not delete unknown entries from the ZIP. The `silo/` directory survives FreeCAD save cycles without corruption. + +--- + +## 2. Archive Structure + +A `.kc` file is a ZIP archive. Its contents are organized into two zones: the standard FreeCAD zone (inherited as-is) and the Kindred zone (`silo/`). + +``` +part.kc (ZIP archive) +│ +│ ── FreeCAD Standard Zone ────────────────────────── +│ +├── Document.xml # Feature tree, parameters, object definitions +├── GuiDocument.xml # Visual state (colors, visibility, camera) +├── *.brp # BREP geometry cache (one per shape) +├── thumbnails/ +│ └── Thumbnail.png # FreeCAD-generated preview +│ +│ ── Kindred Zone ─────────────────────────────────── +│ +└── silo/ + ├── manifest.json # Identity, origin, revision, schema version + ├── metadata.json # Custom schema fields, tags, lifecycle state + ├── history.json # Local revision log (lightweight) + ├── approvals.json # ECO / approval state snapshot + ├── dependencies.json # Assembly link references by Silo UUID + ├── macros/ # Embedded macro references or inline scripts + ├── inspection/ # GD&T annotations, tolerance data, CMM linkage + ├── jobs/ # Compute job YAML definitions + │ └── default.yaml + └── thumbnails/ # Silo-generated renderings (separate from FreeCAD's) +``` + +--- + +## 3. FreeCAD Standard Zone + +These entries are identical to a standard `.fcstd` file. Kindred Create does not modify their structure or semantics. + +| Entry | Description | +|-------|-------------| +| `Document.xml` | Serialized feature tree. Contains all object definitions, parametric properties, sketch geometry, constraints, and inter-object references. This is the canonical representation of the model. | +| `GuiDocument.xml` | View provider state: object colors, visibility flags, camera position, display modes. Not required for geometry reconstruction. | +| `*.brp` | OpenCASCADE BREP files. One per shape object. These are a derived cache — they can be regenerated from `Document.xml` by recomputing the feature tree. | +| `thumbnails/Thumbnail.png` | FreeCAD's built-in thumbnail, generated on save. 128×128 PNG by default. | + +The BREP files are binary and not diffable. `Document.xml` is XML and structurally diffable (see Silo's Intelligent FCStd Diffing module). `GuiDocument.xml` is XML but rarely relevant to version control. + +--- + +## 4. Kindred Zone (`silo/`) + +All Kindred-specific data lives under `silo/`. Each entry is described below with its schema, lifecycle, and owning module. + +### 4.1 `silo/manifest.json` — Required + +The only mandatory `silo/` entry. Identifies this file within the Silo ecosystem. + +```json +{ + "kc_version": "1.0", + "silo_instance": "https://silo.example.com", + "part_uuid": "550e8400-e29b-41d4-a716-446655440000", + "revision_hash": "a1b2c3d4e5f6", + "created_at": "2026-02-13T19:00:00Z", + "modified_at": "2026-02-13T20:30:00Z", + "created_by": "joseph" +} +``` + +| Field | Type | Description | +|-------|------|-------------| +| `kc_version` | string | `.kc` schema version. Used for forward-compatible migrations. | +| `silo_instance` | string | URL of the originating Silo server. Null for offline-created files. | +| `part_uuid` | UUID | Globally unique identifier assigned by Silo. Survives renames and moves. | +| `revision_hash` | string | Hash of the last committed revision. Used for offline reconciliation. | +| `created_at` | ISO 8601 | Timestamp of initial `.kc` creation. | +| `modified_at` | ISO 8601 | Timestamp of last save. | +| `created_by` | string | Username of the creating user. | + +### 4.2 `silo/metadata.json` — Optional + +Custom schema field values, lifecycle state, and tags. Driven by Silo's user-customizable schema engine. + +```json +{ + "schema": "mechanical-part-v2", + "lifecycle": "released", + "tags": ["structural", "aluminum"], + "fields": { + "category": "bracket", + "material": "6061-T6", + "finish": "anodized", + "weight_kg": 0.34, + "project": "PRJ-042" + } +} +``` + +The `schema` field references a schema definition stored on the Silo server. Field names, types, and validation rules are defined by that schema. The client renders form fields dynamically based on the schema descriptor fetched from `GET /api/schemas/{schema_name}/form`. + +### 4.3 `silo/history.json` — Optional + +Lightweight local revision log. The full history lives server-side; this is a portable subset for offline reference. + +```json +{ + "revisions": [ + { + "revision": 3, + "hash": "a1b2c3d4e5f6", + "author": "joseph", + "timestamp": "2026-02-13T20:30:00Z", + "comment": "Added fillet to mounting holes", + "status": "released" + }, + { + "revision": 2, + "hash": "f6e5d4c3b2a1", + "author": "joseph", + "timestamp": "2026-02-12T14:00:00Z", + "comment": "Initial geometry", + "status": "draft" + } + ] +} +``` + +Revisions are listed newest-first. This file is append-only during local editing and reconciled with the server on commit. + +### 4.4 `silo/approvals.json` — Optional + +Snapshot of engineering change order (ECO) and approval workflow state. Server-authoritative — this is a read cache for offline display. + +```json +{ + "eco": "ECO-2026-047", + "state": "pending_review", + "approvers": [ + { + "user": "jane.smith", + "role": "design_lead", + "status": "approved", + "timestamp": "2026-02-13T16:00:00Z" + }, + { + "user": "bob.jones", + "role": "quality", + "status": "pending", + "timestamp": null + } + ] +} +``` + +### 4.5 `silo/dependencies.json` — Optional + +Assembly link references stored by Silo UUID rather than filesystem path. This decouples assembly structure from local file layout. + +```json +{ + "links": [ + { + "uuid": "660e8400-e29b-41d4-a716-446655440001", + "label": "Base Plate", + "part_number": "KC-BRK-0042", + "revision": 2, + "quantity": 1, + "relationship": "component" + }, + { + "uuid": "770e8400-e29b-41d4-a716-446655440002", + "label": "M6 Socket Head Cap Screw", + "part_number": "KC-HDW-0108", + "revision": 1, + "quantity": 4, + "relationship": "component" + } + ] +} +``` + +When opening an assembly `.kc`, the Silo workbench resolves UUIDs to local file paths. Missing dependencies trigger a download prompt if the Silo connection is active. + +### 4.6 `silo/macros/` — Optional + +Embedded macro references or inline Python scripts bound to this part. Files in this directory are registered with Create's macro system on document open. + +``` +silo/macros/ +├── on_save.py # Hook: runs before save +├── generate_drawing.py # Utility: creates a drawing from this part +└── manifest.json # Macro metadata and execution triggers +``` + +Macro manifest: + +```json +{ + "macros": [ + { + "file": "on_save.py", + "trigger": "pre_save", + "description": "Validates wall thickness before save" + }, + { + "file": "generate_drawing.py", + "trigger": "manual", + "description": "Generate 3-view drawing with BOM table" + } + ] +} +``` + +### 4.7 `silo/inspection/` — Optional + +GD&T annotations, tolerance data, and CMM device linkage metadata. Structure TBD pending Tier 5 Quality module specification. + +Provisional layout: + +``` +silo/inspection/ +├── gdt_annotations.json # GD&T callouts linked to face/edge references +├── tolerance_stack.json # Statistical tolerance analysis results +└── cmm_program.json # CMM program reference and measurement linkage +``` + +### 4.8 `silo/jobs/` — Optional + +Compute job YAML definitions attached to this part. These feed into Silo's job queue infrastructure (Tier 3). A part can carry multiple job definitions for different compute workloads. + +```yaml +# silo/jobs/default.yaml +kind: silo/job +version: 1 +metadata: + part: bracket-assembly-v3 + trigger: on-commit +spec: + tasks: + - name: constraint-check + runner: + labels: [cpu, ondsel-solver] + image: kindred/solver-runner:latest + timeout: 300s + - name: appearance-render + runner: + labels: [gpu, render] + image: kindred/render-runner:latest + depends_on: [constraint-check] + resources: + vram: 8Gi +``` + +Job YAMLs use the runner label system described in the Silo Job Queue specification. The `trigger` field determines when the job executes: `on-commit` (every Silo commit), `on-release` (lifecycle transition to released), or `manual` (user-initiated). + +### 4.9 `silo/thumbnails/` — Optional + +Silo-generated renderings, separate from FreeCAD's built-in `thumbnails/Thumbnail.png`. These are produced by the Headless Create module (Tier 1) and may include multiple views or higher-resolution images. + +``` +silo/thumbnails/ +├── isometric.png # Default isometric view +├── front.png # Front orthographic +├── top.png # Top orthographic +└── exploded.png # Exploded assembly view (assemblies only) +``` + +Thumbnail generation policy (single canonical vs. multi-view) is configurable at the Silo instance level. + +--- + +## 5. Interoperability + +### 5.1 FCStd → .kc (Import / Promotion) + +When a user opens an `.fcstd` file in Kindred Create, it loads normally through FreeCAD's standard document loader. The file can be "promoted" to `.kc` through either of two paths: + +**Manual promotion:** User selects File → Save As → `.kc`. Create generates `silo/manifest.json` with a new UUID and prompts for schema field selection if connected to Silo. + +**Silo-triggered promotion:** User commits an `.fcstd` to Silo via the Silo workbench. Silo assigns a UUID, generates the `silo/` directory with defaults, and returns a `.kc` to the client. Subsequent saves default to `.kc`. + +In both cases, no data in the FreeCAD standard zone is modified. The promotion is purely additive. + +### 5.2 .kc → FCStd (Export / Demotion) + +File → Export As → `.fcstd` strips the entire `silo/` directory. The resulting file is a valid `.fcstd` with no Kindred-specific content. This is the recommended path for sharing files with vanilla FreeCAD users. + +### 5.3 Vanilla FreeCAD Behavior + +If a `.kc` file is renamed to `.fcstd` and opened in vanilla FreeCAD: +- The document loads normally. `Document.xml`, `GuiDocument.xml`, and BREP files are read as expected. +- The `silo/` directory is ignored (unknown ZIP entries are silently skipped). +- On save, FreeCAD writes its standard entries. The `silo/` directory survives the save because FreeCAD does not delete unknown ZIP entries. +- **Caveat:** If FreeCAD rewrites the ZIP from scratch (rather than updating in-place), the `silo/` directory may be lost. Testing confirms that FreeCAD 1.0+ preserves unknown entries, but this behavior should be monitored across upstream releases. + +--- + +## 6. Client Implementation Layers + +Implementation in the Create client is organized into four layers, each independently deliverable. + +### Layer 1: Format Registration (C++) + +Register `.kc` as a recognized file type in FreeCAD's application framework. + +**Scope:** +- `src/App/Application.cpp` — register `.kc` extension alongside `.fcstd` in the file type map. Both extensions route to the same `openDocument()` path since the ZIP internals are structurally identical. +- `src/Gui/FileDialog.cpp` — add `.kc` to open/save/export dialogs. New documents default to `.kc`. "Save As" offers both `.kc` and `.fcstd`. +- `src/App/Document.cpp` — on save-as-`.fcstd`, strip the `silo/` directory from the ZIP. On save-as-`.kc`, ensure the `silo/` directory exists (create `manifest.json` with defaults if missing). +- Platform integration — `.kc` MIME type registration, file association on Linux (`.desktop` file / XDG), macOS (`Info.plist`), and Windows (registry / NSIS installer). + +**Risk:** Low. FreeCAD already ignores unknown ZIP entries. This layer is purely file dialog and post-save ZIP manipulation. + +**Acceptance criteria:** +- `.kc` files open in Create without errors. +- "Save As .fcstd" produces a valid `.fcstd` with no `silo/` directory. +- "Save As .kc" produces a ZIP with at minimum `silo/manifest.json`. +- Double-clicking a `.kc` file on all platforms opens Create. + +### Layer 2: Silo Metadata Layer (Python) + +A `KindredDocument` class in `src/Mod/Create/` that wraps the loaded `App::Document` and manages the `silo/` directory contents. + +**Scope:** +- `src/Mod/Create/KindredDocument.py` (new) — load/save logic for all `silo/` entries. +- `src/Mod/Create/InitGui.py` — connect to `App::Document` signals (`signalSaveDocument`, `signalRestoreDocument`) to trigger metadata load/save. + +**Behavior by operation:** + +| Operation | Action | +|-----------|--------| +| Open `.kc` | Parse all `silo/` entries. Expose metadata as properties on the document. | +| Open `.fcstd` | No-op — no `silo/` directory present. `KindredDocument` is inactive. | +| Save `.kc` | Serialize current metadata into `silo/` before FreeCAD writes the ZIP. | +| Save `.fcstd` | Skip metadata serialization. Strip `silo/` if present. | +| Promote `.fcstd` → `.kc` | Generate `silo/manifest.json` with new UUID. Prompt for schema fields. | + +**Behavior by `silo/` entry:** + +| Entry | On open | On save | On promote | +|-------|---------|---------|------------| +| `manifest.json` | Read instance origin, UUID, revision, schema version | Update `modified_at` and `revision_hash` | Generate with new UUID | +| `metadata.json` | Load schema fields, tags, lifecycle | Serialize current state | Generate with defaults from selected schema | +| `history.json` | Load local revision log | Append entry if dirty | Initialize empty | +| `approvals.json` | Load ECO/approval snapshot | Pass-through (server authoritative) | Initialize empty | +| `dependencies.json` | Resolve assembly links by UUID | Update from current assembly link objects | Generate from assembly link scan | +| `macros/` | Register embedded macros | Serialize bound macros | Empty directory | +| `inspection/` | Load GD&T / tolerance data | Serialize annotations | Empty directory | +| `jobs/` | Load job definitions for display | Serialize job YAML edits | Empty directory | +| `thumbnails/` | Load Silo-rendered previews | No-op (server generates these) | Empty directory | + +**Risk:** Medium. Signal timing relative to FreeCAD's ZIP write must be tested carefully to ensure `silo/` entries are written before the archive is finalized. + +**Acceptance criteria:** +- Opening a `.kc` with populated `silo/metadata.json` surfaces schema fields in the Create UI. +- Saving a `.kc` persists metadata changes across close/reopen cycles. +- Promoting an `.fcstd` to `.kc` assigns a UUID and creates `silo/manifest.json`. + +### Layer 3: Silo Workbench Integration (Python) + +The Silo workbench (`mods/silo/`) connects `.kc` files to the live Silo server. + +**Scope:** +- **Commit to Silo** — reads `silo/manifest.json` for the part UUID, uploads the `.kc` via REST. Silo extracts and indexes the `silo/` metadata server-side. +- **Checkout from Silo** — downloads a `.kc` with fully populated `silo/` directory. `KindredDocument` hydrates metadata on open. +- **Dependency resolution** — `silo/dependencies.json` stores assembly references by UUID. On opening an assembly, the workbench resolves UUIDs to local paths or triggers downloads for missing components. +- **Offline reconciliation** — on reconnect, compare `manifest.json` revision hashes. Server wins on conflict unless the user explicitly forces a local override. Display a diff summary before reconciliation. + +**Risk:** Medium. Depends on Silo server API endpoints existing for each metadata type. Can be built incrementally — start with commit/checkout of the full `.kc` blob, then add granular metadata sync per module. + +**Acceptance criteria:** +- Commit/checkout round-trips a `.kc` without metadata loss. +- Assembly checkout resolves all `dependencies.json` UUIDs to local files. +- Offline edits reconcile cleanly when connection is restored. + +### Layer 4: Compute Job Attachment (Python) + +UI for managing `silo/jobs/` YAML definitions. Ties into Silo's Tier 3 compute modules. + +**Scope:** +- Task panel in the Silo workbench for viewing, editing, and attaching job YAMLs. +- Job trigger configuration (on-commit, on-release, manual). +- Status display for running/completed jobs (fetched from Silo server). + +**Risk:** Low (UI-only on the client side). Depends on Silo job queue infrastructure being operational. + +**Acceptance criteria:** +- Users can attach a job YAML to a `.kc` file via the UI. +- Job status is visible in the Silo workbench panel. + +--- + +## 7. Implementation Sequence + +Layers are ordered by dependency and risk: + +1. **Layer 1** (Format Registration) — Small C++ diff. Low risk. Immediately lets users open/save `.kc` files even without Silo running. No functional behavior beyond file association. + +2. **Layer 2** (Metadata Layer) — Bulk of the work. Develop incrementally: start with `manifest.json` only, add other `silo/` entries as their respective Silo modules come online. + +3. **Layer 3** (Silo Integration) — Requires Silo server API endpoints. Build commit/checkout first, add granular metadata sync as modules mature. + +4. **Layer 4** (Job Attachment) — Deferred until Silo Tier 3 (Job Queue + Compute modules) is operational. The `silo/jobs/` directory sits empty until then. + +This sequence ensures Create is backwards-compatible with `.fcstd` at every step. The `.kc` format grows incrementally as Silo modules ship, matching the tiered dependency structure in the platform roadmap. + +--- + +## 8. Version Migration + +The `kc_version` field in `silo/manifest.json` tracks the schema version. When the `.kc` spec evolves: + +- **Additive changes** (new optional `silo/` entries): No migration needed. Older files simply lack the new entries. +- **Breaking changes** (renamed fields, restructured entries): A migration function in `KindredDocument` upgrades `silo/` contents on open. The original file is preserved until the user explicitly saves. +- **Version floor:** Create refuses to open `.kc` files with a `kc_version` newer than it supports, displaying an "update Create" message. + +--- + +## 9. Security Considerations + +**Macro execution:** `silo/macros/` scripts execute with full FreeCAD Python API access. Files from untrusted sources should prompt the user before macro registration. A configurable trust policy (always trust from this Silo instance / never auto-execute / prompt each time) is exposed in Create preferences. + +**Job YAML injection:** `silo/jobs/` YAMLs specify container images and resource requests. The Silo server validates job definitions against an allowlist of approved images and resource limits before dispatching. The client does not execute jobs directly. + +**Metadata tampering:** `silo/manifest.json` contains the revision hash. On commit, Silo validates the hash against its own records. Tampered manifests are rejected with a conflict error requiring re-checkout. + +--- + +## 10. Open Questions + +1. **FreeCAD ZIP rewrite behavior** — Confirm that FreeCAD 1.0+ preserves unknown ZIP entries on save across all platforms. If not, the `silo/` directory must be re-injected post-save via a signal hook. + +2. **Thumbnail policy** — Single canonical isometric thumbnail vs. configurable multi-view renders. Impacts `silo/thumbnails/` size and Headless Create compute cost. + +3. **Offline metadata authority** — How much of `silo/metadata.json` (particularly lifecycle state) can be modified offline? Current proposal: lifecycle transitions require server confirmation; field edits are permitted offline and reconciled on commit. + +4. **Assembly dependency depth** — Should `silo/dependencies.json` be recursive (full assembly tree) or single-level (direct children only)? Single-level is simpler; recursive enables full offline assembly loading. + +5. **Macro sandboxing** — Is a restricted execution environment for `silo/macros/` feasible within FreeCAD's Python runtime, or is trust-based policy the only practical option? + +--- + +## Appendix A: MIME Type and File Association + +| Property | Value | +|----------|-------| +| Extension | `.kc` | +| MIME type | `application/x-kindred-create` | +| UTI (macOS) | `com.kindred-systems.create.document` | +| Magic bytes | `PK` (ZIP header, offset 0) + `silo/manifest.json` entry present | +| Icon | Kindred Create document icon (from `kindred-icons/` asset set) | + +--- + +## Appendix B: Glossary + +| Term | Definition | +|------|------------| +| `.fcstd` | FreeCAD Standard file format. ZIP containing `Document.xml`, `GuiDocument.xml`, BREP cache, and thumbnails. | +| `.kc` | Kindred Create file format. Superset of `.fcstd` with a `silo/` directory. | +| BREP | Boundary Representation. OpenCASCADE geometry format stored as `.brp` files. Derived cache, regenerable from `Document.xml`. | +| Promotion | Converting an `.fcstd` to `.kc` by adding a `silo/` directory with at minimum `manifest.json`. | +| Demotion | Converting a `.kc` to `.fcstd` by stripping the `silo/` directory. | +| Reconciliation | Process of merging offline `.kc` edits with server-side state on reconnect. | +| Schema | A Silo-defined template specifying which metadata fields exist for a given part category. | + +--- + +## Appendix C: References + +- [FreeCAD FCStd File Format](https://wiki.freecad.org/Fcstd_file_format) +- [Silo Platform Roadmap](ROADMAP.md) +- [Silo Gap Analysis](GAP_ANALYSIS.md) +- [Silo Specification](SPECIFICATION.md) diff --git a/docs/UPSTREAM.md b/docs/UPSTREAM.md new file mode 100644 index 0000000000..725623cf68 --- /dev/null +++ b/docs/UPSTREAM.md @@ -0,0 +1,266 @@ +# Upstream Merge Plan: FreeCAD 1.0.0 → 1.2.0-dev + +**Date:** February 2026 +**Status:** Planning + +## Overview + +Kindred Create (`origin/main`) is based on FreeCAD 1.0.0 with ~193 Kindred-specific commits layered on top. The upstream fork (`upstream/main` at `github.com/Kindred-Systems/FreeCAD`) tracks FreeCAD development and is currently at **1.2.0-dev**. The two repositories diverged early and have ~45k commits each from a very old merge base — a traditional `git merge` is not feasible. + +**Goal:** Forward-port all Kindred customizations onto the latest `upstream/main` (FreeCAD 1.2.0-dev) to pick up bug fixes and new features while preserving all Kindred functionality. + +## Strategy: Diff-Based Forward Port + +1. Create a new branch from `upstream/main` +2. Copy Kindred-only files/directories wholesale (no conflicts) +3. Cherry-pick or manually re-apply the ~36 C++ source patches +4. Build, test, and validate + +--- + +## Remotes + +| Remote | URL | Role | +|--------|-----|------| +| `origin` | `git.kindred-systems.com/kindred/create` | Kindred Create (current main) | +| `upstream` | `github.com/Kindred-Systems/FreeCAD` | FreeCAD fork tracking upstream development | +| `internal` | `gitea.kindred.internal:kindred/create-0070` | Internal mirror | + +--- + +## Phase 1: Copy Kindred-Only Files (No Conflicts) + +These files/directories exist only in Kindred Create and can be copied directly onto `upstream/main` without conflict. + +### New directories (copy wholesale) + +| Directory | Description | +|-----------|-------------| +| `kindred-icons/` | 1444 Catppuccin Mocha SVG icon overrides | +| `mods/silo/` | Silo workbench submodule (`silo-mod`) | +| `mods/ztools/` | ZTools workbench submodule | +| `src/Mod/Create/` | Kindred Create workbench (InitGui.py, kc_format.py, update_checker.py, version.py.in) | +| `package/` | rattler-build packaging recipe | +| `docs/` | Kindred documentation (architecture, specifications, guides) | +| `.gitea/` | CI workflows, issue templates, runner configs | + +### New files in existing directories + +| File | Description | +|------|-------------| +| `src/Gui/FileOrigin.cpp/.h` | Origin abstraction layer | +| `src/Gui/FileOriginPython.cpp/.h` | Python bridge for origins | +| `src/Gui/OriginManager.cpp/.h` | Origin manager singleton | +| `src/Gui/OriginManagerDialog.cpp/.h` | Origin management dialog | +| `src/Gui/OriginSelectorWidget.cpp/.h` | Toolbar origin selector | +| `src/Gui/CommandOrigin.cpp` | PLM origin commands (Commit/Pull/Push/Info/BOM) | +| `src/Gui/BreadcrumbToolBar.cpp/.h` | Breadcrumb navigation bar | +| `src/Gui/EditingContext.cpp/.h` | Editing context system | +| `src/Gui/Icons/kindred-create.svg` | App icon | +| `src/Gui/Icons/kindredcreateabout.png` | About dialog image | +| `src/Gui/Icons/kindredcreatesplash*.png` | Splash screen images | +| `src/Gui/Icons/silo-*.svg` | Silo command icons (6 files) | +| `src/Gui/PreferencePacks/KindredCreate/` | Theme preference pack | +| `src/Gui/Stylesheets/KindredCreate.qss` | QSS stylesheet | +| `src/Gui/Stylesheets/parameters/KindredCreate.yaml` | Theme parameters | +| `src/Gui/Stylesheets/images_dark-light/branch_*_dark.svg` | Tree branch line SVGs (7 files) | +| `resources/kindred-create.*` | Platform file associations (ico, icns, xml, desktop) | +| `banner-logo-light.png` | Repository banner | +| `CONTRIBUTING.md` | Contribution guidelines | + +--- + +## Phase 2: Cherry-Pick Core Changes (Conflict Risk) + +36 Kindred commits touch core FreeCAD C++ files. Of those, **38 files** also changed on `upstream/main`, creating potential conflicts. Listed in chronological order (oldest first) for cherry-pick sequence. + +### Commit sequence + +| # | Hash | Summary | Conflict Risk | Files | +|---|------|---------|---------------|-------| +| 1 | `316d4f4b524` | Initial branding (CMakeLists, splash, about, theme, icons, QRC) | **HIGH** — CMakeLists.txt, DlgAbout.cpp, SplashScreen.cpp, resource.qrc all changed upstream | 14 files | +| 2 | `8c6837cc152` | Theme padding/clipping fixes | LOW — KindredCreate.qss is new file | 1 file | +| 3 | `bb3f3ac6d6c` | Dock task panel right, remove non-Kindred themes | **MEDIUM** — MainWindow.cpp, PreferencePacks CMakeLists changed upstream | 8 files | +| 4 | `e85162947b7` | Startup theme selector fix | **MEDIUM** — StartupProcess.cpp changed upstream | 4 files | +| 5 | `eb80c07f57a` | Theme QSS refinements | LOW — Kindred-only files | 4 files | +| 6 | `8639b6fd8ab` | Resolve unknown command/style token errors | **MEDIUM** — StartupProcess.cpp | 5 files | +| 7 | `fea1280fa90` | Theme alternate-background-color | LOW | 2 files | +| 8 | `b3fedfb19fb` | Theme tree item padding | LOW | 2 files | +| 9 | `0d4545b7d67` | Tree branch line SVGs | LOW — new files | 8 files | +| 10 | `434ae797a43` | Theme selector cleanup | **MEDIUM** — StartupProcess.cpp | 4 files | +| 11 | `224feda4ad6` | Catppuccin icon override infrastructure | **MEDIUM** — BitmapFactory.cpp, CMakeLists.txt | 2 files | +| 12 | `7535a48ec4c` | Origin abstraction layer | **HIGH** — Application.cpp, ApplicationPy.cpp/.h, CMakeLists.txt | 6 files (4 new) | +| 13 | `38358e431d2` | LocalFileOrigin and Std_* delegation | **HIGH** — CommandDoc.cpp, FileOrigin.cpp/.h | 3 files | +| 14 | `79c85ed2e5d` | FileOriginPython interactive methods | LOW — Kindred-only files | 3 files | +| 15 | `deeb6376f71` | OriginSelectorWidget | **HIGH** — Action.cpp/.h, CommandStd.cpp, Workbench.cpp, CMakeLists.txt | 8 files | +| 16 | `679aaec6d49` | Origin commands (Commit/Pull/Push) | **MEDIUM** — Application.cpp, Command.h, Workbench.cpp | 5 files | +| 17 | `db85277f262` | OriginManagerDialog | LOW — new files + OriginSelectorWidget.cpp | 3 files | +| 18 | `015df38328c` | Document-origin tracking in window title | **MEDIUM** — MDIView.cpp | 3 files | +| 19 | `a6e84552da5` | Cross-origin detection in SaveAs | **MEDIUM** — CommandDoc.cpp | 1 file | +| 20 | `84b69b935b2` | Build fix: remove SelectModule.h include | LOW | 1 file | +| 21 | `2f594dac0a5` | Use Python API for viewDefaultOrientation | **MEDIUM** — CommandDoc.cpp | 1 file | +| 22 | `724440dcb75` | Build fixes for OriginSelectorWidget/Manager | LOW — Kindred files | 2 files | +| 23 | `c858706d480` | Add silo icons to QRC | LOW — resource.qrc (additive) | 6 files | +| 24 | `d95c850b7b1` | Widen origin selector widget | LOW | 1 file | +| 25 | `10b5c9d584f` | Wire OriginManagerDialog to Silo_Settings | LOW | 1 file | +| 26 | `cc5ba638d1f` | UI polish — Wayland scaling, menu icon size | **HIGH** — DlgSettingsGeneral.cpp/.h/.ui changed upstream | 6 files | +| 27 | `4bf74cf3391` | Build fix for DlgSettingsGeneral | **MEDIUM** — DlgSettingsGeneral.h, StartupProcess.cpp | 2 files | +| 28 | `6773ca0dfd8` | Eliminate QSS/CFG duplication | LOW — Kindred files | 3 files | +| 29 | `977fa3c9347` | QGroupBox indicator, hyperlink color | LOW — KindredCreate.qss | 1 file | +| 30 | `8b2ce4b73a4` | Native Qt start panel + kindred:// URL | **MEDIUM** — MainWindow.cpp | 1 file | +| 31 | `bf637af4e45` | Window flickering and icon clipping fix | **MEDIUM** — MainWindow.cpp/.h | 3 files | +| 32 | `70118201b02` | MDI pre-document tab for Silo new item | **HIGH** — ApplicationPy, BreadcrumbToolBar, EditingContext, MainWindow, Workbench | 11 files | +| 33 | `1f49e3fa6da` | Build fix: ToolBarItem incomplete type, reportException | **LOW** — likely already fixed upstream | 2 files | +| 34 | `f71decca089` | Splash screen: skip runtime draw, mantle bg | **MEDIUM** — SplashScreen.cpp | 3 files | +| 35 | `2b0c6774c07` | Dev build defaults, skip version migration | **MEDIUM** — CMakeLists.txt, DlgVersionMigrator.cpp | 2 files | +| 36 | `ab71902a4c2` | Forward visibility arg in appendToolbar() | LOW — FreeCADGuiInit.py | 1 file | + +### HIGH conflict files (need manual attention) + +These files are modified by both Kindred and upstream. They will almost certainly require manual conflict resolution: + +| File | Kindred Changes | Upstream Risk | +|------|----------------|---------------| +| `CMakeLists.txt` | Kindred version vars, build config | Upstream version bumps, new modules | +| `src/Gui/Application.cpp` | Origin system registration | Core refactoring | +| `src/Gui/ApplicationPy.cpp/.h` | `addFileOrigin()`, MDI tab API | API changes | +| `src/Gui/CommandDoc.cpp` | Origin delegation, cross-origin SaveAs, viewDefaultOrientation | Save/open refactoring | +| `src/Gui/Action.cpp/.h` | OriginSelectorWidget toolbar action | Toolbar system changes | +| `src/Gui/MainWindow.cpp/.h` | Task panel docking, start panel, flicker fix | UI restructuring | +| `src/Gui/Workbench.cpp/.h` | Origin selector, toolbar visibility, ToolBarItem include | Workbench changes | +| `src/Gui/SplashScreen.cpp` | Kindred branding, skip runtime draw | Splash updates | +| `src/Gui/StartupProcess.cpp/.h` | Theme selector, menu icon size | Startup flow changes | +| `src/Gui/CMakeLists.txt` | New source files (Origin*, BreadcrumbToolBar, EditingContext) | New upstream sources | +| `src/Gui/DlgSettingsGeneral.cpp/.h/.ui` | Menu icon size preference | Settings UI changes | + +--- + +## Phase 3: Module-Level Changes + +### Assembly fixes (check if still needed) + +| Hash | Summary | Status | +|------|---------|--------| +| `316d4f4b524` | Joint flip overconstrain fix | May be fixed upstream — verify | +| `9dc50cef727` | SIGSEGV during document restore | May be fixed upstream — verify | +| `ddefb236521` | Solver ignoring datum plane refs | May be fixed upstream — verify | +| `b7374d7b1fc` | findPlacement() datum/origin handling | May be fixed upstream — verify | + +Files touched: `src/Mod/Assembly/App/AssemblyObject.cpp`, `src/Mod/Assembly/UtilsAssembly.py`, `src/Mod/Assembly/InitGui.py` + +### FreeCADInit.py + +| Hash | Summary | +|------|---------| +| (Layer 1 `.kc`) | `addImportType` includes `*.kc` | + +### FreeCADGuiInit.py + +| Hash | Summary | +|------|---------| +| `ab71902a4c2` | Forward visibility arg in `appendToolbar()` | + +--- + +## Phase 4: Build System and Packaging + +| Item | Action | +|------|--------| +| `CMakeLists.txt` | Re-apply Kindred version variables on top of upstream 1.2.0-dev | +| `package/rattler-build/recipe.yaml` | Update for new version, verify dependency pins | +| `.gitea/workflows/` | Verify CI still works with updated source | +| Submodule pins | Re-add `mods/silo`, `mods/ztools` submodules | +| `src/3rdParty/OndselSolver` | Verify our fork is still needed or if upstream fixed the issues | + +--- + +## Phase 5: Validation + +1. **Build**: Full CMake configure + build succeeds +2. **Launch**: Application starts without errors, splash and about dialogs show Kindred branding +3. **Theme**: KindredCreate theme loads correctly, QSS applies +4. **Icons**: kindred-icons override system works (BitmapFactory loads from kindred-icons/) +5. **Origin system**: FileOrigin, OriginManager, OriginSelectorWidget functional +6. **Silo integration**: Auth panel, activity panel, save/commit/pull all work +7. **File format**: `.kc` files open/save with silo/ directory preserved +8. **Assembly**: Verify assembly fixes aren't regressed (or confirm upstream fixed them) +9. **Start panel**: Native Qt start panel loads +10. **URL scheme**: `kindred://` URL handling works + +--- + +## Execution Steps + +```bash +# 1. Ensure upstream is fetched +git fetch upstream + +# 2. Create forward-port branch from upstream/main +git checkout -b kindred-on-upstream-1.2 upstream/main + +# 3. Copy Kindred-only directories +git checkout origin/main -- kindred-icons/ mods/ src/Mod/Create/ package/ docs/ \ + .gitea/ resources/kindred* banner-logo-light.png CONTRIBUTING.md .gitmodules + +# 4. Copy new Kindred source files (no conflicts) +git checkout origin/main -- \ + src/Gui/FileOrigin.cpp src/Gui/FileOrigin.h \ + src/Gui/FileOriginPython.cpp src/Gui/FileOriginPython.h \ + src/Gui/OriginManager.cpp src/Gui/OriginManager.h \ + src/Gui/OriginManagerDialog.cpp src/Gui/OriginManagerDialog.h \ + src/Gui/OriginSelectorWidget.cpp src/Gui/OriginSelectorWidget.h \ + src/Gui/CommandOrigin.cpp \ + src/Gui/BreadcrumbToolBar.cpp src/Gui/BreadcrumbToolBar.h \ + src/Gui/EditingContext.cpp src/Gui/EditingContext.h \ + src/Gui/Icons/kindred-create.svg src/Gui/Icons/kindredcreateabout.png \ + src/Gui/Icons/kindredcreatesplash.png src/Gui/Icons/kindredcreatesplash_2x.png \ + src/Gui/Icons/silo-bom.svg src/Gui/Icons/silo-commit.svg \ + src/Gui/Icons/silo-info.svg src/Gui/Icons/silo-pull.svg \ + src/Gui/Icons/silo-push.svg \ + src/Gui/PreferencePacks/KindredCreate/ \ + src/Gui/Stylesheets/KindredCreate.qss \ + src/Gui/Stylesheets/parameters/KindredCreate.yaml \ + src/Gui/Stylesheets/images_dark-light/ + +# 5. Cherry-pick core changes (oldest to newest) +# Resolve conflicts as they arise +git cherry-pick 316d4f4b524 # Initial branding +git cherry-pick 8c6837cc152 # Theme padding +# ... (continue through all 36 commits) +git cherry-pick ab71902a4c2 # appendToolbar visibility + +# 6. Apply .kc format Layer 1 changes +# (These were written against 1.0.0, re-apply on 1.2.0-dev) + +# 7. Build and test +cmake -B build -S . && cmake --build build + +# 8. Push and create PR +git push -u origin kindred-on-upstream-1.2 +``` + +--- + +## Risk Mitigation + +- **Checkpoint after each cherry-pick**: Commit progress so partial work isn't lost +- **Build after each batch**: Group related commits (e.g., all theme commits) and build after each group +- **Skip already-fixed commits**: Some bug fixes (Assembly, build errors) may already be resolved upstream — check before cherry-picking +- **Test incrementally**: Don't wait until all 36 commits are applied to test + +## Estimated Effort + +| Phase | Effort | +|-------|--------| +| Phase 1 (copy wholesale) | ~30 min | +| Phase 2 (cherry-pick 36 commits) | ~4-8 hours (conflict resolution) | +| Phase 3 (module changes) | ~1 hour | +| Phase 4 (build system) | ~1-2 hours | +| Phase 5 (validation) | ~2-3 hours | + +## Future: Staying in Sync + +After this merge, establish a recurring upstream sync process: +1. Track `upstream/main` with periodic merges (weekly or per-release) +2. Keep Kindred changes as isolated as possible (separate files > modifying upstream files) +3. Consider upstreaming non-Kindred-specific fixes to the FreeCAD fork diff --git a/mods/silo b/mods/silo index be8783bf0a..fed72676bc 160000 --- a/mods/silo +++ b/mods/silo @@ -1 +1 @@ -Subproject commit be8783bf0a98fca9bc89f6bb02bdafc2c3911e4e +Subproject commit fed72676bc52ed63cc95095acba7f6f4eae3ac6a diff --git a/mods/ztools b/mods/ztools index 2bb2949b82..2bf969c62a 160000 --- a/mods/ztools +++ b/mods/ztools @@ -1 +1 @@ -Subproject commit 2bb2949b82d86ccd3661ff0797ad281ddcb731ac +Subproject commit 2bf969c62ac9ec70a4cbbb69bc3361bdc80448d6 diff --git a/src/3rdParty/GSL b/src/3rdParty/GSL index 543d0dd3fe..756c91ab89 160000 --- a/src/3rdParty/GSL +++ b/src/3rdParty/GSL @@ -1 +1 @@ -Subproject commit 543d0dd3fe966ddf20e884b44e5fdbf12cb43784 +Subproject commit 756c91ab895aa52f650599bb1a3fc131f1f4b5ef diff --git a/src/3rdParty/OndselSolver b/src/3rdParty/OndselSolver index 30e9b64e8b..fe41fa3b00 160000 --- a/src/3rdParty/OndselSolver +++ b/src/3rdParty/OndselSolver @@ -1 +1 @@ -Subproject commit 30e9b64e8bf881d438d4b88834f9ba3674865418 +Subproject commit fe41fa3b00fa4e49f5719356d20e2d35591937b6 diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index f2b11c80bc..9750599c7d 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -782,7 +782,7 @@ bool MainWindow::updateComboView(bool show) ->GetGroup("DockWindows") ->GetGroup("ComboView"); bool enable = group->GetBool("Enabled", true); - _updateDockWidget("Std_ComboView", enable, show, Qt::LeftDockWidgetArea, [](QWidget* widget) { + _updateDockWidget("Std_ComboView", enable, show, Qt::RightDockWidgetArea, [](QWidget* widget) { auto pcComboView = qobject_cast(widget); if (widget) { return widget; diff --git a/src/Gui/PreferencePacks/CMakeLists.txt b/src/Gui/PreferencePacks/CMakeLists.txt index 64f2092426..a1c78cee45 100644 --- a/src/Gui/PreferencePacks/CMakeLists.txt +++ b/src/Gui/PreferencePacks/CMakeLists.txt @@ -4,10 +4,6 @@ SET(PreferencePacks_Files SET(PreferencePacks_Directories "KindredCreate" - "FreeCAD Classic" - "Dark behave" - "FreeCAD Light" - "FreeCAD Dark" ) ADD_CUSTOM_TARGET(PreferencePacks_data ALL diff --git a/src/Gui/PreferencePacks/Dark behave/Dark behave.cfg b/src/Gui/PreferencePacks/Dark behave/Dark behave.cfg deleted file mode 100644 index 6d1906f64f..0000000000 --- a/src/Gui/PreferencePacks/Dark behave/Dark behave.cfg +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - #9b4de6 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Behave-dark.qss - - - - - diff --git a/src/Gui/PreferencePacks/FreeCAD Classic/FreeCAD Classic.cfg b/src/Gui/PreferencePacks/FreeCAD Classic/FreeCAD Classic.cfg deleted file mode 100644 index d70940da22..0000000000 --- a/src/Gui/PreferencePacks/FreeCAD Classic/FreeCAD Classic.cfg +++ /dev/null @@ -1,181 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - Light Theme + Dark Background.qss - - FreeCAD Classic - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #feff9e - #000000 - #000000 - #000000 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Gui/PreferencePacks/FreeCAD Classic/post.FCMacro b/src/Gui/PreferencePacks/FreeCAD Classic/post.FCMacro deleted file mode 100644 index f0a0625bc9..0000000000 --- a/src/Gui/PreferencePacks/FreeCAD Classic/post.FCMacro +++ /dev/null @@ -1,8 +0,0 @@ -# Classic theme must delete any set value for the editor text so that it is calculated dynamically when needed -import FreeCAD - -editorPrefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Editor") -editorPrefs.RemInt("Text") - -appPrefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/MainWindow") -appPrefs.RemString("QtStyle") diff --git a/src/Gui/PreferencePacks/FreeCAD Dark/FreeCAD Dark.cfg b/src/Gui/PreferencePacks/FreeCAD Dark/FreeCAD Dark.cfg deleted file mode 100644 index 61a1f7a3c7..0000000000 --- a/src/Gui/PreferencePacks/FreeCAD Dark/FreeCAD Dark.cfg +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - Freecad Overlay.qss - FreeCAD - FreeCAD.qss - FreeCAD Dark - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #1864ab - #f8f9fa - #f8f9fa - #f8f9fa - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Gui/PreferencePacks/FreeCAD Light/FreeCAD Light.cfg b/src/Gui/PreferencePacks/FreeCAD Light/FreeCAD Light.cfg deleted file mode 100644 index e6a4b3d79d..0000000000 --- a/src/Gui/PreferencePacks/FreeCAD Light/FreeCAD Light.cfg +++ /dev/null @@ -1,172 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - Freecad Overlay.qss - FreeCAD - FreeCAD.qss - FreeCAD Light - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #bac8ff - #212529 - #212529 - #212529 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Gui/PreferencePacks/package.xml b/src/Gui/PreferencePacks/package.xml index eacd80cc72..57dca802be 100644 --- a/src/Gui/PreferencePacks/package.xml +++ b/src/Gui/PreferencePacks/package.xml @@ -18,33 +18,6 @@ catppuccin mocha - - FreeCAD Classic - Theme - Removes stylesheets, and applies the classic purple/gray background. Resets all colors to default - 1.0.0 - built-in - background - no stylesheet - classic theme - - - FreeCAD Light - Theme - Applies a basic light theme. - 1.0.0 - built-in - background - light - - - FreeCAD Dark - Theme - Applies a basic dark theme. - 1.0.0 - built-in - background - dark - + diff --git a/src/Mod/AddonManager b/src/Mod/AddonManager index d9c593594a..01e242ec29 160000 --- a/src/Mod/AddonManager +++ b/src/Mod/AddonManager @@ -1 +1 @@ -Subproject commit d9c593594ae4187d09b3ec9c7989db6c3a22d7a2 +Subproject commit 01e242ec29160714074ab9930735fa10fdde804f diff --git a/tests/lib b/tests/lib index f8d7d77c06..56efe39831 160000 --- a/tests/lib +++ b/tests/lib @@ -1 +1 @@ -Subproject commit f8d7d77c06936315286eb55f8de22cd23c188571 +Subproject commit 56efe3983185e3f37e43415d1afa97e3860f187f