app
AI Flow
Public Made by Adomby adom
Adom's AI Flow: a tool to help the AI follow all of the steps it takes to build a board.
main
John Lauer
Publish 0.2.56
73fcf19
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
"""Issues #153 and #163 through the CLI: `silkscreen-audit --board` builds its own input from the saved board
(a 45 degree label beside a round test point is not a collision; a label on a pad is a finding, exit 0), and
`silkscreen fab-check` / `fab-tidy` report and apply the Fab layer standard without a run.
python3 tests/silk-fab-workflow.py <abs path to target/release/adom-aiflow>
"""
import json, os, subprocess, sys, tempfile
from pathlib import Path
BIN = sys.argv[1]
ENV = dict(os.environ, AIFLOW_DASHBOARD='off', AIFLOW_NO_PART_SEARCH='1', AIFLOW_NO_PART_LOOKUP='1')
BOARD = '''(kicad_pcb (version 20241229) (generator "pcbnew") (net 0 "") (layers (0 "F.Cu" signal) (31 "B.Cu" signal))
(gr_rect (start 0 0) (end 30 30) (layer "Edge.Cuts"))
(footprint "TestPoint:TP" (layer "F.Cu") (at 10 10 0)
(property "Reference" "TP1" (at 1.5 -1.5 45) (layer "F.SilkS") (uuid "t1") (effects (font (size 0.8 0.8) (thickness 0.12))))
(property "Value" "TP 3V3" (at 0 4 0) (layer "F.Fab") (uuid "t2") (effects (font (size 1 1) (thickness 0.15))))
(fp_text user "${REFERENCE}" (at 0 2.5 0) (layer "F.Fab") (uuid "t3") (effects (font (size 0.26 0.26) (thickness 0.04))))
(fp_circle (center 0 0) (end 1 0) (stroke (width 0.1) (type solid)) (fill no) (layer "F.Fab"))
(fp_circle (center 0 0) (end 1.5 0) (stroke (width 0.05) (type solid)) (fill no) (layer "F.CrtYd"))
(pad "1" smd circle (at 0 0) (size 2 2) (layers "F.Cu" "F.Mask")))
(footprint "R:R_0805" (layer "F.Cu") (at 20 20 0)
(property "Reference" "R1" (at 0 0 0) (layer "F.SilkS") (uuid "r1") (effects (font (size 0.8 0.8) (thickness 0.12))))
(property "Value" "10k" (at 0 1.6 0) (layer "F.Fab") (uuid "r2") (effects (font (size 1 1) (thickness 0.15))))
(fp_rect (start -1 -0.625) (end 1 0.625) (stroke (width 0.1) (type solid)) (layer "F.Fab"))
(fp_rect (start -1.68 -0.95) (end 1.68 0.95) (stroke (width 0.05) (type solid)) (layer "F.CrtYd"))
(pad "1" smd roundrect (at -0.9 0) (size 1 1.45) (layers "F.Cu" "F.Mask"))
(pad "2" smd roundrect (at 0.9 0) (size 1 1.45) (layers "F.Cu" "F.Mask")))
(via (at 25 5) (size 0.6) (drill 0.3) (layers "F.Cu" "B.Cu") (net 0)))
'''
def call(*args, cwd=None):
return subprocess.run([BIN, '--ai-thread', 'silk-fab-test', *args], capture_output=True, text=True, env=ENV, cwd=cwd)
with tempfile.TemporaryDirectory() as tmp:
p = Path(tmp)
board = p / 'b.kicad_pcb'
board.write_text(BOARD)
# --- #153: the input is built from the board; R1's label sits on its own pads (a real collision), TP1's 45 degree label does not
r = call('--run', str(p / 'norun'), 'silkscreen-audit', '--board', str(board), '--out', str(p / 'res.json'))
out = r.stdout + r.stderr
assert r.returncode == 0 and 'FINDINGS' in out and 'rectangle check' in out, out
inp = json.loads((p / 'silkscreen-audit-input.json').read_text())
assert {i['id'] for i in inp['inventory']} == {'TP1', 'R1', 'via0'}, inp['inventory']
res = json.loads((p / 'res.json').read_text())
hits = {(c['mark'], c['obstacle']) for c in res['collisions']}
assert ('R1-reference', 'R1') in hits, hits
assert not any(m.startswith('TP1') and o == 'TP1' for m, o in hits), hits
# move R1's label off the part: the audit passes
board.write_text(BOARD.replace('(property "Reference" "R1" (at 0 0 0)', '(property "Reference" "R1" (at 0 -2.2 0)'))
r = call('--run', str(p / 'norun'), 'silkscreen-audit', '--board', str(board), '--out', str(p / 'res.json'))
assert r.returncode == 0 and r.stdout.startswith('OK'), r.stdout + r.stderr
# --- #163: fab-check names the sprawl; fab-tidy writes a copy that meets the standard
r = call('--run', str(p / 'norun'), 'silkscreen', 'fab-check', '--board', str(board))
out = r.stdout + r.stderr
assert r.returncode == 0 and 'FINDINGS' in out and 'value(s) shown on the Fab layer' in out and 'fab-tidy' in out, out
r = call('--run', str(p / 'norun'), 'silkscreen', 'fab-tidy', '--board', str(board), '--size', '1')
out = r.stdout + r.stderr
tidied = p / 'b-fab.kicad_pcb'
assert r.returncode == 0 and tidied.is_file() and 'adopt-board' in out, out
assert board.read_text() != tidied.read_text() and '(at 0 -2.2 0) (layer "F.SilkS")' in tidied.read_text()
r = call('--run', str(p / 'norun'), 'silkscreen', 'fab-check', '--board', str(tidied))
assert r.returncode == 0 and r.stdout.startswith('OK: Fab layer meets the standard'), r.stdout + r.stderr
print('PASS: silkscreen-audit builds its input from the board (45 degree label by a round pad clear, a label on its pads a finding); fab-check names the Fab sprawl and fab-tidy fixes it')