@justjoshn/pi-pstack 0.0.0-stage → 0.15.36-pi.1

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 (651) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +95 -2
  3. package/agents/comment-sicko.md +32 -0
  4. package/agents/poteto-agent.md +9 -0
  5. package/automations/benny/FOR_AGENTS.md +82 -0
  6. package/automations/benny/README.md +20 -0
  7. package/automations/benny/skills/reproduce-and-fix-issues/SKILL.md +310 -0
  8. package/automations/benny/skills/reproduce-and-fix-issues/references/control-adapter.md +169 -0
  9. package/automations/benny/skills/reproduce-and-fix-issues/references/feature-map.example.md +205 -0
  10. package/automations/benny/skills/reproduce-and-fix-issues/references/verify-existing-fix.md +93 -0
  11. package/automations/benny/skills/setup-benny/SKILL.md +253 -0
  12. package/automations/benny/skills/triage-issue-reports/SKILL.md +240 -0
  13. package/automations/benny/skills/triage-issue-reports/references/routing.example.md +61 -0
  14. package/automations/benny/templates/configuration.example.yaml +113 -0
  15. package/automations/benny/templates/reproduce-automation-prompt.md +49 -0
  16. package/automations/benny/templates/triage-automation-prompt.md +53 -0
  17. package/docs/guide/01-setup.md +67 -0
  18. package/docs/guide/02-poteto-mode.md +139 -0
  19. package/docs/guide/03-understand.md +79 -0
  20. package/docs/guide/04-design.md +133 -0
  21. package/docs/guide/05-build-and-clean.md +83 -0
  22. package/docs/guide/06-verify-and-ship.md +162 -0
  23. package/docs/guide/07-overnight.md +122 -0
  24. package/docs/guide/08-principles.md +72 -0
  25. package/docs/guide/09-make-it-yours.md +100 -0
  26. package/docs/guide/10-recipes-and-pitfalls.md +182 -0
  27. package/docs/guide/README.md +38 -0
  28. package/docs/guide/images/design.jpg +0 -0
  29. package/docs/guide/images/overnight.jpg +0 -0
  30. package/docs/guide/images/recipes.jpg +0 -0
  31. package/docs/guide/images/router.jpg +0 -0
  32. package/docs/guide/images/understanding.jpg +0 -0
  33. package/docs/guide/images/verification.jpg +0 -0
  34. package/docs/native-gaps.md +67 -0
  35. package/licenses/cursor-team-kit.LICENSE +21 -0
  36. package/licenses/pstack.LICENSE +21 -0
  37. package/package.json +51 -4
  38. package/scripts/live-e2e.mjs +257 -0
  39. package/skills/architect/SKILL.md +79 -0
  40. package/skills/architect/references/design-red-flags.md +57 -0
  41. package/skills/architect/references/rationale-template.md +35 -0
  42. package/skills/architect/references/runner-prompt.md +20 -0
  43. package/skills/arena/SKILL.md +48 -0
  44. package/skills/automate-me/SKILL.md +104 -0
  45. package/skills/benchmark-checklist/SKILL.md +39 -0
  46. package/skills/blast-radius/SKILL.md +50 -0
  47. package/skills/bro/SKILL.md +7 -0
  48. package/skills/control-cli/SKILL.md +109 -0
  49. package/skills/control-ui/SKILL.md +109 -0
  50. package/skills/correct/SKILL.md +32 -0
  51. package/skills/create-formal-verification-skill/SKILL.md +43 -0
  52. package/skills/create-skill/SKILL.md +62 -0
  53. package/skills/create-verification-skill/SKILL.md +44 -0
  54. package/skills/create-verification-skill/references/feature-map-example/README.md +47 -0
  55. package/skills/create-verification-skill/references/feature-map-example/create-note.md +39 -0
  56. package/skills/create-verification-skill/references/feature-map-example/search.md +45 -0
  57. package/skills/deslop/SKILL.md +22 -0
  58. package/skills/figure-it-out/SKILL.md +52 -0
  59. package/skills/how/SKILL.md +36 -0
  60. package/skills/how/references/explainer-prompt.md +55 -0
  61. package/skills/how/references/explorer-prompt.md +35 -0
  62. package/skills/in-your-own-words/SKILL.md +7 -0
  63. package/skills/interrogate/SKILL.md +31 -0
  64. package/skills/ketchup/SKILL.md +43 -0
  65. package/skills/ketchup-video/SKILL.md +29 -0
  66. package/skills/maintain-formal-verification-skill/SKILL.md +58 -0
  67. package/skills/maintain-verification-skill/SKILL.md +39 -0
  68. package/skills/make-bot-ui/SKILL.md +104 -0
  69. package/skills/no-comments/SKILL.md +24 -0
  70. package/skills/poteto-help/SKILL.md +161 -0
  71. package/skills/poteto-help/references/prompting.md +51 -0
  72. package/skills/poteto-help/references/recipes.md +51 -0
  73. package/skills/poteto-mode/SKILL.md +151 -0
  74. package/skills/poteto-mode/playbooks/authoring-a-skill.md +12 -0
  75. package/skills/poteto-mode/playbooks/autonomous-run.md +13 -0
  76. package/skills/poteto-mode/playbooks/autopilot-full.md +25 -0
  77. package/skills/poteto-mode/playbooks/autopilot-stack.md +8 -0
  78. package/skills/poteto-mode/playbooks/babysit.md +23 -0
  79. package/skills/poteto-mode/playbooks/bug-fix.md +15 -0
  80. package/skills/poteto-mode/playbooks/eval.md +25 -0
  81. package/skills/poteto-mode/playbooks/feature.md +21 -0
  82. package/skills/poteto-mode/playbooks/hillclimb.md +21 -0
  83. package/skills/poteto-mode/playbooks/investigation.md +14 -0
  84. package/skills/poteto-mode/playbooks/multi-phase-plan.md +155 -0
  85. package/skills/poteto-mode/playbooks/opening-a-pr.md +34 -0
  86. package/skills/poteto-mode/playbooks/orchestrate.md +25 -0
  87. package/skills/poteto-mode/playbooks/pause-safely.md +10 -0
  88. package/skills/poteto-mode/playbooks/perf-issue.md +25 -0
  89. package/skills/poteto-mode/playbooks/prototype.md +14 -0
  90. package/skills/poteto-mode/playbooks/refactoring.md +16 -0
  91. package/skills/poteto-mode/playbooks/runtime-forensics.md +11 -0
  92. package/skills/poteto-mode/playbooks/session-pickup.md +11 -0
  93. package/skills/poteto-mode/playbooks/shipping.md +12 -0
  94. package/skills/poteto-mode/playbooks/trace-forensics.md +14 -0
  95. package/skills/poteto-mode/playbooks/visual-parity.md +11 -0
  96. package/skills/poteto-mode/playbooks/worktree-cleanup.md +12 -0
  97. package/skills/poteto-mode/references/bugbot-triage.md +142 -0
  98. package/skills/poteto-mode/scripts/bootstrap.ts +62 -0
  99. package/skills/poteto-mode/scripts/bun.lock +67 -0
  100. package/skills/poteto-mode/scripts/check-plan.mjs +205 -0
  101. package/skills/poteto-mode/scripts/check-plan.test.ts +110 -0
  102. package/skills/poteto-mode/scripts/package.json +16 -0
  103. package/skills/poteto-mode/scripts/watch-pr/cli.test.ts +224 -0
  104. package/skills/poteto-mode/scripts/watch-pr/cli.ts +223 -0
  105. package/skills/poteto-mode/scripts/watch-pr/fakes.test-helper.ts +129 -0
  106. package/skills/poteto-mode/scripts/watch-pr/github.test.ts +498 -0
  107. package/skills/poteto-mode/scripts/watch-pr/github.ts +726 -0
  108. package/skills/poteto-mode/scripts/watch-pr/policy.test.ts +482 -0
  109. package/skills/poteto-mode/scripts/watch-pr/policy.ts +842 -0
  110. package/skills/poteto-mode/scripts/watch-pr/render.ts +169 -0
  111. package/skills/poteto-mode/scripts/watch-pr/tsconfig.json +13 -0
  112. package/skills/poteto-mode/scripts/watch-pr/types.compile.ts +93 -0
  113. package/skills/poteto-mode/scripts/watch-pr/types.ts +414 -0
  114. package/skills/poteto-mode/scripts/watch-pr/watch-pr +6 -0
  115. package/skills/poteto-mode/scripts/worktree-audit.sh +156 -0
  116. package/skills/principle-attack-the-premise/SKILL.md +21 -0
  117. package/skills/principle-boundary-discipline/SKILL.md +34 -0
  118. package/skills/principle-build-the-lever/SKILL.md +23 -0
  119. package/skills/principle-encode-lessons-in-structure/SKILL.md +11 -0
  120. package/skills/principle-exhaust-the-design-space/SKILL.md +9 -0
  121. package/skills/principle-experience-first/SKILL.md +19 -0
  122. package/skills/principle-explain-the-number/SKILL.md +18 -0
  123. package/skills/principle-fix-root-causes/SKILL.md +21 -0
  124. package/skills/principle-foundational-thinking/SKILL.md +21 -0
  125. package/skills/principle-guard-the-context-window/SKILL.md +12 -0
  126. package/skills/principle-laziness-protocol/SKILL.md +10 -0
  127. package/skills/principle-make-operations-idempotent/SKILL.md +22 -0
  128. package/skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md +14 -0
  129. package/skills/principle-minimize-reader-load/SKILL.md +18 -0
  130. package/skills/principle-model-the-domain/SKILL.md +24 -0
  131. package/skills/principle-never-block-on-the-human/SKILL.md +15 -0
  132. package/skills/principle-outcome-oriented-execution/SKILL.md +21 -0
  133. package/skills/principle-prove-it-works/SKILL.md +22 -0
  134. package/skills/principle-redesign-from-first-principles/SKILL.md +16 -0
  135. package/skills/principle-separate-before-serializing-shared-state/SKILL.md +16 -0
  136. package/skills/principle-sequence-verifiable-units/SKILL.md +17 -0
  137. package/skills/principle-subtract-before-you-add/SKILL.md +18 -0
  138. package/skills/principle-test-behavior-not-implementation/SKILL.md +20 -0
  139. package/skills/principle-type-system-discipline/SKILL.md +13 -0
  140. package/skills/recall/SKILL.md +35 -0
  141. package/skills/reflect/SKILL.md +69 -0
  142. package/skills/reflect/references/divergent-reviewer.md +38 -0
  143. package/skills/reflect/references/judgment-reviewer.md +37 -0
  144. package/skills/reflect/references/synthesizer.md +56 -0
  145. package/skills/reflect/references/tooling-reviewer.md +48 -0
  146. package/skills/setup-pstack/SKILL.md +74 -0
  147. package/skills/sharpen/SKILL.md +16 -0
  148. package/skills/show-me-your-work/SKILL.md +82 -0
  149. package/skills/show-me-your-work/references/decision-log-template.tsv +1 -0
  150. package/skills/show-me-your-work/scripts/log.sh +42 -0
  151. package/skills/statechart/SKILL.md +82 -0
  152. package/skills/statechart/references/render.md +93 -0
  153. package/skills/statechart/scripts/backends/cfg.ts +33 -0
  154. package/skills/statechart/scripts/backends/mermaid.ts +201 -0
  155. package/skills/statechart/scripts/backends/plain-text.ts +72 -0
  156. package/skills/statechart/scripts/backends/report.ts +177 -0
  157. package/skills/statechart/scripts/frontends/config.ts +276 -0
  158. package/skills/statechart/scripts/frontends/dot.ts +74 -0
  159. package/skills/statechart/scripts/frontends/marks.ts +93 -0
  160. package/skills/statechart/scripts/frontends/messages.ts +52 -0
  161. package/skills/statechart/scripts/frontends/spec.ts +114 -0
  162. package/skills/statechart/scripts/frontends/trace.ts +24 -0
  163. package/skills/statechart/scripts/frontends/value.ts +166 -0
  164. package/skills/statechart/scripts/frontends/verdict.ts +40 -0
  165. package/skills/statechart/scripts/frontends/view.ts +119 -0
  166. package/skills/statechart/scripts/ir.ts +547 -0
  167. package/skills/statechart/scripts/package.json +11 -0
  168. package/skills/statechart/scripts/passes/annotate.ts +128 -0
  169. package/skills/statechart/scripts/passes/label.ts +269 -0
  170. package/skills/statechart/scripts/passes/lift.ts +85 -0
  171. package/skills/statechart/scripts/passes/loop-check.ts +68 -0
  172. package/skills/statechart/scripts/passes/paths.ts +60 -0
  173. package/skills/statechart/scripts/passes/reach.ts +135 -0
  174. package/skills/statechart/scripts/passes/region-check.ts +97 -0
  175. package/skills/statechart/scripts/passes/regions.ts +295 -0
  176. package/skills/statechart/scripts/pipeline.ts +76 -0
  177. package/skills/statechart/scripts/run.ts +481 -0
  178. package/skills/statechart/scripts/statechart +29 -0
  179. package/skills/statechart/scripts/statechart.ts +164 -0
  180. package/skills/statechart/scripts/test/ConfigOracle.java +63 -0
  181. package/skills/statechart/scripts/test/chart.test.ts +1210 -0
  182. package/skills/statechart/scripts/test/charts/Braces.mmd +7 -0
  183. package/skills/statechart/scripts/test/charts/Escapes.mmd +11 -0
  184. package/skills/statechart/scripts/test/charts/Phases.mmd +29 -0
  185. package/skills/statechart/scripts/test/cli.test.ts +1314 -0
  186. package/skills/statechart/scripts/test/config-fuzz.test.ts +263 -0
  187. package/skills/statechart/scripts/test/corpus/Counter/ChartRun.out +57 -0
  188. package/skills/statechart/scripts/test/corpus/Counter/Counter.cfg +3 -0
  189. package/skills/statechart/scripts/test/corpus/Counter/Counter.tla +10 -0
  190. package/skills/statechart/scripts/test/corpus/Counter/chart.mmd +9 -0
  191. package/skills/statechart/scripts/test/corpus/Counter/graph.dot +16 -0
  192. package/skills/statechart/scripts/test/corpus/Counter/report.md +7 -0
  193. package/skills/statechart/scripts/test/corpus/Counter/sany.out +2 -0
  194. package/skills/statechart/scripts/test/corpus/Counter/verdict-1.out +49 -0
  195. package/skills/statechart/scripts/test/corpus/CounterAction/ChartRun.out +60 -0
  196. package/skills/statechart/scripts/test/corpus/CounterAction/CounterAction.cfg +4 -0
  197. package/skills/statechart/scripts/test/corpus/CounterAction/CounterAction.tla +22 -0
  198. package/skills/statechart/scripts/test/corpus/CounterAction/chart.mmd +26 -0
  199. package/skills/statechart/scripts/test/corpus/CounterAction/graph.dot +19 -0
  200. package/skills/statechart/scripts/test/corpus/CounterAction/report.md +20 -0
  201. package/skills/statechart/scripts/test/corpus/CounterAction/sany.out +2 -0
  202. package/skills/statechart/scripts/test/corpus/CounterAction/verdict-1.exit +1 -0
  203. package/skills/statechart/scripts/test/corpus/CounterAction/verdict-1.out +56 -0
  204. package/skills/statechart/scripts/test/corpus/CounterAction/verdict-2.exit +1 -0
  205. package/skills/statechart/scripts/test/corpus/CounterAction/verdict-2.out +82 -0
  206. package/skills/statechart/scripts/test/corpus/CounterAction/verdict-3.out +57 -0
  207. package/skills/statechart/scripts/test/corpus/CounterDeadlock/ChartRun.out +59 -0
  208. package/skills/statechart/scripts/test/corpus/CounterDeadlock/CounterDeadlock.cfg +3 -0
  209. package/skills/statechart/scripts/test/corpus/CounterDeadlock/CounterDeadlock.tla +11 -0
  210. package/skills/statechart/scripts/test/corpus/CounterDeadlock/chart.mmd +22 -0
  211. package/skills/statechart/scripts/test/corpus/CounterDeadlock/graph.dot +16 -0
  212. package/skills/statechart/scripts/test/corpus/CounterDeadlock/report.md +17 -0
  213. package/skills/statechart/scripts/test/corpus/CounterDeadlock/sany.out +2 -0
  214. package/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-1.exit +1 -0
  215. package/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-1.out +56 -0
  216. package/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-2.exit +1 -0
  217. package/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-2.out +77 -0
  218. package/skills/statechart/scripts/test/corpus/CounterFan/ChartRun.out +69 -0
  219. package/skills/statechart/scripts/test/corpus/CounterFan/CounterFan.cfg +2 -0
  220. package/skills/statechart/scripts/test/corpus/CounterFan/CounterFan.tla +11 -0
  221. package/skills/statechart/scripts/test/corpus/CounterFan/chart.mmd +85 -0
  222. package/skills/statechart/scripts/test/corpus/CounterFan/graph.dot +70 -0
  223. package/skills/statechart/scripts/test/corpus/CounterFan/report.md +12 -0
  224. package/skills/statechart/scripts/test/corpus/CounterFan/sany.out +2 -0
  225. package/skills/statechart/scripts/test/corpus/CounterFan/verdict-1.exit +1 -0
  226. package/skills/statechart/scripts/test/corpus/CounterFan/verdict-1.out +67 -0
  227. package/skills/statechart/scripts/test/corpus/CounterFan/verdict-2.out +57 -0
  228. package/skills/statechart/scripts/test/corpus/CounterGuard/ChartRun.exit +1 -0
  229. package/skills/statechart/scripts/test/corpus/CounterGuard/ChartRun.out +85 -0
  230. package/skills/statechart/scripts/test/corpus/CounterGuard/CounterGuard.cfg +6 -0
  231. package/skills/statechart/scripts/test/corpus/CounterGuard/CounterGuard.tla +13 -0
  232. package/skills/statechart/scripts/test/corpus/CounterGuard/chart.mmd +5 -0
  233. package/skills/statechart/scripts/test/corpus/CounterGuard/graph.dot +10 -0
  234. package/skills/statechart/scripts/test/corpus/CounterGuard/report.md +31 -0
  235. package/skills/statechart/scripts/test/corpus/CounterGuard/sany.out +2 -0
  236. package/skills/statechart/scripts/test/corpus/CounterGuard/verdict-1.exit +1 -0
  237. package/skills/statechart/scripts/test/corpus/CounterGuard/verdict-1.out +64 -0
  238. package/skills/statechart/scripts/test/corpus/CounterGuard/verdict-2.exit +1 -0
  239. package/skills/statechart/scripts/test/corpus/CounterGuard/verdict-2.out +77 -0
  240. package/skills/statechart/scripts/test/corpus/CounterInitPast/ChartRun.out +55 -0
  241. package/skills/statechart/scripts/test/corpus/CounterInitPast/CounterInitPast.cfg +3 -0
  242. package/skills/statechart/scripts/test/corpus/CounterInitPast/CounterInitPast.tla +10 -0
  243. package/skills/statechart/scripts/test/corpus/CounterInitPast/chart.mmd +12 -0
  244. package/skills/statechart/scripts/test/corpus/CounterInitPast/graph.dot +6 -0
  245. package/skills/statechart/scripts/test/corpus/CounterInitPast/report.md +12 -0
  246. package/skills/statechart/scripts/test/corpus/CounterInitPast/sany.out +2 -0
  247. package/skills/statechart/scripts/test/corpus/CounterInitPast/verdict-1.exit +1 -0
  248. package/skills/statechart/scripts/test/corpus/CounterInitPast/verdict-1.out +33 -0
  249. package/skills/statechart/scripts/test/corpus/CounterInitPast/verdict-2.out +54 -0
  250. package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/ChartRun.out +54 -0
  251. package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/CounterInitPastHolds.cfg +3 -0
  252. package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/CounterInitPastHolds.tla +10 -0
  253. package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/chart.mmd +1 -0
  254. package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/graph.dot +6 -0
  255. package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/report.md +7 -0
  256. package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/sany.out +2 -0
  257. package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/verdict-1.out +46 -0
  258. package/skills/statechart/scripts/test/corpus/CounterInstance/ChartRun.out +59 -0
  259. package/skills/statechart/scripts/test/corpus/CounterInstance/CounterInstance.cfg +2 -0
  260. package/skills/statechart/scripts/test/corpus/CounterInstance/CounterInstance.tla +10 -0
  261. package/skills/statechart/scripts/test/corpus/CounterInstance/CounterSteps.tla +6 -0
  262. package/skills/statechart/scripts/test/corpus/CounterInstance/chart.mmd +17 -0
  263. package/skills/statechart/scripts/test/corpus/CounterInstance/graph.dot +15 -0
  264. package/skills/statechart/scripts/test/corpus/CounterInstance/report.md +14 -0
  265. package/skills/statechart/scripts/test/corpus/CounterInstance/sany.out +3 -0
  266. package/skills/statechart/scripts/test/corpus/CounterInstance/verdict-1.exit +1 -0
  267. package/skills/statechart/scripts/test/corpus/CounterInstance/verdict-1.out +78 -0
  268. package/skills/statechart/scripts/test/corpus/CounterJump/ChartRun.out +59 -0
  269. package/skills/statechart/scripts/test/corpus/CounterJump/CounterJump.cfg +3 -0
  270. package/skills/statechart/scripts/test/corpus/CounterJump/CounterJump.tla +19 -0
  271. package/skills/statechart/scripts/test/corpus/CounterJump/chart.mmd +26 -0
  272. package/skills/statechart/scripts/test/corpus/CounterJump/graph.dot +22 -0
  273. package/skills/statechart/scripts/test/corpus/CounterJump/report.md +12 -0
  274. package/skills/statechart/scripts/test/corpus/CounterJump/sany.out +2 -0
  275. package/skills/statechart/scripts/test/corpus/CounterJump/verdict-1.exit +1 -0
  276. package/skills/statechart/scripts/test/corpus/CounterJump/verdict-1.out +58 -0
  277. package/skills/statechart/scripts/test/corpus/CounterJump/verdict-2.out +57 -0
  278. package/skills/statechart/scripts/test/corpus/CounterLoop/ChartRun.out +57 -0
  279. package/skills/statechart/scripts/test/corpus/CounterLoop/CounterLoop.cfg +2 -0
  280. package/skills/statechart/scripts/test/corpus/CounterLoop/CounterLoop.tla +11 -0
  281. package/skills/statechart/scripts/test/corpus/CounterLoop/chart.mmd +17 -0
  282. package/skills/statechart/scripts/test/corpus/CounterLoop/graph.dot +15 -0
  283. package/skills/statechart/scripts/test/corpus/CounterLoop/report.md +14 -0
  284. package/skills/statechart/scripts/test/corpus/CounterLoop/sany.out +2 -0
  285. package/skills/statechart/scripts/test/corpus/CounterLoop/verdict-1.exit +1 -0
  286. package/skills/statechart/scripts/test/corpus/CounterLoop/verdict-1.out +76 -0
  287. package/skills/statechart/scripts/test/corpus/CounterOrder/ChartRun.out +59 -0
  288. package/skills/statechart/scripts/test/corpus/CounterOrder/CounterOrder.cfg +3 -0
  289. package/skills/statechart/scripts/test/corpus/CounterOrder/CounterOrder.tla +11 -0
  290. package/skills/statechart/scripts/test/corpus/CounterOrder/chart.mmd +19 -0
  291. package/skills/statechart/scripts/test/corpus/CounterOrder/graph.dot +10 -0
  292. package/skills/statechart/scripts/test/corpus/CounterOrder/report.md +15 -0
  293. package/skills/statechart/scripts/test/corpus/CounterOrder/sany.out +2 -0
  294. package/skills/statechart/scripts/test/corpus/CounterOrder/verdict-1.exit +1 -0
  295. package/skills/statechart/scripts/test/corpus/CounterOrder/verdict-1.out +56 -0
  296. package/skills/statechart/scripts/test/corpus/CounterOrder/verdict-2.exit +1 -0
  297. package/skills/statechart/scripts/test/corpus/CounterOrder/verdict-2.out +67 -0
  298. package/skills/statechart/scripts/test/corpus/CounterRules/ChartRun.out +62 -0
  299. package/skills/statechart/scripts/test/corpus/CounterRules/CounterRules.cfg +6 -0
  300. package/skills/statechart/scripts/test/corpus/CounterRules/CounterRules.tla +24 -0
  301. package/skills/statechart/scripts/test/corpus/CounterRules/Moves.tla +5 -0
  302. package/skills/statechart/scripts/test/corpus/CounterRules/chart.mmd +22 -0
  303. package/skills/statechart/scripts/test/corpus/CounterRules/graph.dot +10 -0
  304. package/skills/statechart/scripts/test/corpus/CounterRules/report.md +23 -0
  305. package/skills/statechart/scripts/test/corpus/CounterRules/sany.out +3 -0
  306. package/skills/statechart/scripts/test/corpus/CounterRules/verdict-1.exit +1 -0
  307. package/skills/statechart/scripts/test/corpus/CounterRules/verdict-1.out +58 -0
  308. package/skills/statechart/scripts/test/corpus/CounterRules/verdict-2.exit +1 -0
  309. package/skills/statechart/scripts/test/corpus/CounterRules/verdict-2.out +66 -0
  310. package/skills/statechart/scripts/test/corpus/CounterRules/verdict-3.exit +1 -0
  311. package/skills/statechart/scripts/test/corpus/CounterRules/verdict-3.out +74 -0
  312. package/skills/statechart/scripts/test/corpus/CounterRules/verdict-4.out +59 -0
  313. package/skills/statechart/scripts/test/corpus/CounterStart/ChartRun.out +58 -0
  314. package/skills/statechart/scripts/test/corpus/CounterStart/CounterStart.cfg +3 -0
  315. package/skills/statechart/scripts/test/corpus/CounterStart/CounterStart.tla +15 -0
  316. package/skills/statechart/scripts/test/corpus/CounterStart/chart.mmd +18 -0
  317. package/skills/statechart/scripts/test/corpus/CounterStart/graph.dot +13 -0
  318. package/skills/statechart/scripts/test/corpus/CounterStart/report.md +11 -0
  319. package/skills/statechart/scripts/test/corpus/CounterStart/sany.out +2 -0
  320. package/skills/statechart/scripts/test/corpus/CounterStart/verdict-1.exit +1 -0
  321. package/skills/statechart/scripts/test/corpus/CounterStart/verdict-1.out +33 -0
  322. package/skills/statechart/scripts/test/corpus/CounterStart/verdict-2.out +57 -0
  323. package/skills/statechart/scripts/test/corpus/CounterStop/ChartRun.out +57 -0
  324. package/skills/statechart/scripts/test/corpus/CounterStop/CounterStop.cfg +3 -0
  325. package/skills/statechart/scripts/test/corpus/CounterStop/CounterStop.tla +15 -0
  326. package/skills/statechart/scripts/test/corpus/CounterStop/chart.mmd +7 -0
  327. package/skills/statechart/scripts/test/corpus/CounterStop/graph.dot +13 -0
  328. package/skills/statechart/scripts/test/corpus/CounterStop/report.md +6 -0
  329. package/skills/statechart/scripts/test/corpus/CounterStop/sany.out +2 -0
  330. package/skills/statechart/scripts/test/corpus/CounterStop/verdict-1.out +49 -0
  331. package/skills/statechart/scripts/test/corpus/CounterTie/ChartRun.out +61 -0
  332. package/skills/statechart/scripts/test/corpus/CounterTie/CounterTie.cfg +4 -0
  333. package/skills/statechart/scripts/test/corpus/CounterTie/CounterTie.tla +14 -0
  334. package/skills/statechart/scripts/test/corpus/CounterTie/chart.mmd +30 -0
  335. package/skills/statechart/scripts/test/corpus/CounterTie/graph.dot +19 -0
  336. package/skills/statechart/scripts/test/corpus/CounterTie/report.md +27 -0
  337. package/skills/statechart/scripts/test/corpus/CounterTie/sany.out +2 -0
  338. package/skills/statechart/scripts/test/corpus/CounterTie/verdict-1.exit +1 -0
  339. package/skills/statechart/scripts/test/corpus/CounterTie/verdict-1.out +56 -0
  340. package/skills/statechart/scripts/test/corpus/CounterTie/verdict-2.exit +1 -0
  341. package/skills/statechart/scripts/test/corpus/CounterTie/verdict-2.out +64 -0
  342. package/skills/statechart/scripts/test/corpus/CounterTie/verdict-3.exit +1 -0
  343. package/skills/statechart/scripts/test/corpus/CounterTie/verdict-3.out +87 -0
  344. package/skills/statechart/scripts/test/corpus/CounterTie/verdict-4.out +57 -0
  345. package/skills/statechart/scripts/test/corpus/CounterTieInGraph/ChartRun.out +60 -0
  346. package/skills/statechart/scripts/test/corpus/CounterTieInGraph/CounterTieInGraph.cfg +3 -0
  347. package/skills/statechart/scripts/test/corpus/CounterTieInGraph/CounterTieInGraph.tla +12 -0
  348. package/skills/statechart/scripts/test/corpus/CounterTieInGraph/chart.mmd +23 -0
  349. package/skills/statechart/scripts/test/corpus/CounterTieInGraph/graph.dot +19 -0
  350. package/skills/statechart/scripts/test/corpus/CounterTieInGraph/report.md +11 -0
  351. package/skills/statechart/scripts/test/corpus/CounterTieInGraph/sany.out +2 -0
  352. package/skills/statechart/scripts/test/corpus/CounterTieInGraph/verdict-1.exit +1 -0
  353. package/skills/statechart/scripts/test/corpus/CounterTieInGraph/verdict-1.out +56 -0
  354. package/skills/statechart/scripts/test/corpus/CounterTieInGraph/verdict-2.out +57 -0
  355. package/skills/statechart/scripts/test/corpus/CounterView/ChartRun.out +61 -0
  356. package/skills/statechart/scripts/test/corpus/CounterView/CounterView.cfg +4 -0
  357. package/skills/statechart/scripts/test/corpus/CounterView/CounterView.tla +14 -0
  358. package/skills/statechart/scripts/test/corpus/CounterView/chart.mmd +23 -0
  359. package/skills/statechart/scripts/test/corpus/CounterView/graph.dot +19 -0
  360. package/skills/statechart/scripts/test/corpus/CounterView/report.md +27 -0
  361. package/skills/statechart/scripts/test/corpus/CounterView/sany.out +2 -0
  362. package/skills/statechart/scripts/test/corpus/CounterView/verdict-1.exit +1 -0
  363. package/skills/statechart/scripts/test/corpus/CounterView/verdict-1.out +56 -0
  364. package/skills/statechart/scripts/test/corpus/CounterView/verdict-2.exit +1 -0
  365. package/skills/statechart/scripts/test/corpus/CounterView/verdict-2.out +64 -0
  366. package/skills/statechart/scripts/test/corpus/CounterView/verdict-3.exit +1 -0
  367. package/skills/statechart/scripts/test/corpus/CounterView/verdict-3.out +87 -0
  368. package/skills/statechart/scripts/test/corpus/CounterView/verdict-4.out +57 -0
  369. package/skills/statechart/scripts/test/corpus/CounterView/view.mjs +1 -0
  370. package/skills/statechart/scripts/test/corpus/DieHard/ChartRun.out +59 -0
  371. package/skills/statechart/scripts/test/corpus/DieHard/DieHard.cfg +4 -0
  372. package/skills/statechart/scripts/test/corpus/DieHard/DieHard.tla +38 -0
  373. package/skills/statechart/scripts/test/corpus/DieHard/chart.mmd +92 -0
  374. package/skills/statechart/scripts/test/corpus/DieHard/graph.dot +126 -0
  375. package/skills/statechart/scripts/test/corpus/DieHard/report.md +17 -0
  376. package/skills/statechart/scripts/test/corpus/DieHard/sany.out +2 -0
  377. package/skills/statechart/scripts/test/corpus/DieHard/verdict-1.exit +1 -0
  378. package/skills/statechart/scripts/test/corpus/DieHard/verdict-1.out +91 -0
  379. package/skills/statechart/scripts/test/corpus/DieHard/verdict-2.out +57 -0
  380. package/skills/statechart/scripts/test/corpus/FirstRule/ChartRun.out +61 -0
  381. package/skills/statechart/scripts/test/corpus/FirstRule/FirstRule.cfg +6 -0
  382. package/skills/statechart/scripts/test/corpus/FirstRule/FirstRule.tla +11 -0
  383. package/skills/statechart/scripts/test/corpus/FirstRule/chart.mmd +22 -0
  384. package/skills/statechart/scripts/test/corpus/FirstRule/graph.dot +16 -0
  385. package/skills/statechart/scripts/test/corpus/FirstRule/report.md +25 -0
  386. package/skills/statechart/scripts/test/corpus/FirstRule/sany.out +2 -0
  387. package/skills/statechart/scripts/test/corpus/FirstRule/verdict-1.exit +1 -0
  388. package/skills/statechart/scripts/test/corpus/FirstRule/verdict-1.out +56 -0
  389. package/skills/statechart/scripts/test/corpus/FirstRule/verdict-2.exit +1 -0
  390. package/skills/statechart/scripts/test/corpus/FirstRule/verdict-2.out +64 -0
  391. package/skills/statechart/scripts/test/corpus/FirstRule/verdict-3.exit +1 -0
  392. package/skills/statechart/scripts/test/corpus/FirstRule/verdict-3.out +64 -0
  393. package/skills/statechart/scripts/test/corpus/FirstRule/verdict-4.exit +1 -0
  394. package/skills/statechart/scripts/test/corpus/FirstRule/verdict-4.out +77 -0
  395. package/skills/statechart/scripts/test/corpus/HiddenClock/ChartRun.out +57 -0
  396. package/skills/statechart/scripts/test/corpus/HiddenClock/HiddenClock.cfg +4 -0
  397. package/skills/statechart/scripts/test/corpus/HiddenClock/HiddenClock.tla +11 -0
  398. package/skills/statechart/scripts/test/corpus/HiddenClock/chart.mmd +13 -0
  399. package/skills/statechart/scripts/test/corpus/HiddenClock/graph.dot +12 -0
  400. package/skills/statechart/scripts/test/corpus/HiddenClock/report.md +11 -0
  401. package/skills/statechart/scripts/test/corpus/HiddenClock/sany.out +2 -0
  402. package/skills/statechart/scripts/test/corpus/HiddenClock/verdict-1.exit +1 -0
  403. package/skills/statechart/scripts/test/corpus/HiddenClock/verdict-1.out +72 -0
  404. package/skills/statechart/scripts/test/corpus/Login/ChartRun.out +57 -0
  405. package/skills/statechart/scripts/test/corpus/Login/Login.cfg +3 -0
  406. package/skills/statechart/scripts/test/corpus/Login/Login.tla +62 -0
  407. package/skills/statechart/scripts/test/corpus/Login/chart.mmd +27 -0
  408. package/skills/statechart/scripts/test/corpus/Login/graph.dot +40 -0
  409. package/skills/statechart/scripts/test/corpus/Login/report.md +7 -0
  410. package/skills/statechart/scripts/test/corpus/Login/sany.out +1 -0
  411. package/skills/statechart/scripts/test/corpus/Login/verdict-1.out +47 -0
  412. package/skills/statechart/scripts/test/corpus/Login/view.mjs +1 -0
  413. package/skills/statechart/scripts/test/corpus/LoginGuarded/ChartRun.out +57 -0
  414. package/skills/statechart/scripts/test/corpus/LoginGuarded/LoginGuarded.cfg +2 -0
  415. package/skills/statechart/scripts/test/corpus/LoginGuarded/LoginGuarded.tla +64 -0
  416. package/skills/statechart/scripts/test/corpus/LoginGuarded/chart.mmd +28 -0
  417. package/skills/statechart/scripts/test/corpus/LoginGuarded/graph.dot +37 -0
  418. package/skills/statechart/scripts/test/corpus/LoginGuarded/report.md +8 -0
  419. package/skills/statechart/scripts/test/corpus/LoginGuarded/sany.out +1 -0
  420. package/skills/statechart/scripts/test/corpus/LoginGuarded/verdict-1.out +47 -0
  421. package/skills/statechart/scripts/test/corpus/LoginGuarded/view.mjs +1 -0
  422. package/skills/statechart/scripts/test/corpus/LoginParallel/ChartRun.out +60 -0
  423. package/skills/statechart/scripts/test/corpus/LoginParallel/LoginParallel.cfg +3 -0
  424. package/skills/statechart/scripts/test/corpus/LoginParallel/LoginParallel.tla +64 -0
  425. package/skills/statechart/scripts/test/corpus/LoginParallel/chart.mmd +44 -0
  426. package/skills/statechart/scripts/test/corpus/LoginParallel/graph.dot +58 -0
  427. package/skills/statechart/scripts/test/corpus/LoginParallel/report.md +17 -0
  428. package/skills/statechart/scripts/test/corpus/LoginParallel/sany.out +1 -0
  429. package/skills/statechart/scripts/test/corpus/LoginParallel/verdict-1.exit +1 -0
  430. package/skills/statechart/scripts/test/corpus/LoginParallel/verdict-1.out +83 -0
  431. package/skills/statechart/scripts/test/corpus/LoginParallel/verdict-2.out +57 -0
  432. package/skills/statechart/scripts/test/corpus/LoginParallel/view.mjs +1 -0
  433. package/skills/statechart/scripts/test/corpus/MediaPlayer/ChartRun.out +60 -0
  434. package/skills/statechart/scripts/test/corpus/MediaPlayer/MediaPlayer.cfg +3 -0
  435. package/skills/statechart/scripts/test/corpus/MediaPlayer/MediaPlayer.tla +103 -0
  436. package/skills/statechart/scripts/test/corpus/MediaPlayer/chart.mmd +43 -0
  437. package/skills/statechart/scripts/test/corpus/MediaPlayer/graph.dot +93 -0
  438. package/skills/statechart/scripts/test/corpus/MediaPlayer/report.md +14 -0
  439. package/skills/statechart/scripts/test/corpus/MediaPlayer/sany.out +1 -0
  440. package/skills/statechart/scripts/test/corpus/MediaPlayer/verdict-1.exit +1 -0
  441. package/skills/statechart/scripts/test/corpus/MediaPlayer/verdict-1.out +59 -0
  442. package/skills/statechart/scripts/test/corpus/MediaPlayer/verdict-2.out +72 -0
  443. package/skills/statechart/scripts/test/corpus/MediaPlayer/view.mjs +3 -0
  444. package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/ChartRun.out +57 -0
  445. package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/MediaPlayerFixed.cfg +2 -0
  446. package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/MediaPlayerFixed.tla +100 -0
  447. package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/chart.mmd +31 -0
  448. package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/graph.dot +85 -0
  449. package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/report.md +9 -0
  450. package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/sany.out +1 -0
  451. package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/verdict-1.out +47 -0
  452. package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/view.mjs +3 -0
  453. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/ChartRun.out +59 -0
  454. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/MediaPlayer.tla +103 -0
  455. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/MediaPlayerProps.cfg +3 -0
  456. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/MediaPlayerProps.tla +6 -0
  457. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/chart.mmd +42 -0
  458. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/graph.dot +93 -0
  459. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/report.md +19 -0
  460. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/sany.out +2 -0
  461. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-1.exit +1 -0
  462. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-1.out +61 -0
  463. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-2.out +59 -0
  464. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-3.out +61 -0
  465. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-4.exit +1 -0
  466. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-4.out +66 -0
  467. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-5.exit +1 -0
  468. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-5.out +58 -0
  469. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-6.out +49 -0
  470. package/skills/statechart/scripts/test/corpus/MediaPlayerProps/view.mjs +3 -0
  471. package/skills/statechart/scripts/test/corpus/PickWorker/ChartRun.out +57 -0
  472. package/skills/statechart/scripts/test/corpus/PickWorker/PickWorker.cfg +6 -0
  473. package/skills/statechart/scripts/test/corpus/PickWorker/PickWorker.tla +11 -0
  474. package/skills/statechart/scripts/test/corpus/PickWorker/chart.mmd +5 -0
  475. package/skills/statechart/scripts/test/corpus/PickWorker/graph.dot +11 -0
  476. package/skills/statechart/scripts/test/corpus/PickWorker/report.md +7 -0
  477. package/skills/statechart/scripts/test/corpus/PickWorker/sany.out +5 -0
  478. package/skills/statechart/scripts/test/corpus/PickWorker/verdict-1.out +70 -0
  479. package/skills/statechart/scripts/test/corpus/Shadow/ChartRun.out +61 -0
  480. package/skills/statechart/scripts/test/corpus/Shadow/Shadow.cfg +4 -0
  481. package/skills/statechart/scripts/test/corpus/Shadow/Shadow.tla +11 -0
  482. package/skills/statechart/scripts/test/corpus/Shadow/ShadowLib.tla +6 -0
  483. package/skills/statechart/scripts/test/corpus/Shadow/ShadowSub.tla +3 -0
  484. package/skills/statechart/scripts/test/corpus/Shadow/chart.mmd +9 -0
  485. package/skills/statechart/scripts/test/corpus/Shadow/graph.dot +16 -0
  486. package/skills/statechart/scripts/test/corpus/Shadow/report.md +8 -0
  487. package/skills/statechart/scripts/test/corpus/Shadow/sany.out +4 -0
  488. package/skills/statechart/scripts/test/corpus/Shadow/verdict-1.out +65 -0
  489. package/skills/statechart/scripts/test/corpus/SpacedNames/ChartRun.out +59 -0
  490. package/skills/statechart/scripts/test/corpus/SpacedNames/SpacedNames.cfg +2 -0
  491. package/skills/statechart/scripts/test/corpus/SpacedNames/SpacedNames.tla +9 -0
  492. package/skills/statechart/scripts/test/corpus/SpacedNames/chart.mmd +23 -0
  493. package/skills/statechart/scripts/test/corpus/SpacedNames/graph.dot +17 -0
  494. package/skills/statechart/scripts/test/corpus/SpacedNames/report.md +15 -0
  495. package/skills/statechart/scripts/test/corpus/SpacedNames/sany.out +1 -0
  496. package/skills/statechart/scripts/test/corpus/SpacedNames/verdict-1.exit +1 -0
  497. package/skills/statechart/scripts/test/corpus/SpacedNames/verdict-1.out +65 -0
  498. package/skills/statechart/scripts/test/corpus/SpacedNames/verdict-2.exit +1 -0
  499. package/skills/statechart/scripts/test/corpus/SpacedNames/verdict-2.out +75 -0
  500. package/skills/statechart/scripts/test/corpus/TwoPhase/ChartRun.out +69 -0
  501. package/skills/statechart/scripts/test/corpus/TwoPhase/TwoPhase.cfg +3 -0
  502. package/skills/statechart/scripts/test/corpus/TwoPhase/TwoPhase.tla +75 -0
  503. package/skills/statechart/scripts/test/corpus/TwoPhase/chart.mmd +60 -0
  504. package/skills/statechart/scripts/test/corpus/TwoPhase/graph.dot +297 -0
  505. package/skills/statechart/scripts/test/corpus/TwoPhase/report.md +20 -0
  506. package/skills/statechart/scripts/test/corpus/TwoPhase/sany.out +1 -0
  507. package/skills/statechart/scripts/test/corpus/TwoPhase/verdict-1.exit +1 -0
  508. package/skills/statechart/scripts/test/corpus/TwoPhase/verdict-1.out +95 -0
  509. package/skills/statechart/scripts/test/corpus/TwoPhase/verdict-2.out +57 -0
  510. package/skills/statechart/scripts/test/corpus/TwoPhase/view.mjs +1 -0
  511. package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/ChartRun.out +57 -0
  512. package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/TwoPhaseFixed.cfg +3 -0
  513. package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/TwoPhaseFixed.tla +75 -0
  514. package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/chart.mmd +37 -0
  515. package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/graph.dot +223 -0
  516. package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/report.md +11 -0
  517. package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/sany.out +1 -0
  518. package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/verdict-1.out +47 -0
  519. package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/view.mjs +1 -0
  520. package/skills/statechart/scripts/test/corpus/TypeGuard/ChartRun.exit +1 -0
  521. package/skills/statechart/scripts/test/corpus/TypeGuard/ChartRun.out +75 -0
  522. package/skills/statechart/scripts/test/corpus/TypeGuard/TypeGuard.cfg +5 -0
  523. package/skills/statechart/scripts/test/corpus/TypeGuard/TypeGuard.tla +11 -0
  524. package/skills/statechart/scripts/test/corpus/TypeGuard/chart.mmd +18 -0
  525. package/skills/statechart/scripts/test/corpus/TypeGuard/graph.dot +14 -0
  526. package/skills/statechart/scripts/test/corpus/TypeGuard/report.md +29 -0
  527. package/skills/statechart/scripts/test/corpus/TypeGuard/sany.out +2 -0
  528. package/skills/statechart/scripts/test/corpus/TypeGuard/verdict-1.exit +1 -0
  529. package/skills/statechart/scripts/test/corpus/TypeGuard/verdict-1.out +64 -0
  530. package/skills/statechart/scripts/test/corpus/TypeGuard/verdict-2.exit +1 -0
  531. package/skills/statechart/scripts/test/corpus/TypeGuard/verdict-2.out +75 -0
  532. package/skills/statechart/scripts/test/corpus/UserNoDeadlock/ChartRun.out +58 -0
  533. package/skills/statechart/scripts/test/corpus/UserNoDeadlock/UserNoDeadlock.cfg +2 -0
  534. package/skills/statechart/scripts/test/corpus/UserNoDeadlock/UserNoDeadlock.tla +8 -0
  535. package/skills/statechart/scripts/test/corpus/UserNoDeadlock/chart.mmd +22 -0
  536. package/skills/statechart/scripts/test/corpus/UserNoDeadlock/graph.dot +16 -0
  537. package/skills/statechart/scripts/test/corpus/UserNoDeadlock/report.md +15 -0
  538. package/skills/statechart/scripts/test/corpus/UserNoDeadlock/sany.out +2 -0
  539. package/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-1.exit +1 -0
  540. package/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-1.out +56 -0
  541. package/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-2.exit +1 -0
  542. package/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-2.out +77 -0
  543. package/skills/statechart/scripts/test/corpus.test.ts +403 -0
  544. package/skills/statechart/scripts/test/differential.test.ts +565 -0
  545. package/skills/statechart/scripts/test/grid/Grid.cfg +2 -0
  546. package/skills/statechart/scripts/test/grid/Grid.tla +9 -0
  547. package/skills/statechart/scripts/test/grid/sany.out +2 -0
  548. package/skills/statechart/scripts/test/java.ts +63 -0
  549. package/skills/statechart/scripts/test/labels.ts +643 -0
  550. package/skills/statechart/scripts/test/messages.test.ts +212 -0
  551. package/skills/statechart/scripts/test/pipeline.test.ts +270 -0
  552. package/skills/statechart/scripts/test/plain-tlc.test.ts +255 -0
  553. package/skills/statechart/scripts/test/render.test.ts +81 -0
  554. package/skills/statechart/scripts/test/tlc-out.test.ts +90 -0
  555. package/skills/statechart/scripts/test/tlc.ts +158 -0
  556. package/skills/statechart/scripts/tsconfig.json +11 -0
  557. package/skills/statechart/scripts/worker.ts +35 -0
  558. package/skills/swarm/SKILL.md +41 -0
  559. package/skills/tdd/SKILL.md +42 -0
  560. package/skills/teach/SKILL.md +21 -0
  561. package/skills/technical-writing/SKILL.md +106 -0
  562. package/skills/typescript-best-practices/SKILL.md +32 -0
  563. package/skills/typescript-best-practices/references/patterns.md +328 -0
  564. package/skills/unslop/SKILL.md +62 -0
  565. package/skills/why/SKILL.md +98 -0
  566. package/skills/why/references/epistemics.md +71 -0
  567. package/skills/why/references/investigator-prompt.md +84 -0
  568. package/skills/why/references/source-playbook.md +17 -0
  569. package/skills/why/references/sources/code-archaeology.md +51 -0
  570. package/skills/why/references/sources/databricks.md +70 -0
  571. package/skills/why/references/sources/datadog.md +97 -0
  572. package/skills/why/references/sources/incident-postmortem.md +5 -0
  573. package/skills/why/references/sources/linear.md +48 -0
  574. package/skills/why/references/sources/notion.md +55 -0
  575. package/skills/why/references/sources/sentry.md +66 -0
  576. package/skills/why/references/sources/slack.md +17 -0
  577. package/skills/why/references/synthesizer-prompt.md +129 -0
  578. package/src/aliases.ts +64 -0
  579. package/src/ask.ts +131 -0
  580. package/src/autocomplete.ts +21 -0
  581. package/src/child-env.ts +44 -0
  582. package/src/index.ts +123 -0
  583. package/src/loop.ts +189 -0
  584. package/src/mode.ts +156 -0
  585. package/src/modes.ts +8 -0
  586. package/src/paths.ts +72 -0
  587. package/src/plan.ts +141 -0
  588. package/src/readonly-shell.ts +107 -0
  589. package/src/rule.ts +56 -0
  590. package/src/sections.ts +117 -0
  591. package/src/subscriptions/cron.ts +75 -0
  592. package/src/subscriptions/github.ts +149 -0
  593. package/src/subscriptions/index.ts +547 -0
  594. package/src/subscriptions/webhook.ts +209 -0
  595. package/src/task/agents.ts +55 -0
  596. package/src/task/card.ts +32 -0
  597. package/src/task/format.ts +88 -0
  598. package/src/task/models.ts +140 -0
  599. package/src/task/records.ts +232 -0
  600. package/src/task/registry.ts +77 -0
  601. package/src/task/runner.ts +370 -0
  602. package/src/task/status.ts +170 -0
  603. package/src/task/stop.ts +100 -0
  604. package/src/task/tool.ts +491 -0
  605. package/src/task/worktree.ts +67 -0
  606. package/src/todo.ts +122 -0
  607. package/src/visualize.ts +244 -0
  608. package/test/aliases.test.ts +57 -0
  609. package/test/ask.test.ts +85 -0
  610. package/test/autocomplete.test.ts +39 -0
  611. package/test/e2e/aliases.e2e.test.ts +81 -0
  612. package/test/e2e/ask.e2e.test.ts +135 -0
  613. package/test/e2e/harness.ts +179 -0
  614. package/test/e2e/host.e2e.test.ts +193 -0
  615. package/test/e2e/lifecycle.e2e.test.ts +99 -0
  616. package/test/e2e/mode.e2e.test.ts +160 -0
  617. package/test/e2e/package.e2e.test.ts +67 -0
  618. package/test/e2e/task.e2e.test.ts +734 -0
  619. package/test/e2e/todo.e2e.test.ts +59 -0
  620. package/test/fixtures/cursor-askquestion-calls.json +806 -0
  621. package/test/fixtures/fake-pi.mjs +96 -0
  622. package/test/fixtures/image-model.ts +16 -0
  623. package/test/fixtures/list-models.ts +15 -0
  624. package/test/fixtures/readonly-shell-exit.ts +17 -0
  625. package/test/fixtures/scripted-model.ts +113 -0
  626. package/test/loop.test.ts +209 -0
  627. package/test/mode.test.ts +143 -0
  628. package/test/plan.test.ts +126 -0
  629. package/test/readonly-shell-security.test.ts +84 -0
  630. package/test/readonly-shell.test.ts +44 -0
  631. package/test/records.test.ts +143 -0
  632. package/test/registry.test.ts +18 -0
  633. package/test/resources.test.ts +162 -0
  634. package/test/rule.test.ts +92 -0
  635. package/test/scripts.test.ts +182 -0
  636. package/test/sections.test.ts +56 -0
  637. package/test/subscriptions-cron.test.ts +60 -0
  638. package/test/subscriptions.test.ts +598 -0
  639. package/test/task-agents.test.ts +49 -0
  640. package/test/task-card.test.ts +34 -0
  641. package/test/task-fork.test.ts +233 -0
  642. package/test/task-format.test.ts +65 -0
  643. package/test/task-model.test.ts +141 -0
  644. package/test/task-runner.test.ts +259 -0
  645. package/test/task-schema.test.ts +50 -0
  646. package/test/task-status.test.ts +155 -0
  647. package/test/task-worktree.test.ts +106 -0
  648. package/test/todo.test.ts +74 -0
  649. package/test/visualize.test.ts +152 -0
  650. package/tsconfig.json +5 -0
  651. package/vitest.config.ts +16 -0
@@ -0,0 +1,135 @@
1
+ import { afterEach, beforeEach, expect, test } from 'vitest';
2
+ import { makeSandbox, type PiEvent, runJson, type Sandbox, script, startRpc, toolEnds } from './harness.ts';
3
+
4
+ let sandbox: Sandbox;
5
+ beforeEach(() => {
6
+ sandbox = makeSandbox();
7
+ });
8
+ afterEach(() => sandbox.dispose());
9
+
10
+ const budget = {
11
+ id: 'budget',
12
+ prompt: 'Pick a reasoning budget',
13
+ options: [
14
+ { id: 'unlimited', label: 'unlimited — max reasoning' },
15
+ { id: 'large', label: 'large — xhigh reasoning' },
16
+ ],
17
+ };
18
+ const areas = {
19
+ id: 'areas',
20
+ prompt: 'Which areas matter most?',
21
+ allow_multiple: true,
22
+ options: [
23
+ { id: 'style', label: 'Response style' },
24
+ { id: 'subagents', label: 'Subagents' },
25
+ { id: 'process', label: 'Process' },
26
+ ],
27
+ };
28
+
29
+ test('asks each question through UI dialogs and returns option IDs (HOST-005)', async () => {
30
+ const rpc = startRpc(sandbox, ['--no-session']);
31
+ try {
32
+ const answers = ['large — xhigh reasoning', 'Subagents', 'Process', '✓ Done selecting'];
33
+ const seen: PiEvent[] = [];
34
+ rpc.child.stdout?.on('data', () => {
35
+ for (const event of rpc.events.filter((candidate) => candidate.type === 'extension_ui_request' && candidate['method'] === 'select' && !seen.includes(candidate))) {
36
+ seen.push(event);
37
+ rpc.send({ type: 'extension_ui_response', id: event['id'], value: answers.shift() });
38
+ }
39
+ });
40
+ rpc.send({ type: 'prompt', message: script([{ tool: 'AskQuestion', args: { questions: [budget, areas] } }]) });
41
+ const end = await rpc.waitFor((event) => event.type === 'tool_execution_end' && event['toolName'] === 'AskQuestion');
42
+ expect(seen.map((event) => [event['title'], event['options']])).toEqual([
43
+ ['Pick a reasoning budget', ['unlimited — max reasoning', 'large — xhigh reasoning', 'Other: (type to answer)']],
44
+ ['Which areas matter most? (pick one at a time, then ✓ Done selecting)', ['Response style', 'Subagents', 'Process', 'Other: (type to answer)', '✓ Done selecting']],
45
+ ['Which areas matter most? (picked: Subagents)', ['Response style', 'Process', 'Other: (type to answer)', '✓ Done selecting']],
46
+ ['Which areas matter most? (picked: Subagents, Process)', ['Response style', 'Other: (type to answer)', '✓ Done selecting']],
47
+ ]);
48
+ const result = end['result'] as { content: { text: string }[]; details: unknown };
49
+ expect(result.content[0]?.text).toBe('budget: large (large — xhigh reasoning)\nareas: subagents (Subagents), process (Process)');
50
+ expect(result.details).toEqual({ answers: { budget: ['large'], areas: ['subagents', 'process'] } });
51
+ } finally {
52
+ await rpc.close();
53
+ }
54
+ });
55
+
56
+ test('shows the title and option descriptions of a Cursor-shaped call and still returns IDs (HOST-005)', async () => {
57
+ // Shape observed in Cursor IDE AskQuestion calls: a top-level title and optional option descriptions.
58
+ const confirm = {
59
+ id: 'confirm',
60
+ prompt: 'Write the rule with this table?',
61
+ options: [
62
+ { id: 'accept', label: 'Accept as-is (Recommended)', description: 'Keep all roles on inherit-parent.' },
63
+ { id: 'change', label: 'Change specific roles' },
64
+ ],
65
+ };
66
+ const rpc = startRpc(sandbox, ['--no-session']);
67
+ try {
68
+ const seen: PiEvent[] = [];
69
+ rpc.child.stdout?.on('data', () => {
70
+ for (const event of rpc.events.filter((candidate) => candidate.type === 'extension_ui_request' && candidate['method'] === 'select' && !seen.includes(candidate))) {
71
+ seen.push(event);
72
+ rpc.send({ type: 'extension_ui_response', id: event['id'], value: (event['options'] as string[])[0] });
73
+ }
74
+ });
75
+ rpc.send({ type: 'prompt', message: script([{ tool: 'AskQuestion', args: { title: 'Confirm pstack rule', questions: [confirm] } }]) });
76
+ const end = await rpc.waitFor((event) => event.type === 'tool_execution_end' && event['toolName'] === 'AskQuestion');
77
+ expect(seen.map((event) => [event['title'], event['options']])).toEqual([
78
+ ['Confirm pstack rule: Write the rule with this table?', ['Accept as-is (Recommended) — Keep all roles on inherit-parent.', 'Change specific roles', 'Other: (type to answer)']],
79
+ ]);
80
+ expect((end['result'] as { details: unknown }).details).toEqual({ answers: { confirm: ['accept'] } });
81
+ } finally {
82
+ await rpc.close();
83
+ }
84
+ });
85
+
86
+ test('a dismissed question is reported, not guessed (HOST-005)', async () => {
87
+ const rpc = startRpc(sandbox, ['--no-session']);
88
+ try {
89
+ let responded = false;
90
+ rpc.child.stdout?.on('data', () => {
91
+ const request = rpc.events.find((event) => event.type === 'extension_ui_request' && event['method'] === 'select');
92
+ if (request === undefined || responded) return;
93
+ responded = true;
94
+ rpc.send({ type: 'extension_ui_response', id: request['id'], cancelled: true });
95
+ });
96
+ rpc.send({ type: 'prompt', message: script([{ tool: 'AskQuestion', args: { questions: [budget] } }]) });
97
+ const end = await rpc.waitFor((event) => event.type === 'tool_execution_end' && event['toolName'] === 'AskQuestion');
98
+ expect((end['result'] as { content: { text: string }[] }).content[0]?.text).toBe('budget: no answer (the user dismissed the question)');
99
+ } finally {
100
+ await rpc.close();
101
+ }
102
+ });
103
+
104
+ test('without a UI the questions resolve as skipped, as Cursor print mode reports (HOST-005)', async () => {
105
+ // Observed: cursor-agent -p called AskQuestion and its final reply said the user skipped the question
106
+ // (parity/pi-pstack-two/evidence/cursor-delegate-v21-resume-run1.json).
107
+ const run = await runJson(sandbox, script([{ tool: 'AskQuestion', args: { questions: [budget] } }]), ['--no-session']);
108
+ const [end] = toolEnds(run.events, 'AskQuestion');
109
+ expect(end?.isError).toBe(false);
110
+ expect(end?.text).toBe('budget: skipped (no one can answer questions in this session; decide yourself and say what you chose)');
111
+ expect(end?.details).toEqual({ answers: {}, skipped: ['budget'] });
112
+ });
113
+
114
+ test('every question offers a typed Other answer, as the Cursor question dialog does (HOST-005)', async () => {
115
+ const rpc = startRpc(sandbox, ['--no-session']);
116
+ try {
117
+ const seen: PiEvent[] = [];
118
+ rpc.child.stdout?.on('data', () => {
119
+ for (const event of rpc.events.filter((candidate) => candidate.type === 'extension_ui_request' && !seen.includes(candidate))) {
120
+ seen.push(event);
121
+ if (event['method'] === 'select') rpc.send({ type: 'extension_ui_response', id: event['id'], value: 'Other: (type to answer)' });
122
+ if (event['method'] === 'input') rpc.send({ type: 'extension_ui_response', id: event['id'], value: 'xhigh but cheaper' });
123
+ }
124
+ });
125
+ rpc.send({ type: 'prompt', message: script([{ tool: 'AskQuestion', args: { questions: [budget] } }]) });
126
+ const end = await rpc.waitFor((event) => event.type === 'tool_execution_end' && event['toolName'] === 'AskQuestion');
127
+ const select = seen.find((event) => event['method'] === 'select');
128
+ expect((select?.['options'] as string[] | undefined)?.at(-1)).toBe('Other: (type to answer)');
129
+ const result = end['result'] as { content: { text: string }[]; details: unknown };
130
+ expect(result.content[0]?.text).toBe('budget: other ("xhigh but cheaper")');
131
+ expect(result.details).toEqual({ answers: { budget: ['other'] }, other: { budget: 'xhigh but cheaper' } });
132
+ } finally {
133
+ await rpc.close();
134
+ }
135
+ });
@@ -0,0 +1,179 @@
1
+ // Drives the real Pi CLI against an isolated agent directory that loads this package and the scripted test model.
2
+ import { type ChildProcess, spawn } from 'node:child_process';
3
+ import { mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+
7
+ import { PACKAGE_ROOT } from '../../src/paths.ts';
8
+
9
+ const PI_CLI = join(PACKAGE_ROOT, 'node_modules/@earendil-works/pi-coding-agent/dist/bundle/cli.js');
10
+ const SCRIPTED_MODEL = join(PACKAGE_ROOT, 'test/fixtures/scripted-model.ts');
11
+ // PSTACK_E2E_PI=<pi executable> runs the suite against an installed Pi, such as the user's launcher, instead of the dev dependency.
12
+ const INSTALLED_PI = process.env['PSTACK_E2E_PI'];
13
+
14
+ /** The command and argv that run Pi with these arguments. */
15
+ export function piInvocation(args: readonly string[]): [string, string[]] {
16
+ return INSTALLED_PI === undefined || INSTALLED_PI === '' ? [process.execPath, [PI_CLI, ...args]] : [INSTALLED_PI, [...args]];
17
+ }
18
+
19
+ export interface Sandbox {
20
+ root: string;
21
+ agentDir: string;
22
+ workDir: string;
23
+ env: Record<string, string>;
24
+ dispose: () => void;
25
+ }
26
+
27
+ export type PiEvent = { type: string } & Record<string, unknown>;
28
+
29
+ export interface RunResult {
30
+ events: PiEvent[];
31
+ exitCode: number | null;
32
+ stderr: string;
33
+ }
34
+
35
+ export function makeSandbox(settings: Record<string, unknown> = {}): Sandbox {
36
+ const root = realpathSync(mkdtempSync(join(tmpdir(), 'pi-pstack-e2e-')));
37
+ const agentDir = join(root, 'agent');
38
+ const workDir = join(root, 'work');
39
+ mkdirSync(agentDir);
40
+ mkdirSync(workDir);
41
+ writeFileSync(join(agentDir, 'settings.json'), JSON.stringify({ packages: [PACKAGE_ROOT], extensions: [SCRIPTED_MODEL], quietStartup: true, ...settings }));
42
+ // HOME moves too, so user-level resources such as ~/.agents/skills stay out of the run.
43
+ const env = { ...process.env, HOME: root, PI_CODING_AGENT_DIR: agentDir, PI_OFFLINE: '1', PI_SKIP_VERSION_CHECK: '1' } as Record<string, string>;
44
+ // Variables that would point a run at the user's real state, or give the parent a subagent identity.
45
+ for (const name of ['PI_CODING_AGENT_SESSION_DIR', 'PI_PSTACK_DEPTH', 'PI_PSTACK_AGENT', 'PI_PSTACK_PARENT_PID']) delete env[name];
46
+ return { root, agentDir, workDir, env, dispose: () => rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 }) };
47
+ }
48
+
49
+ /** Splits a byte stream on LF only, as Pi's JSONL framing requires. */
50
+ export function lineSplitter(onLine: (line: string) => void): (chunk: Buffer) => void {
51
+ let buffer = '';
52
+ return (chunk) => {
53
+ buffer += chunk.toString('utf8');
54
+ let index = buffer.indexOf('\n');
55
+ while (index !== -1) {
56
+ const line = buffer.slice(0, index).replace(/\r$/, '');
57
+ buffer = buffer.slice(index + 1);
58
+ if (line.trim() !== '') onLine(line);
59
+ index = buffer.indexOf('\n');
60
+ }
61
+ };
62
+ }
63
+
64
+ export function runJson(sandbox: Sandbox, prompts: string | string[], args: string[] = [], timeoutMs = 45_000): Promise<RunResult> {
65
+ return new Promise((resolve, reject) => {
66
+ const child = spawn(...piInvocation(['--mode', 'json', '--offline', '--model', 'scripted/echo', ...args, ...[prompts].flat()]), { cwd: sandbox.workDir, env: sandbox.env, stdio: ['ignore', 'pipe', 'pipe'] });
67
+ const events: PiEvent[] = [];
68
+ let stderr = '';
69
+ const timer = setTimeout(() => {
70
+ child.kill('SIGKILL');
71
+ reject(new Error(`pi --mode json timed out after ${timeoutMs}ms\n${stderr}`));
72
+ }, timeoutMs);
73
+ child.stdout.on(
74
+ 'data',
75
+ lineSplitter((line) => events.push(JSON.parse(line) as PiEvent)),
76
+ );
77
+ child.stderr.on('data', (chunk: Buffer) => {
78
+ stderr += chunk.toString('utf8');
79
+ });
80
+ child.on('error', reject);
81
+ child.on('close', (exitCode) => {
82
+ clearTimeout(timer);
83
+ resolve({ events, exitCode, stderr });
84
+ });
85
+ });
86
+ }
87
+
88
+ type Content = string | { type: string; text?: string }[];
89
+ export interface EventMessage {
90
+ role: string;
91
+ content: Content;
92
+ customType?: string;
93
+ toolName?: string;
94
+ isError?: boolean;
95
+ details?: unknown;
96
+ usage?: { totalTokens: number };
97
+ }
98
+
99
+ export const contentText = (content: Content): string => (typeof content === 'string' ? content : content.map((part) => part.text ?? '').join(''));
100
+
101
+ export function messages(events: PiEvent[], role?: string): EventMessage[] {
102
+ return events
103
+ .filter((event) => event.type === 'message_end')
104
+ .map((event) => event['message'] as EventMessage)
105
+ .filter((message) => role === undefined || message.role === role);
106
+ }
107
+
108
+ export const assistantTexts = (events: PiEvent[]): string[] => messages(events, 'assistant').map((message) => contentText(message.content));
109
+
110
+ export interface ToolEnd {
111
+ toolName: string;
112
+ isError: boolean;
113
+ text: string;
114
+ details: unknown;
115
+ usage?: { totalTokens: number };
116
+ }
117
+
118
+ export function toolEnds(events: PiEvent[], toolName: string): ToolEnd[] {
119
+ return events
120
+ .filter((event) => event.type === 'tool_execution_end' && event['toolName'] === toolName)
121
+ .map((event) => {
122
+ const result = event['result'] as { content: Content; details: unknown; usage?: { totalTokens: number } };
123
+ return { toolName, isError: event['isError'] === true, text: contentText(result.content), details: result.details, ...(result.usage === undefined ? {} : { usage: result.usage }) };
124
+ });
125
+ }
126
+
127
+ /** Pi reads a positional argument that starts with @ as a file, so the directive goes on the second line. */
128
+ export const script = (steps: unknown[]): string => `run the script\n@@script ${JSON.stringify(steps)}`;
129
+
130
+ export interface RpcSession {
131
+ child: ChildProcess;
132
+ events: PiEvent[];
133
+ send: (command: Record<string, unknown>) => void;
134
+ waitFor: (predicate: (event: PiEvent) => boolean, timeoutMs?: number) => Promise<PiEvent>;
135
+ close: () => Promise<void>;
136
+ }
137
+
138
+ export function startRpc(sandbox: Sandbox, args: string[] = []): RpcSession {
139
+ const child = spawn(...piInvocation(['--mode', 'rpc', '--offline', '--model', 'scripted/echo', ...args]), { cwd: sandbox.workDir, env: sandbox.env, stdio: ['pipe', 'pipe', 'pipe'] });
140
+ const events: PiEvent[] = [];
141
+ const waiters: { predicate: (event: PiEvent) => boolean; resolve: (event: PiEvent) => void }[] = [];
142
+ child.stdout?.on(
143
+ 'data',
144
+ lineSplitter((line) => {
145
+ const event = JSON.parse(line) as PiEvent;
146
+ events.push(event);
147
+ for (const waiter of waiters.filter((candidate) => candidate.predicate(event))) {
148
+ waiters.splice(waiters.indexOf(waiter), 1);
149
+ waiter.resolve(event);
150
+ }
151
+ }),
152
+ );
153
+ let stderr = '';
154
+ child.stderr?.on('data', (chunk: Buffer) => {
155
+ stderr += chunk.toString('utf8');
156
+ });
157
+ const waitFor = (predicate: (event: PiEvent) => boolean, timeoutMs = 30_000) =>
158
+ new Promise<PiEvent>((resolve, reject) => {
159
+ const seen = events.find(predicate);
160
+ if (seen) return resolve(seen);
161
+ const timer = setTimeout(() => reject(new Error(`timed out waiting for an RPC event\n${stderr}`)), timeoutMs);
162
+ waiters.push({
163
+ predicate,
164
+ resolve: (event) => {
165
+ clearTimeout(timer);
166
+ resolve(event);
167
+ },
168
+ });
169
+ });
170
+ const send = (command: Record<string, unknown>) => child.stdin?.write(`${JSON.stringify(command)}\n`);
171
+ const close = () =>
172
+ new Promise<void>((resolve) => {
173
+ if (child.exitCode !== null) return resolve();
174
+ child.once('close', () => resolve());
175
+ child.stdin?.end();
176
+ setTimeout(() => child.kill('SIGKILL'), 10_000).unref();
177
+ });
178
+ return { child, events, send, waitFor, close };
179
+ }
@@ -0,0 +1,193 @@
1
+ import { mkdirSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+
4
+ import { afterEach, beforeEach, describe, expect, test } from 'vitest';
5
+ import { PACKAGE_ROOT } from '../../src/paths.ts';
6
+ import { assistantTexts, contentText, makeSandbox, runJson, type Sandbox, script, startRpc, toolEnds } from './harness.ts';
7
+
8
+ let sandbox: Sandbox;
9
+ beforeEach(() => {
10
+ sandbox = makeSandbox();
11
+ });
12
+ afterEach(() => sandbox.dispose());
13
+
14
+ const section = (prompt: string, name: string) => {
15
+ const match = new RegExp(`<${name}>\\n([\\s\\S]*?)\\n</${name}>`).exec(prompt);
16
+ if (!match) throw new Error(`system prompt has no <${name}> section`);
17
+ return match[1] ?? '';
18
+ };
19
+
20
+ async function systemPrompt(args: string[] = []): Promise<string> {
21
+ const run = await runJson(sandbox, 'show me\n@@sys', args);
22
+ const [text] = assistantTexts(run.events);
23
+ if (text === undefined) throw new Error(`no reply\n${run.stderr}`);
24
+ return text;
25
+ }
26
+
27
+ /** The system prompt of a long-lived RPC session, where loops can run. */
28
+ async function rpcSystemPrompt(): Promise<string> {
29
+ const rpc = startRpc(sandbox, ['--no-session']);
30
+ try {
31
+ rpc.send({ type: 'prompt', message: 'show me\n@@sys' });
32
+ const reply = await rpc.waitFor((event) => event.type === 'message_end' && (event['message'] as { role: string }).role === 'assistant');
33
+ return contentText((reply['message'] as { content: { type: string; text?: string }[] }).content);
34
+ } finally {
35
+ await rpc.close();
36
+ }
37
+ }
38
+
39
+ describe('host map (HOST-001)', () => {
40
+ test('names the skills, rule, transcript, store, project, and subagent locations in Pi terms', async () => {
41
+ const host = section(await systemPrompt(), 'pstack_host');
42
+ const skills = join(PACKAGE_ROOT, 'skills');
43
+ const workspace = join(sandbox.agentDir, 'pstack/workspaces', `--${sandbox.workDir.replace(/^\//, '').replaceAll('/', '-')}--`);
44
+ expect(host).toContain(`pstack runs here through the pi-pstack package at ${PACKAGE_ROOT}.`);
45
+ expect(host).toContain(`<SKILLS> = ${skills}`);
46
+ expect(host).toContain('"the X skill", "/X", and "principle-X" mean <SKILLS>/X/SKILL.md');
47
+ expect(host).toContain('a delegate that needs poteto-mode reads <SKILLS>/poteto-mode/SKILL.md');
48
+ expect(host).toContain(`- The model rule is ${join(sandbox.agentDir, 'pstack/pstack-models.md')}. Its current content is in <pstack_models>.`);
49
+ expect(host).toContain(`- Skill folders: project \`.pi/skills/\`, personal \`${join(sandbox.agentDir, 'skills')}/\`.`);
50
+ expect(host).toContain(`Subagent transcripts for this workspace: ${join(workspace, 'subagents')}/*_<agent id>.jsonl. A subagent is still running while ${join(workspace, 'subagents')}/<agent id>.lock exists and names a live pid.`);
51
+ expect(host).toMatch(new RegExp(`"The current agent's store" is ${join(workspace, 'store')}/[0-9a-f-]+\\. Create it when a playbook needs it\\.`));
52
+ expect(host).toContain(`- Projects: a program's Project is ${join(workspace, 'projects')}/<project-slug>/, with notes.md as its Project tracker and store/ as its Project store.`);
53
+ expect(host).toMatch(new RegExp(`- Files a tool makes for the user, such as visualize charts, go in ${join(workspace, 'artifacts')}/[0-9a-f-]+\\.`));
54
+ expect(host).toContain(`- Transcripts: this workspace's Pi session files are in ${join(sandbox.agentDir, 'sessions')}/--${sandbox.workDir.replace(/^\//, '').replaceAll('/', '-')}--.`);
55
+ expect(host).toContain('Installed skills (62): architect, arena, automate-me,');
56
+ expect(host).toContain("agent_status reads a subagent's state without waking it.");
57
+ expect(host).toContain('- The user keeps a skill on every turn with `/mode <skill>` (exit `/mode off`) and plans without edits with `/plan` (exit `/plan off`).');
58
+ expect(host).toContain('- MCP tools are named mcp__<server>__<tool>; `pi mcp list` shows the servers.');
59
+ expect(host).toContain('- Isolated workers (Task environment "cloud") run on this machine in their own git worktree on branch pstack/<agent id>');
60
+ });
61
+
62
+ test('names no Cursor host feature (HOST-008)', async () => {
63
+ const prompt = await systemPrompt(['--no-session']);
64
+ const names = ['pstack_host', 'pstack_subagents', 'pstack_models', 'pstack_mode', 'pstack_plan', 'pstack_loop'];
65
+ const pstack = names.map((name) => new RegExp(`<${name}>\\n([\\s\\S]*?)\\n</${name}>`).exec(prompt)?.[1] ?? '').join('\n');
66
+ expect(pstack).not.toMatch(/cursor/i);
67
+ });
68
+
69
+ test('tells a one-shot run it cannot subscribe, and a long-lived session how subscriptions wake it (HOST-010)', async () => {
70
+ const [rpc, oneShot] = [section(await rpcSystemPrompt(), 'pstack_host'), section(await systemPrompt(['--no-session']), 'pstack_host')];
71
+ expect([rpc.includes('- Subscriptions (subscribe_github_pr, subscribe_timer, subscribe_webhook) wake this chat'), oneShot.includes('- Subscriptions: this run ends when it settles, so nothing can wake it')]).toEqual([true, true]);
72
+ });
73
+
74
+ test("names the main chat's own store as the root agent's store", async () => {
75
+ const host = section(await systemPrompt(['--no-session']), 'pstack_host');
76
+ const current = /"The current agent's store" is (\S+)\. /.exec(host)?.[1];
77
+ expect(host).toContain(`"The root agent's store" is ${current}, the store of the main chat that started this subagent tree; in the main chat it is the current agent's store.`);
78
+ });
79
+
80
+ test('names AskQuestion only where a user can answer (HOST-005; review r2: parity 4)', async () => {
81
+ const [rpc, oneShot] = [section(await rpcSystemPrompt(), 'pstack_host'), section(await systemPrompt(['--no-session']), 'pstack_host')];
82
+ expect([
83
+ rpc.includes('- Todo lists: the TodoWrite tool. Structured questions: the AskQuestion tool.'),
84
+ oneShot.includes('- Todo lists: the TodoWrite tool. Structured questions: the AskQuestion tool, but nobody can answer in this run, so every question comes back skipped; decide yourself and say what you chose.'),
85
+ ]).toEqual([true, true]);
86
+ });
87
+
88
+ test('tells a long-lived session how to arm /loop (HOST-004)', async () => {
89
+ const host = section(await rpcSystemPrompt(), 'pstack_host');
90
+ expect(host).toContain(
91
+ '- /loop: the user starts `/loop [interval] <prompt>`. When a playbook says to arm /loop, call the Loop tool with prompt plus interval (fixed cadence) or wake_in (agent-paced). Inside a loop, Loop with wake_in schedules the next run and stop: true ends it.',
92
+ );
93
+ });
94
+
95
+ test('tells a one-shot run, such as a subagent, that it cannot arm /loop (HOST-004, recheck 2)', async () => {
96
+ const host = section(await systemPrompt(['--no-session']), 'pstack_host');
97
+ expect(host).toContain(
98
+ '- /loop: this run ends when it settles (a subagent, or a print or JSON run), so it has no Loop tool and cannot arm a loop. Keep working until the goal is met, and name in the final reply anything the parent chat should loop on.',
99
+ );
100
+ });
101
+
102
+ test('frames an attached skill as the workflow to follow', async () => {
103
+ const host = section(await systemPrompt(), 'pstack_host');
104
+ expect(host).toContain(
105
+ '- A <skill> block in a user message means the user attached that skill to this request. Follow its workflow from its first step, including the steps it says to take before answering, instead of answering directly.',
106
+ );
107
+ });
108
+
109
+ test('names the persisted transcript of this chat', async () => {
110
+ const host = section(await systemPrompt(['--session-dir', join(sandbox.root, 'sessions')]), 'pstack_host');
111
+ expect(host).toMatch(new RegExp(`This chat's transcript is ${join(sandbox.root, 'sessions')}/[^ ]+\\.jsonl\\.`));
112
+ });
113
+
114
+ test('says when the chat is not persisted', async () => {
115
+ const host = section(await systemPrompt(['--no-session']), 'pstack_host');
116
+ expect(host).toContain('This chat is not persisted (--no-session), so it has no transcript file.');
117
+ });
118
+ });
119
+
120
+ describe('subagent catalog (HOST-002)', () => {
121
+ test('lists the subagent types and the models Task accepts', async () => {
122
+ const catalog = section(await systemPrompt(['--no-session']), 'pstack_subagents');
123
+ expect(catalog).toContain('- generalPurpose (default): ');
124
+ expect(catalog).toContain('- poteto-agent (runs in the background unless run_in_background is false): Delegate subagent for code-writing and helper tasks spawned during a `/poteto-mode` run.');
125
+ expect(catalog).toContain('- comment-sicko: A deranged comment-hater that savors deletion and condemns workaround code.');
126
+ expect(catalog).toContain('- inherit (default): the parent model and thinking level. auto and inherit-parent mean the same.');
127
+ expect(catalog).toMatch(/^- This chat runs scripted\/echo(:\w+)?\. pstack's model families \(claude-\*, grok-\*\) go by the model id after its provider\.$/m);
128
+ expect(catalog).toContain('Available models: scripted/echo (thinking: off, minimal, low, medium, high), scripted/plain');
129
+ expect(catalog).toContain('- A Pi model <provider>/<model-id> or <model-id>, optionally with :<level> from the thinking levels the model lists below. A level the model does not list is rejected.');
130
+ });
131
+ });
132
+
133
+ describe('capability-aware sections (C-M4)', () => {
134
+ test('a readonly subagent gets no subagent catalog and no Task or stop_agent lines; its parent gets both', async () => {
135
+ const run = await runJson(sandbox, script([{ tool: 'Task', args: { description: 'probe', prompt: 'go\n@@sys', readonly: true } }]), ['--no-session']);
136
+ const child = toolEnds(run.events, 'Task')[0]?.text ?? '';
137
+ const parentHost = section(await systemPrompt(['--no-session']), 'pstack_host');
138
+ expect([child.includes('<pstack_host>'), child.includes('<pstack_subagents>'), section(child, 'pstack_host').includes('Task'), section(child, 'pstack_host').includes('stop_agent')]).toEqual([true, false, false, false]);
139
+ expect([parentHost.includes('- Subagents: call the Task tool'), parentHost.includes('stop_agent stops a running agent.')]).toEqual([true, true]);
140
+ });
141
+ });
142
+
143
+ describe('model rule (RULE-001)', () => {
144
+ test('reports the default when no rule exists', async () => {
145
+ const models = section(await systemPrompt(['--no-session']), 'pstack_models');
146
+ expect(models).toBe(`No pstack model rule exists at ${join(sandbox.agentDir, 'pstack/pstack-models.md')}. Every role uses its skill default until /setup-pstack writes one.`);
147
+ });
148
+
149
+ test('applies the rule on every request when it exists', async () => {
150
+ mkdirSync(join(sandbox.agentDir, 'pstack'), { recursive: true });
151
+ writeFileSync(join(sandbox.agentDir, 'pstack/pstack-models.md'), '# budget: small (medium)\nswarm workers: scripted/plain\n');
152
+ const run = await runJson(sandbox, ['first\n@@sys', 'second\n@@sys'], ['--no-session']);
153
+ const prompts = assistantTexts(run.events);
154
+ expect(prompts).toHaveLength(2);
155
+ for (const prompt of prompts) expect(section(prompt, 'pstack_models')).toBe(`Path: ${join(sandbox.agentDir, 'pstack/pstack-models.md')}\n# budget: small (medium)\nswarm workers: scripted/plain`);
156
+ });
157
+ });
158
+
159
+ describe('tool listing', () => {
160
+ test('lists the pstack tools a one-shot run can use, and the todolist guideline (HOST-001, TODO-001, recheck 2)', async () => {
161
+ const prompt = await systemPrompt(['--no-session']);
162
+ const tools = /<tools>\n([\s\S]*?)\n<\/tools>/.exec(prompt)?.[1] ?? '';
163
+ expect(
164
+ tools
165
+ .split('\n')
166
+ .filter((line) => /^- (Task|TodoWrite|AskQuestion|Loop):/.test(line))
167
+ .toSorted(),
168
+ ).toEqual([
169
+ '- AskQuestion: Structured multiple-choice questions for the user',
170
+ '- Task: Launch subagents (foreground, background with completion notifications, resume by agent ID)',
171
+ '- TodoWrite: Create and update the todo list for this session',
172
+ ]);
173
+ expect(prompt).toContain('- When a skill or playbook says to open a todolist or todo list, call TodoWrite before other work, with the steps it names as the first items.');
174
+ });
175
+ });
176
+
177
+ describe('image generation (HOST-006)', () => {
178
+ test('the path the host section names generates an image when an image model is configured', async () => {
179
+ const images = makeSandbox({ extensions: [join(PACKAGE_ROOT, 'test/fixtures/scripted-model.ts'), join(PACKAGE_ROOT, 'test/fixtures/image-model.ts')] });
180
+ try {
181
+ // The script follows the host section line: codemode's models.generateImages(), shown with image().
182
+ const code =
183
+ 'const [painter] = await models.getAvailableOfType("image");\nconst result = await models.generateImages(painter, { input: [{ type: "text", text: "a fox" }] });\nfor (const block of result.output) if (block.type === "image") image(block);\nreturn painter.provider + "/" + painter.id + " " + result.stopReason;';
184
+ const run = await runJson(images, script([{ tool: 'codemode', args: { code } }]), ['--no-session', '--tools', '+codemode']);
185
+ const [end] = toolEnds(run.events, 'codemode');
186
+ expect(end?.isError).toBe(false);
187
+ expect(end?.text).toContain('testimg/painter stop');
188
+ expect(JSON.stringify(run.events.find((event) => event.type === 'tool_execution_end' && event['toolName'] === 'codemode'))).toContain('"type":"image"');
189
+ } finally {
190
+ images.dispose();
191
+ }
192
+ });
193
+ });
@@ -0,0 +1,99 @@
1
+ import { afterEach, beforeEach, expect, test } from 'vitest';
2
+ import { contentText, makeSandbox, type PiEvent, type RpcSession, type Sandbox, script, startRpc } from './harness.ts';
3
+
4
+ let sandbox: Sandbox;
5
+ let rpc: RpcSession;
6
+ beforeEach(() => {
7
+ sandbox = makeSandbox();
8
+ rpc = startRpc(sandbox, ['--no-session']);
9
+ });
10
+ afterEach(async () => {
11
+ await rpc.close();
12
+ sandbox.dispose();
13
+ });
14
+
15
+ // Pi sets process.title to "pi", so ps cannot find a child by its arguments; the Task details carry its pid.
16
+ const alive = (pid: number) => {
17
+ try {
18
+ process.kill(pid, 0);
19
+ return true;
20
+ } catch {
21
+ return false;
22
+ }
23
+ };
24
+
25
+ async function gone(pids: readonly number[], timeoutMs = 12_000): Promise<boolean> {
26
+ const deadline = Date.now() + timeoutMs;
27
+ while (Date.now() < deadline) {
28
+ if (pids.every((pid) => !alive(pid))) return true;
29
+ await new Promise<void>((resolve) => setImmediate(resolve));
30
+ }
31
+ return pids.every((pid) => !alive(pid));
32
+ }
33
+
34
+ async function reply(message: string): Promise<string> {
35
+ const mark = rpc.events.length;
36
+ rpc.send({ type: 'prompt', message });
37
+ await rpc.waitFor((event) => event.type === 'agent_settled' && rpc.events.indexOf(event) >= mark);
38
+ const last = rpc.events
39
+ .slice(mark)
40
+ .filter((event) => event.type === 'message_end' && (event['message'] as { role: string }).role === 'assistant')
41
+ .at(-1);
42
+ if (last === undefined) throw new Error('the run produced no assistant message');
43
+ return contentText((last['message'] as { content: { type: string; text?: string }[] }).content);
44
+ }
45
+
46
+ async function backgroundAgent(): Promise<number> {
47
+ const mark = rpc.events.length;
48
+ rpc.send({ type: 'prompt', message: script([{ tool: 'Task', args: { description: 'slow', prompt: 'go\n@@sleep 60000 SLOW', run_in_background: true } }]) });
49
+ const end = await rpc.waitFor((event: PiEvent) => event.type === 'tool_execution_end' && event['toolName'] === 'Task' && rpc.events.indexOf(event) >= mark);
50
+ await rpc.waitFor((event) => event.type === 'agent_settled' && rpc.events.indexOf(event) >= mark);
51
+ return (end['result'] as { details: { pid: number } }).details.pid;
52
+ }
53
+
54
+ // Interactive Pi redraws the chat between the old session's shutdown and the new session's start, so a warning sent
55
+ // at shutdown never reaches the screen. The new session's mode status marks that start.
56
+ test.for([
57
+ { replace: 'new session', command: { type: 'new_session' }, reason: 'new' },
58
+ { replace: 'reload', command: { type: 'prompt', message: '/test-reload' }, reason: 'reload' },
59
+ ])('a $replace shows the stopped-subagent warning after the next session starts', async ({ command, reason }) => {
60
+ await backgroundAgent();
61
+ const mark = rpc.events.length;
62
+ rpc.send({ id: 'replace', ...command });
63
+ await rpc.waitFor((event) => event['id'] === 'replace');
64
+ const after = rpc.events.slice(mark);
65
+ const isUi = (event: PiEvent, method: string) => event.type === 'extension_ui_request' && event['method'] === method;
66
+ const started = after.findIndex((event) => isUi(event, 'setStatus') && event['statusKey'] === 'pstack-mode');
67
+ const warned = await rpc.waitFor((event) => isUi(event, 'notify') && String(event['message']).startsWith('Stopped 1 background') && rpc.events.indexOf(event) >= mark);
68
+ expect([warned['message'], rpc.events.indexOf(warned) - mark > started, started >= 0]).toEqual([`Stopped 1 background subagent (session ${reason}). Resume one with its agent ID.`, true, true]);
69
+ });
70
+
71
+ test('/reload keeps aliases and tools, and stops the old runtime children (PKG-002)', async () => {
72
+ const pid = await backgroundAgent();
73
+ expect(alive(pid)).toBe(true);
74
+ rpc.send({ id: 'reload', type: 'prompt', message: '/test-reload' });
75
+ await rpc.waitFor((event) => event['id'] === 'reload');
76
+ expect(await gone([pid])).toBe(true);
77
+ expect(await reply('/how @@say STILL-ALIASED')).toBe('STILL-ALIASED');
78
+ expect(
79
+ (await reply('tools\n@@tools-list'))
80
+ .split(',')
81
+ .filter((name) => name === 'Task' || name === 'TodoWrite')
82
+ .toSorted(),
83
+ ).toEqual(['Task', 'TodoWrite']);
84
+ });
85
+
86
+ test('a new session resets mode and todos and stops the old children (PKG-002)', async () => {
87
+ rpc.send({ id: 'mode', type: 'prompt', message: '/mode tdd' });
88
+ await rpc.waitFor((event) => event['id'] === 'mode');
89
+ await reply(script([{ tool: 'TodoWrite', args: { merge: false, todos: [{ id: 'a', content: 'Alpha', status: 'pending' }] } }]));
90
+ const pid = await backgroundAgent();
91
+ expect(alive(pid)).toBe(true);
92
+ rpc.send({ id: 'new', type: 'new_session' });
93
+ await rpc.waitFor((event) => event['id'] === 'new');
94
+ expect(await gone([pid])).toBe(true);
95
+ const notice = rpc.events.find((event) => event.type === 'extension_ui_request' && event['method'] === 'notify' && String(event['message']).startsWith('Stopped 1 background'));
96
+ expect(notice?.['message']).toBe('Stopped 1 background subagent (session new). Resume one with its agent ID.');
97
+ expect(await reply('fresh\n@@sys')).not.toContain('<pstack_mode>');
98
+ expect(await reply(script([{ tool: 'TodoWrite', args: { merge: true, todos: [{ id: 'b', content: 'Beta', status: 'pending' }] } }]))).toBe('RESULTS:\n[TodoWrite] Todos (0/1 completed):\n[ ] b: Beta');
99
+ });