dsh-pstack 0.2.0-beta.1 → 0.2.0-beta.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/LICENSE +2 -3
- package/README.md +135 -84
- package/README.zh.md +185 -0
- package/cordis.patch.yml +97 -27
- package/dist/host-contract-CUPSpeNk.d.mts +22 -0
- package/dist/index.d.mts +49 -238
- package/dist/index.mjs +250 -123
- package/dist/models.d.mts +44 -0
- package/dist/models.mjs +201 -0
- package/dist/paths-BT77khwm.mjs +48 -0
- package/dist/pstack/LICENSE +21 -0
- package/dist/pstack/README.md +291 -0
- package/dist/pstack/agents/poteto-agent.md +9 -0
- package/{assets → dist/pstack}/docs/guide/01-setup.md +13 -11
- package/{assets → dist/pstack}/docs/guide/02-poteto-mode.md +4 -4
- package/{assets → dist/pstack}/docs/guide/04-design.md +4 -4
- package/{assets → dist/pstack}/docs/guide/05-build-and-clean.md +2 -2
- package/{assets → dist/pstack}/docs/guide/06-verify-and-ship.md +13 -3
- package/{assets → dist/pstack}/docs/guide/07-overnight.md +15 -13
- package/{assets → dist/pstack}/docs/guide/09-make-it-yours.md +6 -2
- package/{assets → dist/pstack}/docs/guide/10-recipes-and-pitfalls.md +7 -5
- package/{assets → dist/pstack}/docs/guide/README.md +1 -1
- package/dist/pstack/docs/harness/dsh.md +98 -0
- package/{assets → dist/pstack}/skills/architect/SKILL.md +12 -12
- package/dist/pstack/skills/arena/SKILL.md +50 -0
- package/{assets → dist/pstack}/skills/automate-me/SKILL.md +14 -14
- package/{assets → dist/pstack}/skills/benchmark-checklist/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/blast-radius/SKILL.md +4 -6
- package/{assets → dist/pstack}/skills/correct/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/create-formal-verification-skill/SKILL.md +4 -2
- package/{assets → dist/pstack}/skills/create-verification-skill/SKILL.md +5 -5
- package/dist/pstack/skills/figure-it-out/SKILL.md +54 -0
- package/dist/pstack/skills/how/SKILL.md +38 -0
- package/{assets → dist/pstack}/skills/in-your-own-words/SKILL.md +1 -1
- package/dist/pstack/skills/interrogate/SKILL.md +33 -0
- package/{assets → dist/pstack}/skills/ketchup/SKILL.md +3 -5
- package/dist/pstack/skills/ketchup-video/SKILL.md +29 -0
- package/{assets → dist/pstack}/skills/maintain-formal-verification-skill/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/maintain-verification-skill/SKILL.md +3 -3
- package/dist/pstack/skills/make-bot-ui/SKILL.md +117 -0
- package/dist/pstack/skills/no-comments/SKILL.md +26 -0
- package/{assets → dist/pstack}/skills/poteto-help/SKILL.md +34 -31
- package/{assets → dist/pstack}/skills/poteto-help/references/prompting.md +1 -1
- package/{assets → dist/pstack}/skills/poteto-help/references/recipes.md +3 -3
- package/{assets → dist/pstack}/skills/poteto-mode/SKILL.md +20 -19
- package/dist/pstack/skills/poteto-mode/playbooks/authoring-a-skill.md +12 -0
- package/dist/pstack/skills/poteto-mode/playbooks/autonomous-run.md +13 -0
- package/dist/pstack/skills/poteto-mode/playbooks/autopilot-full.md +25 -0
- package/dist/pstack/skills/poteto-mode/playbooks/autopilot-stack.md +8 -0
- package/{assets → dist/pstack}/skills/poteto-mode/playbooks/babysit.md +4 -4
- package/dist/pstack/skills/poteto-mode/playbooks/bug-fix.md +15 -0
- package/{assets → dist/pstack}/skills/poteto-mode/playbooks/eval.md +3 -3
- package/dist/pstack/skills/poteto-mode/playbooks/feature.md +21 -0
- package/{assets → dist/pstack}/skills/poteto-mode/playbooks/hillclimb.md +3 -3
- package/{assets → dist/pstack}/skills/poteto-mode/playbooks/investigation.md +2 -2
- package/{assets → dist/pstack}/skills/poteto-mode/playbooks/multi-phase-plan.md +23 -23
- package/{assets → dist/pstack}/skills/poteto-mode/playbooks/opening-a-pr.md +6 -6
- package/dist/pstack/skills/poteto-mode/playbooks/orchestrate.md +25 -0
- package/{assets → dist/pstack}/skills/poteto-mode/playbooks/pause-safely.md +2 -2
- package/dist/pstack/skills/poteto-mode/playbooks/perf-issue.md +25 -0
- package/{assets → dist/pstack}/skills/poteto-mode/playbooks/prototype.md +4 -4
- package/dist/pstack/skills/poteto-mode/playbooks/refactoring.md +16 -0
- package/dist/pstack/skills/poteto-mode/playbooks/runtime-forensics.md +11 -0
- package/dist/pstack/skills/poteto-mode/playbooks/session-pickup.md +11 -0
- package/{assets → dist/pstack}/skills/poteto-mode/playbooks/shipping.md +2 -2
- package/{assets → dist/pstack}/skills/poteto-mode/playbooks/trace-forensics.md +2 -2
- package/dist/pstack/skills/poteto-mode/playbooks/visual-parity.md +11 -0
- package/dist/pstack/skills/poteto-mode/playbooks/worktree-cleanup.md +12 -0
- package/{assets → dist/pstack}/skills/poteto-mode/scripts/check-plan.mjs +6 -8
- package/dist/pstack/skills/poteto-mode/scripts/check-plan.test.mjs +128 -0
- package/{assets/skills/poteto-mode/scripts/check-plan.test.mjs → dist/pstack/skills/poteto-mode/scripts/expect.mjs} +12 -101
- package/dist/pstack/skills/poteto-mode/scripts/support.mjs +93 -0
- package/dist/pstack/skills/poteto-mode/scripts/watch-pr/cli.mjs +123 -0
- package/dist/pstack/skills/poteto-mode/scripts/watch-pr/cli.test.mjs +217 -0
- package/dist/pstack/skills/poteto-mode/scripts/watch-pr/fakes.test-helper.mjs +119 -0
- package/dist/pstack/skills/poteto-mode/scripts/watch-pr/github.mjs +626 -0
- package/dist/pstack/skills/poteto-mode/scripts/watch-pr/github.test.mjs +521 -0
- package/dist/pstack/skills/poteto-mode/scripts/watch-pr/policy.mjs +657 -0
- package/dist/pstack/skills/poteto-mode/scripts/watch-pr/policy.test.mjs +523 -0
- package/dist/pstack/skills/poteto-mode/scripts/watch-pr/render.mjs +106 -0
- package/dist/pstack/skills/poteto-mode/scripts/watch-pr/types.mjs +9 -0
- package/dist/pstack/skills/poteto-mode/scripts/watch-pr/watch-pr.mjs +5 -0
- package/{assets → dist/pstack}/skills/poteto-mode/scripts/worktree-audit.mjs +15 -22
- package/dist/pstack/skills/poteto-mode/scripts/worktree-audit.test.mjs +134 -0
- package/{assets → dist/pstack}/skills/principle-attack-the-premise/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-boundary-discipline/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-encode-lessons-in-structure/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-exhaust-the-design-space/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-experience-first/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-explain-the-number/SKILL.md +3 -2
- package/{assets → dist/pstack}/skills/principle-fix-root-causes/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-laziness-protocol/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-make-operations-idempotent/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-minimize-reader-load/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-model-the-domain/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-never-block-on-the-human/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-outcome-oriented-execution/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-prove-it-works/SKILL.md +2 -2
- package/{assets → dist/pstack}/skills/principle-redesign-from-first-principles/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-separate-before-serializing-shared-state/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-sequence-verifiable-units/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-subtract-before-you-add/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-test-behavior-not-implementation/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/principle-type-system-discipline/SKILL.md +1 -1
- package/dist/pstack/skills/recall/SKILL.md +37 -0
- package/dist/pstack/skills/reflect/SKILL.md +71 -0
- package/{assets → dist/pstack}/skills/reflect/references/divergent-reviewer.md +4 -4
- package/{assets → dist/pstack}/skills/reflect/references/judgment-reviewer.md +2 -2
- package/{assets → dist/pstack}/skills/reflect/references/synthesizer.md +5 -5
- package/{assets → dist/pstack}/skills/reflect/references/tooling-reviewer.md +2 -2
- package/dist/pstack/skills/setup-pstack/SKILL.md +80 -0
- package/{assets → dist/pstack}/skills/sharpen/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/show-me-your-work/SKILL.md +8 -8
- package/{assets → dist/pstack}/skills/show-me-your-work/scripts/log.mjs +1 -3
- package/dist/pstack/skills/show-me-your-work/scripts/log.test.mjs +56 -0
- package/dist/pstack/skills/statechart/SKILL.md +82 -0
- package/dist/pstack/skills/statechart/references/render.md +93 -0
- package/dist/pstack/skills/statechart/scripts/backends/cfg.mjs +31 -0
- package/dist/pstack/skills/statechart/scripts/backends/mermaid.mjs +186 -0
- package/dist/pstack/skills/statechart/scripts/backends/plain-text.mjs +62 -0
- package/dist/pstack/skills/statechart/scripts/backends/report.mjs +84 -0
- package/dist/pstack/skills/statechart/scripts/frontends/config.mjs +268 -0
- package/dist/pstack/skills/statechart/scripts/frontends/dot.mjs +67 -0
- package/dist/pstack/skills/statechart/scripts/frontends/marks.mjs +94 -0
- package/dist/pstack/skills/statechart/scripts/frontends/messages.mjs +48 -0
- package/dist/pstack/skills/statechart/scripts/frontends/spec.mjs +101 -0
- package/dist/pstack/skills/statechart/scripts/frontends/trace.mjs +39 -0
- package/dist/pstack/skills/statechart/scripts/frontends/value.mjs +180 -0
- package/dist/pstack/skills/statechart/scripts/frontends/verdict.mjs +40 -0
- package/dist/pstack/skills/statechart/scripts/frontends/view.mjs +99 -0
- package/dist/pstack/skills/statechart/scripts/ir.mjs +277 -0
- package/dist/pstack/skills/statechart/scripts/passes/annotate.mjs +92 -0
- package/dist/pstack/skills/statechart/scripts/passes/label.mjs +210 -0
- package/dist/pstack/skills/statechart/scripts/passes/lift.mjs +84 -0
- package/dist/pstack/skills/statechart/scripts/passes/loop-check.mjs +47 -0
- package/dist/pstack/skills/statechart/scripts/passes/paths.mjs +72 -0
- package/dist/pstack/skills/statechart/scripts/passes/reach.mjs +135 -0
- package/dist/pstack/skills/statechart/scripts/passes/region-check.mjs +82 -0
- package/dist/pstack/skills/statechart/scripts/passes/regions.mjs +268 -0
- package/dist/pstack/skills/statechart/scripts/pipeline.mjs +72 -0
- package/dist/pstack/skills/statechart/scripts/run.mjs +440 -0
- package/dist/pstack/skills/statechart/scripts/statechart.mjs +155 -0
- package/dist/pstack/skills/statechart/scripts/statechart.test.mjs +198 -0
- package/dist/pstack/skills/statechart/scripts/worker.mjs +31 -0
- package/dist/pstack/skills/swarm/SKILL.md +43 -0
- package/{assets → dist/pstack}/skills/tdd/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/teach/SKILL.md +2 -2
- package/{assets → dist/pstack}/skills/technical-writing/SKILL.md +1 -1
- package/{assets → dist/pstack}/skills/typescript-best-practices/SKILL.md +3 -6
- package/{assets → dist/pstack}/skills/why/SKILL.md +8 -8
- package/dist/script.d.mts +9 -111
- package/dist/script.mjs +32 -329
- package/dist/skill.d.mts +38 -0
- package/dist/skill.mjs +183 -0
- package/dist/skills/authored/decision-audit/SKILL.md +99 -0
- package/dist/skills/authored/decision-audit/SKILL.zh.md +99 -0
- package/dist/skills/authored/decision-audit/references/recover-commit.md +17 -0
- package/dist/skills/authored/decision-audit/references/recover-commit.zh.md +17 -0
- package/dist/skills/authored/decision-write/SKILL.md +131 -0
- package/dist/skills/authored/decision-write/SKILL.zh.md +131 -0
- package/dist/skills/authored/decision-write/references/land.md +48 -0
- package/dist/skills/authored/decision-write/references/land.zh.md +48 -0
- package/dist/skills/authored/setup-project-docs/SKILL.md +58 -0
- package/dist/skills/authored/setup-project-docs/SKILL.zh.md +58 -0
- package/dist/skills/authored/setup-project-docs/references/decision-conventions.md +11 -0
- package/dist/skills/authored/setup-project-docs/references/decision-conventions.zh.md +11 -0
- package/dist/skills/vendored/retro/SKILL.md +44 -0
- package/dist/skills/vendored/retro/agents/openai.yaml +5 -0
- package/dist/skills/vendored/writing-for-agents/SKILL-MECHANICS.md +22 -0
- package/dist/skills/vendored/writing-for-agents/SKILL.md +81 -0
- package/dist/skills/vendored/writing-for-agents/agents/openai.yaml +3 -0
- package/dist/subagent.d.mts +56 -193
- package/dist/subagent.mjs +443 -741
- package/locale/en.json +3 -2
- package/locale/zh.json +3 -2
- package/package.json +63 -66
- package/assets/agents/poteto-agent.md +0 -8
- package/assets/docs/harness/dsh.md +0 -60
- package/assets/docs/pstack-models.example.md +0 -54
- package/assets/skills/arena/SKILL.md +0 -50
- package/assets/skills/figure-it-out/SKILL.md +0 -54
- package/assets/skills/how/SKILL.md +0 -38
- package/assets/skills/interrogate/SKILL.md +0 -71
- package/assets/skills/interrogate/references/code-quality-review.md +0 -47
- package/assets/skills/interrogate/references/lead-judgment.md +0 -39
- package/assets/skills/interrogate/references/reviewer-prompt.md +0 -62
- package/assets/skills/interrogate/references/rubric.md +0 -77
- package/assets/skills/no-comments/SKILL.md +0 -26
- package/assets/skills/poteto-mode/playbooks/authoring-a-skill.md +0 -12
- package/assets/skills/poteto-mode/playbooks/autonomous-run.md +0 -15
- package/assets/skills/poteto-mode/playbooks/autopilot-full.md +0 -25
- package/assets/skills/poteto-mode/playbooks/autopilot-stack.md +0 -12
- package/assets/skills/poteto-mode/playbooks/bug-fix.md +0 -15
- package/assets/skills/poteto-mode/playbooks/feature.md +0 -21
- package/assets/skills/poteto-mode/playbooks/orchestrate.md +0 -112
- package/assets/skills/poteto-mode/playbooks/perf-issue.md +0 -25
- package/assets/skills/poteto-mode/playbooks/refactoring.md +0 -16
- package/assets/skills/poteto-mode/playbooks/runtime-forensics.md +0 -11
- package/assets/skills/poteto-mode/playbooks/session-pickup.md +0 -11
- package/assets/skills/poteto-mode/playbooks/visual-parity.md +0 -11
- package/assets/skills/poteto-mode/playbooks/worktree-cleanup.md +0 -20
- package/assets/skills/poteto-mode/scripts/orch/orch.mjs +0 -4282
- package/assets/skills/poteto-mode/scripts/orch/orch.test.mjs +0 -2042
- package/assets/skills/poteto-mode/scripts/watch-pr/cli.test.mjs +0 -5101
- package/assets/skills/poteto-mode/scripts/watch-pr/github.test.mjs +0 -1177
- package/assets/skills/poteto-mode/scripts/watch-pr/policy.test.mjs +0 -1441
- package/assets/skills/poteto-mode/scripts/watch-pr/watch-pr.mjs +0 -4601
- package/assets/skills/recall/SKILL.md +0 -37
- package/assets/skills/reflect/SKILL.md +0 -69
- package/assets/skills/setup-pstack/SKILL.md +0 -67
- package/assets/skills/swarm/SKILL.md +0 -43
- package/dist/frontmatter-BQX3ekwP.mjs +0 -229
- package/dist/frontmatter-BQX3ekwP.mjs.map +0 -1
- package/dist/history.d.mts +0 -429
- package/dist/history.mjs +0 -1129
- package/dist/history.mjs.map +0 -1
- package/dist/host-contract-o47JH_r8.d.mts +0 -527
- package/dist/index.mjs.map +0 -1
- package/dist/paths-D_JlVmBk.mjs +0 -42
- package/dist/paths-D_JlVmBk.mjs.map +0 -1
- package/dist/script.mjs.map +0 -1
- package/dist/subagent.mjs.map +0 -1
- /package/{static/icon.png → assets/logo.png} +0 -0
- /package/{assets → dist/pstack}/agents/comment-sicko.md +0 -0
- /package/{assets → dist/pstack}/docs/guide/03-understand.md +0 -0
- /package/{assets → dist/pstack}/docs/guide/08-principles.md +0 -0
- /package/{assets → dist/pstack}/docs/guide/images/design.jpg +0 -0
- /package/{assets → dist/pstack}/docs/guide/images/overnight.jpg +0 -0
- /package/{assets → dist/pstack}/docs/guide/images/recipes.jpg +0 -0
- /package/{assets → dist/pstack}/docs/guide/images/router.jpg +0 -0
- /package/{assets → dist/pstack}/docs/guide/images/understanding.jpg +0 -0
- /package/{assets → dist/pstack}/docs/guide/images/verification.jpg +0 -0
- /package/{assets → dist/pstack}/skills/architect/references/design-red-flags.md +0 -0
- /package/{assets → dist/pstack}/skills/architect/references/rationale-template.md +0 -0
- /package/{assets → dist/pstack}/skills/architect/references/runner-prompt.md +0 -0
- /package/{assets → dist/pstack}/skills/bro/SKILL.md +0 -0
- /package/{assets → dist/pstack}/skills/create-verification-skill/references/feature-map-example/README.md +0 -0
- /package/{assets → dist/pstack}/skills/create-verification-skill/references/feature-map-example/create-note.md +0 -0
- /package/{assets → dist/pstack}/skills/create-verification-skill/references/feature-map-example/search.md +0 -0
- /package/{assets → dist/pstack}/skills/how/references/explainer-prompt.md +0 -0
- /package/{assets → dist/pstack}/skills/how/references/explorer-prompt.md +0 -0
- /package/{assets → dist/pstack}/skills/poteto-mode/references/bugbot-triage.md +0 -0
- /package/{assets → dist/pstack}/skills/principle-build-the-lever/SKILL.md +0 -0
- /package/{assets → dist/pstack}/skills/principle-foundational-thinking/SKILL.md +0 -0
- /package/{assets → dist/pstack}/skills/principle-guard-the-context-window/SKILL.md +0 -0
- /package/{assets → dist/pstack}/skills/show-me-your-work/references/decision-log-template.tsv +0 -0
- /package/{assets → dist/pstack}/skills/typescript-best-practices/references/patterns.md +0 -0
- /package/{assets → dist/pstack}/skills/unslop/SKILL.md +0 -0
- /package/{assets → dist/pstack}/skills/why/references/epistemics.md +0 -0
- /package/{assets → dist/pstack}/skills/why/references/investigator-prompt.md +0 -0
- /package/{assets → dist/pstack}/skills/why/references/source-playbook.md +0 -0
- /package/{assets → dist/pstack}/skills/why/references/sources/code-archaeology.md +0 -0
- /package/{assets → dist/pstack}/skills/why/references/sources/databricks.md +0 -0
- /package/{assets → dist/pstack}/skills/why/references/sources/datadog.md +0 -0
- /package/{assets → dist/pstack}/skills/why/references/sources/incident-postmortem.md +0 -0
- /package/{assets → dist/pstack}/skills/why/references/sources/linear.md +0 -0
- /package/{assets → dist/pstack}/skills/why/references/sources/notion.md +0 -0
- /package/{assets → dist/pstack}/skills/why/references/sources/sentry.md +0 -0
- /package/{assets → dist/pstack}/skills/why/references/sources/slack.md +0 -0
- /package/{assets → dist/pstack}/skills/why/references/synthesizer-prompt.md +0 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { append, holds, loopOf, must, tupleKey, unkey } from "../ir.mjs";
|
|
2
|
+
// runtime/skills/statechart/scripts/passes/loop-check.ts
|
|
3
|
+
function loopCheck({ regions, loops }, { names, keys, drawnLabels, sorted }, { index, from, to }, found) {
|
|
4
|
+
const R = names.length;
|
|
5
|
+
const combo = (i) => {
|
|
6
|
+
const parts = [];
|
|
7
|
+
for (let r = 0; r < R; r++) parts.push(keys[r][i]);
|
|
8
|
+
return tupleKey(parts);
|
|
9
|
+
};
|
|
10
|
+
const stepsFrom = /* @__PURE__ */ new Map();
|
|
11
|
+
const arrowsFrom = [];
|
|
12
|
+
if (loops.length) {
|
|
13
|
+
for (const j of sorted) append(stepsFrom, from[j], j);
|
|
14
|
+
for (const { arrows } of regions) {
|
|
15
|
+
const out = /* @__PURE__ */ new Map();
|
|
16
|
+
for (const a of arrows) append(out, a.from, a);
|
|
17
|
+
arrowsFrom.push(out);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
for (const b of found) {
|
|
21
|
+
if (b.loop === void 0) continue;
|
|
22
|
+
const inLoop = /* @__PURE__ */ new Set();
|
|
23
|
+
const twinsOf = /* @__PURE__ */ new Map();
|
|
24
|
+
for (const i of loopOf(b, index)) {
|
|
25
|
+
inLoop.add(combo(i));
|
|
26
|
+
append(twinsOf, combo(i), i);
|
|
27
|
+
}
|
|
28
|
+
for (const i of loopOf(b, index)) {
|
|
29
|
+
const twins = must(twinsOf, combo(i));
|
|
30
|
+
for (const [r, name] of names.entries()) {
|
|
31
|
+
const takes = (a) => {
|
|
32
|
+
for (const s of twins) for (const j of stepsFrom.get(s) ?? []) if (drawnLabels[j] === a.label && keys[r][to[j]] === a.to) return true;
|
|
33
|
+
return false;
|
|
34
|
+
};
|
|
35
|
+
const rest = [];
|
|
36
|
+
for (let o = 0; o < R; o++) if (o !== r) rest.push(keys[o][i]);
|
|
37
|
+
for (const a of arrowsFrom[r].get(keys[r][i]) ?? []) {
|
|
38
|
+
if (!holds(a.condition, rest)) continue;
|
|
39
|
+
const next = [];
|
|
40
|
+
for (let o = 0; o < R; o++) next.push(o === r ? a.to : keys[o][i]);
|
|
41
|
+
if (!inLoop.has(tupleKey(next)) && !takes(a)) throw new Error(`The chart draws the step ${a.label} out of ${name ? `${name} ` : ""}${unkey(a.from).join(" / ")}, but the ${b.rule.name} loop cannot take it there. Show in a label what stops it.`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export { loopCheck };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { hasRule, must, stateKey } from "../ir.mjs";
|
|
2
|
+
// runtime/skills/statechart/scripts/passes/paths.ts
|
|
3
|
+
function pathGraph(names) {
|
|
4
|
+
const graph = {
|
|
5
|
+
states: /* @__PURE__ */ new Map(),
|
|
6
|
+
steps: []
|
|
7
|
+
};
|
|
8
|
+
const ids = /* @__PURE__ */ new Map();
|
|
9
|
+
const taken = /* @__PURE__ */ new Map();
|
|
10
|
+
const idOf = (vars, start) => {
|
|
11
|
+
if (!vars) throw new Error("TLC's trace has a state with no values.");
|
|
12
|
+
const k = stateKey(names.map((name) => vars[name]));
|
|
13
|
+
let id = ids.get(k);
|
|
14
|
+
if (id === void 0) {
|
|
15
|
+
ids.set(k, id = String(ids.size));
|
|
16
|
+
graph.states.set(id, {
|
|
17
|
+
vars,
|
|
18
|
+
start,
|
|
19
|
+
breaks: []
|
|
20
|
+
});
|
|
21
|
+
} else if (start) must(graph.states, id).start = true;
|
|
22
|
+
return id;
|
|
23
|
+
};
|
|
24
|
+
const route = (seq) => {
|
|
25
|
+
const start = idOf(seq[0].vars, true);
|
|
26
|
+
const path = [];
|
|
27
|
+
let from = start;
|
|
28
|
+
for (let i = 1; i < seq.length; i++) {
|
|
29
|
+
const { action } = seq[i];
|
|
30
|
+
const to = idOf(seq[i].vars, false);
|
|
31
|
+
const k = `${from} ${to} ${action}`;
|
|
32
|
+
let step = taken.get(k);
|
|
33
|
+
if (!step) {
|
|
34
|
+
taken.set(k, step = {
|
|
35
|
+
from,
|
|
36
|
+
to,
|
|
37
|
+
action
|
|
38
|
+
});
|
|
39
|
+
graph.steps.push(step);
|
|
40
|
+
}
|
|
41
|
+
path.push({
|
|
42
|
+
action,
|
|
43
|
+
state: to,
|
|
44
|
+
step
|
|
45
|
+
});
|
|
46
|
+
from = to;
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
start,
|
|
50
|
+
path
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
return {
|
|
54
|
+
graph,
|
|
55
|
+
bug: (rule, trace) => {
|
|
56
|
+
if (!trace.length) throw new Error(`TLC's trace for ${rule.name} has no states.`);
|
|
57
|
+
const bug = {
|
|
58
|
+
rule,
|
|
59
|
+
...route(trace)
|
|
60
|
+
};
|
|
61
|
+
const end = must(graph.states, bug.path.at(-1)?.state ?? bug.start);
|
|
62
|
+
if (!hasRule(end.breaks, rule)) end.breaks.push(rule);
|
|
63
|
+
return bug;
|
|
64
|
+
},
|
|
65
|
+
lasso: ({ seq, loop }) => seq.length ? {
|
|
66
|
+
...route(seq),
|
|
67
|
+
loop,
|
|
68
|
+
stutters: loop === seq.length - 1
|
|
69
|
+
} : void 0
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export { pathGraph };
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { byText, count, defaultState, must, ruleKey, sortBy } from "../ir.mjs";
|
|
2
|
+
// runtime/skills/statechart/scripts/passes/reach.ts
|
|
3
|
+
function walk(graph) {
|
|
4
|
+
const ids = [];
|
|
5
|
+
const states = [];
|
|
6
|
+
const nameOf = [];
|
|
7
|
+
const starts = [];
|
|
8
|
+
const unique = /* @__PURE__ */ new Set();
|
|
9
|
+
for (const [id, s] of graph.states) {
|
|
10
|
+
const name = defaultState(s.vars);
|
|
11
|
+
if (s.start) starts.push(ids.length);
|
|
12
|
+
ids.push(id);
|
|
13
|
+
states.push(s);
|
|
14
|
+
nameOf.push(name);
|
|
15
|
+
unique.add(name);
|
|
16
|
+
}
|
|
17
|
+
const names = Array.from(unique).sort(byText);
|
|
18
|
+
const rankOf = /* @__PURE__ */ new Map();
|
|
19
|
+
for (let i = 0; i < names.length; i++) rankOf.set(names[i], i);
|
|
20
|
+
const n = ids.length;
|
|
21
|
+
const index = /* @__PURE__ */ new Map();
|
|
22
|
+
const nameRank = new Int32Array(n);
|
|
23
|
+
for (let i = 0; i < n; i++) {
|
|
24
|
+
index.set(ids[i], i);
|
|
25
|
+
nameRank[i] = must(rankOf, nameOf[i]);
|
|
26
|
+
}
|
|
27
|
+
const m = graph.steps.length;
|
|
28
|
+
const from = new Int32Array(m);
|
|
29
|
+
const to = new Int32Array(m);
|
|
30
|
+
const action = new Int32Array(m);
|
|
31
|
+
const actions = /* @__PURE__ */ new Map();
|
|
32
|
+
for (let j = 0; j < m; j++) {
|
|
33
|
+
const t = graph.steps[j];
|
|
34
|
+
from[j] = must(index, t.from);
|
|
35
|
+
to[j] = must(index, t.to);
|
|
36
|
+
let a = actions.get(t.action);
|
|
37
|
+
if (a === void 0) actions.set(t.action, a = actions.size);
|
|
38
|
+
action[j] = a;
|
|
39
|
+
}
|
|
40
|
+
const actionRank = new Int32Array(actions.size);
|
|
41
|
+
for (const [i, a] of [...actions.keys()].sort(byText).entries()) actionRank[must(actions, a)] = i;
|
|
42
|
+
const toName = new Int32Array(m);
|
|
43
|
+
for (let j = 0; j < m; j++) {
|
|
44
|
+
action[j] = actionRank[action[j]];
|
|
45
|
+
toName[j] = nameRank[to[j]];
|
|
46
|
+
}
|
|
47
|
+
const first = new Int32Array(n + 1);
|
|
48
|
+
for (let j = 0; j < m; j++) first[from[j] + 1]++;
|
|
49
|
+
for (let i = 0; i < n; i++) first[i + 1] += first[i];
|
|
50
|
+
const fill = first.slice(0, n);
|
|
51
|
+
const next = new Int32Array(m);
|
|
52
|
+
for (const j of sortBy(count(m), [action, toName])) next[fill[from[j]]++] = j;
|
|
53
|
+
starts.sort((a, b) => nameRank[a] - nameRank[b]);
|
|
54
|
+
const depth = new Int32Array(n).fill(-1);
|
|
55
|
+
const via = new Int32Array(n).fill(-1);
|
|
56
|
+
const reached = new Int32Array(n);
|
|
57
|
+
let size = 0;
|
|
58
|
+
for (const s of starts) {
|
|
59
|
+
depth[s] = 0;
|
|
60
|
+
reached[size++] = s;
|
|
61
|
+
}
|
|
62
|
+
for (let q = 0; q < size; q++) {
|
|
63
|
+
const s = reached[q];
|
|
64
|
+
for (let e = first[s]; e < first[s + 1]; e++) {
|
|
65
|
+
const t = to[next[e]];
|
|
66
|
+
if (depth[t] >= 0) continue;
|
|
67
|
+
depth[t] = depth[s] + 1;
|
|
68
|
+
via[t] = next[e];
|
|
69
|
+
reached[size++] = t;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
ids,
|
|
74
|
+
states,
|
|
75
|
+
index,
|
|
76
|
+
nameOf,
|
|
77
|
+
nameRank,
|
|
78
|
+
from,
|
|
79
|
+
to,
|
|
80
|
+
action,
|
|
81
|
+
depth,
|
|
82
|
+
via,
|
|
83
|
+
reached: reached.subarray(0, size),
|
|
84
|
+
starts
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function drawOrder({ depth, nameRank }) {
|
|
88
|
+
const n = depth.length;
|
|
89
|
+
let deepest = 0;
|
|
90
|
+
for (let i = 0; i < n; i++) if (depth[i] > deepest) deepest = depth[i];
|
|
91
|
+
const level = new Int32Array(n);
|
|
92
|
+
for (let i = 0; i < n; i++) level[i] = depth[i] < 0 ? deepest + 1 : depth[i];
|
|
93
|
+
const order = sortBy(count(n), [level, nameRank]);
|
|
94
|
+
const rank = new Int32Array(n);
|
|
95
|
+
for (let p = 0; p < n; p++) rank[order[p]] = p;
|
|
96
|
+
return {
|
|
97
|
+
order,
|
|
98
|
+
rank
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function bugs(graph, { ids, from, via, reached } = walk(graph)) {
|
|
102
|
+
const ends = /* @__PURE__ */ new Map();
|
|
103
|
+
for (const [id, s] of graph.states) for (const rule of s.ends ?? []) ends.set(ruleKey(rule), id);
|
|
104
|
+
const first = /* @__PURE__ */ new Map();
|
|
105
|
+
for (const i of reached) {
|
|
106
|
+
const s = must(graph.states, ids[i]);
|
|
107
|
+
for (const rule of s.past ? s.ends : s.breaks) {
|
|
108
|
+
const k = ruleKey(rule);
|
|
109
|
+
if (!first.has(k) && (ends.get(k) ?? ids[i]) === ids[i]) first.set(k, {
|
|
110
|
+
rule,
|
|
111
|
+
i
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const found = [];
|
|
116
|
+
for (const { rule, i } of first.values()) {
|
|
117
|
+
const path = [];
|
|
118
|
+
let start = i;
|
|
119
|
+
for (let j; (j = via[start]) >= 0; start = from[j]) {
|
|
120
|
+
const step = graph.steps[j];
|
|
121
|
+
path.unshift({
|
|
122
|
+
action: step.action,
|
|
123
|
+
state: step.to,
|
|
124
|
+
step
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
found.push({
|
|
128
|
+
rule,
|
|
129
|
+
start: ids[start],
|
|
130
|
+
path
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return found;
|
|
134
|
+
}
|
|
135
|
+
export { bugs, drawOrder, walk };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { append, holds, tupleKey, unkey } from "../ir.mjs";
|
|
2
|
+
// runtime/skills/statechart/scripts/passes/region-check.ts
|
|
3
|
+
function regionsLie(regions, { names, keys, sorted, drawnLabels, together }, { from, to, starts }, order) {
|
|
4
|
+
if (names.length < 2) return void 0;
|
|
5
|
+
const combo = (i) => {
|
|
6
|
+
const c = [];
|
|
7
|
+
for (let r = 0; r < names.length; r++) c.push(keys[r][i]);
|
|
8
|
+
return c;
|
|
9
|
+
};
|
|
10
|
+
const words = (c) => {
|
|
11
|
+
const parts = [];
|
|
12
|
+
for (let i = 0; i < names.length; i++) parts.push(`${names[i]} ${unkey(c[i]).join(" / ")}`);
|
|
13
|
+
return parts.join(", ");
|
|
14
|
+
};
|
|
15
|
+
const addMove = (moves, m) => moves.set(tupleKey([
|
|
16
|
+
m.from,
|
|
17
|
+
m.text,
|
|
18
|
+
m.to
|
|
19
|
+
]), m);
|
|
20
|
+
let product = [[]];
|
|
21
|
+
for (const r of regions) {
|
|
22
|
+
const next = [];
|
|
23
|
+
for (const c of product) for (const s of r.states) if (s.start) next.push([...c, tupleKey(s.path)]);
|
|
24
|
+
product = next;
|
|
25
|
+
}
|
|
26
|
+
const realStarts = /* @__PURE__ */ new Set();
|
|
27
|
+
for (const i of starts) realStarts.add(tupleKey(combo(i)));
|
|
28
|
+
for (const c of product) if (!realStarts.has(tupleKey(c))) return `The regions chart starts at ${words(c)}, where the model never starts.`;
|
|
29
|
+
for (const [i, r] of regions.entries()) for (const a of r.arrows) if (a.condition.kind === "tuples") return `In ${names[i]}, ${a.label} from ${unkey(a.from).join(" / ")} depends on the other regions in a way that one "and" or "or" condition cannot say.`;
|
|
30
|
+
const real = /* @__PURE__ */ new Map();
|
|
31
|
+
for (const j of sorted) {
|
|
32
|
+
const before = combo(from[j]);
|
|
33
|
+
const after = combo(to[j]);
|
|
34
|
+
if (tupleKey(before) !== tupleKey(after)) addMove(real, {
|
|
35
|
+
from: before,
|
|
36
|
+
text: drawnLabels[j],
|
|
37
|
+
to: after
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const combos = /* @__PURE__ */ new Map();
|
|
41
|
+
for (const i of order) {
|
|
42
|
+
const c = combo(i);
|
|
43
|
+
combos.set(tupleKey(c), c);
|
|
44
|
+
}
|
|
45
|
+
const drawn = /* @__PURE__ */ new Map();
|
|
46
|
+
for (const c of combos.values()) {
|
|
47
|
+
const enabled = /* @__PURE__ */ new Map();
|
|
48
|
+
for (const [i, r] of regions.entries()) {
|
|
49
|
+
const rest = [];
|
|
50
|
+
for (let k = 0; k < c.length; k++) if (k !== i) rest.push(c[k]);
|
|
51
|
+
for (const a of r.arrows) if (a.from === c[i] && holds(a.condition, rest)) append(enabled, a.label, {
|
|
52
|
+
i,
|
|
53
|
+
a
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
for (const [text, list] of enabled) {
|
|
57
|
+
let groups = [];
|
|
58
|
+
if (together.has(text)) {
|
|
59
|
+
const byRegion = /* @__PURE__ */ new Map();
|
|
60
|
+
for (const m of list) append(byRegion, m.i, m);
|
|
61
|
+
groups = [[]];
|
|
62
|
+
for (const opts of byRegion.values()) {
|
|
63
|
+
const next = [];
|
|
64
|
+
for (const g of groups) for (const m of opts) next.push([...g, m]);
|
|
65
|
+
groups = next;
|
|
66
|
+
}
|
|
67
|
+
} else for (const m of list) groups.push([m]);
|
|
68
|
+
for (const group of groups) {
|
|
69
|
+
const to = [...c];
|
|
70
|
+
for (const { i, a } of group) to[i] = a.to;
|
|
71
|
+
addMove(drawn, {
|
|
72
|
+
from: c,
|
|
73
|
+
text,
|
|
74
|
+
to
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
for (const [k, extra] of drawn) if (!real.has(k)) return `The regions chart lets ${words(extra.from)} go to ${words(extra.to)} by ${extra.text}, which the model never does.`;
|
|
80
|
+
for (const [k, missing] of real) if (!drawn.has(k)) return `The model goes from ${words(missing.from)} to ${words(missing.to)} by ${missing.text}, which the regions chart cannot show.`;
|
|
81
|
+
}
|
|
82
|
+
export { regionsLie };
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { append, byText, hasRule, holds, loopOf, must, ruleKey, seqOf, tupleKey, unkey } from "../ir.mjs";
|
|
2
|
+
// runtime/skills/statechart/scripts/passes/regions.ts
|
|
3
|
+
const anyRest = {
|
|
4
|
+
kind: "and",
|
|
5
|
+
otherKeys: []
|
|
6
|
+
};
|
|
7
|
+
function drawRegions({ states: tla, index, from, to }, { names, shapes, drawnLabels, group, keys, kinds, sizes, sorted, pathSteps, notes }, order, found, view) {
|
|
8
|
+
const n = shapes.length;
|
|
9
|
+
const m = drawnLabels.length;
|
|
10
|
+
const R = names.length;
|
|
11
|
+
const lead = new Uint8Array(n);
|
|
12
|
+
const looped = new Uint8Array(n);
|
|
13
|
+
for (const b of found) {
|
|
14
|
+
for (const i of seqOf(b, index).slice(0, b.loop)) lead[i] = 1;
|
|
15
|
+
for (const i of loopOf(b, index)) looped[i] = 1;
|
|
16
|
+
}
|
|
17
|
+
const loop = (j) => R === 1 && pathSteps[j] === 1;
|
|
18
|
+
const stays = (j) => {
|
|
19
|
+
for (let r = 0; r < R; r++) if (kinds[r][from[j]] !== kinds[r][to[j]]) return false;
|
|
20
|
+
return true;
|
|
21
|
+
};
|
|
22
|
+
let inside = 0;
|
|
23
|
+
for (const j of sorted) if (stays(j) && !loop(j)) inside++;
|
|
24
|
+
const comboOf = R === 1 ? (i) => kinds[0][i] : (i) => {
|
|
25
|
+
let c = "";
|
|
26
|
+
for (let r = 0; r < R; r++) c += (r ? "," : "") + kinds[r][i];
|
|
27
|
+
return c;
|
|
28
|
+
};
|
|
29
|
+
const dirty = /* @__PURE__ */ new Map();
|
|
30
|
+
for (const i of order) if (tla[i].breaks.length) {
|
|
31
|
+
const c = comboOf(i);
|
|
32
|
+
if (!dirty.has(c)) dirty.set(c, i);
|
|
33
|
+
}
|
|
34
|
+
const clean = new Uint8Array(n);
|
|
35
|
+
if (dirty.size) for (let i = 0; i < n; i++) clean[i] = dirty.has(comboOf(i)) ? 0 : 1;
|
|
36
|
+
else clean.fill(1);
|
|
37
|
+
const regions = [];
|
|
38
|
+
const objects = [];
|
|
39
|
+
for (const [r, name] of names.entries()) {
|
|
40
|
+
const key = keys[r];
|
|
41
|
+
const kind = kinds[r];
|
|
42
|
+
const states = /* @__PURE__ */ new Map();
|
|
43
|
+
const objectOf = new Array(sizes[r]);
|
|
44
|
+
const keyOf = new Array(sizes[r]);
|
|
45
|
+
const position = new Int32Array(sizes[r]);
|
|
46
|
+
for (const i of order) {
|
|
47
|
+
const s = tla[i];
|
|
48
|
+
let o = objectOf[kind[i]];
|
|
49
|
+
if (!o) {
|
|
50
|
+
o = {
|
|
51
|
+
path: shapes[i][name],
|
|
52
|
+
start: false,
|
|
53
|
+
members: [],
|
|
54
|
+
works: false,
|
|
55
|
+
lead: false,
|
|
56
|
+
repeats: false,
|
|
57
|
+
breaks: [],
|
|
58
|
+
group: void 0
|
|
59
|
+
};
|
|
60
|
+
objectOf[kind[i]] = o;
|
|
61
|
+
keyOf[kind[i]] = key[i];
|
|
62
|
+
position[kind[i]] = states.size;
|
|
63
|
+
states.set(key[i], o);
|
|
64
|
+
}
|
|
65
|
+
o.start ||= s.start;
|
|
66
|
+
o.works ||= clean[i] === 1;
|
|
67
|
+
o.lead ||= lead[i] === 1;
|
|
68
|
+
o.repeats ||= looped[i] === 1;
|
|
69
|
+
o.members.push(i);
|
|
70
|
+
}
|
|
71
|
+
const parents = /* @__PURE__ */ new Set();
|
|
72
|
+
for (const s of states.values()) for (let i = 1; i < s.path.length; i++) parents.add(tupleKey(s.path.slice(0, i)));
|
|
73
|
+
for (const s of states.values()) {
|
|
74
|
+
if (parents.size && parents.has(tupleKey(s.path))) throw new Error(`The view's state() returned ${s.path.join(" / ")} both as a state and as a parent state${name ? ` in ${name}` : ""}. Give that state a child name of its own.`);
|
|
75
|
+
const rules = /* @__PURE__ */ new Map();
|
|
76
|
+
for (const i of s.members) for (const rule of tla[i].breaks) rules.set(ruleKey(rule), rule);
|
|
77
|
+
s.breaks = [];
|
|
78
|
+
for (const rule of [...rules.values()].sort((a, b) => byText(a.name, b.name) || byText(a.kind, b.kind))) {
|
|
79
|
+
let always = true;
|
|
80
|
+
for (const i of s.members) always &&= hasRule(tla[i].breaks, rule);
|
|
81
|
+
s.breaks.push({
|
|
82
|
+
rule,
|
|
83
|
+
always
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const groups = /* @__PURE__ */ new Set();
|
|
87
|
+
for (const i of s.members) groups.add(group(i));
|
|
88
|
+
s.group = groups.size === 1 ? [...groups][0] : void 0;
|
|
89
|
+
}
|
|
90
|
+
const others = [];
|
|
91
|
+
for (let o = 0; o < R; o++) if (o !== r) others.push(o);
|
|
92
|
+
const tuple = (i) => {
|
|
93
|
+
const t = [];
|
|
94
|
+
for (const o of others) t.push(keys[o][i]);
|
|
95
|
+
return t;
|
|
96
|
+
};
|
|
97
|
+
const two = others.length === 1;
|
|
98
|
+
const words = (vs) => {
|
|
99
|
+
const texts = [];
|
|
100
|
+
for (const v of vs) texts.push(unkey(v).join(" / "));
|
|
101
|
+
return texts.sort(byText).join(two ? " or " : ", ");
|
|
102
|
+
};
|
|
103
|
+
const is = (o, vs) => two ? `when ${words(vs)}` : `${names[o]} is ${vs.size > 1 ? "one of " : ""}${words(vs)}`;
|
|
104
|
+
const isNot = (o, vs) => two ? `unless ${words(vs)}` : `${names[o]} is ${vs.length > 1 ? "none of" : "not"} ${words(vs)}`;
|
|
105
|
+
const moves = [];
|
|
106
|
+
const pairs = /* @__PURE__ */ new Map();
|
|
107
|
+
const size = sizes[r];
|
|
108
|
+
for (const j of sorted) {
|
|
109
|
+
const f = kind[from[j]];
|
|
110
|
+
const t = kind[to[j]];
|
|
111
|
+
if (f === t && !loop(j)) continue;
|
|
112
|
+
const text = drawnLabels[j];
|
|
113
|
+
const pair = position[f] * size + position[t];
|
|
114
|
+
let move = pairs.get(pair);
|
|
115
|
+
while (move && move.text !== text) move = move.other;
|
|
116
|
+
if (!move) {
|
|
117
|
+
move = {
|
|
118
|
+
f,
|
|
119
|
+
t,
|
|
120
|
+
text,
|
|
121
|
+
group: [],
|
|
122
|
+
other: pairs.get(pair)
|
|
123
|
+
};
|
|
124
|
+
pairs.set(pair, move);
|
|
125
|
+
moves.push(move);
|
|
126
|
+
}
|
|
127
|
+
if (R > 1) move.group.push(j);
|
|
128
|
+
}
|
|
129
|
+
const tuplesAt = /* @__PURE__ */ new Map();
|
|
130
|
+
const seenAt = /* @__PURE__ */ new Map();
|
|
131
|
+
if (R > 1) for (const i of order) append(tuplesAt, kind[i], i);
|
|
132
|
+
const arrows = [];
|
|
133
|
+
for (const move of moves) {
|
|
134
|
+
const fromKey = keyOf[move.f];
|
|
135
|
+
const toKey = keyOf[move.t];
|
|
136
|
+
if (R === 1) {
|
|
137
|
+
arrows.push({
|
|
138
|
+
from: fromKey,
|
|
139
|
+
to: toKey,
|
|
140
|
+
label: move.text,
|
|
141
|
+
condition: anyRest,
|
|
142
|
+
when: void 0
|
|
143
|
+
});
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const ok = /* @__PURE__ */ new Set();
|
|
147
|
+
for (const j of move.group) ok.add(tupleKey(tuple(from[j])));
|
|
148
|
+
const takes = (t) => ok.has(tupleKey(t));
|
|
149
|
+
let seen = seenAt.get(move.f);
|
|
150
|
+
if (!seen) {
|
|
151
|
+
seen = [];
|
|
152
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
153
|
+
for (const i of must(tuplesAt, move.f)) {
|
|
154
|
+
const t = tuple(i);
|
|
155
|
+
const k = tupleKey(t);
|
|
156
|
+
if (seenKeys.has(k)) continue;
|
|
157
|
+
seenKeys.add(k);
|
|
158
|
+
seen.push(t);
|
|
159
|
+
}
|
|
160
|
+
seenAt.set(move.f, seen);
|
|
161
|
+
}
|
|
162
|
+
const all = [];
|
|
163
|
+
const and = [];
|
|
164
|
+
const or = [];
|
|
165
|
+
for (let j = 0; j < others.length; j++) {
|
|
166
|
+
const values = /* @__PURE__ */ new Set();
|
|
167
|
+
const taken = /* @__PURE__ */ new Set();
|
|
168
|
+
const untaken = /* @__PURE__ */ new Set();
|
|
169
|
+
for (const t of seen) {
|
|
170
|
+
values.add(t[j]);
|
|
171
|
+
if (takes(t)) taken.add(t[j]);
|
|
172
|
+
else untaken.add(t[j]);
|
|
173
|
+
}
|
|
174
|
+
const only = /* @__PURE__ */ new Set();
|
|
175
|
+
for (const v of values) if (!untaken.has(v)) only.add(v);
|
|
176
|
+
all.push(values);
|
|
177
|
+
and.push(taken);
|
|
178
|
+
or.push(only);
|
|
179
|
+
}
|
|
180
|
+
const fits = (condition) => {
|
|
181
|
+
for (const t of seen) if (holds(condition, t) !== takes(t)) return false;
|
|
182
|
+
return true;
|
|
183
|
+
};
|
|
184
|
+
const andHolds = {
|
|
185
|
+
kind: "and",
|
|
186
|
+
otherKeys: and
|
|
187
|
+
};
|
|
188
|
+
const orHolds = {
|
|
189
|
+
kind: "or",
|
|
190
|
+
otherKeys: or
|
|
191
|
+
};
|
|
192
|
+
const text = move.text;
|
|
193
|
+
if (fits(andHolds)) {
|
|
194
|
+
const parts = [];
|
|
195
|
+
for (let j = 0; j < others.length; j++) {
|
|
196
|
+
const no = [];
|
|
197
|
+
for (const v of all[j]) if (!and[j].has(v)) no.push(v);
|
|
198
|
+
if (no.length) parts.push(and[j].size <= no.length ? is(others[j], and[j]) : isNot(others[j], no));
|
|
199
|
+
}
|
|
200
|
+
arrows.push({
|
|
201
|
+
from: fromKey,
|
|
202
|
+
to: toKey,
|
|
203
|
+
label: text,
|
|
204
|
+
condition: andHolds,
|
|
205
|
+
when: parts.length ? two ? parts[0] : `when ${parts.join(" and ")}` : void 0
|
|
206
|
+
});
|
|
207
|
+
} else if (fits(orHolds)) {
|
|
208
|
+
const parts = [];
|
|
209
|
+
for (let j = 0; j < others.length; j++) if (or[j].size) parts.push(is(others[j], or[j]));
|
|
210
|
+
arrows.push({
|
|
211
|
+
from: fromKey,
|
|
212
|
+
to: toKey,
|
|
213
|
+
label: text,
|
|
214
|
+
condition: orHolds,
|
|
215
|
+
when: `when ${parts.join(" or ")}`
|
|
216
|
+
});
|
|
217
|
+
} else arrows.push({
|
|
218
|
+
from: fromKey,
|
|
219
|
+
to: toKey,
|
|
220
|
+
label: text,
|
|
221
|
+
condition: {
|
|
222
|
+
kind: "tuples",
|
|
223
|
+
otherTuples: ok
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
const steps = [];
|
|
228
|
+
for (const [k, a] of arrows.entries()) steps.push({
|
|
229
|
+
from: objectOf[moves[k].f].path,
|
|
230
|
+
to: objectOf[moves[k].t].path,
|
|
231
|
+
label: a.label,
|
|
232
|
+
when: a.label.endsWith("]") ? void 0 : a.when
|
|
233
|
+
});
|
|
234
|
+
regions.push({
|
|
235
|
+
name,
|
|
236
|
+
states: [...states.values()],
|
|
237
|
+
steps,
|
|
238
|
+
arrows
|
|
239
|
+
});
|
|
240
|
+
objects.push(objectOf);
|
|
241
|
+
}
|
|
242
|
+
const hidden = [];
|
|
243
|
+
for (const i of dirty.values()) {
|
|
244
|
+
const ps = [];
|
|
245
|
+
for (let r = 0; r < R; r++) ps.push(objects[r][kinds[r][i]]);
|
|
246
|
+
let works = true;
|
|
247
|
+
for (const s of ps) works &&= s.works;
|
|
248
|
+
if (works) hidden.push(ps);
|
|
249
|
+
}
|
|
250
|
+
for (const ps of hidden) for (const s of ps) s.works = false;
|
|
251
|
+
const paths = [];
|
|
252
|
+
const loops = [];
|
|
253
|
+
for (const b of found) {
|
|
254
|
+
if (b.loop !== 0) paths.push(b.rule.name);
|
|
255
|
+
if (b.loop !== void 0) loops.push(b.rule.name);
|
|
256
|
+
}
|
|
257
|
+
return {
|
|
258
|
+
title: view.title,
|
|
259
|
+
regions,
|
|
260
|
+
notes,
|
|
261
|
+
inside,
|
|
262
|
+
quiet: m - sorted.length,
|
|
263
|
+
colors: view.colors ?? {},
|
|
264
|
+
paths,
|
|
265
|
+
loops
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
export { drawRegions };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ruleKey } from "./ir.mjs";
|
|
2
|
+
import { mermaidLines } from "./backends/mermaid.mjs";
|
|
3
|
+
import { plainText } from "./backends/plain-text.mjs";
|
|
4
|
+
import { report } from "./backends/report.mjs";
|
|
5
|
+
import { asParents, ask, labelGraph, storiesOf } from "./passes/label.mjs";
|
|
6
|
+
import { lift } from "./passes/lift.mjs";
|
|
7
|
+
import { loopCheck } from "./passes/loop-check.mjs";
|
|
8
|
+
import { bugs, drawOrder, walk } from "./passes/reach.mjs";
|
|
9
|
+
import { regionsLie } from "./passes/region-check.mjs";
|
|
10
|
+
import { drawRegions } from "./passes/regions.mjs";
|
|
11
|
+
// runtime/skills/statechart/scripts/pipeline.ts
|
|
12
|
+
function* inParts(lines) {
|
|
13
|
+
let start = 0;
|
|
14
|
+
let size = 0;
|
|
15
|
+
for (let i = 0; i < lines.length; i++) {
|
|
16
|
+
size += lines[i].length + 1;
|
|
17
|
+
if (size > 16777216 || i === lines.length - 1) {
|
|
18
|
+
yield (start ? "\n" : "") + lines.slice(start, i + 1).join("\n");
|
|
19
|
+
start = i + 1;
|
|
20
|
+
size = 0;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const shortestFirst = (a, b) => a.path.length - b.path.length;
|
|
25
|
+
function project(graph, walked, view, found) {
|
|
26
|
+
const { order, rank } = drawOrder(walked);
|
|
27
|
+
const draw = (answers) => {
|
|
28
|
+
const labels = labelGraph(graph, walked, answers, rank, found);
|
|
29
|
+
return {
|
|
30
|
+
labels,
|
|
31
|
+
chart: drawRegions(walked, labels, order, found, view)
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
const answers = ask(graph, walked, view);
|
|
35
|
+
const first = draw(answers);
|
|
36
|
+
const lie = regionsLie(first.chart.regions, first.labels, walked, order);
|
|
37
|
+
const { labels, chart } = lie ? draw(asParents(walked, answers)) : first;
|
|
38
|
+
loopCheck(chart, labels, walked, found);
|
|
39
|
+
return {
|
|
40
|
+
chart: lift(lie ? {
|
|
41
|
+
...chart,
|
|
42
|
+
lie
|
|
43
|
+
} : chart),
|
|
44
|
+
stories: storiesOf(graph, found, walked, first.labels)
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function compile(result, view) {
|
|
48
|
+
const walked = walk(result.graph);
|
|
49
|
+
const found = [...result.paths ?? bugs(result.graph, walked)].sort(shortestFirst);
|
|
50
|
+
for (const p of result.properties) if (p.bug) found.push({
|
|
51
|
+
rule: p.rule,
|
|
52
|
+
...p.bug
|
|
53
|
+
});
|
|
54
|
+
const { chart, stories } = found.length || !result.paths ? project(result.graph, walked, view, found) : {
|
|
55
|
+
chart: void 0,
|
|
56
|
+
stories: /* @__PURE__ */ new Map()
|
|
57
|
+
};
|
|
58
|
+
const text = report(result, found, chart, stories);
|
|
59
|
+
const files = /* @__PURE__ */ new Map();
|
|
60
|
+
if (chart) files.set("chart.mmd", inParts(mermaidLines(chart)));
|
|
61
|
+
files.set("report.md", [text]);
|
|
62
|
+
files.set("tlc.out", plainText(result.messages));
|
|
63
|
+
const drawn = /* @__PURE__ */ new Set();
|
|
64
|
+
for (const b of found) if (b.rule.kind !== "property") drawn.add(ruleKey(b.rule));
|
|
65
|
+
for (const { rule, outcome, messages } of [...result.rules, ...result.properties]) if (outcome === "broken" && messages && !drawn.has(ruleKey(rule))) files.set(`tlc-${rule.name}.out`, plainText(messages));
|
|
66
|
+
return {
|
|
67
|
+
report: text,
|
|
68
|
+
files,
|
|
69
|
+
exit: result.exit
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export { compile, project };
|