jssm 5.144.0 → 5.144.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,10 +18,10 @@ Please edit the file it's derived from, instead: `./src/md/readme_base.md`
18
18
 
19
19
 
20
20
 
21
- * Generated for version 5.144.0 at 6/21/2026, 3:13:56 PM
21
+ * Generated for version 5.144.2 at 6/22/2026, 6:51:17 AM
22
22
 
23
23
  -->
24
- # jssm 5.144.0
24
+ # jssm 5.144.2
25
25
 
26
26
  [**Try the live editor**](https://stonecypher.github.io/jssm-viz-demo/graph_explorer.html) ·
27
27
  [Documentation](https://stonecypher.github.io/jssm/docs/) ·
@@ -312,7 +312,7 @@ That decision shows up everywhere downstream:
312
312
  or run `npm run benny` against your own machine.
313
313
 
314
314
  - **More thoroughly tested than any other JavaScript state-machine
315
- library.** 7,305 tests at 100.0% line coverage
315
+ library.** 7,310 tests at 100.0% line coverage
316
316
  ([report](https://coveralls.io/github/StoneCypher/jssm)), plus
317
317
  fuzz testing via `fast-check`, with parser test data across ten natural
318
318
  languages and Emoji.
@@ -445,11 +445,11 @@ If your contribution is missing here, please open an issue.
445
445
 
446
446
  <br/>
447
447
 
448
- ***7,305 tests***, run 82,347 times.
448
+ ***7,310 tests***, run 82,352 times.
449
449
 
450
- - 6,547 specs with 100.0% coverage
451
- - 758 fuzz tests with 74.4% coverage
452
- - 6,801 TypeScript lines - 1.1 tests per line, 12.1 generated tests per line
450
+ - 6,552 specs with 100.0% coverage
451
+ - 758 fuzz tests with 73.9% coverage
452
+ - 6,892 TypeScript lines - 1.1 tests per line, 11.9 generated tests per line
453
453
 
454
454
  [![Actions Status](https://github.com/StoneCypher/jssm/workflows/Node%20CI/badge.svg)](https://github.com/StoneCypher/jssm/actions)
455
455
  [![NPM version](https://img.shields.io/npm/v/jssm.svg)](https://www.npmjs.com/package/jssm)
@@ -23514,7 +23514,7 @@ var constants = /*#__PURE__*/Object.freeze({
23514
23514
  * Useful for runtime diagnostics and for embedding in serialized machine
23515
23515
  * snapshots so that deserializers can detect version-skew.
23516
23516
  */
23517
- const version = "5.144.0";
23517
+ const version = "5.144.2";
23518
23518
 
23519
23519
  // whargarbl lots of these return arrays could/should be sets
23520
23520
  const { state_name_chars, state_name_first_chars, action_label_chars } = constants;
package/dist/cdn/viz.js CHANGED
@@ -23539,7 +23539,7 @@ var constants = /*#__PURE__*/Object.freeze({
23539
23539
  * Useful for runtime diagnostics and for embedding in serialized machine
23540
23540
  * snapshots so that deserializers can detect version-skew.
23541
23541
  */
23542
- const version = "5.144.0";
23542
+ const version = "5.144.2";
23543
23543
 
23544
23544
  // whargarbl lots of these return arrays could/should be sets
23545
23545
  const { state_name_chars, state_name_first_chars, action_label_chars } = constants;
@@ -0,0 +1,219 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ function parseFslArgs(argv, spec) {
5
+ const positional = [];
6
+ const flags = {};
7
+ const shortMap = {};
8
+ for (const [name, fs] of Object.entries(spec.flags)) {
9
+ if (fs.short) shortMap[fs.short] = name;
10
+ }
11
+ const isBoolean = (name) => spec.flags[name]?.boolean === true;
12
+ const flagType = (name) => {
13
+ const fs = spec.flags[name];
14
+ return fs.type ?? "string";
15
+ };
16
+ const coerce = (name, raw) => {
17
+ const t = flagType(name);
18
+ if (t === "number") {
19
+ const n = Number(raw);
20
+ if (Number.isNaN(n)) {
21
+ throw new Error(`flag --${name} requires a number, got: ${raw}`);
22
+ }
23
+ return n;
24
+ }
25
+ const fs = spec.flags[name];
26
+ if (fs.enum && !fs.enum.includes(raw)) {
27
+ throw new Error(`flag --${name} value '${raw}' not in: ${fs.enum.join(", ")}`);
28
+ }
29
+ return raw;
30
+ };
31
+ let i = 0;
32
+ let positionalOnly = false;
33
+ while (i < argv.length) {
34
+ const a = argv[i];
35
+ if (positionalOnly) {
36
+ positional.push(a);
37
+ i++;
38
+ continue;
39
+ }
40
+ if (a === "--") {
41
+ positionalOnly = true;
42
+ i++;
43
+ continue;
44
+ }
45
+ if (a === "-") {
46
+ positional.push(a);
47
+ i++;
48
+ continue;
49
+ }
50
+ if (a.startsWith("--")) {
51
+ const eq = a.indexOf("=");
52
+ const name = eq >= 0 ? a.slice(2, eq) : a.slice(2);
53
+ if (!(name in spec.flags)) throw new Error(`unknown flag: --${name}`);
54
+ if (isBoolean(name)) {
55
+ flags[name] = true;
56
+ i++;
57
+ } else if (eq >= 0) {
58
+ flags[name] = coerce(name, a.slice(eq + 1));
59
+ i++;
60
+ } else {
61
+ if (i + 1 >= argv.length) throw new Error(`flag --${name} requires a value`);
62
+ flags[name] = coerce(name, argv[i + 1]);
63
+ i += 2;
64
+ }
65
+ continue;
66
+ }
67
+ if (a.startsWith("-") && a.length > 1) {
68
+ const short = a[1];
69
+ const name = shortMap[short];
70
+ if (!name) throw new Error(`unknown flag: -${short}`);
71
+ if (isBoolean(name)) {
72
+ flags[name] = true;
73
+ if (a.length > 2) throw new Error(`combined short flags not supported: ${a}`);
74
+ i++;
75
+ } else if (a.length > 2) {
76
+ flags[name] = coerce(name, a.slice(2));
77
+ i++;
78
+ } else {
79
+ if (i + 1 >= argv.length) throw new Error(`flag -${short} requires a value`);
80
+ flags[name] = coerce(name, argv[i + 1]);
81
+ i += 2;
82
+ }
83
+ continue;
84
+ }
85
+ positional.push(a);
86
+ i++;
87
+ }
88
+ for (const [name, fs] of Object.entries(spec.flags)) {
89
+ if (flags[name] === void 0 && fs.default !== void 0) {
90
+ flags[name] = fs.default;
91
+ }
92
+ }
93
+ const helpText = () => {
94
+ const lines = [];
95
+ lines.push("Usage:");
96
+ lines.push(" " + spec.usage);
97
+ lines.push("");
98
+ lines.push("Options:");
99
+ for (const [name, fs] of Object.entries(spec.flags)) {
100
+ const short = fs.short ? `-${fs.short}, ` : " ";
101
+ const longPart = `--${name}`;
102
+ const arg = fs.boolean ? "" : fs.enum ? ` ${fs.enum.join("|")}` : fs.type === "number" ? " N" : " VALUE";
103
+ const defStr = fs.default !== void 0 ? ` (default: ${fs.default})` : "";
104
+ lines.push(` ${short}${longPart}${arg}${defStr}`);
105
+ }
106
+ return lines.join("\n");
107
+ };
108
+ return { positional, flags, helpText };
109
+ }
110
+
111
+ const getVersion = () => "5.144.2";
112
+ const SPEC = {
113
+ flags: {
114
+ help: { short: "h", boolean: true },
115
+ version: { short: "V", boolean: true }
116
+ },
117
+ usage: "fsl-export-system-prompt [options]"
118
+ };
119
+ const writeStdout = (s) => {
120
+ process.stdout.write(s);
121
+ };
122
+ const writeStderr = (s) => {
123
+ process.stderr.write(s);
124
+ };
125
+ const printErr = (msg) => {
126
+ writeStderr(`fsl-export-system-prompt: error: ${msg}
127
+ `);
128
+ };
129
+ const SYSTEM_PROMPT = `
130
+ # FSL v5 Agent System Prompt (llms.txt)
131
+
132
+ > **Context**: This document is intended to be served as an \`llms.txt\` file (as standardized by [llmstxt.org](https://llmstxt.org) and similar AI directories) to provide Large Language Models with a mathematically precise, up-to-date syntax guide for FSL (Finite State Language).
133
+
134
+ You are an expert developer in FSL (Finite State Language) v5, a domain-specific language for defining mathematically verifiable, finite state machines. Your primary goal is to generate idiomatic, structurally sound FSL v5 code.
135
+
136
+ ## Core Concepts
137
+
138
+ 1. **Machines**: An FSL file defines a state machine. It contains metadata (like \`machine_name\`) and a set of state transitions.
139
+ 2. **States & Transitions**: FSL is built on transitions between states. States are automatically inferred from transitions, or can be explicitly declared.
140
+ 3. **Transition Types**:
141
+ * \`->\` (Legal transition)
142
+ * \`=>\` (Main transition)
143
+ * \`~>\` (Forced transition)
144
+ * \`<->\` (Bi-directional legal)
145
+ * \`<= >\` (Main left, legal right)
146
+ * \`<~>\` (Bi-directional forced)
147
+ 4. **Actions**: Transitions can be triggered by actions. E.g., \`A 'click' -> B;\`
148
+ 5. **Probabilities**: Transitions can carry probabilities. E.g., \`A -> 50% B;\`
149
+ 6. **Attributes**: Machines can have properties like \`machine_name\`, \`machine_author\`, \`machine_version\`.
150
+
151
+ ## Syntax Guide
152
+
153
+ ### Basic Machine
154
+ \`\`\`fsl
155
+ machine_name : "Simple Traffic Light";
156
+ machine_author : "John Doe";
157
+ machine_version : 1.0.0;
158
+
159
+ Red 'timer' => Green 'timer' => Yellow 'timer' => Red;
160
+ \`\`\`
161
+
162
+ ### Actions and Multiple Targets
163
+ \`\`\`fsl
164
+ machine_name : "Vending Machine";
165
+
166
+ Off 'insert coin' -> Idle;
167
+ Idle 'select item' -> Dispensing;
168
+ Dispensing 'dispense' -> Off;
169
+ Idle 'cancel' -> Off;
170
+ \`\`\`
171
+
172
+ ### Explicit State Declarations and Attributes
173
+ \`\`\`fsl
174
+ state Red {
175
+ background-color : red;
176
+ text-color : white;
177
+ };
178
+
179
+ state Green {
180
+ background-color : green;
181
+ };
182
+
183
+ Red -> Green;
184
+ \`\`\`
185
+
186
+ ## Agent Directives
187
+ - **Do not hallucinate features**: FSL is a strict, finite state machine language. Do not attempt to use unbounded loops or syntax from general-purpose languages like Python or JavaScript.
188
+ - **Always output valid FSL**: Ensure statements end with semicolons (\`;\`).
189
+ - **Use single quotes for actions**: E.g., \`StateA 'action name' -> StateB;\`.
190
+
191
+ ---
192
+ *Generated by the FSL v5 Toolchain*
193
+ `;
194
+ async function cli(argv) {
195
+ let parsed;
196
+ try {
197
+ parsed = parseFslArgs(argv, SPEC);
198
+ } catch (e) {
199
+ printErr(e.message);
200
+ return 1;
201
+ }
202
+ if (parsed.flags.help) {
203
+ writeStdout(parsed.helpText() + "\n");
204
+ return 0;
205
+ }
206
+ if (parsed.flags.version) {
207
+ writeStdout("fsl-export-system-prompt " + getVersion() + "\n");
208
+ return 0;
209
+ }
210
+ writeStdout(SYSTEM_PROMPT.trim() + "\n");
211
+ return 0;
212
+ }
213
+
214
+ async function main() {
215
+ const argv = process.argv.slice(2);
216
+ const code = await cli(argv);
217
+ process.exit(code);
218
+ }
219
+ void main();