Adopt KiCad 10-first CAD runtime stack
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
- Standards injection: Agent OS (standards versionnés + profils) citeturn0search3
|
||||
- Role workflows + gates: BMAD-METHOD
|
||||
- Tool-first runtime (local): Agent Zero
|
||||
- Interop tools: MCP (ex: kicad-sch-mcp) citeturn0search9
|
||||
- Interop tools: MCP local en `stdio` via le runtime `kicad-mcp`
|
||||
|
||||
Le repo fournit :
|
||||
- `specs/` pour la source de vérité
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Design Blocks (KiCad 9) + registry
|
||||
# Design Blocks (KiCad 10) + registry
|
||||
|
||||
Les briques se stockent sous `hardware/blocks/**.kicad_block/` (avec un `.kicad_sch` + un `.json` metadata).
|
||||
Un registry est généré automatiquement : `hardware/blocks/REGISTRY.md`.
|
||||
|
||||
Référence : KiCad 9 Design Blocks. citeturn0search8
|
||||
Référence : KiCad 10 Design Blocks. citeturn0search8
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Hardware quickstart (KiCad)
|
||||
# Hardware quickstart (KiCad 10)
|
||||
|
||||
## Prérequis
|
||||
- KiCad 9 installé (inclut `kicad-cli`)
|
||||
- KiCad 10 installé ou une image Docker KiCad 10 compatible (inclut `kicad-cli`)
|
||||
- Python 3.11+
|
||||
- (optionnel) venv
|
||||
|
||||
|
||||
@@ -1,51 +1,6 @@
|
||||
# IA & KiCad en local (bulk edits + analyse)
|
||||
# IA & KiCad en local
|
||||
|
||||
Ce template privilégie **deux couches** complémentaires :
|
||||
Source canonique: `../../docs/KICAD_AI_LOCAL.md`
|
||||
|
||||
1) **schops** (ce repo) : un CLI simple, traçable, qui fait
|
||||
- exports déterministes via `kicad-cli` (ERC / BOM / netlist)
|
||||
- bulk edits via `kicad-sch-api` (fields / footprints / labels)
|
||||
- packaging de Design Blocks KiCad 9
|
||||
|
||||
2) **MCP (optionnel)** : si tu utilises un client IA compatible MCP, tu peux exposer
|
||||
des opérations KiCad comme un “tool server” local.
|
||||
|
||||
## 1) schops
|
||||
|
||||
Install :
|
||||
```bash
|
||||
python -m venv .venv && source .venv/bin/activate
|
||||
pip install -r tools/hw/schops/requirements.txt
|
||||
```
|
||||
|
||||
Workflow typique :
|
||||
```bash
|
||||
python tools/hw/schops/schops.py snapshot --schematic <...> --name before.json
|
||||
python tools/hw/schops/schops.py apply-fields --schematic <...> --rules hardware/rules/fields.yaml
|
||||
python tools/hw/schops/schops.py apply-footprints --schematic <...> --map hardware/rules/footprints.csv
|
||||
python tools/hw/schops/schops.py rename-nets --schematic <...> --rules hardware/rules/nets_rename.yaml
|
||||
python tools/hw/schops/schops.py erc --schematic <...>
|
||||
python tools/hw/schops/schops.py bom --schematic <...> --exclude-dnp
|
||||
python tools/hw/schops/schops.py netlist --schematic <...>
|
||||
python tools/hw/schops/schops.py snapshot --schematic <...> --name after.json
|
||||
```
|
||||
|
||||
Tous les rapports vont dans `artifacts/hw/<timestamp>/`.
|
||||
|
||||
## 2) MCP KiCad (optionnel)
|
||||
|
||||
Si ton client IA supporte MCP, installe un serveur MCP KiCad basé sur `kicad-sch-api` :
|
||||
|
||||
```bash
|
||||
pip install kicad-sch-api kicad-sch-mcp
|
||||
|
||||
# démarre le serveur (stdio)
|
||||
kicad-sch-mcp
|
||||
```
|
||||
|
||||
### Convention d’intégration recommandée
|
||||
|
||||
- **Édits mécaniques** → `schops` (backup + report)
|
||||
- **Création de schéma / placement** (si besoin) → MCP + validation ensuite via `schops` + `kicad-cli`
|
||||
|
||||
> Même avec MCP, garde `kicad-cli` en “source de vérité” pour ERC/BOM/netlist.
|
||||
Le runtime MCP supporté n’est plus décrit localement dans ce miroir pour éviter les divergences.
|
||||
Utiliser le launcher `Kill_LIFE/tools/hw/run_kicad_mcp.sh` et la procédure de `../../docs/MCP_SETUP.md`.
|
||||
|
||||
@@ -1,35 +1,6 @@
|
||||
# MCP setup (KiCad)
|
||||
|
||||
## Option A — Schematic MCP (recommended)
|
||||
`kicad-sch-api` inclut un serveur MCP : `kicad-sch-mcp`. citeturn0search9
|
||||
Source canonique: `../../docs/MCP_SETUP.md`
|
||||
|
||||
Installation :
|
||||
```bash
|
||||
pip install kicad-sch-api
|
||||
# ou via uv
|
||||
# uv tool install kicad-sch-mcp
|
||||
```
|
||||
|
||||
Lancer le serveur (dans le repo) :
|
||||
```bash
|
||||
kicad-sch-mcp
|
||||
```
|
||||
|
||||
Exemple (Claude Desktop) — à adapter selon ton OS :
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"kicad_schematic": {
|
||||
"command": "kicad-sch-mcp",
|
||||
"args": []
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Option B — KiCad “live/PCB” MCP (expérimental)
|
||||
Il existe des serveurs MCP orientés PCB / IPC API (dépend de ta version KiCad et du serveur choisi). citeturn0search1turn0search16
|
||||
|
||||
Dans ce repo, l’approche “robuste” reste :
|
||||
- bulk edits schéma via `kicad-sch-api`
|
||||
- exports/DRC via `kicad-cli`
|
||||
Ce dépôt miroir ne maintient plus une copie indépendante de la procédure MCP.
|
||||
Le chemin supporté reste le launcher `Kill_LIFE/tools/hw/run_kicad_mcp.sh`, qui délègue au serveur KiCad MCP versionné dans le repo compagnon `mascarade`.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
- `kicad/` : projets KiCad
|
||||
- `rules/` : règles champs/footprints/nets
|
||||
- `blocks/` : Design Blocks KiCad 9 (bibliothèque de briques)
|
||||
- `blocks/` : Design Blocks KiCad 10 (bibliothèque de briques)
|
||||
|
||||
⚠️ Les fichiers KiCad réels sont à créer/committer depuis ton poste.
|
||||
Ce template fournit l’outillage (schops + gates + CI).
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Design Blocks (KiCad 9)
|
||||
# Design Blocks (KiCad 10)
|
||||
|
||||
Créer une brique :
|
||||
- isoler un sous-schéma stable (ex: régulateur 3V3)
|
||||
|
||||
@@ -7,7 +7,7 @@ set -euo pipefail
|
||||
#
|
||||
# Env:
|
||||
# KICAD_CLI_BIN: override local path
|
||||
# KICAD_DOCKER_IMAGE: override docker image (default: kicad/kicad:9.0.7-full)
|
||||
# KICAD_DOCKER_IMAGE: override docker image (default: kicad/kicad:nightly)
|
||||
|
||||
BIN="${KICAD_CLI_BIN:-}"
|
||||
if [[ -z "$BIN" ]]; then
|
||||
@@ -28,7 +28,7 @@ if ! command -v docker >/dev/null 2>&1; then
|
||||
exit 127
|
||||
fi
|
||||
|
||||
IMG="${KICAD_DOCKER_IMAGE:-kicad/kicad:9.0.7-full}"
|
||||
IMG="${KICAD_DOCKER_IMAGE:-kicad/kicad:nightly}"
|
||||
|
||||
# run as current user to avoid root-owned artifacts
|
||||
UIDGID="$(id -u):$(id -g)"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
CLI local pour :
|
||||
- ERC/BOM/netlist via `kicad-cli`
|
||||
- bulk edits via `kicad-sch-api` (si installé)
|
||||
- Design Blocks KiCad 9 (structure + metadata)
|
||||
- Design Blocks KiCad 10 (structure + metadata)
|
||||
|
||||
> Philosophie : **bulk edits safe** (backup + report) + exports déterministes (kicad-cli).
|
||||
|
||||
@@ -66,7 +66,7 @@ python tools/hw/schops/schops.py snapshot --schematic ... --name before.json
|
||||
python tools/hw/schops/schops.py snapshot --schematic ... --name after.json
|
||||
```
|
||||
|
||||
## Design Blocks (KiCad 9)
|
||||
## Design Blocks (KiCad 10)
|
||||
Les design blocks sont des dossiers `*.kicad_block` stockés dans une librairie `*.kicad_blocks`.
|
||||
|
||||
```bash
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Goals:
|
||||
- deterministic exports via kicad-cli (ERC / netlist / BOM)
|
||||
- safe bulk edits via kicad-sch-api (fields / footprints / net labels)
|
||||
- Design Blocks (KiCad 9) helpers
|
||||
- Design Blocks (KiCad 10) helpers
|
||||
|
||||
This tool is intentionally conservative:
|
||||
- it always writes an artifacts report
|
||||
@@ -512,7 +512,7 @@ def cmd_snapshot(args) -> int:
|
||||
|
||||
|
||||
# ---------------------------
|
||||
# Design Blocks (KiCad 9)
|
||||
# Design Blocks (KiCad 10)
|
||||
# ---------------------------
|
||||
|
||||
|
||||
@@ -643,7 +643,7 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
p.add_argument("--name", help="output filename (default snapshot.json)")
|
||||
p.set_defaults(fn=cmd_snapshot)
|
||||
|
||||
p = sub.add_parser("block-make", help="Create a KiCad 9 design block folder")
|
||||
p = sub.add_parser("block-make", help="Create a KiCad 10 design block folder")
|
||||
p.add_argument("--name", required=True)
|
||||
p.add_argument("--from-sheet", required=True, help=".kicad_sch file to package as a block")
|
||||
p.add_argument("--lib", required=True, help="Design blocks library folder (usually *.kicad_blocks)")
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends freecad-python3 ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
CMD ["sleep", "infinity"]
|
||||
@@ -0,0 +1,38 @@
|
||||
ARG KICAD_MCP_BASE_IMAGE=kicad/kicad:nightly-full
|
||||
FROM ${KICAD_MCP_BASE_IMAGE}
|
||||
|
||||
ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1
|
||||
|
||||
USER root
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
nodejs \
|
||||
npm \
|
||||
python3-pip \
|
||||
python3-venv \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& python3 -m venv /opt/kicad-mcp/venv \
|
||||
&& /opt/kicad-mcp/venv/bin/pip install --no-cache-dir --upgrade pip
|
||||
|
||||
WORKDIR /opt/kicad-mcp/server
|
||||
|
||||
COPY requirements.txt /tmp/kicad-mcp-requirements.txt
|
||||
RUN /opt/kicad-mcp/venv/bin/pip install --no-cache-dir -r /tmp/kicad-mcp-requirements.txt
|
||||
|
||||
COPY package.json package-lock.json tsconfig.json ./
|
||||
RUN npm ci --ignore-scripts
|
||||
|
||||
COPY src ./src
|
||||
COPY python ./python
|
||||
RUN npx tsc --declaration false --sourceMap false --skipLibCheck
|
||||
|
||||
ENV PATH=/opt/kicad-mcp/venv/bin:${PATH} \
|
||||
KICAD_PYTHON=/opt/kicad-mcp/venv/bin/python
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
CMD ["sleep", "infinity"]
|
||||
@@ -0,0 +1,15 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends build-essential ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& pip install --no-cache-dir --upgrade pip \
|
||||
&& pip install --no-cache-dir platformio
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
CMD ["sleep", "infinity"]
|
||||
@@ -0,0 +1,39 @@
|
||||
# CAD Stack
|
||||
|
||||
Stack Docker CAD/EDA intégrée directement dans `Kill_LIFE`.
|
||||
|
||||
## Direction retenue
|
||||
|
||||
- `KiCad headless`: `kicad-cli` via une image KiCad 10 (`kicad/kicad:nightly` par défaut)
|
||||
- `KiCad MCP`: `kicad-sch-mcp` en `stdio`
|
||||
- `FreeCAD headless`: `FreeCADCmd`
|
||||
- `PlatformIO`: `pio` dans un conteneur Python léger
|
||||
|
||||
## Usage rapide
|
||||
|
||||
```bash
|
||||
tools/hw/cad_stack.sh up
|
||||
tools/hw/cad_stack.sh doctor
|
||||
tools/hw/cad_stack.sh kicad-cli version
|
||||
tools/hw/cad_stack.sh freecad-cmd -c "import FreeCAD; print(FreeCAD.Version())"
|
||||
tools/hw/cad_stack.sh pio system info
|
||||
tools/hw/cad_stack.sh mcp
|
||||
```
|
||||
|
||||
Le workspace monté dans les conteneurs est la racine de `Kill_LIFE` par défaut.
|
||||
`tools/hw/cad_stack.sh build ...` redéploie aussi automatiquement les services persistants reconstruits, pour éviter de garder un ancien conteneur sur une image obsolète.
|
||||
|
||||
Variables utiles :
|
||||
|
||||
- `KICAD_DOCKER_IMAGE` : image KiCad 10 à utiliser. Par défaut, la stack suit la branche `nightly` tant qu’une image stable 10.x n’est pas explicitement épinglée.
|
||||
- `CAD_WORKSPACE_DIR` : workspace monté dans `/workspace`
|
||||
|
||||
## Note MCP
|
||||
|
||||
Le choix ici est volontairement sobre :
|
||||
|
||||
- `stdio` pour l’usage local
|
||||
- `kicad-sch-api` pour le schématique via `kicad-sch-mcp`
|
||||
- `kicad-cli` comme source de vérité pour les exports et checks
|
||||
|
||||
Si un serveur MCP distant devient nécessaire plus tard, il faudra ajouter un vrai transport réseau adapté, pas détourner le mode local.
|
||||
@@ -0,0 +1,39 @@
|
||||
name: kill_life_cad
|
||||
|
||||
services:
|
||||
kicad-headless:
|
||||
image: ${KICAD_DOCKER_IMAGE:-kicad/kicad:nightly-full}
|
||||
working_dir: /workspace
|
||||
command: ["sleep", "infinity"]
|
||||
volumes:
|
||||
- ${CAD_WORKSPACE_DIR:-../..}:/workspace
|
||||
|
||||
kicad-mcp:
|
||||
image: ${KICAD_MCP_IMAGE:-kill_life_cad-kicad-mcp:latest}
|
||||
build:
|
||||
context: ${KICAD_MCP_CONTEXT_DIR:-../../../mascarade/finetune/kicad_mcp_server}
|
||||
dockerfile: ../../../Kill_LIFE/deploy/cad/Dockerfile.kicad-mcp
|
||||
args:
|
||||
KICAD_MCP_BASE_IMAGE: ${KICAD_DOCKER_IMAGE:-kicad/kicad:nightly-full}
|
||||
working_dir: ${CAD_WORKSPACE_DIR:-/workspace}
|
||||
command: ["sleep", "infinity"]
|
||||
volumes:
|
||||
- ${CAD_HOST_ROOT:-/tmp/cad-host}:${CAD_HOST_ROOT:-/tmp/cad-host}
|
||||
|
||||
freecad-headless:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.freecad-headless
|
||||
working_dir: /workspace
|
||||
command: ["sleep", "infinity"]
|
||||
volumes:
|
||||
- ${CAD_WORKSPACE_DIR:-../..}:/workspace
|
||||
|
||||
platformio:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.platformio
|
||||
working_dir: /workspace
|
||||
command: ["sleep", "infinity"]
|
||||
volumes:
|
||||
- ${CAD_WORKSPACE_DIR:-../..}:/workspace
|
||||
@@ -4,7 +4,7 @@
|
||||
- Standards injection: Agent OS (standards versionnés + profils) citeturn0search3
|
||||
- Role workflows + gates: BMAD-METHOD
|
||||
- Tool-first runtime (local): Agent Zero
|
||||
- Interop tools: MCP (ex: kicad-sch-mcp) citeturn0search9
|
||||
- Interop tools: MCP local en `stdio` via le runtime `kicad-mcp`
|
||||
|
||||
Le repo fournit :
|
||||
- `specs/` pour la source de vérité
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
# Design Blocks (KiCad 9) + registry
|
||||
# Design Blocks (KiCad 10) + registry
|
||||
|
||||
Les briques se stockent sous `hardware/blocks/**.kicad_block/` (avec un `.kicad_sch` + un `.json` metadata).
|
||||
Un registry est généré automatiquement : `hardware/blocks/REGISTRY.md`.
|
||||
|
||||
Référence : KiCad 9 Design Blocks. citeturn0search8
|
||||
Référence : KiCad 10 Design Blocks. citeturn0search8
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Easter Egg musique concrète
|
||||
|
||||
_« Le hardware s’écoute, se manipule, se transforme : comme Bernard Parmegiani, chaque export est une métamorphose électronique. »_
|
||||
# Hardware quickstart (KiCad)
|
||||
# Hardware quickstart (KiCad 10)
|
||||
|
||||
> "Chaque bloc hardware est une évolution, chaque bulk edit une adaptation, et chaque export une trace laissée pour les générations futures. (Adrian Tchaikovsky, Children of Time)"
|
||||
|
||||
## Prérequis
|
||||
- KiCad 9 installé (inclut `kicad-cli`)
|
||||
- KiCad 10 installé ou une image Docker KiCad 10 compatible (inclut `kicad-cli`)
|
||||
- Python 3.11+
|
||||
- (optionnel) venv
|
||||
|
||||
|
||||
+30
-6
@@ -5,7 +5,7 @@ Ce template privilégie **deux couches** complémentaires :
|
||||
1) **schops** (ce repo) : un CLI simple, traçable, qui fait
|
||||
- exports déterministes via `kicad-cli` (ERC / BOM / netlist)
|
||||
- bulk edits via `kicad-sch-api` (fields / footprints / labels)
|
||||
- packaging de Design Blocks KiCad 9
|
||||
- packaging de Design Blocks KiCad 10
|
||||
|
||||
2) **MCP (optionnel)** : si tu utilises un client IA compatible MCP, tu peux exposer
|
||||
des opérations KiCad comme un “tool server” local.
|
||||
@@ -34,13 +34,11 @@ Tous les rapports vont dans `artifacts/hw/<timestamp>/`.
|
||||
|
||||
## 2) MCP KiCad (optionnel)
|
||||
|
||||
Si ton client IA supporte MCP, installe un serveur MCP KiCad basé sur `kicad-sch-api` :
|
||||
Si ton client IA supporte MCP, le chemin supporté dans ce workspace est le launcher local de `Kill_LIFE`, branché sur le serveur `mascarade/finetune/kicad_mcp_server` :
|
||||
|
||||
```bash
|
||||
pip install kicad-sch-api kicad-sch-mcp
|
||||
|
||||
# démarre le serveur (stdio)
|
||||
kicad-sch-mcp
|
||||
tools/hw/run_kicad_mcp.sh --doctor
|
||||
tools/hw/run_kicad_mcp.sh
|
||||
```
|
||||
|
||||
### Convention d’intégration recommandée
|
||||
@@ -49,3 +47,29 @@ kicad-sch-mcp
|
||||
- **Création de schéma / placement** (si besoin) → MCP + validation ensuite via `schops` + `kicad-cli`
|
||||
|
||||
> Même avec MCP, garde `kicad-cli` en “source de vérité” pour ERC/BOM/netlist.
|
||||
|
||||
## 3) Stack locale intégrée Kill_LIFE
|
||||
|
||||
`Kill_LIFE` embarque maintenant directement une couche d’exécution locale :
|
||||
|
||||
- `kicad-headless` via une image KiCad 10 compatible (`kicad/kicad:nightly` par défaut)
|
||||
- `kicad-mcp` en `stdio` via le launcher `tools/hw/run_kicad_mcp.sh`
|
||||
- `freecad-headless` via `FreeCADCmd`
|
||||
- `platformio` via `pio`
|
||||
|
||||
Le point important est le suivant :
|
||||
|
||||
- `stdio` reste le bon transport MCP en local
|
||||
- `Streamable HTTP` ne doit être ajouté que pour un vrai serveur distant
|
||||
|
||||
Le détail du pont entre les deux repos est documenté dans [MASCARADE_BRIDGE.md](MASCARADE_BRIDGE.md).
|
||||
|
||||
La configuration MCP versionnée est documentée dans [MCP_SETUP.md](MCP_SETUP.md).
|
||||
|
||||
Point d’entrée pratique côté `Kill_LIFE` :
|
||||
|
||||
```bash
|
||||
tools/hw/cad_stack.sh doctor
|
||||
tools/hw/cad_stack.sh kicad-cli version
|
||||
tools/hw/cad_stack.sh mcp
|
||||
```
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
# Pont Kill_LIFE <-> Mascarade
|
||||
|
||||
Ce document rattache les décisions et implémentations produites pendant la session de travail locale au repo `Kill_LIFE`.
|
||||
|
||||
## But
|
||||
|
||||
Garder une séparation propre entre :
|
||||
|
||||
- `Kill_LIFE` : repo de méthode, specs, gates, evidence packs, workflows hardware/firmware.
|
||||
- `Mascarade` : repo compagnon d’exécution locale pour orchestration LLM, distillation/fine-tuning, et outillage CAD conteneurisé.
|
||||
|
||||
En local, les deux dépôts sont côte à côte :
|
||||
|
||||
- `Kill_LIFE` : `../Kill_LIFE`
|
||||
- `Mascarade` : `../mascarade`
|
||||
|
||||
## Ce qui a été mis en place côté Mascarade
|
||||
|
||||
### 1. Stack CAD/EDA locale
|
||||
|
||||
La stack CAD/EDA a maintenant été intégrée directement dans `Kill_LIFE` :
|
||||
|
||||
- `deploy/cad/docker-compose.yml`
|
||||
- `tools/hw/cad_stack.sh`
|
||||
|
||||
Elle fournit :
|
||||
|
||||
- `kicad-headless` via `kicad-cli` sur une image KiCad 10 compatible
|
||||
- `kicad-mcp` en transport `stdio`, lancé via `tools/hw/run_kicad_mcp.sh`
|
||||
- `freecad-headless` via `FreeCADCmd`
|
||||
- `platformio` via CLI `pio`
|
||||
|
||||
Le repo `Mascarade` reste utile comme repo compagnon pour :
|
||||
|
||||
- orchestration LLM
|
||||
- distillation / fine-tuning
|
||||
- modèles students spécialisés
|
||||
|
||||
### 2. Pipeline local teacher -> student
|
||||
|
||||
Le repo compagnon contient aussi un pipeline local de distillation et fine-tuning :
|
||||
|
||||
- `../mascarade/finetune/distill_dataset.py`
|
||||
- `../mascarade/finetune/distill_and_train.py`
|
||||
- `../mascarade/finetune/run_local.py`
|
||||
- `../mascarade/finetune/batch_local.py`
|
||||
|
||||
Domaines déjà traités ou préparés :
|
||||
|
||||
- `kicad`
|
||||
- `freecad`
|
||||
- `platformio`
|
||||
- `esp32/iot`
|
||||
- `spice`
|
||||
|
||||
Ce pipeline sert à produire de petits modèles spécialisés exploitables localement pour les agents `HW`, `Firmware`, `Doc` et `QA`.
|
||||
|
||||
## Répartition recommandée des rôles
|
||||
|
||||
| Besoin | Repo recommandé | Raison |
|
||||
|---|---|---|
|
||||
| Specs, ADR, gates, evidence packs | `Kill_LIFE` | c’est la source de vérité méthodologique |
|
||||
| Exécution LLM locale et orchestration provider/model | `Mascarade` | c’est le cockpit d’exécution |
|
||||
| KiCad/FreeCAD/PlatformIO en conteneur | `Kill_LIFE` | stack CAD désormais intégrée localement |
|
||||
| Datasets, distillation, adapters LoRA/QLoRA | `Mascarade` | pipeline de training déjà opérationnel |
|
||||
| Rapports finaux, runbooks, conformité | `Kill_LIFE` | cohérence des artefacts et traçabilité |
|
||||
|
||||
## Comment relier les deux dépôts
|
||||
|
||||
### Pour le hardware / CAD
|
||||
|
||||
`Kill_LIFE` garde :
|
||||
|
||||
- les règles
|
||||
- les schémas
|
||||
- les evidence packs
|
||||
- les handoffs
|
||||
|
||||
`Kill_LIFE` exécute maintenant directement :
|
||||
|
||||
- `kicad-cli`
|
||||
- le serveur `kicad-mcp`
|
||||
- `FreeCADCmd`
|
||||
- `pio`
|
||||
|
||||
Le flux recommandé est :
|
||||
|
||||
1. préparer la spec et les critères d’acceptation dans `Kill_LIFE`
|
||||
2. exécuter les outils CAD/EDA dans `Kill_LIFE`
|
||||
3. rapatrier les rapports, exports et décisions dans `Kill_LIFE/docs/` et `Kill_LIFE/artifacts/`
|
||||
|
||||
### Pour les agents IA spécialisés
|
||||
|
||||
`Kill_LIFE` fournit la matière de domaine :
|
||||
|
||||
- `specs/`
|
||||
- `docs/`
|
||||
- `hardware/`
|
||||
- `tools/`
|
||||
- conventions et profils compliance
|
||||
|
||||
`Mascarade` transforme cette matière en :
|
||||
|
||||
- datasets `ShareGPT JSONL`
|
||||
- distillation teacher -> student
|
||||
- adapters LoRA/QLoRA locaux
|
||||
|
||||
Le flux recommandé est :
|
||||
|
||||
1. extraire ou générer des datasets depuis `Kill_LIFE`
|
||||
2. entraîner les students côté `Mascarade`
|
||||
3. réinjecter l’usage de ces students dans les workflows agents de `Kill_LIFE`
|
||||
|
||||
## Alignement avec l’état de l’art au 6 mars 2026
|
||||
|
||||
Points retenus pendant la recherche :
|
||||
|
||||
- `kicad-cli` est la voie officielle pour le headless KiCad
|
||||
- pour MCP, `stdio` reste le bon choix en local
|
||||
- `Streamable HTTP` ne doit être ajouté que si on expose un vrai serveur distant
|
||||
- `FreeCADCmd` est le mode headless propre pour FreeCAD
|
||||
- `PlatformIO` reste le plus simple à conteneuriser via CLI Python
|
||||
|
||||
Conséquence pour `Kill_LIFE` :
|
||||
|
||||
- ne pas mélanger la méthode et la couche d’exécution
|
||||
- documenter `Mascarade` comme repo compagnon, pas comme dépendance cachée
|
||||
- garder les evidence packs et la gouvernance dans `Kill_LIFE`
|
||||
|
||||
## Statut actuel
|
||||
|
||||
L’étape d’intégration côté `Kill_LIFE` est maintenant réalisée.
|
||||
|
||||
La couche CAD/EDA locale vit directement dans ce dépôt :
|
||||
|
||||
- `deploy/cad/docker-compose.yml`
|
||||
- `deploy/cad/Dockerfile.kicad-mcp`
|
||||
- `deploy/cad/Dockerfile.freecad-headless`
|
||||
- `deploy/cad/Dockerfile.platformio`
|
||||
- `tools/hw/cad_stack.sh`
|
||||
|
||||
## Intégration actuelle dans Kill_LIFE
|
||||
|
||||
Le dépôt `Kill_LIFE` expose maintenant un launcher local natif :
|
||||
|
||||
- `tools/hw/cad_stack.sh`
|
||||
- `tools/hw/run_kicad_mcp.sh`
|
||||
|
||||
Ce launcher :
|
||||
|
||||
- monte `Kill_LIFE` comme workspace par défaut
|
||||
- pilote directement `deploy/cad/docker-compose.yml`
|
||||
- évite de cacher une dépendance implicite vers `Mascarade`
|
||||
- laisse `Mascarade` jouer son rôle de repo compagnon pour LLM local et fine-tuning
|
||||
|
||||
Exemples :
|
||||
|
||||
```bash
|
||||
tools/hw/cad_stack.sh doctor
|
||||
tools/hw/cad_stack.sh kicad-cli version
|
||||
tools/hw/cad_stack.sh pio system info
|
||||
tools/hw/run_kicad_mcp.sh --doctor
|
||||
tools/hw/cad_stack.sh mcp
|
||||
```
|
||||
+58
-19
@@ -1,35 +1,74 @@
|
||||
# MCP setup (KiCad)
|
||||
|
||||
## Option A — Schematic MCP (recommended)
|
||||
`kicad-sch-api` inclut un serveur MCP : `kicad-sch-mcp`. citeturn0search9
|
||||
Source canonique pour la configuration MCP locale de `Kill_LIFE`.
|
||||
|
||||
Spec de perimetre:
|
||||
|
||||
- `specs/kicad_mcp_scope_spec.md`
|
||||
|
||||
## Chemin supporté
|
||||
|
||||
- Serveur MCP supporté: `mascarade/finetune/kicad_mcp_server`
|
||||
- Launcher supporté côté `Kill_LIFE`: `tools/hw/run_kicad_mcp.sh`
|
||||
- Transport supporté: `stdio` local uniquement
|
||||
|
||||
`kicad-sch-mcp` n’est plus le chemin recommandé dans ce repo. Il reste un ancien axe documentaire, mais il n’est ni installé ni supporté ici comme runtime principal.
|
||||
|
||||
## Prérequis
|
||||
|
||||
- le repo compagnon `mascarade` existe en voisin (`../mascarade`) ou via `MASCARADE_DIR`
|
||||
- `node` est disponible sur la machine
|
||||
- le serveur est buildé dans `mascarade/finetune/kicad_mcp_server/dist/index.js`
|
||||
- KiCad et son Python sont visibles par le runtime du serveur
|
||||
|
||||
Diagnostic rapide :
|
||||
|
||||
Installation :
|
||||
```bash
|
||||
pip install kicad-sch-api
|
||||
# ou via uv
|
||||
# uv tool install kicad-sch-mcp
|
||||
tools/hw/run_kicad_mcp.sh --doctor
|
||||
python3 tools/hw/mcp_smoke.py
|
||||
```
|
||||
|
||||
Lancer le serveur (dans le repo) :
|
||||
```bash
|
||||
kicad-sch-mcp
|
||||
```
|
||||
## Configuration locale
|
||||
|
||||
Le fichier versionné [mcp.json](../mcp.json) pointe déjà vers le launcher supporté :
|
||||
|
||||
Exemple (Claude Desktop) — à adapter selon ton OS :
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"kicad_schematic": {
|
||||
"command": "kicad-sch-mcp",
|
||||
"args": []
|
||||
"kicad": {
|
||||
"type": "local",
|
||||
"command": "bash",
|
||||
"args": ["tools/hw/run_kicad_mcp.sh"],
|
||||
"tools": ["*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Option B — KiCad “live/PCB” MCP (expérimental)
|
||||
Il existe des serveurs MCP orientés PCB / IPC API (dépend de ta version KiCad et du serveur choisi). citeturn0search1turn0search16
|
||||
Le launcher prépare un runtime local writable sous `.cad-home/kicad-mcp/` et exporte `KICAD_MCP_DATA_DIR` pour éviter les écritures dans un préfixe immuable.
|
||||
|
||||
Dans ce repo, l’approche “robuste” reste :
|
||||
- bulk edits schéma via `kicad-sch-api`
|
||||
- exports/DRC via `kicad-cli`
|
||||
## Serveur auxiliaire
|
||||
|
||||
`Kill_LIFE` expose aussi un serveur MCP auxiliaire `validate-specs` pour la validation repo/specs :
|
||||
|
||||
```bash
|
||||
python3 tools/validate_specs.py --json
|
||||
python3 tools/validate_specs.py --mcp
|
||||
```
|
||||
|
||||
Ce serveur ne remplace pas le runtime KiCad. Il sert à vérifier les specs, la conformité et l’usage RFC2119 côté dépôt.
|
||||
|
||||
## Usage
|
||||
|
||||
Depuis `Kill_LIFE` :
|
||||
|
||||
```bash
|
||||
tools/hw/run_kicad_mcp.sh
|
||||
```
|
||||
|
||||
## Politique de support
|
||||
|
||||
- `stdio` reste le seul transport supporté par défaut
|
||||
- aucun serveur MCP réseau n’est exposé par défaut
|
||||
- les serveurs mock/demo restent hors chemin de production tant qu’ils ne parlent pas à un backend réel
|
||||
- `tools/hw/cad_stack.sh mcp` reste un chemin legacy à réaligner avant d’être re-documenté ici
|
||||
|
||||
+29
-5
@@ -24,15 +24,22 @@ pip install -r requirements-mistral.txt
|
||||
## 3. Build et test minimal (exemple PlatformIO)
|
||||
|
||||
## 3bis. Build et test multi-cible (CI/CD agentique)
|
||||
Le workflow CI/CD compile et teste le firmware sur ESP, STM et Linux automatiquement.
|
||||
Le workflow CI/CD actuellement câblé build l’ESP (`esp32s3_arduino`) et teste la cible native (`linux` -> `native`).
|
||||
|
||||
Par défaut, les wrappers tentent `pio` en natif, puis basculent automatiquement sur `tools/hw/cad_stack.sh pio` si `pio` n’est pas installé sur l’hôte.
|
||||
Tu peux forcer le runner avec `KILL_LIFE_PIO_MODE=native` ou `KILL_LIFE_PIO_MODE=container`.
|
||||
|
||||
Pour lancer manuellement :
|
||||
```bash
|
||||
python tools/build_firmware.py esp
|
||||
python tools/test_firmware.py esp
|
||||
python tools/collect_evidence.py esp
|
||||
python3 tools/build_firmware.py esp
|
||||
python3 tools/collect_evidence.py esp
|
||||
python3 tools/verify_evidence.py esp
|
||||
|
||||
python3 tools/test_firmware.py linux
|
||||
python3 tools/collect_evidence.py linux
|
||||
python3 tools/verify_evidence.py linux
|
||||
```
|
||||
Remplace `esp` par `stm` ou `linux` selon la cible.
|
||||
`stm` reste non supporté tant qu’aucune cible STM n’existe dans `firmware/platformio.ini`.
|
||||
|
||||
Les evidence packs sont générés dans `docs/evidence/`.
|
||||
|
||||
@@ -52,6 +59,23 @@ mkdocs serve
|
||||
- Suivre les guides détaillés dans `docs/`
|
||||
- Consulter la [FAQ](docs/FAQ.md) pour les questions fréquentes
|
||||
|
||||
## 6. Outils CAD/EDA intégrés
|
||||
|
||||
`Kill_LIFE` embarque maintenant une stack CAD/EDA locale :
|
||||
|
||||
```bash
|
||||
make cad-doctor
|
||||
make cad-kicad CAD_ARGS="version"
|
||||
make cad-pio CAD_ARGS="system info"
|
||||
KILL_LIFE_PIO_MODE=container python3 tools/test_firmware.py linux
|
||||
|
||||
tools/hw/cad_stack.sh doctor
|
||||
tools/hw/cad_stack.sh kicad-cli version
|
||||
tools/hw/cad_stack.sh pio system info
|
||||
```
|
||||
|
||||
Le workspace monté est `Kill_LIFE` par défaut.
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Contribuer
|
||||
|
||||
+15
-6
@@ -33,22 +33,31 @@ Ajoute un label `ai:*` :
|
||||
|
||||
## 3) CI/CD multi-cible hardware-in-the-loop
|
||||
|
||||
Le workflow CI/CD compile, teste et valide le firmware sur ESP, STM et Linux.
|
||||
Le workflow CI/CD compile, teste et valide le firmware sur ESP et Linux.
|
||||
Les scripts d’automatisation sont dans `tools/` :
|
||||
- `build_firmware.py` : build par cible
|
||||
- `test_firmware.py` : tests par cible
|
||||
- `collect_evidence.py` : génération evidence pack
|
||||
|
||||
Les wrappers PlatformIO utilisent `pio` en natif si disponible, sinon basculent automatiquement sur la stack conteneurisée `tools/hw/cad_stack.sh pio`.
|
||||
Override possible :
|
||||
- `KILL_LIFE_PIO_MODE=native`
|
||||
- `KILL_LIFE_PIO_MODE=container`
|
||||
|
||||
Les evidence packs sont stockés dans `docs/evidence/`.
|
||||
La couverture est générée via `coverage_badge.py`.
|
||||
|
||||
Pour vérifier manuellement :
|
||||
```bash
|
||||
python tools/build_firmware.py esp
|
||||
python tools/test_firmware.py esp
|
||||
python tools/collect_evidence.py esp
|
||||
python3 tools/build_firmware.py esp
|
||||
python3 tools/collect_evidence.py esp
|
||||
python3 tools/verify_evidence.py esp
|
||||
|
||||
python3 tools/test_firmware.py linux
|
||||
python3 tools/collect_evidence.py linux
|
||||
python3 tools/verify_evidence.py linux
|
||||
```
|
||||
Remplace `esp` par `stm` ou `linux`.
|
||||
`stm` reste non supporté tant qu’aucune cible STM n’existe pas dans `firmware/platformio.ini`.
|
||||
|
||||
Vérifie la présence des artefacts et evidence packs après chaque run.
|
||||
|
||||
@@ -64,7 +73,7 @@ ajoute un check statique de parité routes API.
|
||||
|
||||
Exemple (adapté au repo cible) :
|
||||
```bash
|
||||
python tools/gates/route_parity_check.py \
|
||||
python3 tools/gates/route_parity_check.py \
|
||||
--backend "src/**/*.cpp" \
|
||||
--backend "src/**/*.h" \
|
||||
--frontend "data/webui/**/*.js" \
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
- `kicad/` : projets KiCad
|
||||
- `rules/` : règles champs/footprints/nets
|
||||
- `blocks/` : Design Blocks KiCad 9 (bibliothèque de briques)
|
||||
- `blocks/` : Design Blocks KiCad 10 (bibliothèque de briques)
|
||||
|
||||
⚠️ Les fichiers KiCad réels sont à créer/committer depuis ton poste.
|
||||
Ce template fournit l’outillage (schops + gates + CI).
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Design Blocks (KiCad 9)
|
||||
# Design Blocks (KiCad 10)
|
||||
|
||||
Créer une brique :
|
||||
- isoler un sous-schéma stable (ex: régulateur 3V3)
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"kicad": {
|
||||
"type": "local",
|
||||
"command": "bash",
|
||||
"args": ["tools/hw/run_kicad_mcp.sh"],
|
||||
"tools": ["*"]
|
||||
},
|
||||
"validate-specs": {
|
||||
"type": "local",
|
||||
"command": "python3",
|
||||
"args": ["tools/validate_specs.py"],
|
||||
"args": ["tools/validate_specs.py", "--mcp"],
|
||||
"tools": ["*"]
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+279
@@ -0,0 +1,279 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
COMPOSE_FILE="$ROOT_DIR/deploy/cad/docker-compose.yml"
|
||||
VERBOSE=0
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: tools/hw/cad_stack.sh <command> [args...]
|
||||
|
||||
Stack CAD/EDA locale intégrée à Kill_LIFE.
|
||||
|
||||
Commands:
|
||||
up [services...] Start CAD helper containers
|
||||
down Stop CAD helper containers
|
||||
ps Show CAD container status
|
||||
build [services...] Build local CAD images
|
||||
doctor Print tool versions from the containers
|
||||
kicad-cli <args...> Run kicad-cli with Kill_LIFE mounted as workspace
|
||||
freecad-cmd <args...> Run FreeCADCmd with Kill_LIFE mounted as workspace
|
||||
pio <args...> Run PlatformIO with Kill_LIFE mounted as workspace
|
||||
mcp [args...] Run the KiCad MCP server in stdio mode
|
||||
help Show this help
|
||||
|
||||
Env:
|
||||
CAD_WORKSPACE_DIR Workspace mounted at /workspace (default: Kill_LIFE root)
|
||||
CAD_HOST_ROOT Parent path mounted 1:1 for the MCP container (default: parent of Kill_LIFE)
|
||||
KICAD_DOCKER_IMAGE KiCad v10 image/tag override (default: kicad/kicad:nightly-full)
|
||||
EOF
|
||||
}
|
||||
|
||||
log() {
|
||||
printf '[kill_life:cad] %s\n' "$*"
|
||||
}
|
||||
|
||||
debug() {
|
||||
if [ "$VERBOSE" -eq 1 ]; then
|
||||
printf '[kill_life:cad][dbg] %s\n' "$*" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
die() {
|
||||
printf '[kill_life:cad][err] %s\n' "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
compose() {
|
||||
debug "docker compose -f $COMPOSE_FILE $*"
|
||||
docker compose -f "$COMPOSE_FILE" "$@"
|
||||
}
|
||||
|
||||
ensure_service_up() {
|
||||
local service="$1"
|
||||
if ! compose ps --status running --services | grep -qx "$service"; then
|
||||
log "Starting $service"
|
||||
compose up -d "$service"
|
||||
fi
|
||||
}
|
||||
|
||||
run_shell_as_host_user() {
|
||||
local service="$1"
|
||||
local home_dir="$2"
|
||||
shift 2
|
||||
local shell_command="$*"
|
||||
compose exec -T \
|
||||
--user "$(id -u):$(id -g)" \
|
||||
-e HOME="$home_dir" \
|
||||
"$service" \
|
||||
sh -lc "$shell_command"
|
||||
}
|
||||
|
||||
run_tool_as_host_user() {
|
||||
local service="$1"
|
||||
local home_dir="$2"
|
||||
local prelude="$3"
|
||||
local binary="$4"
|
||||
shift 4
|
||||
compose exec -T \
|
||||
--user "$(id -u):$(id -g)" \
|
||||
-e HOME="$home_dir" \
|
||||
"$service" \
|
||||
sh -lc 'set -e; mkdir -p "$HOME"; '"$prelude"'; exec "$@"' sh "$binary" "$@"
|
||||
}
|
||||
|
||||
run_shell_in_service_user() {
|
||||
local service="$1"
|
||||
local home_dir="$2"
|
||||
shift 2
|
||||
local shell_command="$*"
|
||||
compose exec -T \
|
||||
-e HOME="$home_dir" \
|
||||
"$service" \
|
||||
sh -lc "$shell_command"
|
||||
}
|
||||
|
||||
run_tool_in_service_user() {
|
||||
local service="$1"
|
||||
local home_dir="$2"
|
||||
local prelude="$3"
|
||||
local binary="$4"
|
||||
shift 4
|
||||
compose exec -T \
|
||||
-e HOME="$home_dir" \
|
||||
"$service" \
|
||||
sh -lc 'set -e; mkdir -p "$HOME"; '"$prelude"'; exec "$@"' sh "$binary" "$@"
|
||||
}
|
||||
|
||||
build_cmd() {
|
||||
local restart_services=()
|
||||
if [ "$#" -gt 0 ]; then
|
||||
compose build "$@"
|
||||
for service in "$@"; do
|
||||
case "$service" in
|
||||
kicad-headless|freecad-headless|platformio)
|
||||
restart_services+=("$service")
|
||||
;;
|
||||
esac
|
||||
done
|
||||
else
|
||||
compose build
|
||||
restart_services=(kicad-headless freecad-headless platformio)
|
||||
fi
|
||||
|
||||
if [ "${#restart_services[@]}" -gt 0 ]; then
|
||||
log "Recreating updated services: ${restart_services[*]}"
|
||||
compose up -d --force-recreate "${restart_services[@]}"
|
||||
fi
|
||||
}
|
||||
|
||||
up_cmd() {
|
||||
if [ "$#" -gt 0 ]; then
|
||||
compose up -d "$@"
|
||||
return
|
||||
fi
|
||||
|
||||
compose up -d kicad-headless freecad-headless platformio
|
||||
}
|
||||
|
||||
doctor_cmd() {
|
||||
ensure_service_up kicad-headless
|
||||
ensure_service_up freecad-headless
|
||||
ensure_service_up platformio
|
||||
|
||||
run_shell_as_host_user \
|
||||
kicad-headless \
|
||||
/workspace/.cad-home/kicad-headless \
|
||||
'mkdir -p "$HOME" && kicad-cli version'
|
||||
|
||||
run_shell_in_service_user \
|
||||
freecad-headless \
|
||||
/workspace/.cad-home/freecad-headless \
|
||||
'mkdir -p "$HOME" && freecadcmd -c "import FreeCAD; print(\".\".join(FreeCAD.Version()[:3]))"'
|
||||
|
||||
run_shell_as_host_user \
|
||||
platformio \
|
||||
/workspace/.cad-home/platformio \
|
||||
'mkdir -p "$HOME" "$HOME/.platformio" && export PLATFORMIO_CORE_DIR="$HOME/.platformio" && pio --version'
|
||||
}
|
||||
|
||||
kicad_cli_cmd() {
|
||||
ensure_service_up kicad-headless
|
||||
run_tool_as_host_user \
|
||||
kicad-headless \
|
||||
/workspace/.cad-home/kicad-headless \
|
||||
":" \
|
||||
kicad-cli \
|
||||
"$@"
|
||||
}
|
||||
|
||||
freecad_cmd() {
|
||||
ensure_service_up freecad-headless
|
||||
run_tool_in_service_user \
|
||||
freecad-headless \
|
||||
/workspace/.cad-home/freecad-headless \
|
||||
":" \
|
||||
freecadcmd \
|
||||
"$@"
|
||||
}
|
||||
|
||||
pio_cmd() {
|
||||
ensure_service_up platformio
|
||||
run_tool_as_host_user \
|
||||
platformio \
|
||||
/workspace/.cad-home/platformio \
|
||||
'mkdir -p "$HOME/.platformio"; export PLATFORMIO_CORE_DIR="$HOME/.platformio"' \
|
||||
pio \
|
||||
"$@"
|
||||
}
|
||||
|
||||
mcp_cmd() {
|
||||
"$ROOT_DIR/tools/hw/run_kicad_mcp.sh" "$@"
|
||||
}
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
-v|--verbose)
|
||||
VERBOSE=1
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
CMD="${1:-help}"
|
||||
if [ "$#" -gt 0 ]; then
|
||||
shift
|
||||
fi
|
||||
|
||||
[ -f "$COMPOSE_FILE" ] || die "CAD compose file not found: $COMPOSE_FILE"
|
||||
export CAD_WORKSPACE_DIR="${CAD_WORKSPACE_DIR:-$ROOT_DIR}"
|
||||
export CAD_HOST_ROOT="${CAD_HOST_ROOT:-$(cd "$ROOT_DIR/.." && pwd)}"
|
||||
|
||||
if [ "$CMD" = "help" ]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
case "$CMD" in
|
||||
up|down|ps|build|doctor|kicad-cli|freecad-cmd|pio|mcp)
|
||||
;;
|
||||
*)
|
||||
usage >&2
|
||||
die "unknown command: $CMD"
|
||||
;;
|
||||
esac
|
||||
|
||||
debug "root=$ROOT_DIR"
|
||||
debug "compose_file=$COMPOSE_FILE"
|
||||
debug "workspace_dir=$CAD_WORKSPACE_DIR"
|
||||
debug "command=$CMD"
|
||||
|
||||
case "$CMD" in
|
||||
up)
|
||||
up_cmd "$@"
|
||||
;;
|
||||
down)
|
||||
compose down
|
||||
;;
|
||||
ps)
|
||||
compose ps
|
||||
;;
|
||||
build)
|
||||
build_cmd "$@"
|
||||
;;
|
||||
doctor)
|
||||
doctor_cmd
|
||||
;;
|
||||
kicad-cli)
|
||||
if [ "$#" -eq 0 ]; then
|
||||
echo "cad_stack.sh kicad-cli: missing arguments" >&2
|
||||
exit 2
|
||||
fi
|
||||
kicad_cli_cmd "$@"
|
||||
;;
|
||||
freecad-cmd)
|
||||
if [ "$#" -eq 0 ]; then
|
||||
echo "cad_stack.sh freecad-cmd: missing arguments" >&2
|
||||
exit 2
|
||||
fi
|
||||
freecad_cmd "$@"
|
||||
;;
|
||||
pio)
|
||||
if [ "$#" -eq 0 ]; then
|
||||
echo "cad_stack.sh pio: missing arguments" >&2
|
||||
exit 2
|
||||
fi
|
||||
pio_cmd "$@"
|
||||
;;
|
||||
mcp)
|
||||
mcp_cmd "$@"
|
||||
;;
|
||||
esac
|
||||
@@ -7,6 +7,6 @@ if [[ -z "${SCHEMATIC}" ]]; then
|
||||
exit 2
|
||||
fi
|
||||
|
||||
python tools/hw/schops/schops.py erc --schematic "${SCHEMATIC}"
|
||||
python tools/hw/schops/schops.py netlist --schematic "${SCHEMATIC}"
|
||||
python tools/hw/schops/schops.py bom --schematic "${SCHEMATIC}"
|
||||
python3 tools/hw/schops/schops.py erc --schematic "${SCHEMATIC}"
|
||||
python3 tools/hw/schops/schops.py netlist --schematic "${SCHEMATIC}"
|
||||
python3 tools/hw/schops/schops.py bom --schematic "${SCHEMATIC}"
|
||||
|
||||
+4
-4
@@ -24,12 +24,12 @@ fi
|
||||
echo "Using schematic: ${SCHEM:-<none>}"
|
||||
echo "Using pcb: ${PCB:-<none>}"
|
||||
|
||||
OUTDIR="$(python tools/hw/exports.py ${SCHEM:+--schematic "$SCHEM"} ${PCB:+--pcb "$PCB"})"
|
||||
OUTDIR="$(python3 tools/hw/exports.py ${SCHEM:+--schematic "$SCHEM"} ${PCB:+--pcb "$PCB"})"
|
||||
echo "Previews: ${OUTDIR}"
|
||||
|
||||
python tools/hw/blocks/lint_blocks.py --blocks-dir hardware/blocks
|
||||
python tools/hw/blocks/generate_registry.py --blocks-dir hardware/blocks --out hardware/blocks/REGISTRY.md
|
||||
python3 tools/hw/blocks/lint_blocks.py --blocks-dir hardware/blocks
|
||||
python3 tools/hw/blocks/generate_registry.py --blocks-dir hardware/blocks --out hardware/blocks/REGISTRY.md
|
||||
|
||||
python tools/compliance/validate.py
|
||||
python3 tools/compliance/validate.py
|
||||
|
||||
echo "OK"
|
||||
|
||||
@@ -7,7 +7,7 @@ set -euo pipefail
|
||||
#
|
||||
# Env:
|
||||
# KICAD_CLI_BIN: override local path
|
||||
# KICAD_DOCKER_IMAGE: override docker image (default: kicad/kicad:9.0.7-full)
|
||||
# KICAD_DOCKER_IMAGE: override docker image (default: kicad/kicad:nightly)
|
||||
|
||||
BIN="${KICAD_CLI_BIN:-}"
|
||||
if [[ -z "$BIN" ]]; then
|
||||
@@ -28,7 +28,7 @@ if ! command -v docker >/dev/null 2>&1; then
|
||||
exit 127
|
||||
fi
|
||||
|
||||
IMG="${KICAD_DOCKER_IMAGE:-kicad/kicad:9.0.7-full}"
|
||||
IMG="${KICAD_DOCKER_IMAGE:-kicad/kicad:nightly}"
|
||||
|
||||
# run as current user to avoid root-owned artifacts
|
||||
UIDGID="$(id -u):$(id -g)"
|
||||
|
||||
Executable
+163
@@ -0,0 +1,163 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Minimal STDIO smoke test for the supported KiCad MCP launcher."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import selectors
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--timeout",
|
||||
type=float,
|
||||
default=20.0,
|
||||
help="Seconds to wait for each MCP response.",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def read_response(proc: subprocess.Popen[str], timeout: float) -> dict[str, Any]:
|
||||
if proc.stdout is None:
|
||||
raise RuntimeError("stdout pipe is not available")
|
||||
|
||||
if proc.stdout.closed:
|
||||
raise RuntimeError("stdout pipe is closed")
|
||||
|
||||
deadline = time.monotonic() + timeout
|
||||
selector = selectors.DefaultSelector()
|
||||
selector.register(proc.stdout, selectors.EVENT_READ)
|
||||
buffer = ""
|
||||
|
||||
try:
|
||||
while True:
|
||||
remaining = deadline - time.monotonic()
|
||||
if remaining <= 0:
|
||||
raise RuntimeError(f"Timed out after {timeout:.1f}s waiting for MCP response")
|
||||
|
||||
events = selector.select(remaining)
|
||||
if not events:
|
||||
raise RuntimeError(f"Timed out after {timeout:.1f}s waiting for MCP response")
|
||||
|
||||
line = proc.stdout.readline()
|
||||
if not line:
|
||||
raise RuntimeError("MCP process closed stdout before replying")
|
||||
|
||||
buffer += line
|
||||
if "\n" not in buffer:
|
||||
continue
|
||||
|
||||
message, _, remainder = buffer.partition("\n")
|
||||
buffer = remainder
|
||||
message = message.strip()
|
||||
if not message:
|
||||
continue
|
||||
|
||||
return json.loads(message)
|
||||
finally:
|
||||
selector.close()
|
||||
|
||||
|
||||
def send_message(proc: subprocess.Popen[str], payload: dict[str, Any]) -> None:
|
||||
if proc.stdin is None:
|
||||
raise RuntimeError("stdin pipe is not available")
|
||||
|
||||
body = json.dumps(payload)
|
||||
proc.stdin.write(body + "\n")
|
||||
proc.stdin.flush()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
launcher = ROOT / "tools" / "hw" / "run_kicad_mcp.sh"
|
||||
|
||||
proc = subprocess.Popen(
|
||||
["bash", str(launcher)],
|
||||
cwd=ROOT,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
bufsize=1,
|
||||
start_new_session=True,
|
||||
)
|
||||
|
||||
try:
|
||||
send_message(
|
||||
proc,
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "initialize",
|
||||
"params": {
|
||||
"protocolVersion": "2025-03-26",
|
||||
"capabilities": {},
|
||||
"clientInfo": {"name": "kill-life-mcp-smoke", "version": "1.0.0"},
|
||||
},
|
||||
},
|
||||
)
|
||||
init = read_response(proc, args.timeout)
|
||||
|
||||
result = init.get("result") or {}
|
||||
protocol_version = result.get("protocolVersion")
|
||||
server_info = result.get("serverInfo") or {}
|
||||
server_name = server_info.get("name", "unknown")
|
||||
|
||||
send_message(
|
||||
proc,
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "notifications/initialized",
|
||||
"params": {},
|
||||
},
|
||||
)
|
||||
send_message(
|
||||
proc,
|
||||
{"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {}},
|
||||
)
|
||||
tools_resp = read_response(proc, args.timeout)
|
||||
tools = (tools_resp.get("result") or {}).get("tools") or []
|
||||
|
||||
if not protocol_version:
|
||||
raise RuntimeError("initialize response missing protocolVersion")
|
||||
if not tools:
|
||||
raise RuntimeError("tools/list returned no tools")
|
||||
|
||||
print(f"OK: server={server_name} protocol={protocol_version} tools={len(tools)}")
|
||||
return 0
|
||||
except Exception as exc:
|
||||
print(f"ERROR: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
finally:
|
||||
if proc.poll() is None:
|
||||
os.killpg(proc.pid, signal.SIGTERM)
|
||||
try:
|
||||
proc.wait(timeout=5)
|
||||
except subprocess.TimeoutExpired:
|
||||
os.killpg(proc.pid, signal.SIGKILL)
|
||||
proc.wait(timeout=5)
|
||||
|
||||
stderr_output = ""
|
||||
if proc.stderr is not None:
|
||||
try:
|
||||
stderr_output = proc.stderr.read().strip()
|
||||
except Exception:
|
||||
stderr_output = ""
|
||||
if stderr_output:
|
||||
sys.stderr.write(stderr_output + "\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Executable
+264
@@ -0,0 +1,264 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
COMPOSE_FILE="$ROOT_DIR/deploy/cad/docker-compose.yml"
|
||||
VERBOSE=0
|
||||
DOCTOR=0
|
||||
RUNTIME="${KICAD_MCP_RUNTIME:-auto}"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: tools/hw/run_kicad_mcp.sh [--doctor] [--verbose] [-- <server args>]
|
||||
|
||||
Launch the supported KiCad MCP server from the companion `mascarade` repo.
|
||||
|
||||
Options:
|
||||
--doctor Print resolved paths and exit
|
||||
--verbose Print resolved command before exec
|
||||
-h, --help Show this help
|
||||
|
||||
Environment:
|
||||
MASCARADE_DIR Override the companion repo path (default: ../mascarade)
|
||||
KICAD_MCP_ENTRYPOINT Override the Node entrypoint
|
||||
KICAD_MCP_HOME Override the MCP runtime home (default: .cad-home/kicad-mcp)
|
||||
NODE_BIN Override the Node executable (default: node)
|
||||
KICAD_MCP_DATA_DIR Override the writable data directory used by the server
|
||||
KICAD_MCP_RUNTIME host | container | auto (default: auto)
|
||||
EOF
|
||||
}
|
||||
|
||||
log() {
|
||||
printf '[kill_life:mcp] %s\n' "$*" >&2
|
||||
}
|
||||
|
||||
debug() {
|
||||
if [ "$VERBOSE" -eq 1 ]; then
|
||||
log "$*"
|
||||
fi
|
||||
}
|
||||
|
||||
cleanup_container() {
|
||||
if [ -n "${ACTIVE_CONTAINER_NAME:-}" ]; then
|
||||
docker rm -f "$ACTIVE_CONTAINER_NAME" >/dev/null 2>&1 || true
|
||||
fi
|
||||
}
|
||||
|
||||
die() {
|
||||
printf '[kill_life:mcp][err] %s\n' "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
compose() {
|
||||
docker compose -f "$COMPOSE_FILE" "$@"
|
||||
}
|
||||
|
||||
build_pythonpath() {
|
||||
local -a candidates=()
|
||||
local value=""
|
||||
|
||||
if [ -n "${KICAD_PYTHONPATH:-}" ]; then
|
||||
value="${KICAD_PYTHONPATH}"
|
||||
elif [ -n "${PYTHONPATH:-}" ]; then
|
||||
value="${PYTHONPATH}"
|
||||
else
|
||||
candidates=(
|
||||
/usr/lib/kicad/lib/python3/dist-packages
|
||||
/usr/local/lib/kicad/lib/python3/dist-packages
|
||||
/usr/lib/python3/dist-packages
|
||||
/usr/local/lib/python3/dist-packages
|
||||
/usr/lib/python3.12/dist-packages
|
||||
/usr/local/lib/python3.12/dist-packages
|
||||
)
|
||||
for candidate in "${candidates[@]}"; do
|
||||
if [ -d "$candidate" ]; then
|
||||
if [ -n "$value" ]; then
|
||||
value="${value}:$candidate"
|
||||
else
|
||||
value="$candidate"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
printf '%s' "$value"
|
||||
}
|
||||
|
||||
resolve_probe_python() {
|
||||
if [ -n "${KICAD_PYTHON:-}" ]; then
|
||||
printf '%s' "$KICAD_PYTHON"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -x "$SERVER_DIR/venv/bin/python" ]; then
|
||||
printf '%s' "$SERVER_DIR/venv/bin/python"
|
||||
return 0
|
||||
fi
|
||||
|
||||
command -v python3 || true
|
||||
}
|
||||
|
||||
probe_pcbnew() {
|
||||
local probe_python="$1"
|
||||
local pythonpath="$2"
|
||||
|
||||
[ -n "$probe_python" ] || return 1
|
||||
|
||||
if [ -n "$pythonpath" ]; then
|
||||
env PYTHONPATH="$pythonpath" "$probe_python" -c 'import pcbnew' >/dev/null 2>&1
|
||||
return $?
|
||||
fi
|
||||
|
||||
"$probe_python" -c 'import pcbnew' >/dev/null 2>&1
|
||||
}
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--doctor)
|
||||
DOCTOR=1
|
||||
shift
|
||||
;;
|
||||
--runtime)
|
||||
[ "$#" -ge 2 ] || die "--runtime requires a value"
|
||||
RUNTIME="$2"
|
||||
shift 2
|
||||
;;
|
||||
--runtime=*)
|
||||
RUNTIME="${1#*=}"
|
||||
shift
|
||||
;;
|
||||
--container)
|
||||
RUNTIME="container"
|
||||
shift
|
||||
;;
|
||||
--host)
|
||||
RUNTIME="host"
|
||||
shift
|
||||
;;
|
||||
--verbose)
|
||||
VERBOSE=1
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
REPO_PARENT="$(cd "$ROOT_DIR/.." && pwd)"
|
||||
export CAD_HOST_ROOT="${CAD_HOST_ROOT:-$REPO_PARENT}"
|
||||
export CAD_WORKSPACE_DIR="${CAD_WORKSPACE_DIR:-$ROOT_DIR}"
|
||||
export KICAD_MCP_IMAGE="${KICAD_MCP_IMAGE:-kill_life_cad-kicad-mcp:latest}"
|
||||
MASCARADE_DIR="${MASCARADE_DIR:-$REPO_PARENT/mascarade}"
|
||||
SERVER_DIR="$MASCARADE_DIR/finetune/kicad_mcp_server"
|
||||
ENTRYPOINT="${KICAD_MCP_ENTRYPOINT:-$SERVER_DIR/dist/index.js}"
|
||||
NODE_BIN="${NODE_BIN:-node}"
|
||||
MCP_HOME="${KICAD_MCP_HOME:-$ROOT_DIR/.cad-home/kicad-mcp}"
|
||||
CONFIG_HOME="${XDG_CONFIG_HOME:-$MCP_HOME/.config}"
|
||||
CACHE_HOME="${XDG_CACHE_HOME:-$MCP_HOME/.cache}"
|
||||
DATA_DIR="${KICAD_MCP_DATA_DIR:-$MCP_HOME/data}"
|
||||
PYTHONPATH_VALUE="$(build_pythonpath)"
|
||||
PROBE_PYTHON="$(resolve_probe_python)"
|
||||
HOST_PCBNEW_STATUS="missing"
|
||||
CONTAINER_STATUS="unknown"
|
||||
|
||||
if probe_pcbnew "$PROBE_PYTHON" "$PYTHONPATH_VALUE"; then
|
||||
HOST_PCBNEW_STATUS="ok"
|
||||
fi
|
||||
|
||||
if command -v docker >/dev/null 2>&1 && [ -f "$COMPOSE_FILE" ]; then
|
||||
CONTAINER_STATUS="available"
|
||||
else
|
||||
CONTAINER_STATUS="missing"
|
||||
fi
|
||||
|
||||
if [ "$DOCTOR" -eq 1 ]; then
|
||||
cat <<EOF
|
||||
ROOT_DIR=$ROOT_DIR
|
||||
MASCARADE_DIR=$MASCARADE_DIR
|
||||
SERVER_DIR=$SERVER_DIR
|
||||
ENTRYPOINT=$ENTRYPOINT
|
||||
NODE_BIN=$NODE_BIN
|
||||
KICAD_MCP_HOME=$MCP_HOME
|
||||
XDG_CONFIG_HOME=$CONFIG_HOME
|
||||
XDG_CACHE_HOME=$CACHE_HOME
|
||||
KICAD_MCP_DATA_DIR=$DATA_DIR
|
||||
PROBE_PYTHON=$PROBE_PYTHON
|
||||
KICAD_PYTHONPATH=$PYTHONPATH_VALUE
|
||||
HOST_PCBNEW_IMPORT=$HOST_PCBNEW_STATUS
|
||||
CONTAINER_STATUS=$CONTAINER_STATUS
|
||||
KICAD_MCP_IMAGE=$KICAD_MCP_IMAGE
|
||||
SELECTED_RUNTIME=$RUNTIME
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
command -v "$NODE_BIN" >/dev/null 2>&1 || die "node executable not found: $NODE_BIN"
|
||||
[ -d "$MASCARADE_DIR" ] || die "companion repo not found: $MASCARADE_DIR"
|
||||
[ -f "$ENTRYPOINT" ] || die "MCP entrypoint missing: $ENTRYPOINT (run npm build in mascarade/finetune/kicad_mcp_server)"
|
||||
[ -n "$PROBE_PYTHON" ] || die "no Python executable found for KiCad MCP runtime"
|
||||
|
||||
mkdir -p "$MCP_HOME" "$CONFIG_HOME" "$CACHE_HOME" "$DATA_DIR"
|
||||
|
||||
export HOME="$MCP_HOME"
|
||||
export XDG_CONFIG_HOME="$CONFIG_HOME"
|
||||
export XDG_CACHE_HOME="$CACHE_HOME"
|
||||
export KICAD_MCP_DATA_DIR="$DATA_DIR"
|
||||
if [ -n "$PYTHONPATH_VALUE" ]; then
|
||||
export KICAD_PYTHONPATH="$PYTHONPATH_VALUE"
|
||||
fi
|
||||
|
||||
case "$RUNTIME" in
|
||||
auto)
|
||||
if [ "$HOST_PCBNEW_STATUS" = "ok" ]; then
|
||||
RUNTIME="host"
|
||||
else
|
||||
RUNTIME="container"
|
||||
fi
|
||||
;;
|
||||
host|container)
|
||||
;;
|
||||
*)
|
||||
die "invalid runtime: $RUNTIME"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$RUNTIME" = "host" ]; then
|
||||
probe_pcbnew "$PROBE_PYTHON" "${KICAD_PYTHONPATH:-}" || die "pcbnew is not importable from $PROBE_PYTHON. Install KiCad with Python bindings, set KICAD_PYTHON/KICAD_PYTHONPATH, or use --container."
|
||||
debug "exec host $NODE_BIN $ENTRYPOINT $*"
|
||||
exec "$NODE_BIN" "$ENTRYPOINT" "$@"
|
||||
fi
|
||||
|
||||
command -v docker >/dev/null 2>&1 || die "docker is required for container runtime"
|
||||
[ -f "$COMPOSE_FILE" ] || die "compose file not found: $COMPOSE_FILE"
|
||||
|
||||
if ! docker image inspect "$KICAD_MCP_IMAGE" >/dev/null 2>&1; then
|
||||
log "Building kicad-mcp container (KiCad v10 via kicad/kicad:nightly-full)"
|
||||
compose build kicad-mcp >&2
|
||||
fi
|
||||
|
||||
ACTIVE_CONTAINER_NAME="${KICAD_MCP_CONTAINER_NAME:-kill-life-kicad-mcp-$(id -u)-$$}"
|
||||
trap cleanup_container EXIT INT TERM
|
||||
|
||||
debug "exec container kicad-mcp $*"
|
||||
compose run --rm --no-deps -T \
|
||||
--name "$ACTIVE_CONTAINER_NAME" \
|
||||
--user "$(id -u):$(id -g)" \
|
||||
-e HOME="$MCP_HOME" \
|
||||
-e XDG_CONFIG_HOME="$CONFIG_HOME" \
|
||||
-e XDG_CACHE_HOME="$CACHE_HOME" \
|
||||
-e KICAD_MCP_DATA_DIR="$DATA_DIR" \
|
||||
kicad-mcp \
|
||||
sh -lc 'set -e; mkdir -p "$HOME" "$XDG_CONFIG_HOME" "$XDG_CACHE_HOME" "$KICAD_MCP_DATA_DIR"; exec node /opt/kicad-mcp/server/dist/index.js "$@"' sh "$@"
|
||||
status=$?
|
||||
trap - EXIT INT TERM
|
||||
cleanup_container
|
||||
exit $status
|
||||
@@ -3,7 +3,7 @@
|
||||
CLI local pour :
|
||||
- ERC/BOM/netlist via `kicad-cli`
|
||||
- bulk edits via `kicad-sch-api` (si installé)
|
||||
- Design Blocks KiCad 9 (structure + metadata)
|
||||
- Design Blocks KiCad 10 (structure + metadata)
|
||||
|
||||
> Philosophie : **bulk edits safe** (backup + report) + exports déterministes (kicad-cli).
|
||||
|
||||
@@ -66,7 +66,7 @@ python tools/hw/schops/schops.py snapshot --schematic ... --name before.json
|
||||
python tools/hw/schops/schops.py snapshot --schematic ... --name after.json
|
||||
```
|
||||
|
||||
## Design Blocks (KiCad 9)
|
||||
## Design Blocks (KiCad 10)
|
||||
Les design blocks sont des dossiers `*.kicad_block` stockés dans une librairie `*.kicad_blocks`.
|
||||
|
||||
```bash
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Goals:
|
||||
- deterministic exports via kicad-cli (ERC / netlist / BOM)
|
||||
- safe bulk edits via kicad-sch-api (fields / footprints / net labels)
|
||||
- Design Blocks (KiCad 9) helpers
|
||||
- Design Blocks (KiCad 10) helpers
|
||||
|
||||
This tool is intentionally conservative:
|
||||
- it always writes an artifacts report
|
||||
@@ -515,7 +515,7 @@ def cmd_snapshot(args) -> int:
|
||||
|
||||
|
||||
# ---------------------------
|
||||
# Design Blocks (KiCad 9)
|
||||
# Design Blocks (KiCad 10)
|
||||
# ---------------------------
|
||||
|
||||
|
||||
@@ -646,7 +646,7 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
p.add_argument("--name", help="output filename (default snapshot.json)")
|
||||
p.set_defaults(fn=cmd_snapshot)
|
||||
|
||||
p = sub.add_parser("block-make", help="Create a KiCad 9 design block folder")
|
||||
p = sub.add_parser("block-make", help="Create a KiCad 10 design block folder")
|
||||
p.add_argument("--name", required=True)
|
||||
p.add_argument("--from-sheet", required=True, help=".kicad_sch file to package as a block")
|
||||
p.add_argument("--lib", required=True, help="Design blocks library folder (usually *.kicad_blocks)")
|
||||
|
||||
Reference in New Issue
Block a user