refactor: remove LibreOffice Calc extension from server repo

Move pkg/calc/ to its own repository (19 files, ~4,600 lines):
- silo_calc_component.py, sync_engine.py, dialogs.py, push/pull
- AI client, completion wizard, settings, sheet format
- Addons.xcu, manifest.xml, description.xml, tests

Replace docs/CALC_EXTENSION.md with redirect to silo-calc repo
and reference to server-side ODS export endpoints.

The Calc extension now lives at:
https://git.kindred-systems.com/kindred/silo-calc
This commit is contained in:
Forbes
2026-02-06 16:19:15 -06:00
parent 503c3d1831
commit 60fa48285d
20 changed files with 2 additions and 4590 deletions

View File

@@ -1,191 +1,10 @@
# LibreOffice Calc Extension
**Last Updated:** 2026-02-01
---
## Overview
The Silo Calc extension (`silo-calc.oxt`) is a LibreOffice Calc add-on that
connects project BOM spreadsheets directly to the Silo parts database.
Engineers work in their familiar spreadsheet environment while Silo handles
part number generation, revision tracking, and data synchronization.
The extension is a Python UNO component packaged as an `.oxt` file. It uses
only stdlib (`urllib`, `json`, `ssl`) -- no pip dependencies. The same
`SiloClient` pattern and auth flow from the FreeCAD workbench is reused.
---
## Architecture
```
Engineer's workstation Silo server (silod)
+--------------------------+ +------------------------+
| LibreOffice Calc | | Go API server |
| +----------------------+ | REST | +--------------------+ |
| | Silo Extension (.oxt)| <--------> | | ODS endpoints | |
| | - Pull/Push BOM | | API | | (internal/ods) | |
| | - Completion Wizard | | | +--------------------+ |
| | - AI Describe | | | | |
| +----------------------+ | | +--------------------+ |
| UNO API | cells | | | PostgreSQL | |
| +----------------------+ | | +--------------------+ |
| | Project Workbook | | +------------------------+
| | ~/projects/sheets/ | |
| | 3DX10/3DX10.ods | |
+--------------------------+
Extension also calls OpenRouter AI API directly for
description generation (does not go through silod).
```
---
## Extension Structure
```
pkg/calc/
META-INF/manifest.xml Extension manifest
description.xml Extension metadata (id, version, publisher)
description/description_en.txt English description
Addons.xcu Toolbar + menu registration
ProtocolHandler.xcu Dispatch protocol registration
silo_calc_component.py UNO DispatchProvider entry point
pythonpath/silo_calc/
__init__.py
ai_client.py OpenRouter API client
client.py SiloClient (HTTP, auth, SSL)
completion_wizard.py 3-step new item wizard
dialogs.py UNO dialog toolkit wrappers
project_files.py Local project file management
pull.py Sheet population from server
push.py Sheet changes back to server
settings.py JSON settings (~/.config/silo/calc-settings.json)
sheet_format.py Column layout constants
sync_engine.py Row hashing, classification, diff
tests/
test_basics.py 31 unit tests (no UNO/network required)
```
---
## Toolbar Commands
| Button | Command | Description |
|--------|---------|-------------|
| Login | `SiloLogin` | Username/password dialog, creates API token |
| Pull BOM | `SiloPullBOM` | Assembly picker -> expanded BOM -> populates sheet |
| Pull Project | `SiloPullProject` | Project picker -> all project items -> multi-sheet workbook |
| Push | `SiloPush` | Classifies rows -> creates/updates items -> auto-tags project |
| Add Item | `SiloAddItem` | Completion wizard (category -> description -> fields) |
| Refresh | `SiloRefresh` | Re-pull (placeholder) |
| Settings | `SiloSettings` | API URL, token, SSL, OpenRouter config |
| AI Describe | `SiloAIDescription` | AI description from seller description |
---
## BOM Sheet Format
28 columns total: 11 visible core, 13 hidden properties, 4 hidden sync tracking.
### Visible Columns
| Col | Header | Notes |
|-----|--------|-------|
| A | Item | Assembly/section header |
| B | Level | BOM depth (0=top) |
| C | Source | M=manufactured, P=purchased |
| D | PN | Part number (read-only for existing) |
| E | Description | Required for new items |
| F | Seller Description | Vendor catalog text |
| G | Unit Cost | Currency |
| H | QTY | Decimal quantity |
| I | Ext Cost | Formula =G*H (not stored) |
| J | Sourcing Link | URL |
| K | Schema | Schema name |
### Hidden Property Columns (L-X)
Manufacturer, Manufacturer PN, Supplier, Supplier PN, Lead Time, Min Order
Qty, Lifecycle Status, RoHS, Country of Origin, Material, Finish, Notes,
Long Description. Populated from revision properties, collapsed by default.
### Hidden Sync Columns (Y-AB)
`_silo_row_hash` (SHA-256), `_silo_row_status`, `_silo_updated_at`,
`_silo_parent_pn`. Used for change detection and conflict resolution.
### Row Status Colors
| Status | Color | Hex |
|--------|-------|-----|
| synced | light green | #C6EFCE |
| modified | light yellow | #FFEB9C |
| new | light blue | #BDD7EE |
| error | light red | #FFC7CE |
| conflict | orange | #F4B084 |
---
## Completion Wizard
Three-step guided workflow for adding new BOM rows:
1. **Category** -- select from schema categories (F01-X08)
2. **Description** -- required text, with AI generation offer when blank
3. **Common fields** -- sourcing type, unit cost, quantity, sourcing link
If a manually entered PN already exists in the database, the PN Conflict
Resolution dialog offers: use existing item, auto-generate new PN, or cancel.
New items are automatically tagged with the workbook's project code.
---
## OpenRouter AI Integration
The extension calls the OpenRouter API (OpenAI-compatible) to generate
standardized part descriptions from verbose seller descriptions. This is
useful because seller descriptions are typically detailed catalog text while
BOM descriptions need to be concise (max 60 chars, title case, component
type first, standard abbreviations).
### Configuration
Settings dialog fields (or `OPENROUTER_API_KEY` env var):
- **API Key** -- OpenRouter bearer token (masked in UI)
- **AI Model** -- default `openai/gpt-4.1-nano`
- **AI Instructions** -- customizable system prompt
### Workflow
1. Paste seller description into column F
2. Click "AI Describe" on toolbar
3. Review side-by-side dialog (seller text left, AI result right)
4. Edit if needed, click Accept
5. Description written to column E
The AI client (`ai_client.py`) is designed for reuse. The generic
`chat_completion()` function can be called by future features (price
analysis, sourcing assistance) without modification.
---
The Silo Calc extension has been moved to its own repository: [silo-calc](https://git.kindred-systems.com/kindred/silo-calc).
## Server-Side ODS Support
Pure Go ODS library at `internal/ods/` for server-side spreadsheet generation.
No headless LibreOffice dependency -- ODS is a ZIP of XML files.
### Library (`internal/ods/`)
- `ods.go` -- types: Workbook, Sheet, Column, Row, Cell, CellType
- `writer.go` -- generates valid ODS ZIP archives
- `reader.go` -- parses ODS back to Go structs
- `ods_test.go` -- 10 round-trip tests
### ODS Endpoints
The server-side ODS library (`internal/ods/`) and ODS endpoints remain in this repository. See `docs/SPECIFICATION.md` Section 11 for the full endpoint listing.
| Method | Path | Description |
|--------|------|-------------|
@@ -195,61 +14,3 @@ No headless LibreOffice dependency -- ODS is a ZIP of XML files.
| GET | `/api/items/{pn}/bom/export.ods` | BOM as formatted ODS |
| GET | `/api/projects/{code}/sheet.ods` | Multi-sheet project workbook |
| POST | `/api/sheets/diff` | Upload ODS, return JSON diff |
---
## Build and Install
```makefile
make build-calc-oxt # zip pkg/calc/ into silo-calc.oxt
make install-calc # unopkg add silo-calc.oxt
make uninstall-calc # unopkg remove io.kindredsystems.silo.calc
make test-calc # python3 -m unittest (31 tests)
```
---
## Implementation Status
| Component | Status | Notes |
|-----------|--------|-------|
| Extension skeleton | Done | manifest, description, Addons.xcu, ProtocolHandler.xcu |
| SiloClient | Done | HTTP client adapted from FreeCAD workbench |
| Settings | Done | JSON persistence, env var fallbacks |
| Login dialog | Done | Two-step username/password |
| Settings dialog | Done | API URL, token, SSL, OpenRouter fields |
| Pull BOM | Done | Full column set, hidden groups, hash tracking |
| Pull Project | Done | Items sheet + BOM sheet |
| Push | Done | Create/update, auto project tagging, conflict detection |
| Completion wizard | Done | 3-step with PN conflict resolution |
| AI description | Done | OpenRouter client, review dialog, toolbar button |
| Refresh | Stub | Placeholder only |
| Go ODS library | Done | Writer, reader, 10 round-trip tests |
| ODS endpoints | Done | 6 handlers registered |
| Makefile targets | Done | build, install, uninstall, test, clean |
### Known Issues
- Refresh command is a placeholder (shows "coming soon")
- No integration tests with a running Silo instance yet
- `completion_wizard.py` uses simple input boxes instead of proper list dialogs
- Push does not yet handle BOM relationship creation (item fields only)
---
## Testing
31 unit tests in `pkg/calc/tests/test_basics.py`, runnable without UNO or
network access:
- TestSheetFormat (7) -- column indices, headers, sheet type detection
- TestSyncEngine (9) -- hashing, classification, diff, conflict detection
- TestSettings (3) -- load/save/auth
- TestProjectFiles (3) -- path resolution, read/write
- TestAIClient (9) -- constants, configuration, error handling
```
$ python3 -m unittest pkg/calc/tests/test_basics.py -v
Ran 31 tests in 0.031s
OK
```