npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

secs-gem-host

v0.2.0

Published

SECS/GEM host test tool: E30 startup conformance, JSON scenarios, and an MCP server for AI agents.

Readme

secs-gem-host

The open-source SECS/GEM host you point at equipment-side software to see whether it actually works. One command runs the SEMI E30 host startup sequence and prints a PASS/FAIL conformance table; the same engine is exposed as an MCP server so an AI agent can drive it.

npx secs-gem-host connect 127.0.0.1:5501 --report

Node ≥ 20. MIT. No runtime dependency except the MCP SDK.

Commands

secs-gem-host connect <host:port> [startup|state] [options]
secs-gem-host mcp

| Option | Meaning | |---|---| | --device-id <n> | HSMS session / device id (default 0) | | --passive | listen for the equipment instead of connecting to it; the <host:port> positional is the bind address, so use 127.0.0.1:<port> unless you need other machines to reach it | | --report | run a conformance report, print the table, exit 1 on any FAIL. The kind is the positional after <host:port>: startup (default) is the 10-step E30 startup; state is the 6 E30 state rules — S1F1 aborted with S1F0 before S1F13, S2F41 refused with HCACK 2 until S1F17 — and must run on a fresh connection | | --scenario <file> | run a JSON scenario after startup | | --model <file> | equipment model used by startup steps 6–8 (default: bundled models/default.json) | | --quiet | suppress the decoded message log | | --linktest <sec> | linktest interval, 0 disables (default 30) | | --t3 --t5 --t6 --t7 --t8 <sec> | HSMS timers in seconds (E37 defaults 45 10 5 10 5) |

Plain connect stays up, prints every message in and out in SML with a timestamp and a direction, and re-runs the whole startup after a reconnect — like a real host.

The E30 startup

| Step | Send | Expect | PASS when | |---|---|---|---| | HSMS | Select.req | Select.rsp | status 0 within T6 | | 1 | S1F13 W | S1F14 | COMMACK 0, MDLN/SOFTREV present | | 2 | S1F17 W | S1F18 | ONLACK 0 or 2 | | 3 | S1F3 W (empty) | S1F4 | list, within T3 | | 4 | S1F11 W (empty) | S1F12 | non-empty SVID list | | 5 | S2F29 W (empty) | S2F30 | list | | 6 | S2F33 W (delete all, then define) | S2F34 | DRACK 0 | | 7 | S2F35 W | S2F36 | LRACK 0 | | 8 | S2F37 W (CEED true, all) | S2F38 | ERACK 0 | | 9 | S5F3 W (ALED enable, zero-length ALID = all alarms) | S5F4 | ACKC5 0 | | 10 | S2F31 W (now) | S2F32 | TIACK 0 | | idle | Linktest.req every 30 s | Linktest.rsp | within T6 |

The host answers S1F13 with S1F14, S1F1 with S1F2, S5F1 with S5F2, S6F11 with S6F12 and S6F1 with S6F2, and sends S9F3/S9F5/S9F9 on the standard conditions.

Beyond the per-step result, --report flags: S9Fx received, unsolicited <SxFy> before S1F14, reply outside T3 on <SxFy>, wrong system bytes on reply <SxFy>, W-bit set on reply <SxFy>, and primary with even function <SxFy>.

Scenarios

A scenario is a JSON array of steps run after startup. Bodies use the same item-tree shape as the SECS-II codec API.

[
  { "send": "S2F41", "body": { "type": "L", "children": [
      { "type": "A", "value": "START" },
      { "type": "L", "children": [] }
  ] } },
  { "expect": "S6F11", "ceid": 10001, "within": 5000 },
  { "wait": 1000 },
  { "drop-ack": "S6F11" },
  { "sleep-t3": true }
]

| Step | Effect | |---|---| | {"send": "SxFy", "body": ...} | send a message; an odd function sets the W-bit and waits for the reply | | {"expect": "SxFy", "ceid": n, "within": ms} | wait for a received message, optionally matching a CEID | | {"wait": ms} | pause | | {"drop-ack": "SxFy"} | do not ack the next SxFy primary, to exercise the equipment's retry/spool path | | {"sleep-t3": true} | answer the next primary 46 s late, past T3, on purpose |

Exit code is 1 if any scenario step or any startup step failed.

Item-tree body syntax

{ "type": "L", "children": [
  { "type": "A", "value": "TEXT" },
  { "type": "U4", "value": [1, 2, 3] },
  { "type": "BOOLEAN", "value": [true] },
  { "type": "B", "value": [0, 255] }
] }

Types: L B BOOLEAN A J I1 I2 I4 I8 U1 U2 U4 U8 F4 F8. Non-list scalar values are arrays; A/J take a string.

MCP server

Register it with Claude Code:

claude mcp add secs-gem-host -- npx -y secs-gem-host mcp

or in .mcp.json:

{
  "mcpServers": {
    "secs-gem-host": { "command": "npx", "args": ["-y", "secs-gem-host", "mcp"] }
  }
}

Tools: connect, disconnect, send, startup, events, status. startup returns the report object (rows, passed, total, flags) plus the rendered table; its optional kind is "startup" (default) or "state" for the six E30 state rules, which needs a fresh connection.

scadathings_feedback is the one tool that does not talk to equipment: it POSTs to scadathings.com to say whether one of its articles helped you solve a SECS/GEM problem, or that the article is wrong or outdated. It takes slug (e.g. secs-gem-s1f13-establish-communications), helped, and optionally a note (≤ 500 chars) and an agent name. Only what you pass is sent.

Equipment model

--model takes a JSON file describing what steps 6–8 should define:

{
  "mdln": "GENERIC-1",
  "softrev": "1.0.0",
  "svs": [{ "id": 101, "name": "SV_101", "type": "U2", "units": "", "value": 0 }],
  "reports": [{ "rptid": 10001, "vids": [10001, 10002] }],
  "events": [{ "ceid": 10001, "name": "EVENT_10001", "rptids": [10001] }],
  "alarms": [{ "alid": 1001, "text": "ALARM_1001" }]
}

The bundled default follows a common industrial numbering scheme: SVIDs 1–3 for the fixed GEM variables, 101+ for process values, 10000+ for named SVs and DVs, RPTID and CEID in parallel from 10001, ALIDs from 1001.

Testing your own equipment: write a model file

The bundled model is a guess. Real equipment has its own ids, and steps 6-8 define reports and link events by number — so with the default model the equipment answers DRACK 4 / LRACK 4 / ERACK 1 ("that id does not exist here"), which is a mismatch, not a defect.

  1. Copy models/default.json next to your run (keep it out of any public repo if the ids are customer data).
  2. Replace svs, reports, events and alarms with the equipment's own SVIDs, VIDs, RPTIDs, CEIDs and ALIDs. Step 4's S1F12 namelist prints the SVIDs the equipment actually has; the run also flags model VIDs not in equipment SVID list: <ids> before it sends S2F33. That flag is advisory — a VID that is a DV or an EC is legitimately absent from the S1F12 namelist.
  3. Run with --model <file>.
node dist/cli.js connect 127.0.0.1:5000 --report --t3 5 --device-id 1 --model site-model.json

--device-id must match the equipment's configured session id. If it does not, the equipment answers every primary with S9F1 (unrecognised device id) and every step fails.

Known findings

Results of running this tool against real equipment implementations.

secs-gem-simulator EQ1 (2026-09-05)

node dist/cli.js connect 127.0.0.1:5501 --report --quiet

Step Sent    Expect  Got     Ack  Time(ms)    Result  Note
------------------------------------------------------------------------
1    S1F13   S1F14   -       -    45009/45000 FAIL    T3 (S1F13) timeout
2    S1F17   S1F18   -       -    45018/45000 FAIL    T3 (S1F17) timeout
3    S1F3    S1F4    -       -    45005/45000 FAIL    T3 (S1F3) timeout
4    S1F11   S1F12   -       -    45026/45000 FAIL    T3 (S1F11) timeout
5    S2F29   S2F30   -       -    45005/45000 FAIL    T3 (S2F29) timeout
6    S2F33   S2F34   -       -    45022/45000 FAIL    T3 (S2F33) timeout
7    S2F35   S2F36   -       -    45010/45000 FAIL    T3 (S2F35) timeout
8    S2F37   S2F38   -       -    45020/45000 FAIL    T3 (S2F37) timeout
9    S5F3    S5F4    -       -    45007/45000 FAIL    T3 (S5F3) timeout
10   S2F31   S2F32   -       -    45021/45000 FAIL    T3 (S2F31) timeout
------------------------------------------------------------------------
E30 startup: 0/10 passed
flag: reply outside T3 on S1F13
flag: reply outside T3 on S1F17
flag: reply outside T3 on S1F3
flag: reply outside T3 on S1F11
flag: reply outside T3 on S2F29
flag: reply outside T3 on S2F33
flag: reply outside T3 on S2F35
flag: reply outside T3 on S2F37
flag: reply outside T3 on S5F3
flag: reply outside T3 on S2F31
exit=1

Every row is the same failure, so it is one finding, not ten.

  • Step 1 — the simulator did not send S1F14; the host waited the full T3 and gave up.
  • Steps 2–10 — S1F18, S1F4, S1F12, S2F30, S2F34, S2F36, S2F38, S5F4 and S2F32 never arrived either, for the same reason. The host sent S9F9 (transaction timer timeout) after each one and carried on to the next step, as E30 requires.

As of 2026-09-05 the simulator completes HSMS Select and answers Linktest, but sends no reply to any SECS-II data message. Every step therefore timed out at T3 (45 s), so the run takes about 7.5 minutes; pass --t3 5 to shorten it.

Changelog

0.2.0

  • --report state: six steps that score the E30 state rules instead of the startup sequence. Run on a fresh connection: S1F1 must come back as S1F0 before S1F13, and S2F41 must be refused (HCACK ≠ 0) until S1F17 has put the tool ON-LINE REMOTE. secs-gem-host connect 127.0.0.1:5501 state --report.
  • The MCP startup tool takes kind: "startup" | "state".

0.1.1

  • S5F3 "enable all alarms" is now E5-correct. The body was L[B 0x80, U4 [0]]; "all alarms" is a zero-length ALID item, L[B 0x80, U4 []]. Equipment that rejects an unknown ALID answered ACKC5 1 to the old body.
  • DRACK 4 / LRACK 4 / ERACK 1 now say what to do: the note names the model mismatch and points at --model, and the SVID namelist from step 4 is compared against the model's report VIDs, so the run flags model VIDs not in equipment SVID list: <ids> before S2F33 goes out.

Development

npm install
npm test        # tsc && chmod +x dist/cli.js && node --test "dist/test/**/*.js"

Licence

MIT © Yoseok Jung