@olierjs/fugue-cli 0.0.0-stage → 0.1.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.
Files changed (53) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +99 -2
  3. package/THIRD_PARTY_NOTICES +467 -0
  4. package/bin/fugue-cli.mjs +23 -0
  5. package/dist/darwin-arm64/fugue-cli +0 -0
  6. package/dist/darwin-x64/fugue-cli +0 -0
  7. package/dist/linux-arm64/fugue-cli +0 -0
  8. package/dist/linux-x64/fugue-cli +0 -0
  9. package/dist/win32-arm64/fugue-cli.exe +0 -0
  10. package/dist/win32-x64/fugue-cli.exe +0 -0
  11. package/package.json +27 -4
  12. package/scripts/postinstall.mjs +13 -0
  13. package/scripts/skills.mjs +104 -0
  14. package/skills/fugue-show-me/SKILL.md +16 -0
  15. package/skills/fugue-stack/SKILL.md +10 -0
  16. package/skills/plan-with-remote/SKILL.md +60 -0
  17. package/skills/plan-with-remote/references/configuration.md +43 -0
  18. package/skills/plan-with-remote/scripts/client.mjs +61 -0
  19. package/skills/plan-with-remote/scripts/config.mjs +53 -0
  20. package/skills/plan-with-remote/scripts/planning.mjs +279 -0
  21. package/skills/plan-with-remote/scripts/protocol.mjs +147 -0
  22. package/skills/plan-with-remote/scripts/service.mjs +146 -0
  23. package/skills/plan-with-remote/scripts/storage.mjs +74 -0
  24. package/skills/show-me/SKILL.md +128 -0
  25. package/skills/show-me/agents/openai.yaml +2 -0
  26. package/skills/statechart/SKILL.md +36 -0
  27. package/skills/statechart/scripts/bug-states.mjs +81 -0
  28. package/skills/statechart/scripts/chart-edges.mjs +68 -0
  29. package/skills/statechart/scripts/chart-parts.mjs +21 -0
  30. package/skills/statechart/scripts/chart-to-tla.mjs +205 -0
  31. package/skills/statechart/scripts/compare-charts.mjs +74 -0
  32. package/skills/statechart/scripts/lib.mjs +970 -0
  33. package/skills/statechart/scripts/map-view.mjs +92 -0
  34. package/skills/statechart/scripts/property-loop.mjs +60 -0
  35. package/skills/statechart/scripts/read-check.mjs +79 -0
  36. package/skills/statechart/scripts/regions-chart.mjs +307 -0
  37. package/skills/statechart/scripts/render.mjs +531 -0
  38. package/skills/statechart/scripts/rule-book.mjs +84 -0
  39. package/skills/statechart/scripts/second-replay.mjs +122 -0
  40. package/skills/statechart/scripts/snapshot.mjs +74 -0
  41. package/skills/statechart/scripts/spec-text.mjs +126 -0
  42. package/skills/statechart/scripts/statechart-help.mjs +350 -0
  43. package/skills/statechart/scripts/statechart.mjs +903 -0
  44. package/skills/statechart/scripts/test/band.mmd +15 -0
  45. package/skills/statechart/scripts/test/regions.mmd +62 -0
  46. package/skills/statechart/scripts/test/statechart.test.mjs +6854 -0
  47. package/skills/statechart/scripts/test/sync.mmd +19 -0
  48. package/skills/statechart/scripts/test/upload.mmd +16 -0
  49. package/skills/statechart/scripts/tlc-to-chart-args.mjs +52 -0
  50. package/skills/statechart/scripts/tlc-to-chart.mjs +802 -0
  51. package/skills/statechart/scripts/tlc-tools.mjs +69 -0
  52. package/skills/statechart/scripts/ways-in.mjs +69 -0
  53. package/upstream-skills.json +18 -0
@@ -0,0 +1,350 @@
1
+ import { CACHE_NAME, PACKAGES } from "./render.mjs";
2
+
3
+ export const USAGE = {
4
+ "from-spec":
5
+ "node statechart.mjs from-spec SPEC.tla [--config FILE] [--fixed FIXED.tla [--fixed-config FILE] | --against AGREED.tla [--against-config FILE]] [--label TEXT] [--map FILE] [--expect-broken RULE]... [--title TEXT] [--out DIR] [--cover] [--png [--theme NAME]]",
6
+ "from-chart":
7
+ "node statechart.mjs from-chart CHART.mmd [--module NAME] [--expect-broken RULE]... [--title TEXT] [--out DIR] [--png [--theme NAME]]",
8
+ render: "node statechart.mjs render CHART.mmd [--theme NAME] [--out FILE]",
9
+ };
10
+ export const usage = (lines) => `Usage: ${lines.join("\n ")}`;
11
+
12
+ const FROM_SPEC = `from-spec SPEC.tla
13
+ Checks each INVARIANT in SPEC.cfg in a separate TLC run. TLC stops at the first rule that a state
14
+ breaks, and the separate runs find the rest. Each run also has the rule as a CONSTRAINT, so TLC
15
+ stops each path at its first state that breaks the rule, and a rule that stays broken reports
16
+ only the step that broke it. SPEC.cfg has SPECIFICATION and one INVARIANT line per rule. Each
17
+ PROPERTY, a rule about whole behaviors, gets one TLC run too, and the charts do not draw it. TLC
18
+ checks a PROPERTY with no [], <>, or ~> only in the initial states, and the command says so. A
19
+ rule listed as both INVARIANT and PROPERTY is checked once, as an INVARIANT. After those runs
20
+ print their results, one more run dumps the state graph and checks every INVARIANT on every
21
+ state in it, and then the command draws the charts. TLC goes down from the next-state action
22
+ through each \\/, \\E, LET, and definition, and names each step after the last definition on that
23
+ path. It stops at any other expression, such as /\\, IF, or CASE, so a definition inside one names
24
+ no step. Give each kind of step its own definition, and join them with \\/ in the next-state
25
+ action. The command warns when steps carry the name of the whole next-state action. The command
26
+ prints the config that it checks each model with, and stops when a config does not exist, with
27
+ the configs beside the spec.
28
+
29
+ --config FILE The config for SPEC.tla. Default: SPEC.cfg next to the spec.
30
+ --fixed FIXED.tla The model of the open fix. It is a copy of the spec in a different file, such
31
+ as SpecFixed.tla or fix/Spec.tla. The command checks it the same way, with
32
+ FIXED.cfg, or with the config of SPEC.tla when there is no FIXED.cfg. The
33
+ charts then mark each bad state fixed or still wrong. A rule that the
34
+ config of FIXED.tla does not check stays as wrong as it is today. When the
35
+ fix shows the same states and steps as a bug of such a rule, the story says
36
+ "does not check this rule".
37
+ --fixed-config FILE
38
+ The config for FIXED.tla.
39
+ --against AGREED.tla
40
+ The spec that SPEC.tla must follow, when SPEC.tla models the code. It is a
41
+ different file from SPEC.tla. The command checks it with AGREED.cfg, and
42
+ never with the config of SPEC.tla. SPEC.tla may add variables, record fields,
43
+ and actions that AGREED.tla does not have. The comparison leaves them out.
44
+ Do not use it with --fixed.
45
+ --against-config FILE
46
+ The config for AGREED.tla, when it is not AGREED.cfg. Give the config that the
47
+ spec's authors say the unchanged spec passes. When the spec shows the same
48
+ states and steps as a bug of a rule that this config does not check, the
49
+ story says "does not check this rule".
50
+ --label TEXT The name of the --fixed or --against model in the charts and the stories.
51
+ Default: "the fix", or "the spec".
52
+ --map FILE The labels for each model state and step. Default: SPEC.map.mjs next to the
53
+ spec. When the file does not exist, the command writes one from the spec's
54
+ VARIABLES and actions to fill in, and exits 2 before it runs TLC. Its
55
+ comments say what each function gets. The map reads a sequence or tuple
56
+ from 1, as in TLA+, so v.seat[1] is its first item. A map that reads from
57
+ 0, such as v.pc[r - 1], gets the item before the one it wants, and stops
58
+ the run when it reads index 0.
59
+ --cover Draw only the shortest path from the start to each settled state, plus
60
+ every bug path, in the overview. A state is settled when only the
61
+ mapping's readerActions are enabled. The command prints the states and
62
+ arrows that the overview leaves out. The counts of states that work or
63
+ break a rule still include the states it leaves out. When no step in
64
+ TLC's graph is a reader action, the overview draws every state.
65
+
66
+ With --fixed or --against, SPEC.tla (and FIXED.tla) models the code, and the command finds each
67
+ condition of an action that no comment ties to code with a file and line, as in \\* pay.ts:120.
68
+ A condition is a conjunct of the action that changes nothing and reads a variable that the
69
+ action does not change. A rule can hold only because the model waits for a condition that the
70
+ code does not check, so the command prints these conditions when a rule holds.
71
+ With --against, each story says whether a config beside AGREED.tla expects TLC to break the
72
+ bug's rule. A config's "\\* expect: RULE" line says what TLC finds, and "\\* module: NAME" names
73
+ the module it checks when the folder has more than one .tla file. The command warns when no
74
+ config beside AGREED.tla has an expect line for that module.`;
75
+
76
+ const FROM_CHART = `from-chart CHART.mmd
77
+ Writes NAME.tla, NAME.cfg, and NAME.map.mjs next to the chart. When NAME.tla already exists, it
78
+ writes none of them. Otherwise it replaces a NAME.cfg or NAME.map.mjs that is there. Then it
79
+ checks the spec as from-spec does, and compares the chart that the spec draws with CHART.mmd.
80
+
81
+ --module NAME The TLA+ module name. Default: the chart's file name in CamelCase, such as
82
+ NotesApp for notes-app.mmd.
83
+
84
+ The chart is a Mermaid stateDiagram-v2. Each transition label is one action. For parallel
85
+ regions, split one top-level composite with --, and put each part in a named composite, such as
86
+ state Connection { ... }. Each region is one variable. A step moves every region whose current
87
+ state has a transition with the step's label, and the other regions stay where they are. Each
88
+ rule is one comment line:
89
+ %% never NAME: A & B -- the rule in one sentence
90
+ Each name after the colon is a state caption or a composite, and each comes from a different
91
+ region. A composite stands for every state in it. A "%% when ID, ID" or "%% when not ID, ID" line
92
+ right after a transition is its guard, and the transition's label must end with the guard's
93
+ words in [ ]. The region takes the transition only while each other region that the line names
94
+ is in one of the states that it names, or with not, while none is. A transition with no label is
95
+ its own action. NAME.cfg has SPECIFICATION Spec, INVARIANT TypeOK, and one INVARIANT per never
96
+ line. The command refuses final, choice, fork, and history states, and regions below the top
97
+ level.
98
+
99
+ The comparison looks at reachable states, start states, and labeled steps. A chart with regions
100
+ compares as its combined machine, with each state named by its region states joined by " | ", so
101
+ a guard that blocks a step in only some combinations of regions shows as a difference. The
102
+ guard's words in [ ] are not part of the label. A loop compares like any other step. An edge
103
+ label "a or b" counts as two labels. An edge with no label counts only when no labeled edge joins
104
+ the same two states.`;
105
+
106
+ const RENDER = `render CHART.mmd
107
+ Draws one chart as a PNG. It does not run TLC, so the chart can come from from-spec, from
108
+ from-chart, or from a person.
109
+
110
+ --theme NAME The colors of the PNG: light, dark, or classic. Default: light.
111
+ --out FILE The PNG to write. Default: the chart's path with .png in place of .mmd. The
112
+ command makes the folder when it does not exist.
113
+
114
+ Exit codes
115
+ 0 The command wrote the PNG.
116
+ 2 The command cannot finish: a bad argument, a chart that it cannot read, a renderer that it
117
+ cannot install or load, or a PNG that it cannot render or write. It writes no PNG then.`;
118
+
119
+ const PNG = `PNG
120
+ Pele lays out each chart, and resvg draws it at twice its size. A chart that is more than 100
121
+ million pixels at that size draws smaller, at about 100 million pixels. The first PNG installs
122
+ ${PACKAGES.join(" and ")} with npm into a cache folder. The folder is
123
+ $XDG_CACHE_HOME/statechart/${CACHE_NAME}, or
124
+ ~/.cache/statechart/${CACHE_NAME} when XDG_CACHE_HOME is not set. Delete that folder to
125
+ install them again. When npm or the packages fail, the command prints why, exits 2, and writes
126
+ no file.
127
+ The PNG uses the font that fc-match finds for system-ui. The command measures each label in that
128
+ font, so no label goes past its box. When that font is wider than the widths that Pele has built
129
+ in, the command makes the wrap width wider by the same amount, so the lines break where the chart
130
+ breaks them. Without fc-match, or when resvg cannot read that font, the PNG uses Pele's widths.
131
+ Pele puts parallel regions side by side. When a chart with regions has no top-level direction,
132
+ the PNG puts the legend above the regions, so the PNG is narrower.
133
+ --theme picks light, dark, or classic. light is the default. classic keeps the group fills from
134
+ the chart's own classDef lines.`;
135
+
136
+ const COMMON = `Both commands
137
+ --expect-broken RULE
138
+ An INVARIANT or PROPERTY that is known to break. Repeat it, or list rules
139
+ with commas, as in A,B. The command then exits 0 when exactly these rules
140
+ break, and the --fixed or --against model breaks no other rule.
141
+ --title TEXT The chart title. Each bug chart adds ", bug N".
142
+ --out DIR The output folder. Default: NAME-statechart next to the input. A run writes its
143
+ files in a temporary folder, and then replaces the whole output folder with
144
+ it. When runs overlap, the output folder has the files of the run that
145
+ finished last. The command does not use an output folder that has files that
146
+ it did not write. On a filesystem that cannot rename, the command copies the
147
+ files into place, and overlapping runs can mix their files.
148
+ --png Also draw each chart as a PNG. The PNG section tells how.
149
+ --theme NAME The colors of each PNG: light, dark, or classic. Default: light. It needs
150
+ --png.
151
+ -h, --help Print this help, and exit 0.
152
+
153
+ Output
154
+ The command prints whether each rule holds, the chart's counts, and one story per bug.
155
+ from-chart also prints the comparison. The command writes these files in the output folder:
156
+ chart.mmd The overview.
157
+ bug-N.mmd Only the steps of bug N, numbered. Bugs are numbered by fewest reader steps,
158
+ then fewest model steps, then rule name, then cause. Bugs that only the
159
+ --fixed or --against model has come last.
160
+ bug-N-developer.mmd, bug-N-layered.mmd
161
+ The path of bug N through the developer's states, when the mapping exports
162
+ detail(). The layered chart puts each detail state in a box named by its
163
+ state label. A state with a blank detail stays a plain state.
164
+ stories.md One entry per bug: the rule, why it breaks, the steps that lead into it, the
165
+ shortest path in reader steps, and what the --fixed or --against model does
166
+ instead. The rule's sentence is the \\* comment lines above the rule in the
167
+ spec, or in a module in its folder that the spec EXTENDS, directly or
168
+ through another module. With --fixed or --against, the other spec and its
169
+ modules count too, after SPEC.tla and its modules. The entry numbers each
170
+ step that changes the state label, each reader action, each step that
171
+ changes a variable that the rule reads, and the step into the bug. Between
172
+ them, it counts the hidden steps and names each different step once. Above
173
+ the steps, a line names up to five different steps that lead into the bug,
174
+ most common first, and counts the rest. When more than one step or start
175
+ state leads into the bug, the entry says that the path is the shortest that
176
+ TLC found. A step leads into the bug when it goes there from a state that
177
+ keeps the bug's own rule. That state can already break other rules. "(the
178
+ state stays the same)" marks a step on that line that keeps the state's
179
+ label and is not on the bug's path. from-spec does not draw such a step.
180
+ When TLC names the steps only after the whole next-state action, the entry
181
+ cannot count them. Then one line per broken PROPERTY with its sentence,
182
+ which comes only from its own spec file, the reader states that repeat
183
+ forever, if any, and the TLC output that has its counterexample.
184
+ summary.json The counts behind the chart. Each bug has counterexamples, how many model
185
+ states end it, each with its own TLC trace; lastSteps, the steps that lead
186
+ into it, most common first; and startsHere, whether a start state is in it.
187
+ brokenProperties has each broken PROPERTY, its rule sentence, the reader
188
+ states that repeat forever as repeats, and its TLC output. mixedStatus
189
+ lists the states that break a rule in some cases. chartGroups counts the
190
+ drawn states of each group, and mixedGroups lists the states in more than
191
+ one group. With --cover, cover lists the states and arrows that the
192
+ overview leaves out. With --fixed or --against, uncited has the conditions
193
+ with no file and line for each code model. With --against, second.listed
194
+ has what each config beside AGREED.tla expects, and each bug has the
195
+ configs that list it.
196
+ tlc/ The config and the TLC output of each run. When the overview has regions,
197
+ from-spec also writes tlc/regions-all.mmd, the regions with every arrow, and
198
+ tlc/regions-proof.mmd, every state and step of TLC's graph in one region.
199
+ compare-charts.mjs tlc/regions-all.mmd tlc/regions-proof.mmd repeats the
200
+ proof. It prints "same" and exits 0, or prints each difference and exits 1.
201
+ *.png Each chart as a PNG, with --png. A run without --png deletes them.
202
+
203
+ Reading a chart
204
+ from-spec draws the overview as two parallel regions when every state reads "context: progress":
205
+ the contexts on one side, the progress on the other, both at the same time. It does so only when
206
+ that has fewer states, when the regions combine back into exactly every state and step of TLC's
207
+ graph, and when each state's color is the worse color of its two region states. Otherwise it puts
208
+ the states of one context in a box named context, and prints why. Each state in a box shows only
209
+ its progress, and a context with one state stays a plain state.
210
+ Regions draw only the arrows of the shortest way to each state, of each bug path, and of the
211
+ nearest step with each label. The script checks that these arrows make no step that TLC's graph
212
+ does not have. At a step that they make wrongly, it puts back every arrow that the full regions
213
+ take there.
214
+ An arrow from a box's border leaves from every state in the box. The chart draws it only when
215
+ every state in the box takes the step with the same labels to the same state, and no state
216
+ outside the box has the box's name.
217
+ In regions, a step leaves every region that has it. "[when A or B]" or "[unless A or B]",
218
+ whichever is shorter, says which states of the other region the step needs, and a "%% when" or
219
+ "%% when not" line under it lists their ids. A loop says the region may also stay.
220
+ Other words in [ ] come from the mapping's guard(), and "after N s" from its timer(). An edge
221
+ shows guard() words only when every model step behind it has them. In regions, they replace
222
+ "when A or B" and "unless A or B". TLC does not check them, and has no clock, so a reviewer
223
+ checks them against the code.
224
+ Gray states work. Red states break a rule. An orange state breaks a rule in some cases: a model
225
+ state under its label breaks a rule, and a path without a bug reaches another one. A white state
226
+ is reached only after a bug: every path from the start to its model states passes a state that
227
+ breaks a rule, and none of them breaks one. With --fixed, red, orange, and white describe the
228
+ fix, and green states are fixed by it or exist only with it. A purple state breaks a rule only
229
+ with the fix: today it works, is reached only after a bug, or does not exist. With --against, a
230
+ state takes the worse of its two models' colors, red, then orange, then white, and green states
231
+ exist only in the spec.
232
+ When the mapping exports group(), the fill is the state's group, which the legend names. A chart
233
+ state is in a group when all its model states are in it, and a region state when every state
234
+ that it is part of is in it. A state in no group, or in more than one, is gray. The legend lists
235
+ the groups that the chart draws: first the groups in groupColors, in that order, then the others
236
+ from A to Z, and then each status border that the chart uses. groupColors gives a group a light
237
+ "#rgb" or "#rrggbb" color. A group with no color takes the next free palette color: light blue,
238
+ orange, purple, yellow, teal, tan, then pink. A group cannot have the name of a status, such as
239
+ "Breaks a rule". Without group(), the legend shows only the statuses that the chart uses. In the
240
+ .mmd file, the status is a thick border of its color, gray for a white state, on top of the group
241
+ fill. In a PNG, a red, orange, purple, or white state is a box of that color with a border and
242
+ text of its color in place of its group fill, and a fixed state is a green box, so each box shows
243
+ one signal.
244
+ A thick blue border and numbered labels mark the bug. With group(), and in a PNG, the blue border
245
+ marks only the states on the bug's path that work, and the numbered labels show the rest.
246
+ Mermaid state diagrams cannot color an edge.
247
+ Each bug replays on the other model by its state labels and step words, which are what the
248
+ reader sees. The replay takes the bug's own steps. Between them, it also takes the other model's
249
+ steps of actions that SPEC.tla's state graph does not have, when they keep the state label, are
250
+ not reader actions, and change no variable that the broken rule reads. A bug step that the story
251
+ hides must keep the state label on the other model too, unless that model cannot take it. A step
252
+ that the reader sees takes a step with the same words between the same two state labels, and
253
+ prefers a step of the same action. A hidden step of an action that the other model does not have
254
+ is skipped. A step that the reader sees of such an action takes any step to the same shared state
255
+ when it changes a shared variable, or else a step with the same words between the same two state
256
+ labels.
257
+ A label "with the fix, STEP" or "in the spec, STEP" is a step that only the other model takes. On
258
+ a bug's path it leaves the state before the first step that the other model shows the reader
259
+ differently, and ends where that model goes instead. The story quotes the other model's words
260
+ when they differ. "with the fix, STEP cannot happen at step N" or "in the spec, STEP cannot
261
+ happen at step N" loops on the state where that model stops the step, on an arrow of its own. On
262
+ the overview, the label ends with "of bug M". Outside regions, two states otherwise have at most
263
+ one arrow between them. Its lines are the numbered steps, then SPEC.tla's steps, then the other
264
+ model's steps, with a blank line between each group.
265
+ The other model may have other variables, record fields, and actions. The comparison leaves out a
266
+ variable or field that no state of one model has, in its state graph or its traces, and one whose
267
+ values never have the same type in the two models. One mapping draws both models, so it may read
268
+ only what both have. The command stops when the mapping reads, on a state of the other model, a
269
+ variable or field that no state of that model has, or one whose value has a type that SPEC.tla
270
+ never has there. It also stops when the mapping lists the fields of such a state, as a spread,
271
+ Object.keys, or JSON.stringify does. Test "name" in v before the mapping reads a field that the
272
+ other model lacks. The command also stops when a label, guard, group, or cause that the mapping
273
+ makes for the other model has the word "undefined" in it.
274
+ A chart with another model has the line "%% second model (fix|against): LABEL" right after
275
+ stateDiagram-v2. Each chart starts with front matter that keeps Mermaid from shrinking it to the
276
+ page or wrapping its labels again.
277
+ An edge lists every step that takes it, most common first. Words that the steps share at the
278
+ start are written once, as in "you tap Pay or Back".
279
+
280
+ Regenerate
281
+ List every rule that is known to break with --expect-broken, the goals and the known bugs. Each
282
+ run then exits 0 until a rule changes, so one script rebuilds every chart and stops on any change:
283
+ set -e
284
+ node statechart.mjs from-spec Code.tla --against Agreed.tla --expect-broken NoLostUpload --png
285
+ A run that leaves a broken rule out of --expect-broken exits 1, and set -e stops the script there.
286
+
287
+ TLC
288
+ TLA2TOOLS is the path to tla2tools.jar, and JAVA is the path to the java binary. With only
289
+ TLA2TOOLS set, the command runs java from PATH. Otherwise it uses TLC 1.7.4 and Java temurin-25
290
+ from mise, or JAVA when it is set, and installs what is missing with mise. The first install
291
+ downloads about 305 MB and needs the network. It checks the checksum of tla2tools.jar. mise runs
292
+ in an empty temporary folder, so the mise files around the spec, in a repo, or above TMPDIR do
293
+ not apply, do not change, and need no trust. When mise cannot start or fails, the command prints
294
+ why, the install command, and how to set TLA2TOOLS and JAVA instead.
295
+ When the command starts, it copies its input files, which Exit codes lists. TLC checks the
296
+ copies, so an edit during the run does not change what TLC checks.
297
+ TLC checks each rule with one worker per CPU. When a rule is broken, TLC checks it again with one
298
+ worker, which finds the shortest bug paths, the same on every run. The command then prints how
299
+ many times TLC ran and how long that took.
300
+ TLC can find that a rule is broken and then stop on an error, such as a Java exception. The
301
+ command then keeps the paths that TLC printed, marks the rule broken, and warns that the charts
302
+ can miss states that break it. A smaller constant can let TLC finish.
303
+
304
+ Exit codes
305
+ 0 Every rule holds, or exactly the --expect-broken rules break. from-chart also draws CHART.mmd
306
+ back unchanged.
307
+ 1 Another rule is broken, an expected rule holds, or the chart that the spec draws is not
308
+ CHART.mmd. The output says which.
309
+ 2 The command cannot finish: a bad argument, a missing file, a chart or TLC output that it
310
+ cannot read, no TLC, a helper script that cannot start, an output folder with files that the
311
+ command did not write, an input file whose content changed during the run, a new mapping to
312
+ fill in, a mapping that it cannot use, a renderer that --png cannot install or load, or a
313
+ chart that --png cannot render.
314
+ When a chart does not render, the command keeps the files it wrote and exits 2, whatever the
315
+ rules give. Otherwise, exit 2 does not change the output folder, unless the command moved it
316
+ aside and cannot put it back. Then the message names the folder's new path. When the command
317
+ stops after TLC has run, it keeps the files that it wrote, TLC's output among them, in a
318
+ temporary folder, and the message names it. When TLC's state graph is too large to draw, the
319
+ command prints whether each rule holds and exits 2, whatever the rules give. It stops TLC as
320
+ soon as the graph passes that size. The input files are the spec and config, the --fixed or
321
+ --against spec and config, the chart, and the map. Each .tla file in the same folder that an
322
+ input .tla file EXTENDS or INSTANCEs is an input file too, and so is each file that an input
323
+ .mjs or .js file imports by a relative path. Before --png renders, and again before it writes
324
+ the output folder, the command compares the content of each input file with its content at
325
+ the start. A save that does not change the content does not stop the run.`;
326
+
327
+ export const HELP = {
328
+ "": `${usage([...Object.values(USAGE), "node statechart.mjs [from-spec|from-chart|render] --help"])}
329
+
330
+ Draws a Mermaid statechart from TLC's state graph of a TLA+ spec. The spec can model any system,
331
+ such as a product flow, a protocol, a service, a job queue, or an algorithm. A mapping labels each
332
+ state and step in the words of the person who reads the chart, and the help calls that person the
333
+ reader. The reader can be a user, an operator, an engineer, or a reviewer.
334
+
335
+ ${FROM_SPEC}
336
+
337
+ ${FROM_CHART}
338
+
339
+ ${COMMON}
340
+
341
+ ${RENDER}
342
+
343
+ ${PNG}`,
344
+ "from-spec": `${usage([USAGE["from-spec"]])}\n\n${FROM_SPEC}\n\n${COMMON}\n\n${PNG}`,
345
+ "from-chart": `${usage([USAGE["from-chart"]])}\n\n${FROM_CHART}\n\n${COMMON}\n\n${PNG}`,
346
+ render: `${usage([USAGE.render])}\n\n${RENDER}\n\n${PNG}`,
347
+ };
348
+
349
+ export const more = (cmd) =>
350
+ `Run node statechart.mjs ${cmd ? `${cmd} ` : ""}--help for the flags, the output, and the exit codes.`;