Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
d160295
Extract OleReader to shared parsers/ole-reader module with hierarchic…
valentinozegna Mar 4, 2026
fd18360
Add DSN CFBF container exploration tests
valentinozegna Mar 4, 2026
1fcc600
Add BinaryReader for DSN binary parsing
valentinozegna Mar 4, 2026
710f3c4
Add GenericParser prefix/preamble system and structure type enum
valentinozegna Mar 4, 2026
459c0ea
Add DSN structure parsers for netlist-critical types
valentinozegna Mar 4, 2026
8952d70
Add DSN page parser with geometric pin-to-net connectivity
valentinozegna Mar 4, 2026
be467c6
Integrate DSN parser into cadenceHandler with DAT fallback
valentinozegna Mar 4, 2026
eb946d0
Uppercase net names in DSN parser to match Allegro export convention
valentinozegna Mar 4, 2026
2141b38
Add DSN coverage tests and golden files for 9 new Cadence fixtures
valentinozegna Mar 4, 2026
1b71b0e
Use T0x10 netId for net grouping, add DSN debug scripts
valentinozegna Mar 4, 2026
cf3bf01
Wire graph name resolution with segmentId discovery
valentinozegna Mar 5, 2026
b14c627
DSN parser: OPC connectivity, multi-name netId, sentinel pin handling
valentinozegna Mar 5, 2026
6e5af12
Remove unused propPairs plumbing from DSN parser
valentinozegna Mar 5, 2026
4832d56
DSN parser: cross-page net disambiguation, dead code cleanup
valentinozegna Mar 5, 2026
4c28cfe
DSN parser: pin-to-pin sentinel connections, assembleNets refactor
valentinozegna Mar 5, 2026
d956755
Consolidate 24 DSN debug scripts into dsn-inspect.ts
valentinozegna Mar 5, 2026
8d7633d
Widen type-check and lint to include scripts, remove cadence.zip
valentinozegna Mar 5, 2026
b4ca8c4
refactor: move DAT parsers into dat/ subdirectory to mirror dsn/ stru…
valentinozegna Mar 5, 2026
b6c6148
refactor: make buildCadencePinMap pure by returning new ComponentDetails
valentinozegna Mar 5, 2026
3755718
refactor: make DSN the preferred Cadence parsing path
valentinozegna Mar 5, 2026
37a7b7a
feat: parse Package streams for pin numbering and add mpn field to DS…
valentinozegna Mar 5, 2026
a67eeb4
fix: improve pin number resolution with multi-unit and version suffix…
valentinozegna Mar 5, 2026
277e0a1
feat: detect DNS at parse time and strip DNI/NF markers from componen…
valentinozegna Mar 6, 2026
838a6f6
feat: add NC and DNM to DNS detection patterns
valentinozegna Mar 6, 2026
94f9de2
docs: document DNS detection patterns and DAT parser graphical-only l…
valentinozegna Mar 6, 2026
1e31bea
chore: add tmp/ to gitignore and configure Claude Code permissions an…
valentinozegna Mar 6, 2026
8ce40af
feat: extract MPN, Value, and pin names from DSN prefix properties
valentinozegna Mar 6, 2026
a483fd7
feat: add --export-json CLI command for standalone netlist export
valentinozegna Mar 6, 2026
7f5754c
fix: only check first word per segment in enforce-dedicated-tools hook
valentinozegna Mar 6, 2026
6ab3d22
feat: improve DSN pin number coverage from 89.7% to 95.7%
valentinozegna Mar 6, 2026
229beba
feat: sequential Cache stream parser improves PinNum to 98.3% and Pin…
valentinozegna Mar 6, 2026
63af5f8
feat: close DSN coverage gaps and update format documentation
valentinozegna Mar 6, 2026
dd91050
fix: case-insensitive value comparison in coverage report
valentinozegna Mar 6, 2026
4887dd3
feat: positional device assignment for multi-section components (PinN…
valentinozegna Mar 6, 2026
f81454c
feat: global symbol bbox matching resolves power pin connectivity (Pi…
valentinozegna Mar 6, 2026
4270322
feat: OPC edge-midpoint matching for direct pin-to-OPC connections
valentinozegna Mar 6, 2026
329ddea
feat: resolve OPC net names via Library strLst (CutiePi PinNum 99.8% …
valentinozegna Mar 6, 2026
c40d864
docs: update OPC fallback comment to reflect strLst-based resolution
valentinozegna Mar 6, 2026
a6a4af7
feat: Cache pinMap fallback for physical-vs-schematic pad mismatch (P…
valentinozegna Mar 7, 2026
b58a81f
refactor: split dsn-parser.ts monolith into focused modules
valentinozegna Mar 7, 2026
7f70e65
feat: add --coverage CLI command for DSN vs DAT parity analysis
valentinozegna Mar 10, 2026
ffd092a
feat: prefer .dat path for Cadence designs and extract descriptions
valentinozegna Mar 10, 2026
8609f6d
refactor: split service.ts into service/ modules
valentinozegna Mar 10, 2026
b8c4699
refactor: move async-mutex into service/tools/
valentinozegna Mar 10, 2026
ccfec22
fix: exact refdes prefix matching, Altium encoding fallback, and over…
valentinozegna Mar 10, 2026
f4c6ac2
Add v0.1.0 changelog
valentinozegna Mar 10, 2026
2c73d61
v0.1.0
valentinozegna Mar 10, 2026
6475661
chore: fork fixture submodules and add Allegro netlist exports
valentinozegna Mar 10, 2026
2abea87
chore: fork LAUNCHXL-CC1310 submodule and update Allegro exports
valentinozegna Mar 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions .claude/hooks/enforce-dedicated-tools.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env bash
set -uo pipefail

# PreToolUse hook: block Bash commands that should use dedicated tools.
#
# Only blocks when a blocked tool is the PRIMARY command (first in a pipeline).
# Blocked tools after a pipe are allowed (e.g., `npm test | tail -20` is fine).

input=$(cat)
cmd=$(echo "$input" | jq -r '.tool_input.command // empty')

if [[ -z "$cmd" ]]; then
exit 0
fi

# Blocked tools: name -> message
declare -A BLOCKED
BLOCKED[find]="Use the Glob tool to find files, or Grep to search contents."
BLOCKED[fd]="Use the Glob tool to find files, or Grep to search contents."
BLOCKED[grep]="Use the Grep tool instead."
BLOCKED[egrep]="Use the Grep tool instead."
BLOCKED[fgrep]="Use the Grep tool instead."
BLOCKED[rg]="Use the Grep tool instead."
BLOCKED[ag]="Use the Grep tool instead."
BLOCKED[ack]="Use the Grep tool instead."
BLOCKED[cat]="Use the Read tool instead."
BLOCKED[head]="Use the Read tool instead."
BLOCKED[tail]="Use the Read tool instead."
BLOCKED[less]="Use the Read tool instead."
BLOCKED[more]="Use the Read tool instead."
BLOCKED[sed]="Use the Edit tool for modifications, or Read for viewing."
BLOCKED[awk]="Use the Edit tool for modifications, or Read for viewing."

# Sanitize a word: strip quotes, backslashes, shell syntax, then basename
sanitize() {
local w="$1"
w="${w//\\/}" # backslashes
w="${w//\"/}" # double quotes
w="${w//\'/}" # single quotes
w="${w//\(/}" # parens
w="${w//\)/}"
w="${w//\{/}" # braces
w="${w//\}/}"
w="${w//\$/}" # dollar signs
w="${w//\`/}" # backticks
if [[ -z "$w" ]] || [[ "$w" == -* ]]; then
return
fi
basename -- "$w" 2>/dev/null || echo "$w"
}

# Extract the first segment of a pipeline (everything before the first |)
# Also split on ; and && and || to get each independent command
# We only check the primary command of each independent statement
first_segments=""
remainder="$cmd"

# Split on ; && || first to get independent statements
# Then for each statement, only check the first pipeline segment
while IFS= read -r statement; do
# Get text before the first pipe (the primary command of this pipeline)
first_seg="${statement%%|*}"
first_segments+="$first_seg"$'\n'
done < <(echo "$cmd" | sed 's/&&/\n/g; s/||/\n/g; s/;/\n/g')

# Check only the first non-flag, non-empty word of each segment (the command name)
while IFS= read -r segment; do
for word in $segment; do
clean=$(sanitize "$word")
if [[ -z "$clean" ]]; then
continue
fi
# Found the command name; check it and move to next segment
if [[ -n "${BLOCKED[$clean]+x}" ]]; then
echo "BLOCKED: '$clean' is not allowed in Bash. ${BLOCKED[$clean]}" >&2
exit 2
fi
break
done
done <<< "$first_segments"

exit 0
37 changes: 37 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,42 @@
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(npm test *)",
"Bash(npx tsx *)",
"Bash(npx prettier *)",
"Bash(npx eslint *)",
"Bash(bun *)",
"Bash(strings *)",
"Bash(xxd *)",
"Bash(hexdump *)",
"Bash(wc *)",
"Bash(git *)",
"Bash(gh *)",
"Bash(ls *)",
"Bash(mkdir *)",
"Bash(rm tmp/*)",
"Bash(mv tmp/*)",
"Bash(cp tmp/*)",
"Bash(echo *)",
"Bash(which *)",
"Bash(node *)",
"Bash(jq *)"
]
},
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/enforce-dedicated-tools.sh",
"timeout": 5000
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ opencode.json
# OS
.DS_Store
Thumbs.db
*.xsd

# Test coverage
coverage/
Expand All @@ -43,5 +44,7 @@ telemetry-*.zip

# Private files and plans
private/
references/
plans/
.plans/
.plans/
tmp/
12 changes: 12 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,15 @@
[submodule "test/fixtures/cadence/BeagleBone-Black-copy"]
path = test/fixtures/cadence/BeagleBone-Black-copy
url = https://github.com/valentinozegna/beaglebone-black-copy
[submodule "test/fixtures/cadence/OSHW-Jetson-Series"]
path = test/fixtures/cadence/OSHW-Jetson-Series
url = https://github.com/valentinozegna/OSHW-Jetson-Series
[submodule "test/fixtures/cadence/BeagleBoard-xM"]
path = test/fixtures/cadence/BeagleBoard-xM
url = https://github.com/valentinozegna/beagleboard-xm
[submodule "test/fixtures/cadence/CutiePi"]
path = test/fixtures/cadence/CutiePi
url = https://github.com/valentinozegna/cutiepi-board
[submodule "test/fixtures/cadence/LAUNCHXL-CC1310"]
path = test/fixtures/cadence/LAUNCHXL-CC1310
url = https://github.com/valentinozegna/kHome
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,33 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.0] - 2026-03-10

### Added

- DSN binary parser: complete parser for Cadence `.DSN` schematic files (CFBF/OLE container format), providing direct netlist extraction without requiring Cadence's exported `.dat` files. Achieves 100% pin number coverage and 96.1% pin name coverage across 9 test fixtures. Extracts nets, components, pin numbers, pin names, MPN, and Value fields directly from binary schematics.
- DNS (Do Not Stuff) detection at parse time: strips DNI, NF, NC, DNM markers from component fields
- `--export-json` CLI command for standalone netlist export (no MCP server required)
- `--coverage` CLI command for DSN vs DAT parity analysis
- Design descriptions extracted from Cadence project files in `list_designs`
- DSN coverage tests and golden files for 9 Cadence fixtures (BeagleBoard-xM, BeagleBone-Black, CutiePi, LAUNCHXL-CC1310, OSHW-Jetson-Series x5)

### Changed

- `list_designs` prefers `.dat` path for Cadence designs when exported files exist; falls back to `.DSN` path otherwise
- OleReader extracted to shared `parsers/ole-reader` module with hierarchical path support
- DAT parsers reorganized into `dat/` subdirectory
- DSN parser split from monolith into focused modules (`page-parser`, `cache-parser`, `package-parser`, `library-parser`, etc.)
- `service.ts` split into `service/` modules
- Developer scripts consolidated: 24 ad-hoc DSN debug scripts merged into `dsn-inspect.ts`

### Fixed

- Pin number resolution for multi-unit components and version suffix matching
- `list_components` exact refdes prefix matching (e.g., `C` no longer matches `CON`, `L` no longer matches `LED`)
- Altium parser encoding fallback: tries UTF-8 first, falls back to latin1 for Windows-1252 encoded files (fixes corrupted special characters)
- Altium net names with overbar notation (e.g., `\V\C\C`) unescaped to plain text (`VCC`)

## [0.0.22] - 2026-03-02

### Added
Expand Down
36 changes: 36 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ The tag push triggers the release workflow, which automatically:
- Creates GitHub Release with binaries
- Publishes to npm via OIDC (no tokens)

## Scripts

Developer and agent utility scripts for golden file generation, DSN parser coverage analysis, and binary inspection. See [scripts/AGENTS.md](scripts/AGENTS.md) for usage.

## Testing

Tests are colocated with source files (e.g., `service.test.ts`). Run with:
Expand All @@ -96,3 +100,35 @@ npm publishing uses OIDC trusted publishing (configured on npmjs.com) - no token
- OIDC requires npm 11.5.1+ (Node 22 ships with older npm, so we explicitly upgrade)
- Use `npm install` instead of `npm ci` - npm 11.x has stricter lock file validation that fails with cross-platform optional deps (esbuild, rollup)
- Never commit any lockfile (`bun.lock`, `package-lock.json`) - vitest/rollup have cross-platform optional deps

## DSN Parser Reference

**MANDATORY**: Before modifying ANY file under `src/parsers/cadence/dsn/`, you MUST read the corresponding C++ reference implementation in `references/OpenOrCadParser/`. This directory is gitignored but accessible to all agent tools (Glob, Grep, Read). Do not skip this step. The C++ source is the ground truth for how the binary format works, and our TypeScript is a port of it.

### Reference workflow

1. **Read `docs/dsn-format.md`** for the binary format spec
2. **Read the corresponding C++ file** in `references/OpenOrCadParser/` before writing any code
3. Cross-reference `docs/dsn.xsd` / `docs/olb.xsd` for structure/field names if needed

### C++ reference mapping

The TypeScript files in `src/parsers/cadence/dsn/` map to C++ files in `references/OpenOrCadParser/`:

| TypeScript | C++ reference (read this FIRST) |
|---|---|
| `cache-parser.ts` | `src/Streams/StreamCache.cpp` |
| `page-parser.ts` | `src/Streams/StreamPage.cpp` |
| `package-parser.ts` | `src/Streams/StreamPackage.cpp` |
| `library-parser.ts` | `src/Streams/StreamLibrary.cpp` |
| Any structure parsing | `src/Structures/` (e.g., `StructPlacedInstance.cpp`, `StructT0x10.cpp`, `StructWire.cpp`) |
| Prefix/preamble logic | `src/GenericParser.cpp` |

### Additional resources

- **Cadence schemas**: `docs/dsn.xsd`, `docs/olb.xsd`
- **Coverage scripts**: `scripts/dsn-coverage-report.ts`, `scripts/dsn-inspect.ts` (see `scripts/AGENTS.md`)

## Git Guidelines

See the `release` skill (`.claude/skills/release.md`) for commit, push, PR, and release workflows.
5 changes: 5 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@ Universal Netlist MCP Server
Copyright 2024-2025 Valentino Zegna

This product includes software developed by Valentino Zegna.

This product includes code derived from OpenOrCadParser
(https://github.com/Werni2A/OpenOrCadParser)
Copyright (c) 2021 Dominik Wernberger
Licensed under the MIT License
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,13 @@ This project is hosted on GitHub under the [IntelligentElectron](https://github.

Universal Netlist MCP Server and the universal netlist open standard are original works by Valentino Zegna.

## Acknowledgments

The Cadence DSN binary parser is a TypeScript port of
[OpenOrCadParser](https://github.com/Werni2A/OpenOrCadParser) by Dominik
Wernberger. Their work reverse-engineering the OrCAD binary format made
direct schematic parsing possible.

## License

Apache License 2.0 - see [LICENSE](LICENSE)
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The Universal Netlist MCP Server provides tools for querying electronic design n

| Format | Input Files | Description |
|--------|------------|-------------|
| Cadence (CIS / HDL) | `.dat` netlist files | Exported Allegro netlist files (`pstxnet.dat`, `pstxprt.dat`, `pstchip.dat`) from Cadence Capture CIS or HDL designs |
| Cadence (CIS / HDL) | `.dat` files (preferred) or `.DSN` (fallback) | Exported Allegro netlist files (`pstxnet.dat`, `pstxprt.dat`, `pstchip.dat`) are preferred. When unavailable, the `.DSN` binary schematic is parsed directly. |
| Altium Designer | `.SchDoc` | Altium schematic documents (discovered via `.PrjPcb` project files) |

## Design Philosophy
Expand Down
Loading