docs: remove stale documentation and update for post-ztools architecture #369
@@ -20,10 +20,7 @@ FreeCAD startup
|
||||
│ └─ for each addon in order:
|
||||
│ └─ exec(InitGui.py)
|
||||
│ ├─ sdk (priority 0): logs "SDK loaded"
|
||||
│ ├─ ztools (priority 50): schedules deferred _register() (2000ms)
|
||||
│ │ ├─ imports ZTools commands
|
||||
│ │ ├─ installs _ZToolsManipulator (global)
|
||||
│ │ └─ injects commands into editing contexts
|
||||
│ ├─ gears (priority 40): registers GearsWorkbench
|
||||
│ └─ silo (priority 60): registers SiloWorkbench
|
||||
│ └─ schedules deferred Silo overlay registration (2500ms)
|
||||
├─ EditingContextResolver singleton created (MainWindow constructor)
|
||||
@@ -34,7 +31,6 @@ FreeCAD startup
|
||||
├─ 500ms: _register_kc_format() → .kc file format
|
||||
├─ 1500ms: _register_silo_origin() → registers Silo FileOrigin
|
||||
├─ 2000ms: _setup_silo_auth_panel() → "Database Auth" dock
|
||||
├─ 2000ms: ZTools _register() → commands + manipulator
|
||||
├─ 2500ms: Silo overlay registration → "Silo Origin" toolbar overlay
|
||||
├─ 3000ms: _check_silo_first_start() → settings prompt
|
||||
├─ 4000ms: _setup_silo_activity_panel() → "Database Activity" dock
|
||||
@@ -65,7 +61,7 @@ The loader (`addon_loader.py`) processes addons in this order:
|
||||
5. **Load** — execute `Init.py` (console) then `InitGui.py` (GUI) for each addon
|
||||
6. **Register** — populate `FreeCAD.KindredAddons` registry with addon state
|
||||
|
||||
Current load order: **sdk** (0) → **ztools** (50) → **silo** (60)
|
||||
Current load order: **sdk** (0) → **gears** (40) → **silo** (60)
|
||||
|
||||
## Key source layout
|
||||
|
||||
@@ -98,14 +94,12 @@ mods/sdk/ [dir] Kindred addon SDK — stable API contract
|
||||
│ └── catppuccin-mocha.yaml 26 colors + 14 semantic roles
|
||||
└── Init.py / InitGui.py Minimal log messages
|
||||
|
||||
mods/ztools/ [submodule] command provider (not a workbench)
|
||||
├── package.xml Manifest (priority 50, depends on sdk)
|
||||
├── ztools/InitGui.py Deferred command registration + _ZToolsManipulator
|
||||
├── ztools/ztools/
|
||||
│ ├── commands/ Datum, pattern, pocket, assembly, spreadsheet
|
||||
│ ├── datums/core.py Datum creation via Part::AttachExtension
|
||||
│ └── resources/ Icons (SDK theme tokens), theme utilities
|
||||
└── CatppuccinMocha/ Theme preference pack (QSS)
|
||||
mods/gears/ [submodule → gears.git] Gears workbench
|
||||
├── package.xml Manifest (priority 40, depends on sdk)
|
||||
└── ... Parametric gear generation
|
||||
|
||||
mods/solver/ [submodule → solver.git] Solver addon
|
||||
└── ... Solver plugin support
|
||||
|
||||
mods/silo/ [submodule → silo-mod.git] FreeCAD workbench
|
||||
├── freecad/package.xml Manifest (priority 60, depends on sdk)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,31 +1,8 @@
|
||||
# Components
|
||||
|
||||
## ztools (command provider)
|
||||
## Gears workbench
|
||||
|
||||
ZTools is no longer a standalone workbench. It registers as a command provider that
|
||||
injects tools into the appropriate editing contexts via `WorkbenchManipulator` and
|
||||
the `EditingContextResolver` system.
|
||||
|
||||
**Registered commands (9):**
|
||||
|
||||
| Command | Function | Injected Into |
|
||||
|---------|----------|---------------|
|
||||
| `ZTools_DatumCreator` | Create datum planes, axes, points (16 modes) | PartDesign Helper Features |
|
||||
| `ZTools_DatumManager` | Manage existing datum objects | PartDesign Helper Features |
|
||||
| `ZTools_EnhancedPocket` | Flip-side pocket (cut outside sketch profile) | PartDesign Modeling Features |
|
||||
| `ZTools_RotatedLinearPattern` | Linear pattern with incremental rotation | PartDesign Transformation Features |
|
||||
| `ZTools_AssemblyLinearPattern` | Pattern assembly components linearly | Assembly |
|
||||
| `ZTools_AssemblyPolarPattern` | Pattern assembly components around axis | Assembly |
|
||||
| `ZTools_SpreadsheetStyle{Bold,Italic,Underline}` | Text style toggles | Spreadsheet |
|
||||
| `ZTools_SpreadsheetAlign{Left,Center,Right}` | Cell alignment | Spreadsheet |
|
||||
| `ZTools_Spreadsheet{BgColor,TextColor,QuickAlias}` | Colors and alias creation | Spreadsheet |
|
||||
|
||||
**Integration** via `_ZToolsManipulator` (WorkbenchManipulator) and `injectEditingCommands()`:
|
||||
- Commands are injected into native workbench toolbars (PartDesign, Assembly, Spreadsheet)
|
||||
- Context toolbar injections ensure commands appear when the relevant editing context is active
|
||||
- PartDesign menu items inserted after `PartDesign_Boolean`
|
||||
|
||||
**Datum types (7):** offset_from_face, offset_from_plane, midplane, 3_points, normal_to_edge, angled, tangent_to_cylinder. All except tangent_to_cylinder use `Part::AttachExtension` for automatic parametric updates.
|
||||
Gears (`mods/gears/`) is a default addon providing parametric gear generation. Added as a submodule in the `feat/gears-addon` branch and merged to main.
|
||||
|
||||
---
|
||||
|
||||
@@ -110,10 +87,6 @@ Notable theme customizations beyond standard Catppuccin colors:
|
||||
|
||||
`silo-auth.svg`, `silo-bom.svg`, `silo-commit.svg`, `silo-info.svg`, `silo-new.svg`, `silo-open.svg`, `silo-pull.svg`, `silo-push.svg`, `silo-save.svg`, `silo.svg`
|
||||
|
||||
### Missing icons
|
||||
|
||||
3 command icon names have no corresponding SVG file: `silo-tag`, `silo-rollback`, `silo-status`. The `_icon()` function returns an empty string for these, so `Silo_TagProjects`, `Silo_Rollback`, and `Silo_SetStatus` render without toolbar icons.
|
||||
|
||||
### Palette
|
||||
|
||||
All silo-* icons use the Catppuccin Mocha color scheme. See `icons/kindred/README.md` for palette specification and icon design standards.
|
||||
|
||||
@@ -18,11 +18,11 @@ Strategy for integrating ztools and Silo as built-in addons while maintaining cl
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Layer 5: Kindred Addons (mods/) │
|
||||
│ ┌──────────────────┐ ┌──────────────────┐ │
|
||||
│ │ ztools │ │ Silo │ │
|
||||
│ │ Datum Creator │ │ Open/Save/Commit│ │
|
||||
│ │ Enhanced Pocket │ │ Part numbering │ │
|
||||
│ │ Assembly Patterns│ │ Revision control│ │
|
||||
│ │ Spreadsheet fmt │ │ BOM management │ │
|
||||
│ │ Silo │ │ Gears │ │
|
||||
│ │ Open/Save/Commit│ │ Parametric gear │ │
|
||||
│ │ Part numbering │ │ generation │ │
|
||||
│ │ Revision control│ │ │ │
|
||||
│ │ BOM management │ │ │ │
|
||||
│ └──────────────────┘ └──────────────────┘ │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Layer 4: Kindred Addon SDK (mods/sdk/) │
|
||||
@@ -91,7 +91,7 @@ The SDK is loaded first (priority 0) and has no dependencies.
|
||||
|
||||
### Layer 5: Kindred Addons -- `mods/`
|
||||
|
||||
Pure Python addons with `package.xml` manifests. Self-contained with `Init.py`, `InitGui.py`, and `<kindred>` metadata. Developed and versioned independently as git submodules. Must declare `<dependency>sdk</dependency>` to use SDK APIs.
|
||||
Pure Python addons with `package.xml` manifests. Self-contained with `Init.py`, `InitGui.py`, and `<kindred>` metadata. Developed and versioned independently as git submodules. Must declare `<dependency>sdk</dependency>` to use SDK APIs. Current addons: **silo** (PLM), **gears** (parametric gear generation).
|
||||
|
||||
---
|
||||
|
||||
@@ -101,7 +101,7 @@ Pure Python addons with `package.xml` manifests. Self-contained with `Init.py`,
|
||||
|
||||
**Implementation:** `src/Mod/Create/addon_loader.py` implements manifest-driven loading with dependency resolution. Replaces the original `exec()`-based approach. Each addon provides a `package.xml` with `<kindred>` extensions specifying version bounds, load priority, and dependencies.
|
||||
|
||||
**Default workbench:** `PartDesignWorkbench` (set in `PreferencePacks/KindredCreate/KindredCreate.cfg`). ZTools is no longer a workbench — its commands are injected into native workbench toolbars via the `EditingContextResolver` and `WorkbenchManipulator` systems.
|
||||
**Default workbench:** `PartDesignWorkbench` (set in `PreferencePacks/KindredCreate/KindredCreate.cfg`).
|
||||
|
||||
**Registry:** `FreeCAD.KindredAddons` provides runtime introspection — `.loaded()` returns addon names and states, `.get(name)` returns manifest data, `.contexts()` lists registered editing contexts.
|
||||
|
||||
@@ -111,7 +111,7 @@ Pure Python addons with `package.xml` manifests. Self-contained with `Init.py`,
|
||||
|
||||
**Implementation:** `mods/sdk/kindred_sdk/` package with wrappers for editing contexts, theme tokens, FileOrigin registration, and dock panel creation. YAML-driven palette system (`palettes/catppuccin-mocha.yaml`) replaces hardcoded color dicts that were duplicated across 5+ locations.
|
||||
|
||||
**Migration:** Silo has been migrated to use the SDK (#250) — it declares `<dependency>sdk</dependency>` and uses `kindred_sdk` for overlay registration and theme tokens. ztools has **not yet been migrated**: its `package.xml` lacks `<kindred>` metadata and its `InitGui.py` does not import from `kindred_sdk`. See KNOWN_ISSUES.md next step #9.
|
||||
**Migration:** Silo has been migrated to use the SDK (#250) — it declares `<dependency>sdk</dependency>` and uses `kindred_sdk` for overlay registration and theme tokens. Gears also depends on the SDK. The former ztools addon was removed from the build (#344) and archived to `reference/ztools/` (#345) as part of the UI/UX rework (#346); its commands will be reimplemented through the KCSDK system.
|
||||
|
||||
### Phase 1.75: C++ module scaffold -- DONE
|
||||
|
||||
@@ -121,17 +121,16 @@ Pure Python addons with `package.xml` manifests. Self-contained with `Init.py`,
|
||||
|
||||
### Phase 2: Enhanced Pocket as C++ feature -- NOT STARTED
|
||||
|
||||
**Goal:** Replace the Python boolean-operation workaround in `ZTools_EnhancedPocket` with a proper `Create::FlipPocket` C++ feature inheriting from `PartDesign::ProfileBased`.
|
||||
**Goal:** Implement a proper `Create::FlipPocket` C++ feature inheriting from `PartDesign::ProfileBased`.
|
||||
|
||||
**Rationale:** The current Python implementation creates a standard Pocket then applies a boolean Common. A native feature would integrate properly with the feature tree, support undo/redo correctly, and perform better on complex geometry.
|
||||
**Rationale:** The former ztools Python implementation created a standard Pocket then applied a boolean Common. A native feature would integrate properly with the feature tree, support undo/redo correctly, and perform better on complex geometry.
|
||||
|
||||
**Scope:**
|
||||
- `src/Mod/Create/App/FeatureFlipPocket.cpp` -- Feature implementation
|
||||
- `src/Mod/Create/Gui/TaskFlipPocket.cpp` -- Task panel
|
||||
- `src/Mod/Create/Gui/ViewProviderFlipPocket.cpp` -- View provider
|
||||
- Update `ZTools_EnhancedPocket` to create `Create::FlipPocket` instead of the workaround
|
||||
|
||||
**Decision:** Deferred. The Python approach is functional for current needs. Revisit when performance or feature-tree integration becomes a problem.
|
||||
**Decision:** Deferred. The former Python approach was functional. Revisit as part of the KCSDK-driven command reimplementation (#346).
|
||||
|
||||
### Phase 3: Datum C++ helpers -- NOT STARTED (SUPERSEDED)
|
||||
|
||||
@@ -192,10 +191,10 @@ FreeCADGui (EditingContextResolver, DockWindowManager, OriginManager, ...)
|
||||
| 1 | #350 | DONE | Scaffold KCSDK library + kcsdk pybind11 module |
|
||||
| 2 | #351 | DONE | Migrate editing context API to kcsdk |
|
||||
| 3 | #352 | DONE | Panel provider system (IPanelProvider) |
|
||||
| 4 | #353 | — | C++ theme engine |
|
||||
| 5 | #354 | — | Toolbar provider system (IToolbarProvider) |
|
||||
| 6 | #355 | — | Menu and action system |
|
||||
| 7 | #356 | — | Status bar provider + origin migration |
|
||||
| 4 | #353 | DONE | C++ theme engine |
|
||||
| 5 | #354 | DONE | Toolbar provider system (IToolbarProvider) |
|
||||
| 6 | #355 | DONE | Menu and action system |
|
||||
| 7 | #356 | DONE | Status bar provider + origin migration |
|
||||
| 8 | #357 | — | Deprecation cleanup + SDK v1.0.0 |
|
||||
|
||||
**Key files:**
|
||||
@@ -221,15 +220,15 @@ FreeCADGui (EditingContextResolver, DockWindowManager, OriginManager, ...)
|
||||
|
||||
3. **Silo server distributed separately.** Users deploy the Silo server independently. Setup instructions live in `mods/silo/README.md`.
|
||||
|
||||
4. **Version synchronization via submodule pins.** ztools and Silo versions are pinned git submodule commits. Updates are deliberate:
|
||||
4. **Version synchronization via submodule pins.** Addon versions are pinned git submodule commits. Updates are deliberate:
|
||||
```bash
|
||||
cd mods/ztools && git pull origin main && cd ../..
|
||||
git add mods/ztools && git commit -m "Update ztools submodule"
|
||||
cd mods/silo && git pull origin main && cd ../..
|
||||
git add mods/silo && git commit -m "Update silo submodule"
|
||||
```
|
||||
|
||||
5. **Python-first approach.** C++ extensions are deferred until Python cannot achieve the requirement. The AttachExtension approach for datums validated this strategy.
|
||||
5. **Python-first approach.** C++ extensions are deferred until Python cannot achieve the requirement.
|
||||
|
||||
6. **Graceful degradation.** The addon loader skips addons that fail validation or loading. Each addon load is wrapped in try/except with console logging. The SDK, ztools, and Silo can all be absent without breaking the bootstrap.
|
||||
6. **Graceful degradation.** The addon loader skips addons that fail validation or loading. Each addon load is wrapped in try/except with console logging. Any addon can be absent without breaking the bootstrap.
|
||||
|
||||
7. **SDK as adaptation layer.** Addons call `kindred_sdk.*` instead of `FreeCADGui.*` platform internals. This creates a single point of adaptation during upstream rebases — update the SDK wrappers, not every addon.
|
||||
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
# Known Issues
|
||||
|
||||
## Issues
|
||||
|
||||
### Critical
|
||||
|
||||
1. ~~**QSS duplication.**~~ Resolved. The canonical QSS lives in `src/Gui/Stylesheets/KindredCreate.qss`. The PreferencePacks copy is now generated at build time via `configure_file()` in `src/Gui/PreferencePacks/CMakeLists.txt`. The unused `resources/preferences/KindredCreate/` directory has been removed.
|
||||
|
||||
2. ~~**WorkbenchManipulator timing.**~~ Resolved. ZTools is no longer a workbench. Commands are registered via a deferred `QTimer.singleShot(2000ms)` in `InitGui.py`, which activates dependent workbenches first, then imports ZTools commands and installs the `_ZToolsManipulator`. The `EditingContextResolver` handles toolbar visibility based on editing context.
|
||||
|
||||
3. ~~**Silo shortcut persistence.**~~ Resolved. `Silo_ToggleMode` removed; file operations now delegate to the selected origin via the unified origin system.
|
||||
|
||||
### High
|
||||
|
||||
4. **Silo authentication not production-hardened.** Local auth (bcrypt) works end-to-end. LDAP (FreeIPA) and OIDC (Keycloak) backends are coded but depend on infrastructure not yet deployed. FreeCAD client has `Silo_Auth` dock panel for login and API token management. Server has session middleware (`alexedwards/scs`), CSRF protection (`nosurf`), and role-based access control (admin/editor/viewer). Migration `009_auth.sql` adds users, api_tokens, and sessions tables.
|
||||
|
||||
5. **No unit tests.** Zero test coverage for ztools and Silo FreeCAD commands. Silo Go backend also lacks tests.
|
||||
|
||||
6. **Assembly solver datum handling is minimal.** `UtilsAssembly.findPlacement()` handles standard shapes (faces, edges, vertices) and `App::Line` origin objects. It does not extract placement from `PartDesign::Plane` or `PartDesign::Point` datum objects — when no element is selected, it returns a default `App.Placement()`. This means assembly joints referencing datum planes/points may produce incorrect placement.
|
||||
|
||||
### Medium
|
||||
|
||||
7. **`Silo_BOM` requires Silo-tracked document.** Depends on `SiloPartNumber` property. Unregistered documents show a warning with no registration path.
|
||||
|
||||
8. **PartDesign menu insertion fragility.** `_ZToolsPartDesignManipulator.modifyMenuBar()` inserts after `PartDesign_Boolean`. If upstream renames this command, insertions silently fail.
|
||||
|
||||
9. **tangent_to_cylinder falls back to manual placement.** TangentPlane MapMode requires a vertex reference not collected by the current UI.
|
||||
|
||||
10. ~~**`delete_bom_entry()` bypasses error normalization.**~~ Resolved. `delete_bom_entry()` uses `self._request("DELETE", ...)` which routes through `SiloClient._request()` with proper error handling.
|
||||
|
||||
11. ~~**Missing Silo icons.**~~ Resolved. All three icons now exist: `silo-tag.svg`, `silo-rollback.svg`, `silo-status.svg` in `mods/silo/freecad/resources/icons/`.
|
||||
|
||||
### Fixed (retain for reference)
|
||||
|
||||
12. **OndselSolver Newton-Raphson convergence.** `NewtonRaphson::isConvergedToNumericalLimit()` compared `dxNorms->at(iterNo)` to itself instead of `dxNorms->at(iterNo - 1)`. This prevented convergence detection on complex assemblies, causing solver exhaustion and "grounded object moved" warnings. Fixed in Kindred fork (`src/3rdParty/OndselSolver`). Needs upstreaming to `FreeCAD/OndselSolver`.
|
||||
|
||||
13. **Assembly solver crash on document restore.** `AssemblyObject::onChanged()` called `updateSolveStatus()` when the Group property changed during document restore, triggering the solver while child objects were still deserializing (SIGSEGV). Fixed with `isRestoring()` and `isPerformingTransaction()` guards at `src/Mod/Assembly/App/AssemblyObject.cpp:143`.
|
||||
|
||||
14. **`DlgSettingsGeneral::applyMenuIconSize` visibility.** The method was `private` but called from `StartupProcess.cpp`. Fixed by moving to `public` (PR #49). Also required `Dialog::` namespace qualifier in `StartupProcess.cpp`.
|
||||
|
||||
---
|
||||
|
||||
## Incomplete features
|
||||
|
||||
### Silo
|
||||
|
||||
| Feature | Status | Notes |
|
||||
|---------|--------|-------|
|
||||
| Authentication | Local auth complete | LDAP/OIDC backends coded, pending infrastructure. Auth dock panel available. |
|
||||
| CSRF protection | Implemented | `nosurf` library on web form routes |
|
||||
| File locking | Not implemented | Needed to prevent concurrent edits |
|
||||
| Odoo ERP integration | Stub only | Returns "not yet implemented" |
|
||||
| Part number date segments | Unknown | `formatDate()` reference is stale — function not found in codebase |
|
||||
| Location/inventory APIs | Tables exist, no handlers | |
|
||||
| CSV import rollback | Not implemented | `bom_handlers.go` |
|
||||
| SSE event streaming | Implemented | Reconnect logic with exponential backoff |
|
||||
| Database Activity panel | Implemented | Dock panel showing real-time server events |
|
||||
| Start panel | Implemented | In-viewport start page with recent files and Silo integration |
|
||||
|
||||
### ztools
|
||||
|
||||
| Feature | Status | Notes |
|
||||
|---------|--------|-------|
|
||||
| Tangent-to-cylinder attachment | Manual fallback | No vertex ref in UI |
|
||||
| Angled datum live editing | Incomplete | AttachmentOffset not updated in panel |
|
||||
| Assembly pattern undo | Not implemented | |
|
||||
|
||||
---
|
||||
|
||||
## Next steps
|
||||
|
||||
1. **Authentication hardening** -- Deploy FreeIPA and Keycloak infrastructure. End-to-end test LDAP and OIDC flows. Harden token rotation and session expiry.
|
||||
|
||||
2. **BOM-Assembly bridge** -- Auto-populate Silo BOM from Assembly component links on save. See `docs/BOM_MERGE.md` for specification.
|
||||
|
||||
3. **File locking** -- Pessimistic locks on `Silo_Open` to prevent concurrent edits. Requires server-side lock table and client-side lock display.
|
||||
|
||||
4. ~~**Build system**~~ Done. CMake install rules in `src/Mod/Create/CMakeLists.txt` handle all `mods/` submodules.
|
||||
|
||||
5. **Test coverage** -- Unit tests for ztools datum creation, Silo FreeCAD commands, and Go API endpoints.
|
||||
|
||||
6. ~~**QSS consolidation**~~ Done. Canonical QSS is `src/Gui/Stylesheets/KindredCreate.qss`; PreferencePacks copy generated at build time via `configure_file()`.
|
||||
|
||||
7. **Update notification UI** -- Display in-app notification when a new release is available (issue #30). The update checker backend (`update_checker.py`) runs at startup; notification UI still needed.
|
||||
|
||||
8. **KC file format completion** -- Populate `silo_instance` and `revision_hash` in manifest.json. Implement write-back for history.json, approvals.json, dependencies.json. See `docs/KC_SPECIFICATION.md`.
|
||||
|
||||
9. **ztools SDK migration** -- Add `<kindred>` metadata to `mods/ztools/package.xml` (load priority, version bounds, SDK dependency). Migrate `InitGui.py` to use `kindred_sdk` APIs for context/overlay registration.
|
||||
|
||||
10. **DAG cross-item edges** -- Assembly constraints referencing geometry in child parts should populate `dag_cross_edges`. Deferred until assembly constraint model is finalized.
|
||||
@@ -1,395 +0,0 @@
|
||||
# DAG Client Integration Contract
|
||||
|
||||
**Status:** Draft
|
||||
**Last Updated:** 2026-02-13
|
||||
|
||||
This document describes what silo-mod and Headless Create runners need to implement to integrate with the Silo dependency DAG and worker system.
|
||||
|
||||
---
|
||||
|
||||
## 1. Overview
|
||||
|
||||
The DAG system has two client-side integration points:
|
||||
|
||||
1. **silo-mod workbench** (desktop) -- pushes DAG data to Silo on save or revision create.
|
||||
2. **silorunner + silo-mod** (headless) -- extracts DAGs, validates features, and exports geometry as compute jobs.
|
||||
|
||||
Both share the same Python codebase in the silo-mod repository. Desktop users call the code interactively; runners call it headlessly via `create --console`.
|
||||
|
||||
---
|
||||
|
||||
## 2. DAG Sync Payload
|
||||
|
||||
Clients push feature trees to Silo via:
|
||||
|
||||
```
|
||||
PUT /api/items/{partNumber}/dag
|
||||
Authorization: Bearer <user_token or runner_token>
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
### 2.1 Request Body
|
||||
|
||||
```json
|
||||
{
|
||||
"revision_number": 3,
|
||||
"nodes": [
|
||||
{
|
||||
"node_key": "Sketch001",
|
||||
"node_type": "sketch",
|
||||
"properties_hash": "a1b2c3d4e5f6...",
|
||||
"metadata": {
|
||||
"label": "Base Profile",
|
||||
"constraint_count": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"node_key": "Pad001",
|
||||
"node_type": "pad",
|
||||
"properties_hash": "f6e5d4c3b2a1...",
|
||||
"metadata": {
|
||||
"label": "Main Extrusion",
|
||||
"length": 25.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"source_key": "Sketch001",
|
||||
"target_key": "Pad001",
|
||||
"edge_type": "depends_on"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 Field Reference
|
||||
|
||||
**Nodes:**
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `node_key` | string | yes | Unique within item+revision. Use Create's internal object name (e.g. `Sketch001`, `Pad003`). |
|
||||
| `node_type` | string | yes | One of: `sketch`, `pad`, `pocket`, `fillet`, `chamfer`, `constraint`, `body`, `part`, `datum`. |
|
||||
| `properties_hash` | string | no | SHA-256 hex digest of the node's parametric inputs. Used for memoization. |
|
||||
| `validation_state` | string | no | One of: `clean`, `dirty`, `validating`, `failed`. Defaults to `clean`. |
|
||||
| `metadata` | object | no | Arbitrary key-value pairs for display or debugging. |
|
||||
|
||||
**Edges:**
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `source_key` | string | yes | The node that is depended upon. |
|
||||
| `target_key` | string | yes | The node that depends on the source. |
|
||||
| `edge_type` | string | no | One of: `depends_on` (default), `references`, `constrains`. |
|
||||
|
||||
**Direction convention:** Edges point from dependency to dependent. If Pad001 depends on Sketch001, the edge is `source_key: "Sketch001"`, `target_key: "Pad001"`.
|
||||
|
||||
### 2.3 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"synced": true,
|
||||
"node_count": 15,
|
||||
"edge_count": 14
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Computing properties_hash
|
||||
|
||||
The `properties_hash` enables memoization -- if a node's inputs haven't changed since the last validation, it can be skipped. Computing it:
|
||||
|
||||
```python
|
||||
import hashlib
|
||||
import json
|
||||
|
||||
def compute_properties_hash(feature_obj):
|
||||
"""Hash the parametric inputs of a Create feature."""
|
||||
inputs = {}
|
||||
|
||||
if feature_obj.TypeId == "Sketcher::SketchObject":
|
||||
# Hash geometry + constraints
|
||||
inputs["geometry_count"] = feature_obj.GeometryCount
|
||||
inputs["constraint_count"] = feature_obj.ConstraintCount
|
||||
inputs["geometry"] = str(feature_obj.Shape.exportBrep())
|
||||
elif feature_obj.TypeId == "PartDesign::Pad":
|
||||
inputs["length"] = feature_obj.Length.Value
|
||||
inputs["type"] = str(feature_obj.Type)
|
||||
inputs["reversed"] = feature_obj.Reversed
|
||||
inputs["sketch"] = feature_obj.Profile[0].Name
|
||||
# ... other feature types
|
||||
|
||||
canonical = json.dumps(inputs, sort_keys=True)
|
||||
return hashlib.sha256(canonical.encode()).hexdigest()
|
||||
```
|
||||
|
||||
The exact inputs per feature type are determined by what parametric values affect the feature's geometry. Include anything that, if changed, would require recomputation.
|
||||
|
||||
---
|
||||
|
||||
## 4. Feature Tree Walking
|
||||
|
||||
To extract the DAG from a Create document:
|
||||
|
||||
```python
|
||||
import FreeCAD
|
||||
|
||||
def extract_dag(doc):
|
||||
"""Walk a Create document and return nodes + edges."""
|
||||
nodes = []
|
||||
edges = []
|
||||
|
||||
for obj in doc.Objects:
|
||||
# Skip non-feature objects
|
||||
if not hasattr(obj, "TypeId"):
|
||||
continue
|
||||
|
||||
node_type = classify_type(obj.TypeId)
|
||||
if node_type is None:
|
||||
continue
|
||||
|
||||
nodes.append({
|
||||
"node_key": obj.Name,
|
||||
"node_type": node_type,
|
||||
"properties_hash": compute_properties_hash(obj),
|
||||
"metadata": {
|
||||
"label": obj.Label,
|
||||
"type_id": obj.TypeId,
|
||||
}
|
||||
})
|
||||
|
||||
# Walk dependencies via InList (objects this one depends on)
|
||||
for dep in obj.InList:
|
||||
if hasattr(dep, "TypeId") and classify_type(dep.TypeId):
|
||||
edges.append({
|
||||
"source_key": dep.Name,
|
||||
"target_key": obj.Name,
|
||||
"edge_type": "depends_on",
|
||||
})
|
||||
|
||||
return nodes, edges
|
||||
|
||||
|
||||
def classify_type(type_id):
|
||||
"""Map Create TypeIds to DAG node types."""
|
||||
mapping = {
|
||||
"Sketcher::SketchObject": "sketch",
|
||||
"PartDesign::Pad": "pad",
|
||||
"PartDesign::Pocket": "pocket",
|
||||
"PartDesign::Fillet": "fillet",
|
||||
"PartDesign::Chamfer": "chamfer",
|
||||
"PartDesign::Body": "body",
|
||||
"Part::Feature": "part",
|
||||
"Sketcher::SketchConstraint": "constraint",
|
||||
}
|
||||
return mapping.get(type_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. When to Push DAG Data
|
||||
|
||||
Push the DAG to Silo in these scenarios:
|
||||
|
||||
| Event | Trigger | Who |
|
||||
|-------|---------|-----|
|
||||
| User saves in silo-mod | On save callback | Desktop silo-mod workbench |
|
||||
| User creates a revision | After `POST /api/items/{pn}/revisions` succeeds | Desktop silo-mod workbench |
|
||||
| Runner extracts DAG | After `create-dag-extract` job completes | silorunner via `PUT /api/runner/jobs/{id}/dag` |
|
||||
| Runner validates | After `create-validate` job, push updated validation states | silorunner via `PUT /api/runner/jobs/{id}/dag` |
|
||||
|
||||
---
|
||||
|
||||
## 6. Runner Entry Points
|
||||
|
||||
silo-mod must provide these Python entry points for headless invocation:
|
||||
|
||||
### 6.1 silo.runner.dag_extract
|
||||
|
||||
Extracts the feature DAG from a Create file and writes it as JSON.
|
||||
|
||||
```python
|
||||
# silo/runner.py
|
||||
|
||||
def dag_extract(input_path, output_path):
|
||||
"""
|
||||
Extract feature DAG from a Create file.
|
||||
|
||||
Args:
|
||||
input_path: Path to the .kc (Kindred Create) file.
|
||||
output_path: Path to write the JSON output.
|
||||
|
||||
Output JSON format:
|
||||
{
|
||||
"nodes": [...], // Same format as DAG sync payload
|
||||
"edges": [...]
|
||||
}
|
||||
"""
|
||||
doc = FreeCAD.openDocument(input_path)
|
||||
nodes, edges = extract_dag(doc)
|
||||
|
||||
with open(output_path, 'w') as f:
|
||||
json.dump({"nodes": nodes, "edges": edges}, f)
|
||||
|
||||
FreeCAD.closeDocument(doc.Name)
|
||||
```
|
||||
|
||||
### 6.2 silo.runner.validate
|
||||
|
||||
Rebuilds all features and reports pass/fail per node.
|
||||
|
||||
```python
|
||||
def validate(input_path, output_path):
|
||||
"""
|
||||
Validate a Create file by rebuilding all features.
|
||||
|
||||
Output JSON format:
|
||||
{
|
||||
"valid": true/false,
|
||||
"nodes": [
|
||||
{
|
||||
"node_key": "Pad001",
|
||||
"state": "clean", // or "failed"
|
||||
"message": null, // error message if failed
|
||||
"properties_hash": "..."
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
doc = FreeCAD.openDocument(input_path)
|
||||
doc.recompute()
|
||||
|
||||
results = []
|
||||
all_valid = True
|
||||
for obj in doc.Objects:
|
||||
if not hasattr(obj, "TypeId"):
|
||||
continue
|
||||
node_type = classify_type(obj.TypeId)
|
||||
if node_type is None:
|
||||
continue
|
||||
|
||||
state = "clean"
|
||||
message = None
|
||||
if hasattr(obj, "isValid") and not obj.isValid():
|
||||
state = "failed"
|
||||
message = f"Feature {obj.Label} failed to recompute"
|
||||
all_valid = False
|
||||
|
||||
results.append({
|
||||
"node_key": obj.Name,
|
||||
"state": state,
|
||||
"message": message,
|
||||
"properties_hash": compute_properties_hash(obj),
|
||||
})
|
||||
|
||||
with open(output_path, 'w') as f:
|
||||
json.dump({"valid": all_valid, "nodes": results}, f)
|
||||
|
||||
FreeCAD.closeDocument(doc.Name)
|
||||
```
|
||||
|
||||
### 6.3 silo.runner.export
|
||||
|
||||
Exports geometry to STEP, IGES, or other formats.
|
||||
|
||||
```python
|
||||
def export(input_path, output_path, format="step"):
|
||||
"""
|
||||
Export a Create file to an external format.
|
||||
|
||||
Args:
|
||||
input_path: Path to the .kc file.
|
||||
output_path: Path to write the exported file.
|
||||
format: Export format ("step", "iges", "stl", "obj").
|
||||
"""
|
||||
doc = FreeCAD.openDocument(input_path)
|
||||
|
||||
import Part
|
||||
shapes = [obj.Shape for obj in doc.Objects if hasattr(obj, "Shape")]
|
||||
compound = Part.makeCompound(shapes)
|
||||
|
||||
format_map = {
|
||||
"step": "STEP",
|
||||
"iges": "IGES",
|
||||
"stl": "STL",
|
||||
"obj": "OBJ",
|
||||
}
|
||||
|
||||
Part.export([compound], output_path)
|
||||
FreeCAD.closeDocument(doc.Name)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Headless Invocation
|
||||
|
||||
The `silorunner` binary shells out to Create (with silo-mod installed):
|
||||
|
||||
```bash
|
||||
# DAG extraction
|
||||
create --console -e "from silo.runner import dag_extract; dag_extract('/tmp/job/part.kc', '/tmp/job/dag.json')"
|
||||
|
||||
# Validation
|
||||
create --console -e "from silo.runner import validate; validate('/tmp/job/part.kc', '/tmp/job/result.json')"
|
||||
|
||||
# Export
|
||||
create --console -e "from silo.runner import export; export('/tmp/job/part.kc', '/tmp/job/output.step', 'step')"
|
||||
```
|
||||
|
||||
**Prerequisites:** The runner host must have:
|
||||
- Headless Create installed (Kindred's fork of FreeCAD)
|
||||
- silo-mod installed as a Create addon (so `from silo.runner import ...` works)
|
||||
- No display server required -- `--console` mode is headless
|
||||
|
||||
---
|
||||
|
||||
## 8. Validation Result Handling
|
||||
|
||||
After a runner completes a `create-validate` job, it should:
|
||||
|
||||
1. Read the result JSON.
|
||||
2. Push updated validation states via `PUT /api/runner/jobs/{jobID}/dag`:
|
||||
|
||||
```json
|
||||
{
|
||||
"revision_number": 3,
|
||||
"nodes": [
|
||||
{"node_key": "Sketch001", "node_type": "sketch", "validation_state": "clean", "properties_hash": "abc..."},
|
||||
{"node_key": "Pad001", "node_type": "pad", "validation_state": "failed", "properties_hash": "def..."}
|
||||
],
|
||||
"edges": [
|
||||
{"source_key": "Sketch001", "target_key": "Pad001"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
3. Complete the job via `POST /api/runner/jobs/{jobID}/complete` with the summary result.
|
||||
|
||||
---
|
||||
|
||||
## 9. SSE Events
|
||||
|
||||
Clients should listen for these events on `GET /api/events`:
|
||||
|
||||
| Event | Payload | When |
|
||||
|-------|---------|------|
|
||||
| `dag.updated` | `{item_id, part_number, revision_number, node_count, edge_count}` | After any DAG sync |
|
||||
| `dag.validated` | `{item_id, part_number, valid, failed_count}` | After validation completes |
|
||||
| `job.created` | `{job_id, definition_name, trigger, item_id}` | Job auto-triggered or manually created |
|
||||
| `job.claimed` | `{job_id, runner_id, runner}` | Runner claims a job |
|
||||
| `job.progress` | `{job_id, progress, message}` | Runner reports progress |
|
||||
| `job.completed` | `{job_id, runner_id}` | Job finishes successfully |
|
||||
| `job.failed` | `{job_id, runner_id, error}` | Job fails |
|
||||
| `job.cancelled` | `{job_id, cancelled_by}` | Job cancelled by user |
|
||||
|
||||
---
|
||||
|
||||
## 10. Cross-Item Edges
|
||||
|
||||
For assembly constraints that reference geometry in child parts (e.g. a mate constraint between two parts), use the `dag_cross_edges` table. These edges bridge the BOM DAG and the feature DAG.
|
||||
|
||||
Cross-item edges are **not** included in the standard `PUT /dag` sync. They will be managed through a dedicated endpoint in a future iteration once the assembly constraint model in Create/silo-mod is finalized.
|
||||
|
||||
For now, the DAG sync covers intra-item dependencies only. Assembly-level interference detection uses the BOM DAG (`relationships` table) combined with per-item feature DAGs.
|
||||
@@ -1,26 +1,30 @@
|
||||
# Kindred Create
|
||||
|
||||
**Last updated:** 2026-02-08
|
||||
**Branch:** main @ `cf523f1d87a`
|
||||
**Kindred Create:** v0.1.0
|
||||
**FreeCAD base:** v1.0.0
|
||||
**Last updated:** 2026-03-02
|
||||
**Branch:** main @ `b0621f9731c`
|
||||
**Kindred Create:** v0.1.5
|
||||
**FreeCAD base:** v1.2.0
|
||||
|
||||
## Documentation
|
||||
|
||||
| Document | Contents |
|
||||
|----------|----------|
|
||||
| [ARCHITECTURE.md](ARCHITECTURE.md) | Bootstrap flow, source layout, submodules |
|
||||
| [COMPONENTS.md](COMPONENTS.md) | ztools, Silo, Origin commands, theme, icons |
|
||||
| [KNOWN_ISSUES.md](KNOWN_ISSUES.md) | Bugs, incomplete features, next steps |
|
||||
| [COMPONENTS.md](COMPONENTS.md) | Silo, Gears, Origin commands, theme, icons |
|
||||
| [INTEGRATION_PLAN.md](INTEGRATION_PLAN.md) | Architecture layers, integration phases |
|
||||
| [CI_CD.md](CI_CD.md) | Build and release workflows |
|
||||
| [INTER_SOLVER.md](INTER_SOLVER.md) | Inter-solver communication |
|
||||
| [DAG_CLIENT_INTEGRATION.md](DAG_CLIENT_INTEGRATION.md) | DAG client integration (draft) |
|
||||
| [BOM_MERGE.md](BOM_MERGE.md) | Bill of materials merge specification |
|
||||
| [KC_SPECIFICATION.md](KC_SPECIFICATION.md) | .kc file format specification |
|
||||
|
||||
## Submodules
|
||||
|
||||
| Submodule | Path | Source | Pinned commit |
|
||||
|-----------|------|--------|---------------|
|
||||
| ztools | `mods/ztools` | `git.kindred-systems.com/forbes/ztools` | `3298d1c` |
|
||||
| silo-mod | `mods/silo` | `git.kindred-systems.com/kindred/silo-mod` | `f9924d3` |
|
||||
| silo-mod | `mods/silo` | `git.kindred-systems.com/kindred/silo-mod` | `cc6a79f` |
|
||||
| gears | `mods/gears` | `git.kindred-systems.com/kindred/gears` | `1e26c39` |
|
||||
| solver | `mods/solver` | `git.kindred-systems.com/kindred/solver` | `cd7f66f` |
|
||||
| OndselSolver | `src/3rdParty/OndselSolver` | `git.kindred-systems.com/kindred/solver` | `fe41fa3` |
|
||||
| GSL | `src/3rdParty/GSL` | `github.com/microsoft/GSL` | `756c91a` |
|
||||
| AddonManager | `src/Mod/AddonManager` | `github.com/FreeCAD/AddonManager` | `01e242e` |
|
||||
@@ -28,4 +32,6 @@
|
||||
|
||||
The silo submodule was split from a monorepo into three repos: `silo-client` (shared Python API client), `silo-mod` (FreeCAD workbench, used as Create's submodule), and `silo-calc` (LibreOffice Calc extension). The `silo-mod` repo includes `silo-client` as its own submodule.
|
||||
|
||||
OndselSolver is forked from `github.com/FreeCAD/OndselSolver` to carry a Newton-Raphson convergence fix (see [KNOWN_ISSUES.md](KNOWN_ISSUES.md#12)).
|
||||
OndselSolver is forked from `github.com/FreeCAD/OndselSolver` to carry a Newton-Raphson convergence fix.
|
||||
|
||||
The ztools addon was removed from the build (#344) and archived to `reference/ztools/` (#345) as part of the UI/UX rework (#346). Its commands will be reimplemented through the KCSDK system.
|
||||
|
||||
@@ -1,332 +0,0 @@
|
||||
# Kindred Create Repository State Report
|
||||
|
||||
**Generated:** 2026-01-31
|
||||
**Branch:** main
|
||||
**Parent repo:** create-0070 @ `364a7057ef`
|
||||
**Submodules:**
|
||||
- ztools @ `8d1f195` (ztools-0065, main)
|
||||
- silo @ `c778825` (silo-0062, main)
|
||||
|
||||
---
|
||||
|
||||
## Recent Changes (This Session)
|
||||
|
||||
### Assembly Solver Fix
|
||||
- `610fd43` — PartDesign datum planes (including ZTools datums) now work
|
||||
correctly as joint references in Assembly. `findPlacement()` in
|
||||
`src/Mod/Assembly/UtilsAssembly.py` extracts geometry from
|
||||
`PartDesign::Plane` and `PartDesign::Point` objects instead of returning
|
||||
zero placements.
|
||||
|
||||
### ZTools Bug Fixes
|
||||
- `665bdb2` — Three fixes in the ztools submodule:
|
||||
- Removed `int()` wrapper from `getStandardButtons()` (Qt6/PySide6
|
||||
compatibility — `StandardButton` enum is not int-castable).
|
||||
- Guarded `_setup_ztools_viewprovider()` against C++ ViewProviders
|
||||
that lack a `Proxy` attribute (`PartDesign::Plane` uses
|
||||
`ViewProviderDatumPlane`, pure C++).
|
||||
- Changed `setEditorMode(prop, 2)` to `setPropertyStatus(prop, "Hidden")`
|
||||
for persistent attachment property hiding across save/reload.
|
||||
|
||||
### ZTools Parametric Datums via AttachExtension
|
||||
- `2c716b4` — ZTools datum planes now leverage FreeCAD's built-in
|
||||
`Part::AttachExtension` for automatic parametric updates. Instead of
|
||||
`MapMode = "Deactivated"` with manual placement, each datum type maps to a
|
||||
vanilla `MapMode` (`FlatFace`, `ThreePointsPlane`, `NormalToEdge`, etc.)
|
||||
with appropriate `AttachmentSupport` and `AttachmentOffset`. Datums update
|
||||
automatically when source geometry changes on recompute.
|
||||
|
||||
### Stylesheet Fixes (Uncommitted — Staged)
|
||||
- **Tree branch indicators**: Created `branch_closed.svg` and
|
||||
`branch_open.svg` in `images_dark-light/` with Catppuccin `#cdd6f4`
|
||||
chevrons. Added `QTreeView::branch` image rules for expand/collapse states.
|
||||
- **Spinbox/combobox arrows**: Synced all three QSS copies so the CSS
|
||||
border-triangle arrow fix (previously only in `resources/preferences/`)
|
||||
now applies at runtime via `src/Gui/Stylesheets/KindredCreate.qss`.
|
||||
- **Header clipping**: Added `min-height: 20px` to `QHeaderView::section`.
|
||||
- **QSS sync**: All four copies (`resources/preferences/`, `src/Gui/Stylesheets/`,
|
||||
`src/Gui/PreferencePacks/`, `mods/ztools/CatppuccinMocha/`) are now
|
||||
byte-identical. Merged dock widget padding and spreadsheet cell editor
|
||||
styling improvements that existed only in the Stylesheets copy.
|
||||
|
||||
### ZTools-PartDesign Merge (Uncommitted — Staged)
|
||||
- `_ZToolsPartDesignManipulator` in `mods/ztools/ztools/InitGui.py` uses
|
||||
`Gui.addWorkbenchManipulator()` to inject ZTools commands into PartDesign's
|
||||
C++ toolbars:
|
||||
- `ZTools_DatumCreator` + `ZTools_DatumManager` → "Part Design Helper Features"
|
||||
- `ZTools_EnhancedPocket` → "Part Design Modeling Features"
|
||||
- `ZTools_RotatedLinearPattern` → "Part Design Transformation Features"
|
||||
- Same commands also inserted into the Part Design menu after `PartDesign_Boolean`.
|
||||
|
||||
### Silo Enhancements (Uncommitted — Staged)
|
||||
- **File menu integration**: `SiloMenuManipulator` in `src/Mod/Create/InitGui.py`
|
||||
injects `Silo_New`, `Silo_Open`, `Silo_Save`, `Silo_Commit`, `Silo_Pull`,
|
||||
`Silo_Push`, and `Silo_BOM` into the File menu across all workbenches.
|
||||
- **Toolbar toggle**: `Silo_ToggleMode` checkable command swaps `Ctrl+O/S/N`
|
||||
between standard FreeCAD file commands and Silo equivalents. Appended to the
|
||||
global File toolbar via the manipulator.
|
||||
- **SSL certificate browsing**: Settings dialog now includes a file browser for
|
||||
custom CA certificates (`SslCertPath` preference). `_get_ssl_context()` loads
|
||||
the custom cert before system CAs.
|
||||
- **BOM integration**: Upstream BOM feature (`Silo_BOM` command with tabbed
|
||||
dialog — BOM + Where Used) merged with local changes and added to the
|
||||
Create File menu manipulator.
|
||||
|
||||
---
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
create-0070/ Kindred Create (FreeCAD 1.0+ fork)
|
||||
├── src/
|
||||
│ ├── Mod/
|
||||
│ │ ├── Assembly/ Assembly solver (OndselSolver)
|
||||
│ │ ├── PartDesign/ Part modeling (C++ workbench)
|
||||
│ │ ├── Sketcher/ 2D constraint sketcher
|
||||
│ │ ├── Create/ Kindred bootstrap module (Python)
|
||||
│ │ │ └── InitGui.py Loads ztools+silo, installs manipulators
|
||||
│ │ └── ... Other FreeCAD modules
|
||||
│ └── Gui/
|
||||
│ ├── Stylesheets/ QSS themes + arrow/branch SVGs
|
||||
│ ├── PreferencePacks/ Preference pack bundles
|
||||
│ └── WorkbenchManipulatorPython.cpp Menu/toolbar injection API
|
||||
├── mods/
|
||||
│ ├── ztools/ [submodule] ztools-0065
|
||||
│ │ └── ztools/
|
||||
│ │ ├── InitGui.py ZToolsWorkbench + PartDesign manipulator
|
||||
│ │ └── ztools/
|
||||
│ │ ├── commands/ Datum, pattern, pocket, assembly, spreadsheet
|
||||
│ │ ├── datums/core.py Datum creation with AttachExtension
|
||||
│ │ └── resources/ Icons, theme utilities
|
||||
│ └── silo/ [submodule] silo-0062
|
||||
│ └── pkg/freecad/
|
||||
│ ├── InitGui.py SiloWorkbench
|
||||
│ └── silo_commands.py 12 commands + SiloClient API
|
||||
└── resources/
|
||||
└── preferences/KindredCreate/ Canonical QSS + preference pack
|
||||
```
|
||||
|
||||
### Integration Flow
|
||||
|
||||
```
|
||||
FreeCAD startup
|
||||
└─ src/Mod/Create/InitGui.py exec()
|
||||
├─ exec(mods/ztools/ztools/InitGui.py)
|
||||
│ ├─ registers ZToolsWorkbench
|
||||
│ └─ installs _ZToolsPartDesignManipulator (global)
|
||||
├─ exec(mods/silo/pkg/freecad/InitGui.py)
|
||||
│ └─ registers SiloWorkbench
|
||||
└─ QTimer.singleShot(2000):
|
||||
├─ _setup_silo_menu()
|
||||
│ └─ installs SiloMenuManipulator (global)
|
||||
│ ├─ modifyMenuBar: Silo commands in File menu
|
||||
│ └─ modifyToolBars: Silo_ToggleMode in File toolbar
|
||||
├─ _check_silo_first_start()
|
||||
└─ _setup_silo_activity_panel()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Submodule Status
|
||||
|
||||
### ztools (ztools-0065)
|
||||
|
||||
| Commit | Description |
|
||||
|--------|-------------|
|
||||
| `8d1f195` | Add PartDesign WorkbenchManipulator and sync Catppuccin theme |
|
||||
| `005348b` | Leverage FreeCAD AttachExtension for parametric datum updates |
|
||||
| `0e95d1c` | Fix Qt6 StandardButton TypeError and C++ ViewProvider Proxy errors |
|
||||
| `98bd444` | Fix workbench init and spreadsheet syntax errors |
|
||||
|
||||
**Custom commands**: 9 registered
|
||||
- `ZTools_DatumCreator`, `ZTools_DatumManager`
|
||||
- `ZTools_RotatedLinearPattern`
|
||||
- `ZTools_EnhancedPocket`
|
||||
- `ZTools_AssemblyLinearPattern`, `ZTools_AssemblyPolarPattern`
|
||||
- `ZTools_SpreadsheetStyle{Bold,Italic,Underline}`, `ZTools_SpreadsheetAlign{Left,Center,Right}`, `ZTools_Spreadsheet{BgColor,TextColor,QuickAlias}`
|
||||
|
||||
**Datum types supported**: offset_from_face, offset_from_plane, midplane,
|
||||
3_points, normal_to_edge, angled, tangent_to_cylinder
|
||||
|
||||
### silo (silo-0062)
|
||||
|
||||
| Commit | Description |
|
||||
|--------|-------------|
|
||||
| `c778825` | Add Silo mode toggle, SSL cert browsing, and BOM menu integration |
|
||||
| `8c06899` | (upstream) Various fixes |
|
||||
| `bce7d5a` | Add BOM handling and routes to API and web UI |
|
||||
| `3a79d89` | feat: add BOM system with API, database repository, and FreeCAD command |
|
||||
| `8e44ed2` | Fix SIGSEGV: defer document open after dialog close |
|
||||
|
||||
**FreeCAD commands**: 12 registered
|
||||
- `Silo_Open`, `Silo_New`, `Silo_Save`, `Silo_Commit`
|
||||
- `Silo_Pull`, `Silo_Push`, `Silo_Info`, `Silo_BOM`
|
||||
- `Silo_TagProjects`, `Silo_Rollback`, `Silo_SetStatus`
|
||||
- `Silo_Settings`, `Silo_ToggleMode`
|
||||
|
||||
**API surface**: 38 REST routes covering items, revisions, files, BOM,
|
||||
projects, schemas, and Odoo integration stubs. See
|
||||
`mods/silo/docs/REPOSITORY_STATUS.md` for full route table.
|
||||
|
||||
**BOM API methods** (new):
|
||||
- `get_bom()`, `get_bom_expanded()`, `get_bom_where_used()`
|
||||
- `add_bom_entry()`, `update_bom_entry()`, `delete_bom_entry()`
|
||||
|
||||
---
|
||||
|
||||
## Potential Issues
|
||||
|
||||
### Critical
|
||||
|
||||
1. **Three QSS copies can drift again.** The canonical source is
|
||||
`resources/preferences/KindredCreate/KindredCreate.qss`. The other copies
|
||||
(`src/Gui/Stylesheets/`, `src/Gui/PreferencePacks/`, `mods/ztools/CatppuccinMocha/`)
|
||||
must be kept in sync manually. Consider a build step or symlinks to
|
||||
eliminate duplication.
|
||||
|
||||
2. **WorkbenchManipulator command registration timing.** The
|
||||
`_ZToolsPartDesignManipulator` appends commands by name (e.g.
|
||||
`ZTools_DatumCreator`). If the ZTools workbench has not been initialized
|
||||
(first activation) when the user switches to PartDesign, the commands may
|
||||
not be registered yet. The `Create/InitGui.py` `exec()` loads the
|
||||
workbench class but `Initialize()` only runs on first activation. The
|
||||
manipulator API tolerates missing commands silently (toolbar append
|
||||
returns without error), but the buttons won't appear until ZTools
|
||||
initializes. Mitigation: force-activate ZToolsWorkbench during Create
|
||||
module load, or defer manipulator installation.
|
||||
|
||||
3. **Silo toggle mode shortcut persistence.** `_swap_shortcuts()` stores
|
||||
original shortcuts in a module-level dict (`_original_shortcuts`). If
|
||||
FreeCAD crashes with Silo mode ON, the original shortcuts are lost and
|
||||
standard commands will have no keyboard shortcuts on next launch. Consider
|
||||
persisting original shortcuts to preferences.
|
||||
|
||||
### High
|
||||
|
||||
4. **Silo has no authentication.** All API endpoints are publicly accessible.
|
||||
Required before multi-user deployment. See
|
||||
`mods/silo/docs/REPOSITORY_STATUS.md` for full list.
|
||||
|
||||
5. **No unit tests for silo FreeCAD commands or ztools.** Python code has zero
|
||||
test coverage. The Go backend also lacks tests per the silo status report.
|
||||
|
||||
6. **Assembly solver `findPlacement()` geometry extraction is minimal.** The
|
||||
fix at `UtilsAssembly.py:1006` extracts placement from `obj.Shape.Faces[0]`
|
||||
for `PartDesign::Plane`. This works for planar datums but does not handle
|
||||
edge cases like empty shapes or non-planar datum objects.
|
||||
|
||||
### Medium
|
||||
|
||||
7. **`Silo_BOM` depends on `get_tracked_object()`** which looks for a
|
||||
`SiloPartNumber` property on document objects. Documents not registered
|
||||
with Silo show a warning dialog. The UX could be improved with a
|
||||
one-click registration flow from the BOM dialog.
|
||||
|
||||
8. **`_ZToolsPartDesignManipulator.modifyMenuBar()` inserts after
|
||||
`PartDesign_Boolean`.** If upstream FreeCAD renames or removes this
|
||||
command, the menu insertions silently fail. The toolbar appends (by
|
||||
toolbar name) are more robust.
|
||||
|
||||
9. **ZTools `plane_tangent_to_cylinder` falls back to manual placement**
|
||||
because the TangentPlane MapMode requires a vertex reference not currently
|
||||
collected by the UI. This is the only datum type that does not benefit
|
||||
from automatic parametric updates.
|
||||
|
||||
10. **Silo `delete_bom_entry()` uses raw `urllib.request`** instead of the
|
||||
`_request()` helper method on `SiloClient`. This bypasses error
|
||||
normalization. Should be refactored to use `self._request("DELETE", ...)`.
|
||||
|
||||
---
|
||||
|
||||
## Feature Stubs and TODOs
|
||||
|
||||
### From silo REPOSITORY_STATUS
|
||||
|
||||
| Feature | Status | Location |
|
||||
|---------|--------|----------|
|
||||
| Odoo ERP integration | Stub (returns "not yet implemented") | `internal/odoo/` |
|
||||
| Part number date segments | Broken (`formatDate()` returns error) | `internal/partnum/generator.go:102` |
|
||||
| Location/Inventory APIs | Tables exist, no handlers | `migrations/001_initial.sql` |
|
||||
| File locking | Not implemented | — |
|
||||
| Authentication/Authorization | Not implemented | — |
|
||||
| CSRF protection | Not implemented | Web UI only |
|
||||
| CSV import transaction rollback | Not implemented | `bom_handlers.go` |
|
||||
|
||||
### From ztools
|
||||
|
||||
| Feature | Status | Location |
|
||||
|---------|--------|----------|
|
||||
| Tangent-to-cylinder attachment | Manual fallback (no vertex ref) | `datums/core.py` |
|
||||
| Angled datum live editing | AttachmentOffset rotation not updated in panel | `datum_viewprovider.py` |
|
||||
| Assembly pattern undo support | Not implemented | `assembly_pattern_commands.py` |
|
||||
|
||||
### From Create integration plan
|
||||
|
||||
| Phase | Feature | Status |
|
||||
|-------|---------|--------|
|
||||
| 1 | Addon auto-loading | Done (`src/Mod/Create/InitGui.py`) |
|
||||
| 2 | Enhanced Pocket as C++ feature | Not started |
|
||||
| 3 | Datum C++ helpers | Not started (Python AttachExtension approach used instead) |
|
||||
| 4 | Theme system refinement | Partially done (QSS synced, not moved to Create module) |
|
||||
| 5 | Silo deep integration | Done (manipulator-based menu/toolbar injection) |
|
||||
| 6 | Build system integration | Not started |
|
||||
|
||||
---
|
||||
|
||||
## File Change Summary (Uncommitted)
|
||||
|
||||
### Parent repo (create-0070)
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `resources/preferences/KindredCreate/KindredCreate.qss` | Branch indicators, header min-height, dock/actiongroup improvements, spreadsheet cell editor |
|
||||
| `src/Gui/Stylesheets/KindredCreate.qss` | Synced with canonical |
|
||||
| `src/Gui/PreferencePacks/KindredCreate/KindredCreate.qss` | Synced with canonical |
|
||||
| `src/Gui/Stylesheets/images_dark-light/branch_closed.svg` | New: right-pointing chevron |
|
||||
| `src/Gui/Stylesheets/images_dark-light/branch_open.svg` | New: down-pointing chevron |
|
||||
| `src/Mod/Create/InitGui.py` | Expanded SiloMenuManipulator (BOM, full commands, toolbar toggle) |
|
||||
| `mods/silo` | Submodule pointer updated |
|
||||
| `mods/ztools` | Submodule pointer updated |
|
||||
|
||||
### ztools submodule (committed + pushed)
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `ztools/InitGui.py` | Added `_ZToolsPartDesignManipulator` |
|
||||
| `CatppuccinMocha/CatppuccinMocha.qss` | Synced with canonical KindredCreate.qss |
|
||||
|
||||
### silo submodule (committed + pushed)
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `pkg/freecad/silo_commands.py` | SSL cert browsing, `Silo_ToggleMode`, BOM merge |
|
||||
| `pkg/freecad/InitGui.py` | Added `Silo_ToggleMode` to toolbar |
|
||||
|
||||
---
|
||||
|
||||
## Silo Integration Path
|
||||
|
||||
Based on `mods/silo/docs/REPOSITORY_STATUS.md` and the existing
|
||||
`docs/INTEGRATION_PLAN.md`, the integration path forward is:
|
||||
|
||||
### Completed
|
||||
- Addon auto-loading via `src/Mod/Create/InitGui.py`
|
||||
- Global File menu injection via `WorkbenchManipulator`
|
||||
- Toolbar toggle for Silo mode (shortcut swapping)
|
||||
- SSL certificate configuration for internal CAs
|
||||
- BOM command integrated into File menu
|
||||
|
||||
### Next Steps
|
||||
1. **Authentication** — LDAP/FreeIPA integration for multi-user. Silo server
|
||||
needs auth middleware; FreeCAD client needs credential storage in preferences.
|
||||
2. **BOM-Assembly bridge** — Auto-populate Silo BOM from FreeCAD Assembly
|
||||
component links. When a user saves an assembly, extract child part numbers
|
||||
from `Assembly_InsertLink` objects and sync to Silo BOM.
|
||||
3. **File locking** — Pessimistic locks on checkout (`Silo_Open`) to prevent
|
||||
concurrent edits. Requires server-side lock table and client-side
|
||||
lock-status display.
|
||||
4. **Status bar integration** — Show current Silo item part number, revision,
|
||||
and sync status in FreeCAD's status bar. Use
|
||||
`FreeCADGui.getMainWindow().statusBar()`.
|
||||
5. **Build system** — CMake install rules for `mods/` submodules so `.deb`
|
||||
packages include ztools and silo without manual intervention.
|
||||
@@ -10,7 +10,6 @@
|
||||
- [Installation](./guide/installation.md)
|
||||
- [Building from Source](./guide/building.md)
|
||||
- [Workbenches](./guide/workbenches.md)
|
||||
- [ztools](./guide/ztools.md)
|
||||
- [Silo](./guide/silo.md)
|
||||
- [Document Templates](./guide/templates.md)
|
||||
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
# ztools
|
||||
|
||||
ztools is a pure-Python FreeCAD workbench that consolidates part design, assembly, and sketcher tools into a single unified interface. It is the **default workbench** when Kindred Create launches.
|
||||
|
||||
- **Submodule path:** `mods/ztools/`
|
||||
- **Source:** `git.kindred-systems.com/forbes/ztools`
|
||||
- **Stats:** 6,400+ lines of code, 24+ command classes, 33 custom icons, 17 toolbars
|
||||
|
||||
## Commands
|
||||
|
||||
### Datum Creator (`ZTools_DatumCreator`)
|
||||
|
||||
Creates datum geometry (planes, axes, points) with 16 creation modes. The task panel auto-detects the geometry type from your selection and offers appropriate modes. Supports custom naming, spreadsheet linking, and body- or document-level creation.
|
||||
|
||||
### Datum Manager (`ZTools_DatumManager`)
|
||||
|
||||
Manages existing datums. (Stub — planned for Phase 1, Q1 2026.)
|
||||
|
||||
### Enhanced Pocket (`ZTools_EnhancedPocket`)
|
||||
|
||||
Extends FreeCAD's Pocket feature with **Flip Side to Cut** — a SOLIDWORKS-style feature that removes material *outside* the sketch profile rather than inside. Uses a Boolean Common operation internally. Supports all standard pocket types: Dimension, Through All, To First, Up To Face, Two Dimensions. Taper angle is supported for standard pockets (disabled for flipped).
|
||||
|
||||
### Rotated Linear Pattern (`ZTools_RotatedLinearPattern`)
|
||||
|
||||
Creates a linear pattern with incremental rotation per instance. Configure direction, spacing, number of occurrences, and cumulative or per-instance rotation. Source components are automatically hidden.
|
||||
|
||||
### Assembly Linear Pattern (`ZTools_AssemblyLinearPattern`)
|
||||
|
||||
Creates linear patterns of assembly components. Supports multi-component selection, direction vectors, total length or spacing modes, and creation as Links (recommended) or copies. Auto-detects the parent assembly.
|
||||
|
||||
### Assembly Polar Pattern (`ZTools_AssemblyPolarPattern`)
|
||||
|
||||
Creates polar (circular) patterns of assembly components. Supports custom or preset axes (X/Y/Z), full circle or custom angle, center point definition, and creation as Links or copies.
|
||||
|
||||
### Spreadsheet Formatting (9 commands)
|
||||
|
||||
| Command | Action |
|
||||
|---------|--------|
|
||||
| `ZTools_SpreadsheetStyleBold` | Toggle bold |
|
||||
| `ZTools_SpreadsheetStyleItalic` | Toggle italic |
|
||||
| `ZTools_SpreadsheetStyleUnderline` | Toggle underline |
|
||||
| `ZTools_SpreadsheetAlignLeft` | Left align |
|
||||
| `ZTools_SpreadsheetAlignCenter` | Center align |
|
||||
| `ZTools_SpreadsheetAlignRight` | Right align |
|
||||
| `ZTools_SpreadsheetBgColor` | Background color picker |
|
||||
| `ZTools_SpreadsheetTextColor` | Text color picker |
|
||||
| `ZTools_SpreadsheetQuickAlias` | Auto-create aliases from row/column labels |
|
||||
|
||||
## Datum creation modes
|
||||
|
||||
### Planes (7 modes)
|
||||
|
||||
| Mode | Description | Input |
|
||||
|------|-------------|-------|
|
||||
| Offset from Face | Offsets a planar face along its normal | Face + distance (mm) |
|
||||
| Offset from Plane | Offsets an existing datum plane | Datum plane + distance (mm) |
|
||||
| Midplane | Plane halfway between two parallel faces | Two parallel faces |
|
||||
| 3 Points | Plane through three non-collinear points | Three vertices |
|
||||
| Normal to Edge | Plane perpendicular to an edge at a parameter location | Edge + parameter (0.0–1.0) |
|
||||
| Angled | Rotates a plane about an edge by a specified angle | Face + edge + angle (degrees) |
|
||||
| Tangent to Cylinder | Plane tangent to a cylindrical face at an angular position | Cylindrical face + angle (degrees) |
|
||||
|
||||
### Axes (4 modes)
|
||||
|
||||
| Mode | Description | Input |
|
||||
|------|-------------|-------|
|
||||
| 2 Points | Axis through two points | Two vertices |
|
||||
| From Edge | Axis along a linear edge | Linear edge |
|
||||
| Cylinder Center | Axis along the centerline of a cylinder | Cylindrical face |
|
||||
| Plane Intersection | Axis at the intersection of two planes | Two non-parallel planes |
|
||||
|
||||
### Points (5 modes)
|
||||
|
||||
| Mode | Description | Input |
|
||||
|------|-------------|-------|
|
||||
| At Vertex | Point at a vertex location | Vertex |
|
||||
| XYZ Coordinates | Point at explicit coordinates | x, y, z (mm) |
|
||||
| On Edge | Point at a location along an edge | Edge + parameter (0.0–1.0) |
|
||||
| Face Center | Point at the center of mass of a face | Face |
|
||||
| Circle Center | Point at the center of a circular or arc edge | Circular edge |
|
||||
|
||||
## PartDesign injection
|
||||
|
||||
ztools registers a `_ZToolsPartDesignManipulator` that hooks into the PartDesign workbench at startup. This injects the following commands into PartDesign's toolbars and menus:
|
||||
|
||||
| PartDesign toolbar | Injected command |
|
||||
|--------------------|-----------------|
|
||||
| Part Design Helper Features | `ZTools_DatumCreator`, `ZTools_DatumManager` |
|
||||
| Part Design Modeling Features | `ZTools_EnhancedPocket` |
|
||||
| Part Design Transformation Features | `ZTools_RotatedLinearPattern` |
|
||||
|
||||
The manipulator is registered in `InitGui.py` when the Create bootstrap module loads addon workbenches.
|
||||
|
||||
## Directory structure
|
||||
|
||||
```
|
||||
mods/ztools/
|
||||
├── ztools/ztools/
|
||||
│ ├── InitGui.py # Workbench registration + manipulator
|
||||
│ ├── Init.py # Console initialization
|
||||
│ ├── commands/
|
||||
│ │ ├── datum_commands.py # DatumCreator + DatumManager
|
||||
│ │ ├── datum_viewprovider.py # ViewProvider + edit panel
|
||||
│ │ ├── pocket_commands.py # EnhancedPocket + FlippedPocket
|
||||
│ │ ├── pattern_commands.py # RotatedLinearPattern
|
||||
│ │ ├── assembly_pattern_commands.py # Linear + Polar assembly patterns
|
||||
│ │ └── spreadsheet_commands.py # 9 formatting commands
|
||||
│ ├── datums/
|
||||
│ │ └── core.py # 16 datum creation functions
|
||||
│ └── resources/ # Icons and theme
|
||||
└── CatppuccinMocha/ # Theme preference pack
|
||||
```
|
||||
|
||||
## Internal properties
|
||||
|
||||
ztools stores metadata on feature objects using these properties (preserved for backward compatibility):
|
||||
|
||||
| Property | Purpose |
|
||||
|----------|---------|
|
||||
| `ZTools_Type` | Feature type identifier |
|
||||
| `ZTools_Params` | JSON creation parameters |
|
||||
| `ZTools_SourceRefs` | JSON source geometry references |
|
||||
|
||||
## Known gaps
|
||||
|
||||
- Datum Manager is a stub — full implementation planned for Q1 2026
|
||||
- Datum parameter changes don't recalculate from source geometry yet
|
||||
- Enhanced Pocket taper angle is disabled for flipped pockets
|
||||
|
||||
## Further reading
|
||||
|
||||
- `mods/ztools/KINDRED_INTEGRATION.md` — integration architecture and migration options
|
||||
- `mods/ztools/ROADMAP.md` — phased development plan (Q1–Q4 2026)
|
||||
Reference in New Issue
Block a user