@olierjs/fugue-cli 0.1.0 → 0.1.3
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 +54 -2
- package/THIRD_PARTY_NOTICES +52 -1
- package/dist/darwin-arm64/fugue-cli +0 -0
- package/dist/darwin-x64/fugue-cli +0 -0
- package/dist/linux-arm64/fugue-cli +0 -0
- package/dist/linux-x64/fugue-cli +0 -0
- package/dist/win32-arm64/fugue-cli.exe +0 -0
- package/dist/win32-x64/fugue-cli.exe +0 -0
- package/package.json +2 -1
- package/skills/fugue-show-me/SKILL.md +44 -0
- package/skills/fugue-show-me/assets/diagram.css +77 -0
- package/skills/fugue-show-me/references/pele.md +68 -0
- package/skills/fugue-show-me/scripts/render-html.mjs +116 -0
- package/skills/show-me/SKILL.md +128 -0
- package/skills/show-me/agents/openai.yaml +2 -0
- package/skills/statechart/SKILL.md +36 -0
- package/skills/statechart/scripts/bug-states.mjs +81 -0
- package/skills/statechart/scripts/chart-edges.mjs +68 -0
- package/skills/statechart/scripts/chart-parts.mjs +21 -0
- package/skills/statechart/scripts/chart-to-tla.mjs +205 -0
- package/skills/statechart/scripts/compare-charts.mjs +74 -0
- package/skills/statechart/scripts/lib.mjs +970 -0
- package/skills/statechart/scripts/map-view.mjs +92 -0
- package/skills/statechart/scripts/property-loop.mjs +60 -0
- package/skills/statechart/scripts/read-check.mjs +79 -0
- package/skills/statechart/scripts/regions-chart.mjs +307 -0
- package/skills/statechart/scripts/render.mjs +531 -0
- package/skills/statechart/scripts/rule-book.mjs +84 -0
- package/skills/statechart/scripts/second-replay.mjs +122 -0
- package/skills/statechart/scripts/snapshot.mjs +74 -0
- package/skills/statechart/scripts/spec-text.mjs +126 -0
- package/skills/statechart/scripts/statechart-help.mjs +350 -0
- package/skills/statechart/scripts/statechart.mjs +903 -0
- package/skills/statechart/scripts/test/band.mmd +15 -0
- package/skills/statechart/scripts/test/regions.mmd +62 -0
- package/skills/statechart/scripts/test/statechart.test.mjs +6854 -0
- package/skills/statechart/scripts/test/sync.mmd +19 -0
- package/skills/statechart/scripts/test/upload.mmd +16 -0
- package/skills/statechart/scripts/tlc-to-chart-args.mjs +52 -0
- package/skills/statechart/scripts/tlc-to-chart.mjs +802 -0
- package/skills/statechart/scripts/tlc-tools.mjs +69 -0
- package/skills/statechart/scripts/ways-in.mjs +69 -0
- package/upstream-skills.json +18 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import process from "node:process";
|
|
6
|
+
|
|
7
|
+
// TLC's v1.8.0 is a rolling pre-release whose jar is re-uploaded, so pin the newest immutable
|
|
8
|
+
// release. The scripts read 1.7.4's output, which has no trace spec.
|
|
9
|
+
export const TLC_TOOL =
|
|
10
|
+
"github:tlaplus/tlaplus[asset_pattern=tla2tools.jar,checksum=sha256:936a262061c914694dfd669a543be24573c45d5aa0ff20a8b96b23d01e050e88]@1.7.4";
|
|
11
|
+
export const JAVA_TOOL = "java@temurin-25";
|
|
12
|
+
|
|
13
|
+
const SET_TLC_VARS =
|
|
14
|
+
"set TLA2TOOLS to the path of tla2tools.jar, and JAVA to a java binary (Java 11 or later).";
|
|
15
|
+
const indent = (text) => text.replace(/^/gm, " ");
|
|
16
|
+
|
|
17
|
+
export function findTlc() {
|
|
18
|
+
const { TLA2TOOLS, JAVA } = process.env;
|
|
19
|
+
for (const [name, file] of Object.entries({ JAVA, TLA2TOOLS }))
|
|
20
|
+
if (file && !fs.existsSync(file)) throw new Error(`${name} is ${file}, which does not exist.`);
|
|
21
|
+
if (TLA2TOOLS) return { jar: TLA2TOOLS, java: JAVA || "java" };
|
|
22
|
+
const command = (tools) =>
|
|
23
|
+
`cd "$(mktemp -d)" && MISE_CEILING_PATHS="$PWD" mise install ${tools.map((t) => `'${t}'`).join(" ")}`;
|
|
24
|
+
const empty = fs.mkdtempSync(path.join(os.tmpdir(), "statechart-mise-"));
|
|
25
|
+
const env = { ...process.env, MISE_CEILING_PATHS: empty };
|
|
26
|
+
const run = (...args) => spawnSync("mise", args, { cwd: empty, env, encoding: "utf8" });
|
|
27
|
+
const mise = (...args) => {
|
|
28
|
+
const r = run(...args);
|
|
29
|
+
if (r.error)
|
|
30
|
+
throw new Error(
|
|
31
|
+
`Cannot find TLC. It installs with mise, which cannot start: ${r.error.message}. Install mise (https://mise.jdx.dev), or ${SET_TLC_VARS}`,
|
|
32
|
+
);
|
|
33
|
+
if (r.status === 0) return r.stdout.trim();
|
|
34
|
+
const said = (r.stderr ?? "").trim();
|
|
35
|
+
if (!said || /not installed|mise bin/.test(said)) return "";
|
|
36
|
+
throw new Error(
|
|
37
|
+
`Cannot find TLC, because mise failed:\n${indent(said)}\nThe install command: ${command(JAVA ? [TLC_TOOL] : [JAVA_TOOL, TLC_TOOL])}\nFix that, or ${SET_TLC_VARS}`,
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
const resolve = () => {
|
|
41
|
+
const home = mise("where", TLC_TOOL);
|
|
42
|
+
const jar = home && path.join(home, "tla2tools.jar");
|
|
43
|
+
const java = JAVA || mise("which", "java", "--tool", JAVA_TOOL);
|
|
44
|
+
return { jar: jar && fs.existsSync(jar) ? jar : "", java };
|
|
45
|
+
};
|
|
46
|
+
try {
|
|
47
|
+
const found = resolve();
|
|
48
|
+
if (found.jar && found.java) return found;
|
|
49
|
+
const tools = [!found.java && JAVA_TOOL, !found.jar && TLC_TOOL].filter(Boolean);
|
|
50
|
+
const names = [!found.jar && "TLC", !found.java && "Java"].filter(Boolean);
|
|
51
|
+
console.error(`Installing ${names.join(" and ")} with mise. This happens once.`);
|
|
52
|
+
const r = run("install", "--quiet", ...tools);
|
|
53
|
+
const installed = resolve();
|
|
54
|
+
if (installed.jar && installed.java) return installed;
|
|
55
|
+
const said =
|
|
56
|
+
`${r.stderr ?? ""}${r.stdout ?? ""}`.trim() ||
|
|
57
|
+
`mise install exited ${r.status}, with no output`;
|
|
58
|
+
throw new Error(
|
|
59
|
+
`Cannot find TLC, and mise could not install it:\n${indent(said)}\nThe install command: ${command(tools)}\nOr ${SET_TLC_VARS}`,
|
|
60
|
+
);
|
|
61
|
+
} finally {
|
|
62
|
+
fs.rmSync(empty, { recursive: true, force: true });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function cannotRunTlc({ java, jar }, r) {
|
|
67
|
+
const said = `java exited ${r.status ?? r.signal}:\n${indent(`${r.stderr}${r.stdout}`.trim())}`;
|
|
68
|
+
return `cannot run TLC with ${java} -cp ${jar}: ${r.error?.message ?? said}\nFix that, or ${SET_TLC_VARS}`;
|
|
69
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { joinAnd } from "./lib.mjs";
|
|
2
|
+
import { badOf, reachableAvoiding } from "./bug-states.mjs";
|
|
3
|
+
|
|
4
|
+
export function stepsIntoBugs(cs, m, raw, { story, summary, next }) {
|
|
5
|
+
if (!cs.length || (!story && !summary)) return cs;
|
|
6
|
+
const { graph: g, stateKeys } = m;
|
|
7
|
+
const unnamed = new Set(next);
|
|
8
|
+
const rules = new Set(cs.map((c) => c.invariant));
|
|
9
|
+
const clean = new Map([...rules].map((r) => [r, reachableAvoiding(m, badOf(raw, r))]));
|
|
10
|
+
const byEnd = new Map();
|
|
11
|
+
for (const c of cs) for (const k of c.ends) byEnd.set(k, [...(byEnd.get(k) ?? []), c]);
|
|
12
|
+
const ways = new Map(cs.map((c) => [c, { steps: new Map(), n: 0, nameless: 0, action: null }]));
|
|
13
|
+
for (const e of g.edges) {
|
|
14
|
+
const into = byEnd.get(stateKeys.get(e.to))?.filter((c) => clean.get(c.invariant).has(e.from));
|
|
15
|
+
if (!into?.length) continue;
|
|
16
|
+
const [before, after] = [g.nodes.get(e.from).vars, g.nodes.get(e.to).vars];
|
|
17
|
+
const label = m.step(e.action, before, after) || e.action;
|
|
18
|
+
const moves = m.key(before) !== m.key(after);
|
|
19
|
+
for (const c of into) {
|
|
20
|
+
const w = ways.get(c);
|
|
21
|
+
const s = w.steps.get(label) ?? { n: 0, moves: false };
|
|
22
|
+
w.steps.set(label, { n: s.n + 1, moves: s.moves || moves });
|
|
23
|
+
w.n++;
|
|
24
|
+
if (!unnamed.has(e.action)) continue;
|
|
25
|
+
w.nameless++;
|
|
26
|
+
w.action = e.action;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const starts = [...g.nodes.values()].filter((n) => n.init).map((n) => stateKeys.get(n.id));
|
|
30
|
+
return cs.map((c) => {
|
|
31
|
+
const { steps, n, nameless, action } = ways.get(c);
|
|
32
|
+
const lastSteps = [...steps]
|
|
33
|
+
.sort((a, b) => b[1].n - a[1].n || (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0))
|
|
34
|
+
.map(([l]) => l);
|
|
35
|
+
const onPath = new Set(c.path.slice(1).map((p) => p.label));
|
|
36
|
+
const startsIn = starts.filter((k) => c.ends.has(k)).length;
|
|
37
|
+
return {
|
|
38
|
+
...c,
|
|
39
|
+
lastSteps,
|
|
40
|
+
keptSteps: new Set(lastSteps.filter((l) => !steps.get(l).moves && !onPath.has(l))),
|
|
41
|
+
nameless: nameless ? { action, all: nameless === n } : null,
|
|
42
|
+
waysIn: n + startsIn,
|
|
43
|
+
startsHere: startsIn > 0,
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function waysLine(c) {
|
|
49
|
+
const quoted = c.lastSteps.map(
|
|
50
|
+
(l) => `"${l}"${c.keptSteps.has(l) ? " (the state stays the same)" : ""}`,
|
|
51
|
+
);
|
|
52
|
+
const named = quoted.slice(0, 5);
|
|
53
|
+
const more = quoted.length - named.length;
|
|
54
|
+
const list = joinAnd(more ? [...named, `${more} more`] : named);
|
|
55
|
+
const steps = c.nameless
|
|
56
|
+
? `In the model, steps labeled ${list} lead into this bug. TLC names ${c.nameless.all ? "them" : "some of them"} ${c.nameless.action}, the whole next-state action, so the story cannot count them.`
|
|
57
|
+
: c.lastSteps.length === 1
|
|
58
|
+
? `In the model, one step leads into this bug: ${list}.`
|
|
59
|
+
: c.lastSteps.length
|
|
60
|
+
? `In the model, ${c.lastSteps.length} different steps lead into this bug: ${list}.`
|
|
61
|
+
: "";
|
|
62
|
+
const start = !c.startsHere
|
|
63
|
+
? ""
|
|
64
|
+
: steps
|
|
65
|
+
? "The model can also start in this bug."
|
|
66
|
+
: "The model starts in this bug.";
|
|
67
|
+
const shortest = c.waysIn > 1 ? "The steps below are the shortest path that TLC found." : "";
|
|
68
|
+
return [steps, start, shortest].filter(Boolean).join(" ");
|
|
69
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"name": "show-me",
|
|
4
|
+
"repository": "https://github.com/humanlayer/skills.git",
|
|
5
|
+
"revision": "653b6411c1f70c275a18e37673b042ff99f67ceb",
|
|
6
|
+
"path": "plugins/show-me/skills/show-me",
|
|
7
|
+
"destination": "skills/show-me",
|
|
8
|
+
"license": "MIT"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "statechart",
|
|
12
|
+
"repository": "https://github.com/cursor/plugins.git",
|
|
13
|
+
"revision": "99b609a72323b70204eab407c622f436e858e112",
|
|
14
|
+
"path": "pstack/skills/statechart",
|
|
15
|
+
"destination": "skills/statechart",
|
|
16
|
+
"license": "MIT"
|
|
17
|
+
}
|
|
18
|
+
]
|