Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
0795f07
Add optional description and metadata fields to SDCPN nodes
claude Sep 1, 2026
a4cf3de
Fix formatting and avoid deep draft typing over stored nets
claude Sep 1, 2026
2635b14
Merge remote-tracking branch 'origin/main' into claude/fe-1567-sdcpn-…
claude Sep 1, 2026
3eb6fcf
Split the description/metadata changeset per package and document cha…
claude Sep 1, 2026
a804e8d
Restore immer mutation style in the local-storage demo
claude Sep 1, 2026
5485f79
Derive input metadata types from the SDCPN types
claude Sep 1, 2026
a83c8d8
Fix the DescriptionTextArea doc comment and give the textarea a fixed…
claude Sep 1, 2026
2174fc5
Add descriptions to the nodes of the built-in example nets
claude Sep 1, 2026
7f4a71b
Regenerate skill rules for the changeset keyword
claude Sep 1, 2026
23def78
Move changeset guidance into a publishing-packages skill
claude Sep 1, 2026
88e1cfa
Reword the changesets for consumers
claude Sep 1, 2026
d30fc2c
Merge origin/main into claude/fe-1567-sdcpn-description-metadata
claude Sep 3, 2026
7363092
Merge branch 'main' into claude/fe-1567-sdcpn-description-metadata
CiaranMn Sep 4, 2026
8220267
Merge branch 'main' into claude/fe-1567-sdcpn-description-metadata
CiaranMn Sep 4, 2026
2512b26
Fit the description textarea to its content on mount
claude Sep 4, 2026
363b0bb
Add descriptions to the Café Queue and Drone Patrol examples
claude Sep 4, 2026
94ad663
Add descriptions to the website example models
claude Sep 4, 2026
6a4c5d8
Store the truck-fleet scenario code in the form the compiler accepts
claude Sep 4, 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
33 changes: 33 additions & 0 deletions .agents/skills/publishing-packages/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
name: publishing-packages
description: Conventions for publishing npm packages from this repository, including when a PR needs a changeset and how to write one. Use when adding or editing a changeset, versioning or releasing a package, or deciding whether a change to a publishable library needs a changelog entry.
license: AGPL-3.0
metadata:
triggers:
type: domain
enforcement: suggest
priority: high
keywords:
- changeset
- changelog
- npm publish
- release
- version bump
intent-patterns:
- "\\b(add|write|create|edit|split)\\b.*?\\bchangesets?\\b"
- "\\b(publish|release|version)\\b.*?\\bpackages?\\b"
---

# Publishing Packages

npm-publishable packages in this repository are versioned and released with [changesets](https://github.com/changesets/changesets). The changeset configuration, including which packages are ignored, lives in [`.changeset/config.json`](../../../.changeset/config.json).

## Changesets

A PR that changes an npm-publishable package adds a changeset file under `.changeset/`. The changeset text becomes the package's published changelog entry, so write it for the package's consumers:

- Describe the change as a consumer of the package experiences it: behaviour changes, bug fixes, and interface changes. Leave out implementation details that do not affect consumers, and do not mention this repository or its internal systems.
- Every sentence must apply to each package the changeset lists. When a PR changes several packages in different ways, write a separate changeset for each package.
- Use at most one paragraph per changeset.

A package's own `AGENTS.md` can carry further conventions, such as the bump level it accepts; check it before writing the changeset.
5 changes: 5 additions & 0 deletions .changeset/sdcpn-description-metadata-core.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hashintel/petrinaut-core": patch
---

SDCPN elements carry an optional `description` (places, transitions, types, subnets, component instances, and the net root) and an optional `metadata` record of JSON values (transitions, subnets, component instances, and the net root). `metadata` is host-defined and opaque to the library. Both fields validate against the entity schemas, survive file import/export, and are preserved when an `SDCPNInput` is normalized. Files written without the fields still validate.
5 changes: 5 additions & 0 deletions .changeset/sdcpn-description-metadata-ui.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hashintel/petrinaut": patch
---

The place, transition, component-instance, and type properties panels display and allow editing of the element's optional `description`.
1 change: 1 addition & 0 deletions .claude/skills/publishing-packages
27 changes: 27 additions & 0 deletions .claude/skills/skill-rules.json
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,33 @@
"blockMessage": "Skill is required to proceed",
"skipConditions": {}
},
"publishing-packages": {
"type": "domain",
"enforcement": "suggest",
"priority": "high",
"description": "Conventions for publishing npm packages from this repository, including when a PR needs a changeset and how to write one. Use when adding or editing a changeset, versioning or releasing a package, or deciding whether a change to a publishable library needs a changelog entry.",
"promptTriggers": {
"keywords": [
"changeset",
"changelog",
"npm publish",
"release",
"version bump"
],
"intentPatterns": [
"\\b(add|write|create|edit|split)\\b.*?\\bchangesets?\\b",
"\\b(publish|release|version)\\b.*?\\bpackages?\\b"
]
},
"fileTriggers": {
"include": [],
"exclude": [],
"content": [],
"create-only": false
},
"blockMessage": "Skill is required to proceed",
"skipConditions": {}
},
"rust-coding-style": {
"type": "domain",
"enforcement": "suggest",
Expand Down
5 changes: 2 additions & 3 deletions apps/petrinaut-website/scripts/generate-example-artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
exampleCatalog,
type ExampleCatalogEntry,
} from "../src/examples/catalog-metadata.ts";
import { normalizeExampleDefinition } from "../src/examples/normalize-example.ts";

const scriptDirectory = dirname(fileURLToPath(import.meta.url));
const examplesDirectory = resolve(scriptDirectory, "../src/examples");
Expand All @@ -33,8 +32,8 @@ const readModelFile = async (slug: string): Promise<SDCPN> => {
if (!parsed.ok) {
throw new Error(`${slug}: ${parsed.error}`);
}
const { title: _title, ...rawDefinition } = parsed.sdcpn;
return normalizeExampleDefinition(slug, rawDefinition);
const { title: _title, ...definition } = parsed.sdcpn;
return definition;
};

const loadDefinition = (entry: ExampleCatalogEntry): Promise<SDCPN> => {
Expand Down
5 changes: 2 additions & 3 deletions apps/petrinaut-website/src/examples/catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
type ExampleSlug,
type ModelFileExampleSlug,
} from "./catalog-metadata";
import { normalizeExampleDefinition } from "./normalize-example";

export {
exampleCatalog,
Expand Down Expand Up @@ -88,8 +87,8 @@ const loadModelFile = async (slug: ModelFileExampleSlug): Promise<SDCPN> => {
throw new Error(parsed.error);
}

const { title: _title, ...rawDefinition } = parsed.sdcpn;
return normalizeExampleDefinition(slug, rawDefinition);
const { title: _title, ...definition } = parsed.sdcpn;
return definition;
};

const loadDefinition = async (entry: ExampleCatalogEntry): Promise<SDCPN> => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
{
"id": "place__idle_tankers",
"name": "IdleTankers",
"description": "Tankers parked at the depot and free to be dispatched. Dispatch takes one; unloading returns it.",
"colorId": null,
"dynamicsEnabled": false,
"differentialEquationId": null,
Expand All @@ -13,6 +14,7 @@
{
"id": "place__loads_delivered",
"name": "LoadsDelivered",
"description": "Cumulative count of tanker deliveries unloaded at a customer.",
"colorId": null,
"dynamicsEnabled": false,
"differentialEquationId": null,
Expand All @@ -23,6 +25,7 @@
{
"id": "place__s1_order_placed",
"name": "SteadyNitrogenOrderPlaced",
"description": "An open order from the steady nitrogen customer, waiting for a tanker. At most one is open at a time because raising an order also takes the order permit.",
"colorId": null,
"dynamicsEnabled": false,
"differentialEquationId": null,
Expand All @@ -33,6 +36,7 @@
{
"id": "place__s1_order_permits",
"name": "SteadyNitrogenOrderPermits",
"description": "The single permit that lets the steady nitrogen customer have one order open at a time. Raising an order takes it; unloading the delivery hands it back.",
"colorId": null,
"dynamicsEnabled": false,
"differentialEquationId": null,
Expand All @@ -43,6 +47,7 @@
{
"id": "place__s1_on_route",
"name": "SteadyNitrogenOnRoute",
"description": "A dispatched tanker travelling to the steady nitrogen customer with a 12-unit load.",
"colorId": null,
"dynamicsEnabled": false,
"differentialEquationId": null,
Expand All @@ -53,6 +58,7 @@
{
"id": "place__s1_vented",
"name": "SteadyNitrogenVented",
"description": "Cumulative units of product the steady nitrogen customer lost through the relief valve because the tank was full.",
"colorId": null,
"dynamicsEnabled": false,
"differentialEquationId": null,
Expand All @@ -63,6 +69,7 @@
{
"id": "place__s1_line_running",
"name": "SteadyNitrogenLineRunning",
"description": "Marker token present while the production line of the steady nitrogen customer is running on gas from the tank.",
"colorId": null,
"dynamicsEnabled": false,
"differentialEquationId": null,
Expand All @@ -73,6 +80,7 @@
{
"id": "place__s1_line_stopped",
"name": "SteadyNitrogenLineStopped",
"description": "Marker token present while the line of the steady nitrogen customer is stopped because the tank is empty.",
"colorId": null,
"dynamicsEnabled": false,
"differentialEquationId": null,
Expand All @@ -83,6 +91,7 @@
{
"id": "place__s1_stockouts",
"name": "SteadyNitrogenStockouts",
"description": "Cumulative count of times the tank of the steady nitrogen customer ran dry and stopped the line.",
"colorId": null,
"dynamicsEnabled": false,
"differentialEquationId": null,
Expand All @@ -93,6 +102,7 @@
{
"id": "place__s1_consumed",
"name": "SteadyNitrogenConsumed",
"description": "Cumulative units drawn by the process of the steady nitrogen customer.",
"colorId": null,
"dynamicsEnabled": false,
"differentialEquationId": null,
Expand All @@ -103,6 +113,7 @@
{
"id": "place__s1_evaporated",
"name": "SteadyNitrogenEvaporated",
"description": "Cumulative units lost to boil-off from the cryogenic tank of the steady nitrogen customer.",
"colorId": null,
"dynamicsEnabled": false,
"differentialEquationId": null,
Expand All @@ -113,6 +124,7 @@
{
"id": "place__s1_contents",
"name": "SteadyNitrogenContents",
"description": "Units of liquid in the tank of the steady nitrogen customer. Draw and boil-off take one at a time and a delivery adds 12; Contents plus Ullage is the tank's capacity.",
"colorId": null,
"dynamicsEnabled": false,
"differentialEquationId": null,
Expand All @@ -123,6 +135,7 @@
{
"id": "place__s1_ullage",
"name": "SteadyNitrogenUllage",
"description": "Empty space in the tank of the steady nitrogen customer, in units. Every unit drawn, boiled off, or vented frees one; a delivery needs 12 free units to unload.",
"colorId": null,
"dynamicsEnabled": false,
"differentialEquationId": null,
Expand All @@ -133,6 +146,7 @@
{
"id": "place__s1_units_drawn_since_order",
"name": "SteadyNitrogenUnitsDrawnSinceOrder",
"description": "Counter of units the steady nitrogen customer has drawn since the last order was raised. Reaching 8 raises the next order, so ordering follows consumption rather than tank level.",
"colorId": null,
"dynamicsEnabled": false,
"differentialEquationId": null,
Expand All @@ -145,6 +159,7 @@
{
"id": "transition__s1_draw",
"name": "Draw a unit (SteadyNitrogen)",
"description": "The process of the steady nitrogen customer draws one unit from the tank into Consumed, freeing one unit of ullage and advancing the units-drawn counter. Enabled only while draw_enabled is set, so the shut-plant scenario can switch consumption off.",
"inputArcs": [
{
"placeId": "place__s1_contents",
Expand Down Expand Up @@ -175,6 +190,7 @@
{
"id": "transition__s1_boil_off",
"name": "Boil off a unit (SteadyNitrogen)",
"description": "Heat leak evaporates one unit from the tank of the steady nitrogen customer into Evaporated, freeing one unit of ullage. Runs whether or not the customer is drawing.",
"inputArcs": [
{
"placeId": "place__s1_contents",
Expand All @@ -201,6 +217,7 @@
{
"id": "transition__s1_raise_order",
"name": "Raise an order, 8 units drawn (SteadyNitrogen)",
"description": "Places an order for the steady nitrogen customer once 8 units have been drawn since the last order, consuming the counter and the single order permit.",
"inputArcs": [
{
"placeId": "place__s1_units_drawn_since_order",
Expand Down Expand Up @@ -228,6 +245,7 @@
{
"id": "transition__s1_dispatch",
"name": "Dispatch a tanker (SteadyNitrogen)",
"description": "Pairs the open order of the steady nitrogen customer with an idle tanker and sends it on route.",
"inputArcs": [
{
"placeId": "place__s1_order_placed",
Expand Down Expand Up @@ -255,6 +273,7 @@
{
"id": "transition__s1_arrive",
"name": "Unload the tanker (SteadyNitrogen)",
"description": "The tanker arrives at the steady nitrogen customer and discharges 12 units into the tank, which must have 12 units of ullage to take them. Returns the order permit and the tanker to the depot and counts a delivery.",
"inputArcs": [
{
"placeId": "place__s1_on_route",
Expand Down Expand Up @@ -294,6 +313,7 @@
{
"id": "transition__s1_vent",
"name": "Vent through the relief valve (SteadyNitrogen)",
"description": "With no ullage left in the tank of the steady nitrogen customer, boil-off gas has nowhere to go: one unit is vented and one unit of ullage is left free.",
"inputArcs": [
{
"placeId": "place__s1_contents",
Expand Down Expand Up @@ -325,6 +345,7 @@
{
"id": "transition__s1_stop_line",
"name": "Stop the line (SteadyNitrogen)",
"description": "When the tank of the steady nitrogen customer is empty (inhibitor arc on Contents) the running line stops and a stockout is counted.",
"inputArcs": [
{
"placeId": "place__s1_line_running",
Expand Down Expand Up @@ -356,6 +377,7 @@
{
"id": "transition__s1_resume_line",
"name": "Resume the line (SteadyNitrogen)",
"description": "The stopped line of the steady nitrogen customer restarts as soon as the read arc sees product back in the tank.",
"inputArcs": [
{
"placeId": "place__s1_line_stopped",
Expand Down Expand Up @@ -482,5 +504,6 @@
"meta": {
"generator": "Petrinaut"
},
"title": "Gases 1 — plain net, one customer (consumption trigger)"
"title": "Gases 1 — plain net, one customer (consumption trigger)",
"description": "The one-customer plain net with a different ordering policy: an order is raised after 8 units have been drawn rather than when the tank level drops below a trigger. Boil-off drains the tank without advancing the counter, so a shut plant can run dry before an order is ever placed."
}
Loading
Loading