pi-t3-pstack 0.0.0-stage → 0.1.0

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 (598) hide show
  1. package/LICENSE +23 -0
  2. package/index.ts +87 -0
  3. package/package.json +62 -4
  4. package/pstack/.claude-plugin/icon.png +0 -0
  5. package/pstack/.claude-plugin/plugin.json +35 -0
  6. package/pstack/.codex-plugin/plugin.json +50 -0
  7. package/pstack/README.md +26 -0
  8. package/pstack/agents/comment-sicko.md +32 -0
  9. package/pstack/agents/poteto-agent.md +8 -0
  10. package/pstack/agents/thermo-nuclear-code-quality-review-subagent.md +23 -0
  11. package/pstack/agents/thermo-nuclear-review-subagent.md +28 -0
  12. package/pstack/assets/pstack-icon.png +0 -0
  13. package/pstack/assets/pstack-icon.prompt.txt +8 -0
  14. package/pstack/hooks/codex-hooks.json +16 -0
  15. package/pstack/hooks/hooks.json +15 -0
  16. package/pstack/hooks/session-start-context.md +17 -0
  17. package/pstack/hooks/session-start.ps1 +33 -0
  18. package/pstack/hooks/session-start.sh +34 -0
  19. package/pstack/models.json +261 -0
  20. package/pstack/skills/architect/SKILL.md +85 -0
  21. package/pstack/skills/architect/references/design-red-flags.md +57 -0
  22. package/pstack/skills/architect/references/rationale-template.md +35 -0
  23. package/pstack/skills/architect/references/runner-prompt.md +20 -0
  24. package/pstack/skills/arena/SKILL.md +55 -0
  25. package/pstack/skills/automate-me/SKILL.md +104 -0
  26. package/pstack/skills/benchmark-checklist/SKILL.md +39 -0
  27. package/pstack/skills/blast-radius/SKILL.md +50 -0
  28. package/pstack/skills/bro/SKILL.md +7 -0
  29. package/pstack/skills/correct/SKILL.md +32 -0
  30. package/pstack/skills/create-formal-verification-skill/SKILL.md +43 -0
  31. package/pstack/skills/create-verification-skill/SKILL.md +44 -0
  32. package/pstack/skills/create-verification-skill/references/feature-map-example/README.md +47 -0
  33. package/pstack/skills/create-verification-skill/references/feature-map-example/create-note.md +39 -0
  34. package/pstack/skills/create-verification-skill/references/feature-map-example/search.md +45 -0
  35. package/pstack/skills/deslop/SKILL.md +22 -0
  36. package/pstack/skills/figure-it-out/SKILL.md +52 -0
  37. package/pstack/skills/fix-ci/SKILL.md +29 -0
  38. package/pstack/skills/fix-merge-conflicts/SKILL.md +32 -0
  39. package/pstack/skills/get-pr-comments/SKILL.md +23 -0
  40. package/pstack/skills/how/SKILL.md +43 -0
  41. package/pstack/skills/how/references/explainer-prompt.md +55 -0
  42. package/pstack/skills/how/references/explorer-prompt.md +35 -0
  43. package/pstack/skills/in-your-own-words/SKILL.md +7 -0
  44. package/pstack/skills/interrogate/SKILL.md +37 -0
  45. package/pstack/skills/ketchup/SKILL.md +43 -0
  46. package/pstack/skills/ketchup-video/SKILL.md +29 -0
  47. package/pstack/skills/maintain-formal-verification-skill/SKILL.md +58 -0
  48. package/pstack/skills/maintain-verification-skill/SKILL.md +39 -0
  49. package/pstack/skills/make-pr-easy-to-review/SKILL.md +59 -0
  50. package/pstack/skills/no-comments/SKILL.md +24 -0
  51. package/pstack/skills/poteto-help/SKILL.md +162 -0
  52. package/pstack/skills/poteto-help/references/prompting.md +51 -0
  53. package/pstack/skills/poteto-help/references/recipes.md +51 -0
  54. package/pstack/skills/poteto-mode/SKILL.md +186 -0
  55. package/pstack/skills/poteto-mode/brief.md +70 -0
  56. package/pstack/skills/poteto-mode/playbooks/authoring-a-skill.md +12 -0
  57. package/pstack/skills/poteto-mode/playbooks/autonomous-run.md +13 -0
  58. package/pstack/skills/poteto-mode/playbooks/autopilot-full.md +25 -0
  59. package/pstack/skills/poteto-mode/playbooks/autopilot-stack.md +8 -0
  60. package/pstack/skills/poteto-mode/playbooks/babysit.md +23 -0
  61. package/pstack/skills/poteto-mode/playbooks/bug-fix.md +15 -0
  62. package/pstack/skills/poteto-mode/playbooks/eval.md +25 -0
  63. package/pstack/skills/poteto-mode/playbooks/feature.md +21 -0
  64. package/pstack/skills/poteto-mode/playbooks/hillclimb.md +21 -0
  65. package/pstack/skills/poteto-mode/playbooks/investigation.md +14 -0
  66. package/pstack/skills/poteto-mode/playbooks/multi-phase-plan.md +155 -0
  67. package/pstack/skills/poteto-mode/playbooks/opening-a-pr.md +34 -0
  68. package/pstack/skills/poteto-mode/playbooks/orchestrate.md +25 -0
  69. package/pstack/skills/poteto-mode/playbooks/pause-safely.md +10 -0
  70. package/pstack/skills/poteto-mode/playbooks/perf-issue.md +25 -0
  71. package/pstack/skills/poteto-mode/playbooks/prototype.md +14 -0
  72. package/pstack/skills/poteto-mode/playbooks/refactoring.md +16 -0
  73. package/pstack/skills/poteto-mode/playbooks/runtime-forensics.md +11 -0
  74. package/pstack/skills/poteto-mode/playbooks/session-pickup.md +11 -0
  75. package/pstack/skills/poteto-mode/playbooks/shipping.md +12 -0
  76. package/pstack/skills/poteto-mode/playbooks/trace-forensics.md +14 -0
  77. package/pstack/skills/poteto-mode/playbooks/visual-parity.md +11 -0
  78. package/pstack/skills/poteto-mode/playbooks/worktree-cleanup.md +12 -0
  79. package/pstack/skills/poteto-mode/references/bugbot-triage.md +142 -0
  80. package/pstack/skills/poteto-mode/references/licenses/LICENSE +23 -0
  81. package/pstack/skills/poteto-mode/references/licenses/LICENSE-cursor-team-kit +21 -0
  82. package/pstack/skills/poteto-mode/references/licenses/LICENSE-thermos +21 -0
  83. package/pstack/skills/poteto-mode/references/licenses/NOTICE.md +14 -0
  84. package/pstack/skills/poteto-mode/scripts/.prettierrc.json +3 -0
  85. package/pstack/skills/poteto-mode/scripts/bootstrap.ts +62 -0
  86. package/pstack/skills/poteto-mode/scripts/bun.lock +67 -0
  87. package/pstack/skills/poteto-mode/scripts/check-plan.mjs +205 -0
  88. package/pstack/skills/poteto-mode/scripts/check-plan.test.ts +110 -0
  89. package/pstack/skills/poteto-mode/scripts/package.json +12 -0
  90. package/pstack/skills/poteto-mode/scripts/resolve-codex-transcript +4 -0
  91. package/pstack/skills/poteto-mode/scripts/resolve-codex-transcript.ts +314 -0
  92. package/pstack/skills/poteto-mode/scripts/test-utils/node-test.ts +204 -0
  93. package/pstack/skills/poteto-mode/scripts/watch-pr/cli.test.ts +225 -0
  94. package/pstack/skills/poteto-mode/scripts/watch-pr/cli.ts +231 -0
  95. package/pstack/skills/poteto-mode/scripts/watch-pr/fakes.test-helper.ts +142 -0
  96. package/pstack/skills/poteto-mode/scripts/watch-pr/github.test.ts +498 -0
  97. package/pstack/skills/poteto-mode/scripts/watch-pr/github.ts +760 -0
  98. package/pstack/skills/poteto-mode/scripts/watch-pr/policy.test.ts +483 -0
  99. package/pstack/skills/poteto-mode/scripts/watch-pr/policy.ts +1023 -0
  100. package/pstack/skills/poteto-mode/scripts/watch-pr/render.ts +188 -0
  101. package/pstack/skills/poteto-mode/scripts/watch-pr/settle.test.ts +552 -0
  102. package/pstack/skills/poteto-mode/scripts/watch-pr/settle.ts +406 -0
  103. package/pstack/skills/poteto-mode/scripts/watch-pr/tsconfig.json +18 -0
  104. package/pstack/skills/poteto-mode/scripts/watch-pr/types.compile.ts +93 -0
  105. package/pstack/skills/poteto-mode/scripts/watch-pr/types.ts +444 -0
  106. package/pstack/skills/poteto-mode/scripts/watch-pr/verdicts.test.ts +796 -0
  107. package/pstack/skills/poteto-mode/scripts/watch-pr/watch-pr +3 -0
  108. package/pstack/skills/poteto-mode/scripts/worktree-audit.sh +170 -0
  109. package/pstack/skills/principle-attack-the-premise/SKILL.md +21 -0
  110. package/pstack/skills/principle-boundary-discipline/SKILL.md +34 -0
  111. package/pstack/skills/principle-build-the-lever/SKILL.md +23 -0
  112. package/pstack/skills/principle-encode-lessons-in-structure/SKILL.md +11 -0
  113. package/pstack/skills/principle-exhaust-the-design-space/SKILL.md +9 -0
  114. package/pstack/skills/principle-experience-first/SKILL.md +19 -0
  115. package/pstack/skills/principle-explain-the-number/SKILL.md +18 -0
  116. package/pstack/skills/principle-fix-root-causes/SKILL.md +21 -0
  117. package/pstack/skills/principle-foundational-thinking/SKILL.md +21 -0
  118. package/pstack/skills/principle-guard-the-context-window/SKILL.md +12 -0
  119. package/pstack/skills/principle-laziness-protocol/SKILL.md +10 -0
  120. package/pstack/skills/principle-make-operations-idempotent/SKILL.md +22 -0
  121. package/pstack/skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md +14 -0
  122. package/pstack/skills/principle-minimize-reader-load/SKILL.md +18 -0
  123. package/pstack/skills/principle-model-the-domain/SKILL.md +24 -0
  124. package/pstack/skills/principle-never-block-on-the-human/SKILL.md +15 -0
  125. package/pstack/skills/principle-outcome-oriented-execution/SKILL.md +21 -0
  126. package/pstack/skills/principle-prove-it-works/SKILL.md +22 -0
  127. package/pstack/skills/principle-redesign-from-first-principles/SKILL.md +16 -0
  128. package/pstack/skills/principle-separate-before-serializing-shared-state/SKILL.md +16 -0
  129. package/pstack/skills/principle-sequence-verifiable-units/SKILL.md +17 -0
  130. package/pstack/skills/principle-subtract-before-you-add/SKILL.md +18 -0
  131. package/pstack/skills/principle-test-behavior-not-implementation/SKILL.md +20 -0
  132. package/pstack/skills/principle-type-system-discipline/SKILL.md +13 -0
  133. package/pstack/skills/recall/SKILL.md +35 -0
  134. package/pstack/skills/reflect/SKILL.md +86 -0
  135. package/pstack/skills/reflect/references/divergent-reviewer.md +38 -0
  136. package/pstack/skills/reflect/references/judgment-reviewer.md +37 -0
  137. package/pstack/skills/reflect/references/synthesizer.md +56 -0
  138. package/pstack/skills/reflect/references/tooling-reviewer.md +48 -0
  139. package/pstack/skills/reflect/scripts/find-transcript.mjs +245 -0
  140. package/pstack/skills/setup-pstack/SKILL.md +77 -0
  141. package/pstack/skills/setup-pstack/scripts/read-sheet.sh +14 -0
  142. package/pstack/skills/setup-pstack/scripts/t3-sheet.mjs +169 -0
  143. package/pstack/skills/sharpen/SKILL.md +16 -0
  144. package/pstack/skills/show-me-your-work/SKILL.md +82 -0
  145. package/pstack/skills/show-me-your-work/references/decision-log-template.tsv +1 -0
  146. package/pstack/skills/show-me-your-work/scripts/log.sh +42 -0
  147. package/pstack/skills/statechart/SKILL.md +82 -0
  148. package/pstack/skills/statechart/references/render.md +93 -0
  149. package/pstack/skills/statechart/scripts/backends/cfg.ts +33 -0
  150. package/pstack/skills/statechart/scripts/backends/mermaid.ts +201 -0
  151. package/pstack/skills/statechart/scripts/backends/plain-text.ts +72 -0
  152. package/pstack/skills/statechart/scripts/backends/report.ts +177 -0
  153. package/pstack/skills/statechart/scripts/frontends/config.ts +276 -0
  154. package/pstack/skills/statechart/scripts/frontends/dot.ts +74 -0
  155. package/pstack/skills/statechart/scripts/frontends/marks.ts +93 -0
  156. package/pstack/skills/statechart/scripts/frontends/messages.ts +52 -0
  157. package/pstack/skills/statechart/scripts/frontends/spec.ts +114 -0
  158. package/pstack/skills/statechart/scripts/frontends/trace.ts +24 -0
  159. package/pstack/skills/statechart/scripts/frontends/value.ts +166 -0
  160. package/pstack/skills/statechart/scripts/frontends/verdict.ts +40 -0
  161. package/pstack/skills/statechart/scripts/frontends/view.ts +119 -0
  162. package/pstack/skills/statechart/scripts/ir.ts +547 -0
  163. package/pstack/skills/statechart/scripts/package.json +11 -0
  164. package/pstack/skills/statechart/scripts/passes/annotate.ts +128 -0
  165. package/pstack/skills/statechart/scripts/passes/label.ts +269 -0
  166. package/pstack/skills/statechart/scripts/passes/lift.ts +85 -0
  167. package/pstack/skills/statechart/scripts/passes/loop-check.ts +68 -0
  168. package/pstack/skills/statechart/scripts/passes/paths.ts +60 -0
  169. package/pstack/skills/statechart/scripts/passes/reach.ts +135 -0
  170. package/pstack/skills/statechart/scripts/passes/region-check.ts +97 -0
  171. package/pstack/skills/statechart/scripts/passes/regions.ts +295 -0
  172. package/pstack/skills/statechart/scripts/pipeline.ts +76 -0
  173. package/pstack/skills/statechart/scripts/run.ts +481 -0
  174. package/pstack/skills/statechart/scripts/statechart +29 -0
  175. package/pstack/skills/statechart/scripts/statechart.ts +164 -0
  176. package/pstack/skills/statechart/scripts/test/ConfigOracle.java +63 -0
  177. package/pstack/skills/statechart/scripts/test/chart.test.ts +1210 -0
  178. package/pstack/skills/statechart/scripts/test/charts/Braces.mmd +7 -0
  179. package/pstack/skills/statechart/scripts/test/charts/Escapes.mmd +11 -0
  180. package/pstack/skills/statechart/scripts/test/charts/Phases.mmd +29 -0
  181. package/pstack/skills/statechart/scripts/test/cli.test.ts +1314 -0
  182. package/pstack/skills/statechart/scripts/test/config-fuzz.test.ts +263 -0
  183. package/pstack/skills/statechart/scripts/test/corpus/Counter/ChartRun.out +57 -0
  184. package/pstack/skills/statechart/scripts/test/corpus/Counter/Counter.cfg +3 -0
  185. package/pstack/skills/statechart/scripts/test/corpus/Counter/Counter.tla +10 -0
  186. package/pstack/skills/statechart/scripts/test/corpus/Counter/chart.mmd +9 -0
  187. package/pstack/skills/statechart/scripts/test/corpus/Counter/graph.dot +16 -0
  188. package/pstack/skills/statechart/scripts/test/corpus/Counter/report.md +7 -0
  189. package/pstack/skills/statechart/scripts/test/corpus/Counter/sany.out +2 -0
  190. package/pstack/skills/statechart/scripts/test/corpus/Counter/verdict-1.out +49 -0
  191. package/pstack/skills/statechart/scripts/test/corpus/CounterAction/ChartRun.out +60 -0
  192. package/pstack/skills/statechart/scripts/test/corpus/CounterAction/CounterAction.cfg +4 -0
  193. package/pstack/skills/statechart/scripts/test/corpus/CounterAction/CounterAction.tla +22 -0
  194. package/pstack/skills/statechart/scripts/test/corpus/CounterAction/chart.mmd +26 -0
  195. package/pstack/skills/statechart/scripts/test/corpus/CounterAction/graph.dot +19 -0
  196. package/pstack/skills/statechart/scripts/test/corpus/CounterAction/report.md +20 -0
  197. package/pstack/skills/statechart/scripts/test/corpus/CounterAction/sany.out +2 -0
  198. package/pstack/skills/statechart/scripts/test/corpus/CounterAction/verdict-1.exit +1 -0
  199. package/pstack/skills/statechart/scripts/test/corpus/CounterAction/verdict-1.out +56 -0
  200. package/pstack/skills/statechart/scripts/test/corpus/CounterAction/verdict-2.exit +1 -0
  201. package/pstack/skills/statechart/scripts/test/corpus/CounterAction/verdict-2.out +82 -0
  202. package/pstack/skills/statechart/scripts/test/corpus/CounterAction/verdict-3.out +57 -0
  203. package/pstack/skills/statechart/scripts/test/corpus/CounterDeadlock/ChartRun.out +59 -0
  204. package/pstack/skills/statechart/scripts/test/corpus/CounterDeadlock/CounterDeadlock.cfg +3 -0
  205. package/pstack/skills/statechart/scripts/test/corpus/CounterDeadlock/CounterDeadlock.tla +11 -0
  206. package/pstack/skills/statechart/scripts/test/corpus/CounterDeadlock/chart.mmd +22 -0
  207. package/pstack/skills/statechart/scripts/test/corpus/CounterDeadlock/graph.dot +16 -0
  208. package/pstack/skills/statechart/scripts/test/corpus/CounterDeadlock/report.md +17 -0
  209. package/pstack/skills/statechart/scripts/test/corpus/CounterDeadlock/sany.out +2 -0
  210. package/pstack/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-1.exit +1 -0
  211. package/pstack/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-1.out +56 -0
  212. package/pstack/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-2.exit +1 -0
  213. package/pstack/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-2.out +77 -0
  214. package/pstack/skills/statechart/scripts/test/corpus/CounterFan/ChartRun.out +69 -0
  215. package/pstack/skills/statechart/scripts/test/corpus/CounterFan/CounterFan.cfg +2 -0
  216. package/pstack/skills/statechart/scripts/test/corpus/CounterFan/CounterFan.tla +11 -0
  217. package/pstack/skills/statechart/scripts/test/corpus/CounterFan/chart.mmd +85 -0
  218. package/pstack/skills/statechart/scripts/test/corpus/CounterFan/graph.dot +70 -0
  219. package/pstack/skills/statechart/scripts/test/corpus/CounterFan/report.md +12 -0
  220. package/pstack/skills/statechart/scripts/test/corpus/CounterFan/sany.out +2 -0
  221. package/pstack/skills/statechart/scripts/test/corpus/CounterFan/verdict-1.exit +1 -0
  222. package/pstack/skills/statechart/scripts/test/corpus/CounterFan/verdict-1.out +67 -0
  223. package/pstack/skills/statechart/scripts/test/corpus/CounterFan/verdict-2.out +57 -0
  224. package/pstack/skills/statechart/scripts/test/corpus/CounterGuard/ChartRun.exit +1 -0
  225. package/pstack/skills/statechart/scripts/test/corpus/CounterGuard/ChartRun.out +85 -0
  226. package/pstack/skills/statechart/scripts/test/corpus/CounterGuard/CounterGuard.cfg +6 -0
  227. package/pstack/skills/statechart/scripts/test/corpus/CounterGuard/CounterGuard.tla +13 -0
  228. package/pstack/skills/statechart/scripts/test/corpus/CounterGuard/chart.mmd +5 -0
  229. package/pstack/skills/statechart/scripts/test/corpus/CounterGuard/graph.dot +10 -0
  230. package/pstack/skills/statechart/scripts/test/corpus/CounterGuard/report.md +31 -0
  231. package/pstack/skills/statechart/scripts/test/corpus/CounterGuard/sany.out +2 -0
  232. package/pstack/skills/statechart/scripts/test/corpus/CounterGuard/verdict-1.exit +1 -0
  233. package/pstack/skills/statechart/scripts/test/corpus/CounterGuard/verdict-1.out +64 -0
  234. package/pstack/skills/statechart/scripts/test/corpus/CounterGuard/verdict-2.exit +1 -0
  235. package/pstack/skills/statechart/scripts/test/corpus/CounterGuard/verdict-2.out +77 -0
  236. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPast/ChartRun.out +55 -0
  237. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPast/CounterInitPast.cfg +3 -0
  238. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPast/CounterInitPast.tla +10 -0
  239. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPast/chart.mmd +12 -0
  240. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPast/graph.dot +6 -0
  241. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPast/report.md +12 -0
  242. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPast/sany.out +2 -0
  243. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPast/verdict-1.exit +1 -0
  244. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPast/verdict-1.out +33 -0
  245. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPast/verdict-2.out +54 -0
  246. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPastHolds/ChartRun.out +54 -0
  247. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPastHolds/CounterInitPastHolds.cfg +3 -0
  248. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPastHolds/CounterInitPastHolds.tla +10 -0
  249. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPastHolds/chart.mmd +1 -0
  250. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPastHolds/graph.dot +6 -0
  251. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPastHolds/report.md +7 -0
  252. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPastHolds/sany.out +2 -0
  253. package/pstack/skills/statechart/scripts/test/corpus/CounterInitPastHolds/verdict-1.out +46 -0
  254. package/pstack/skills/statechart/scripts/test/corpus/CounterInstance/ChartRun.out +59 -0
  255. package/pstack/skills/statechart/scripts/test/corpus/CounterInstance/CounterInstance.cfg +2 -0
  256. package/pstack/skills/statechart/scripts/test/corpus/CounterInstance/CounterInstance.tla +10 -0
  257. package/pstack/skills/statechart/scripts/test/corpus/CounterInstance/CounterSteps.tla +6 -0
  258. package/pstack/skills/statechart/scripts/test/corpus/CounterInstance/chart.mmd +17 -0
  259. package/pstack/skills/statechart/scripts/test/corpus/CounterInstance/graph.dot +15 -0
  260. package/pstack/skills/statechart/scripts/test/corpus/CounterInstance/report.md +14 -0
  261. package/pstack/skills/statechart/scripts/test/corpus/CounterInstance/sany.out +3 -0
  262. package/pstack/skills/statechart/scripts/test/corpus/CounterInstance/verdict-1.exit +1 -0
  263. package/pstack/skills/statechart/scripts/test/corpus/CounterInstance/verdict-1.out +78 -0
  264. package/pstack/skills/statechart/scripts/test/corpus/CounterJump/ChartRun.out +59 -0
  265. package/pstack/skills/statechart/scripts/test/corpus/CounterJump/CounterJump.cfg +3 -0
  266. package/pstack/skills/statechart/scripts/test/corpus/CounterJump/CounterJump.tla +19 -0
  267. package/pstack/skills/statechart/scripts/test/corpus/CounterJump/chart.mmd +26 -0
  268. package/pstack/skills/statechart/scripts/test/corpus/CounterJump/graph.dot +22 -0
  269. package/pstack/skills/statechart/scripts/test/corpus/CounterJump/report.md +12 -0
  270. package/pstack/skills/statechart/scripts/test/corpus/CounterJump/sany.out +2 -0
  271. package/pstack/skills/statechart/scripts/test/corpus/CounterJump/verdict-1.exit +1 -0
  272. package/pstack/skills/statechart/scripts/test/corpus/CounterJump/verdict-1.out +58 -0
  273. package/pstack/skills/statechart/scripts/test/corpus/CounterJump/verdict-2.out +57 -0
  274. package/pstack/skills/statechart/scripts/test/corpus/CounterLoop/ChartRun.out +57 -0
  275. package/pstack/skills/statechart/scripts/test/corpus/CounterLoop/CounterLoop.cfg +2 -0
  276. package/pstack/skills/statechart/scripts/test/corpus/CounterLoop/CounterLoop.tla +11 -0
  277. package/pstack/skills/statechart/scripts/test/corpus/CounterLoop/chart.mmd +17 -0
  278. package/pstack/skills/statechart/scripts/test/corpus/CounterLoop/graph.dot +15 -0
  279. package/pstack/skills/statechart/scripts/test/corpus/CounterLoop/report.md +14 -0
  280. package/pstack/skills/statechart/scripts/test/corpus/CounterLoop/sany.out +2 -0
  281. package/pstack/skills/statechart/scripts/test/corpus/CounterLoop/verdict-1.exit +1 -0
  282. package/pstack/skills/statechart/scripts/test/corpus/CounterLoop/verdict-1.out +76 -0
  283. package/pstack/skills/statechart/scripts/test/corpus/CounterOrder/ChartRun.out +59 -0
  284. package/pstack/skills/statechart/scripts/test/corpus/CounterOrder/CounterOrder.cfg +3 -0
  285. package/pstack/skills/statechart/scripts/test/corpus/CounterOrder/CounterOrder.tla +11 -0
  286. package/pstack/skills/statechart/scripts/test/corpus/CounterOrder/chart.mmd +19 -0
  287. package/pstack/skills/statechart/scripts/test/corpus/CounterOrder/graph.dot +10 -0
  288. package/pstack/skills/statechart/scripts/test/corpus/CounterOrder/report.md +15 -0
  289. package/pstack/skills/statechart/scripts/test/corpus/CounterOrder/sany.out +2 -0
  290. package/pstack/skills/statechart/scripts/test/corpus/CounterOrder/verdict-1.exit +1 -0
  291. package/pstack/skills/statechart/scripts/test/corpus/CounterOrder/verdict-1.out +56 -0
  292. package/pstack/skills/statechart/scripts/test/corpus/CounterOrder/verdict-2.exit +1 -0
  293. package/pstack/skills/statechart/scripts/test/corpus/CounterOrder/verdict-2.out +67 -0
  294. package/pstack/skills/statechart/scripts/test/corpus/CounterRules/ChartRun.out +62 -0
  295. package/pstack/skills/statechart/scripts/test/corpus/CounterRules/CounterRules.cfg +6 -0
  296. package/pstack/skills/statechart/scripts/test/corpus/CounterRules/CounterRules.tla +24 -0
  297. package/pstack/skills/statechart/scripts/test/corpus/CounterRules/Moves.tla +5 -0
  298. package/pstack/skills/statechart/scripts/test/corpus/CounterRules/chart.mmd +22 -0
  299. package/pstack/skills/statechart/scripts/test/corpus/CounterRules/graph.dot +10 -0
  300. package/pstack/skills/statechart/scripts/test/corpus/CounterRules/report.md +23 -0
  301. package/pstack/skills/statechart/scripts/test/corpus/CounterRules/sany.out +3 -0
  302. package/pstack/skills/statechart/scripts/test/corpus/CounterRules/verdict-1.exit +1 -0
  303. package/pstack/skills/statechart/scripts/test/corpus/CounterRules/verdict-1.out +58 -0
  304. package/pstack/skills/statechart/scripts/test/corpus/CounterRules/verdict-2.exit +1 -0
  305. package/pstack/skills/statechart/scripts/test/corpus/CounterRules/verdict-2.out +66 -0
  306. package/pstack/skills/statechart/scripts/test/corpus/CounterRules/verdict-3.exit +1 -0
  307. package/pstack/skills/statechart/scripts/test/corpus/CounterRules/verdict-3.out +74 -0
  308. package/pstack/skills/statechart/scripts/test/corpus/CounterRules/verdict-4.out +59 -0
  309. package/pstack/skills/statechart/scripts/test/corpus/CounterStart/ChartRun.out +58 -0
  310. package/pstack/skills/statechart/scripts/test/corpus/CounterStart/CounterStart.cfg +3 -0
  311. package/pstack/skills/statechart/scripts/test/corpus/CounterStart/CounterStart.tla +15 -0
  312. package/pstack/skills/statechart/scripts/test/corpus/CounterStart/chart.mmd +18 -0
  313. package/pstack/skills/statechart/scripts/test/corpus/CounterStart/graph.dot +13 -0
  314. package/pstack/skills/statechart/scripts/test/corpus/CounterStart/report.md +11 -0
  315. package/pstack/skills/statechart/scripts/test/corpus/CounterStart/sany.out +2 -0
  316. package/pstack/skills/statechart/scripts/test/corpus/CounterStart/verdict-1.exit +1 -0
  317. package/pstack/skills/statechart/scripts/test/corpus/CounterStart/verdict-1.out +33 -0
  318. package/pstack/skills/statechart/scripts/test/corpus/CounterStart/verdict-2.out +57 -0
  319. package/pstack/skills/statechart/scripts/test/corpus/CounterStop/ChartRun.out +57 -0
  320. package/pstack/skills/statechart/scripts/test/corpus/CounterStop/CounterStop.cfg +3 -0
  321. package/pstack/skills/statechart/scripts/test/corpus/CounterStop/CounterStop.tla +15 -0
  322. package/pstack/skills/statechart/scripts/test/corpus/CounterStop/chart.mmd +7 -0
  323. package/pstack/skills/statechart/scripts/test/corpus/CounterStop/graph.dot +13 -0
  324. package/pstack/skills/statechart/scripts/test/corpus/CounterStop/report.md +6 -0
  325. package/pstack/skills/statechart/scripts/test/corpus/CounterStop/sany.out +2 -0
  326. package/pstack/skills/statechart/scripts/test/corpus/CounterStop/verdict-1.out +49 -0
  327. package/pstack/skills/statechart/scripts/test/corpus/CounterTie/ChartRun.out +61 -0
  328. package/pstack/skills/statechart/scripts/test/corpus/CounterTie/CounterTie.cfg +4 -0
  329. package/pstack/skills/statechart/scripts/test/corpus/CounterTie/CounterTie.tla +14 -0
  330. package/pstack/skills/statechart/scripts/test/corpus/CounterTie/chart.mmd +30 -0
  331. package/pstack/skills/statechart/scripts/test/corpus/CounterTie/graph.dot +19 -0
  332. package/pstack/skills/statechart/scripts/test/corpus/CounterTie/report.md +27 -0
  333. package/pstack/skills/statechart/scripts/test/corpus/CounterTie/sany.out +2 -0
  334. package/pstack/skills/statechart/scripts/test/corpus/CounterTie/verdict-1.exit +1 -0
  335. package/pstack/skills/statechart/scripts/test/corpus/CounterTie/verdict-1.out +56 -0
  336. package/pstack/skills/statechart/scripts/test/corpus/CounterTie/verdict-2.exit +1 -0
  337. package/pstack/skills/statechart/scripts/test/corpus/CounterTie/verdict-2.out +64 -0
  338. package/pstack/skills/statechart/scripts/test/corpus/CounterTie/verdict-3.exit +1 -0
  339. package/pstack/skills/statechart/scripts/test/corpus/CounterTie/verdict-3.out +87 -0
  340. package/pstack/skills/statechart/scripts/test/corpus/CounterTie/verdict-4.out +57 -0
  341. package/pstack/skills/statechart/scripts/test/corpus/CounterTieInGraph/ChartRun.out +60 -0
  342. package/pstack/skills/statechart/scripts/test/corpus/CounterTieInGraph/CounterTieInGraph.cfg +3 -0
  343. package/pstack/skills/statechart/scripts/test/corpus/CounterTieInGraph/CounterTieInGraph.tla +12 -0
  344. package/pstack/skills/statechart/scripts/test/corpus/CounterTieInGraph/chart.mmd +23 -0
  345. package/pstack/skills/statechart/scripts/test/corpus/CounterTieInGraph/graph.dot +19 -0
  346. package/pstack/skills/statechart/scripts/test/corpus/CounterTieInGraph/report.md +11 -0
  347. package/pstack/skills/statechart/scripts/test/corpus/CounterTieInGraph/sany.out +2 -0
  348. package/pstack/skills/statechart/scripts/test/corpus/CounterTieInGraph/verdict-1.exit +1 -0
  349. package/pstack/skills/statechart/scripts/test/corpus/CounterTieInGraph/verdict-1.out +56 -0
  350. package/pstack/skills/statechart/scripts/test/corpus/CounterTieInGraph/verdict-2.out +57 -0
  351. package/pstack/skills/statechart/scripts/test/corpus/CounterView/ChartRun.out +61 -0
  352. package/pstack/skills/statechart/scripts/test/corpus/CounterView/CounterView.cfg +4 -0
  353. package/pstack/skills/statechart/scripts/test/corpus/CounterView/CounterView.tla +14 -0
  354. package/pstack/skills/statechart/scripts/test/corpus/CounterView/chart.mmd +23 -0
  355. package/pstack/skills/statechart/scripts/test/corpus/CounterView/graph.dot +19 -0
  356. package/pstack/skills/statechart/scripts/test/corpus/CounterView/report.md +27 -0
  357. package/pstack/skills/statechart/scripts/test/corpus/CounterView/sany.out +2 -0
  358. package/pstack/skills/statechart/scripts/test/corpus/CounterView/verdict-1.exit +1 -0
  359. package/pstack/skills/statechart/scripts/test/corpus/CounterView/verdict-1.out +56 -0
  360. package/pstack/skills/statechart/scripts/test/corpus/CounterView/verdict-2.exit +1 -0
  361. package/pstack/skills/statechart/scripts/test/corpus/CounterView/verdict-2.out +64 -0
  362. package/pstack/skills/statechart/scripts/test/corpus/CounterView/verdict-3.exit +1 -0
  363. package/pstack/skills/statechart/scripts/test/corpus/CounterView/verdict-3.out +87 -0
  364. package/pstack/skills/statechart/scripts/test/corpus/CounterView/verdict-4.out +57 -0
  365. package/pstack/skills/statechart/scripts/test/corpus/CounterView/view.mjs +1 -0
  366. package/pstack/skills/statechart/scripts/test/corpus/DieHard/ChartRun.out +59 -0
  367. package/pstack/skills/statechart/scripts/test/corpus/DieHard/DieHard.cfg +4 -0
  368. package/pstack/skills/statechart/scripts/test/corpus/DieHard/DieHard.tla +38 -0
  369. package/pstack/skills/statechart/scripts/test/corpus/DieHard/chart.mmd +92 -0
  370. package/pstack/skills/statechart/scripts/test/corpus/DieHard/graph.dot +126 -0
  371. package/pstack/skills/statechart/scripts/test/corpus/DieHard/report.md +17 -0
  372. package/pstack/skills/statechart/scripts/test/corpus/DieHard/sany.out +2 -0
  373. package/pstack/skills/statechart/scripts/test/corpus/DieHard/verdict-1.exit +1 -0
  374. package/pstack/skills/statechart/scripts/test/corpus/DieHard/verdict-1.out +91 -0
  375. package/pstack/skills/statechart/scripts/test/corpus/DieHard/verdict-2.out +57 -0
  376. package/pstack/skills/statechart/scripts/test/corpus/FirstRule/ChartRun.out +61 -0
  377. package/pstack/skills/statechart/scripts/test/corpus/FirstRule/FirstRule.cfg +6 -0
  378. package/pstack/skills/statechart/scripts/test/corpus/FirstRule/FirstRule.tla +11 -0
  379. package/pstack/skills/statechart/scripts/test/corpus/FirstRule/chart.mmd +22 -0
  380. package/pstack/skills/statechart/scripts/test/corpus/FirstRule/graph.dot +16 -0
  381. package/pstack/skills/statechart/scripts/test/corpus/FirstRule/report.md +25 -0
  382. package/pstack/skills/statechart/scripts/test/corpus/FirstRule/sany.out +2 -0
  383. package/pstack/skills/statechart/scripts/test/corpus/FirstRule/verdict-1.exit +1 -0
  384. package/pstack/skills/statechart/scripts/test/corpus/FirstRule/verdict-1.out +56 -0
  385. package/pstack/skills/statechart/scripts/test/corpus/FirstRule/verdict-2.exit +1 -0
  386. package/pstack/skills/statechart/scripts/test/corpus/FirstRule/verdict-2.out +64 -0
  387. package/pstack/skills/statechart/scripts/test/corpus/FirstRule/verdict-3.exit +1 -0
  388. package/pstack/skills/statechart/scripts/test/corpus/FirstRule/verdict-3.out +64 -0
  389. package/pstack/skills/statechart/scripts/test/corpus/FirstRule/verdict-4.exit +1 -0
  390. package/pstack/skills/statechart/scripts/test/corpus/FirstRule/verdict-4.out +77 -0
  391. package/pstack/skills/statechart/scripts/test/corpus/HiddenClock/ChartRun.out +57 -0
  392. package/pstack/skills/statechart/scripts/test/corpus/HiddenClock/HiddenClock.cfg +4 -0
  393. package/pstack/skills/statechart/scripts/test/corpus/HiddenClock/HiddenClock.tla +11 -0
  394. package/pstack/skills/statechart/scripts/test/corpus/HiddenClock/chart.mmd +13 -0
  395. package/pstack/skills/statechart/scripts/test/corpus/HiddenClock/graph.dot +12 -0
  396. package/pstack/skills/statechart/scripts/test/corpus/HiddenClock/report.md +11 -0
  397. package/pstack/skills/statechart/scripts/test/corpus/HiddenClock/sany.out +2 -0
  398. package/pstack/skills/statechart/scripts/test/corpus/HiddenClock/verdict-1.exit +1 -0
  399. package/pstack/skills/statechart/scripts/test/corpus/HiddenClock/verdict-1.out +72 -0
  400. package/pstack/skills/statechart/scripts/test/corpus/Login/ChartRun.out +57 -0
  401. package/pstack/skills/statechart/scripts/test/corpus/Login/Login.cfg +3 -0
  402. package/pstack/skills/statechart/scripts/test/corpus/Login/Login.tla +62 -0
  403. package/pstack/skills/statechart/scripts/test/corpus/Login/chart.mmd +27 -0
  404. package/pstack/skills/statechart/scripts/test/corpus/Login/graph.dot +40 -0
  405. package/pstack/skills/statechart/scripts/test/corpus/Login/report.md +7 -0
  406. package/pstack/skills/statechart/scripts/test/corpus/Login/sany.out +1 -0
  407. package/pstack/skills/statechart/scripts/test/corpus/Login/verdict-1.out +47 -0
  408. package/pstack/skills/statechart/scripts/test/corpus/Login/view.mjs +1 -0
  409. package/pstack/skills/statechart/scripts/test/corpus/LoginGuarded/ChartRun.out +57 -0
  410. package/pstack/skills/statechart/scripts/test/corpus/LoginGuarded/LoginGuarded.cfg +2 -0
  411. package/pstack/skills/statechart/scripts/test/corpus/LoginGuarded/LoginGuarded.tla +64 -0
  412. package/pstack/skills/statechart/scripts/test/corpus/LoginGuarded/chart.mmd +28 -0
  413. package/pstack/skills/statechart/scripts/test/corpus/LoginGuarded/graph.dot +37 -0
  414. package/pstack/skills/statechart/scripts/test/corpus/LoginGuarded/report.md +8 -0
  415. package/pstack/skills/statechart/scripts/test/corpus/LoginGuarded/sany.out +1 -0
  416. package/pstack/skills/statechart/scripts/test/corpus/LoginGuarded/verdict-1.out +47 -0
  417. package/pstack/skills/statechart/scripts/test/corpus/LoginGuarded/view.mjs +1 -0
  418. package/pstack/skills/statechart/scripts/test/corpus/LoginParallel/ChartRun.out +60 -0
  419. package/pstack/skills/statechart/scripts/test/corpus/LoginParallel/LoginParallel.cfg +3 -0
  420. package/pstack/skills/statechart/scripts/test/corpus/LoginParallel/LoginParallel.tla +64 -0
  421. package/pstack/skills/statechart/scripts/test/corpus/LoginParallel/chart.mmd +44 -0
  422. package/pstack/skills/statechart/scripts/test/corpus/LoginParallel/graph.dot +58 -0
  423. package/pstack/skills/statechart/scripts/test/corpus/LoginParallel/report.md +17 -0
  424. package/pstack/skills/statechart/scripts/test/corpus/LoginParallel/sany.out +1 -0
  425. package/pstack/skills/statechart/scripts/test/corpus/LoginParallel/verdict-1.exit +1 -0
  426. package/pstack/skills/statechart/scripts/test/corpus/LoginParallel/verdict-1.out +83 -0
  427. package/pstack/skills/statechart/scripts/test/corpus/LoginParallel/verdict-2.out +57 -0
  428. package/pstack/skills/statechart/scripts/test/corpus/LoginParallel/view.mjs +1 -0
  429. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayer/ChartRun.out +60 -0
  430. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayer/MediaPlayer.cfg +3 -0
  431. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayer/MediaPlayer.tla +103 -0
  432. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayer/chart.mmd +43 -0
  433. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayer/graph.dot +93 -0
  434. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayer/report.md +14 -0
  435. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayer/sany.out +1 -0
  436. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayer/verdict-1.exit +1 -0
  437. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayer/verdict-1.out +59 -0
  438. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayer/verdict-2.out +72 -0
  439. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayer/view.mjs +3 -0
  440. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerFixed/ChartRun.out +57 -0
  441. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerFixed/MediaPlayerFixed.cfg +2 -0
  442. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerFixed/MediaPlayerFixed.tla +100 -0
  443. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerFixed/chart.mmd +31 -0
  444. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerFixed/graph.dot +85 -0
  445. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerFixed/report.md +9 -0
  446. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerFixed/sany.out +1 -0
  447. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerFixed/verdict-1.out +47 -0
  448. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerFixed/view.mjs +3 -0
  449. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/ChartRun.out +59 -0
  450. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/MediaPlayer.tla +103 -0
  451. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/MediaPlayerProps.cfg +3 -0
  452. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/MediaPlayerProps.tla +6 -0
  453. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/chart.mmd +42 -0
  454. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/graph.dot +93 -0
  455. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/report.md +19 -0
  456. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/sany.out +2 -0
  457. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-1.exit +1 -0
  458. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-1.out +61 -0
  459. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-2.out +59 -0
  460. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-3.out +61 -0
  461. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-4.exit +1 -0
  462. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-4.out +66 -0
  463. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-5.exit +1 -0
  464. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-5.out +58 -0
  465. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-6.out +49 -0
  466. package/pstack/skills/statechart/scripts/test/corpus/MediaPlayerProps/view.mjs +3 -0
  467. package/pstack/skills/statechart/scripts/test/corpus/PickWorker/ChartRun.out +57 -0
  468. package/pstack/skills/statechart/scripts/test/corpus/PickWorker/PickWorker.cfg +6 -0
  469. package/pstack/skills/statechart/scripts/test/corpus/PickWorker/PickWorker.tla +11 -0
  470. package/pstack/skills/statechart/scripts/test/corpus/PickWorker/chart.mmd +5 -0
  471. package/pstack/skills/statechart/scripts/test/corpus/PickWorker/graph.dot +11 -0
  472. package/pstack/skills/statechart/scripts/test/corpus/PickWorker/report.md +7 -0
  473. package/pstack/skills/statechart/scripts/test/corpus/PickWorker/sany.out +5 -0
  474. package/pstack/skills/statechart/scripts/test/corpus/PickWorker/verdict-1.out +70 -0
  475. package/pstack/skills/statechart/scripts/test/corpus/Shadow/ChartRun.out +61 -0
  476. package/pstack/skills/statechart/scripts/test/corpus/Shadow/Shadow.cfg +4 -0
  477. package/pstack/skills/statechart/scripts/test/corpus/Shadow/Shadow.tla +11 -0
  478. package/pstack/skills/statechart/scripts/test/corpus/Shadow/ShadowLib.tla +6 -0
  479. package/pstack/skills/statechart/scripts/test/corpus/Shadow/ShadowSub.tla +3 -0
  480. package/pstack/skills/statechart/scripts/test/corpus/Shadow/chart.mmd +9 -0
  481. package/pstack/skills/statechart/scripts/test/corpus/Shadow/graph.dot +16 -0
  482. package/pstack/skills/statechart/scripts/test/corpus/Shadow/report.md +8 -0
  483. package/pstack/skills/statechart/scripts/test/corpus/Shadow/sany.out +4 -0
  484. package/pstack/skills/statechart/scripts/test/corpus/Shadow/verdict-1.out +65 -0
  485. package/pstack/skills/statechart/scripts/test/corpus/SpacedNames/ChartRun.out +59 -0
  486. package/pstack/skills/statechart/scripts/test/corpus/SpacedNames/SpacedNames.cfg +2 -0
  487. package/pstack/skills/statechart/scripts/test/corpus/SpacedNames/SpacedNames.tla +9 -0
  488. package/pstack/skills/statechart/scripts/test/corpus/SpacedNames/chart.mmd +23 -0
  489. package/pstack/skills/statechart/scripts/test/corpus/SpacedNames/graph.dot +17 -0
  490. package/pstack/skills/statechart/scripts/test/corpus/SpacedNames/report.md +15 -0
  491. package/pstack/skills/statechart/scripts/test/corpus/SpacedNames/sany.out +1 -0
  492. package/pstack/skills/statechart/scripts/test/corpus/SpacedNames/verdict-1.exit +1 -0
  493. package/pstack/skills/statechart/scripts/test/corpus/SpacedNames/verdict-1.out +65 -0
  494. package/pstack/skills/statechart/scripts/test/corpus/SpacedNames/verdict-2.exit +1 -0
  495. package/pstack/skills/statechart/scripts/test/corpus/SpacedNames/verdict-2.out +75 -0
  496. package/pstack/skills/statechart/scripts/test/corpus/TwoPhase/ChartRun.out +69 -0
  497. package/pstack/skills/statechart/scripts/test/corpus/TwoPhase/TwoPhase.cfg +3 -0
  498. package/pstack/skills/statechart/scripts/test/corpus/TwoPhase/TwoPhase.tla +75 -0
  499. package/pstack/skills/statechart/scripts/test/corpus/TwoPhase/chart.mmd +60 -0
  500. package/pstack/skills/statechart/scripts/test/corpus/TwoPhase/graph.dot +297 -0
  501. package/pstack/skills/statechart/scripts/test/corpus/TwoPhase/report.md +20 -0
  502. package/pstack/skills/statechart/scripts/test/corpus/TwoPhase/sany.out +1 -0
  503. package/pstack/skills/statechart/scripts/test/corpus/TwoPhase/verdict-1.exit +1 -0
  504. package/pstack/skills/statechart/scripts/test/corpus/TwoPhase/verdict-1.out +95 -0
  505. package/pstack/skills/statechart/scripts/test/corpus/TwoPhase/verdict-2.out +57 -0
  506. package/pstack/skills/statechart/scripts/test/corpus/TwoPhase/view.mjs +1 -0
  507. package/pstack/skills/statechart/scripts/test/corpus/TwoPhaseFixed/ChartRun.out +57 -0
  508. package/pstack/skills/statechart/scripts/test/corpus/TwoPhaseFixed/TwoPhaseFixed.cfg +3 -0
  509. package/pstack/skills/statechart/scripts/test/corpus/TwoPhaseFixed/TwoPhaseFixed.tla +75 -0
  510. package/pstack/skills/statechart/scripts/test/corpus/TwoPhaseFixed/chart.mmd +37 -0
  511. package/pstack/skills/statechart/scripts/test/corpus/TwoPhaseFixed/graph.dot +223 -0
  512. package/pstack/skills/statechart/scripts/test/corpus/TwoPhaseFixed/report.md +11 -0
  513. package/pstack/skills/statechart/scripts/test/corpus/TwoPhaseFixed/sany.out +1 -0
  514. package/pstack/skills/statechart/scripts/test/corpus/TwoPhaseFixed/verdict-1.out +47 -0
  515. package/pstack/skills/statechart/scripts/test/corpus/TwoPhaseFixed/view.mjs +1 -0
  516. package/pstack/skills/statechart/scripts/test/corpus/TypeGuard/ChartRun.exit +1 -0
  517. package/pstack/skills/statechart/scripts/test/corpus/TypeGuard/ChartRun.out +75 -0
  518. package/pstack/skills/statechart/scripts/test/corpus/TypeGuard/TypeGuard.cfg +5 -0
  519. package/pstack/skills/statechart/scripts/test/corpus/TypeGuard/TypeGuard.tla +11 -0
  520. package/pstack/skills/statechart/scripts/test/corpus/TypeGuard/chart.mmd +18 -0
  521. package/pstack/skills/statechart/scripts/test/corpus/TypeGuard/graph.dot +14 -0
  522. package/pstack/skills/statechart/scripts/test/corpus/TypeGuard/report.md +29 -0
  523. package/pstack/skills/statechart/scripts/test/corpus/TypeGuard/sany.out +2 -0
  524. package/pstack/skills/statechart/scripts/test/corpus/TypeGuard/verdict-1.exit +1 -0
  525. package/pstack/skills/statechart/scripts/test/corpus/TypeGuard/verdict-1.out +64 -0
  526. package/pstack/skills/statechart/scripts/test/corpus/TypeGuard/verdict-2.exit +1 -0
  527. package/pstack/skills/statechart/scripts/test/corpus/TypeGuard/verdict-2.out +75 -0
  528. package/pstack/skills/statechart/scripts/test/corpus/UserNoDeadlock/ChartRun.out +58 -0
  529. package/pstack/skills/statechart/scripts/test/corpus/UserNoDeadlock/UserNoDeadlock.cfg +2 -0
  530. package/pstack/skills/statechart/scripts/test/corpus/UserNoDeadlock/UserNoDeadlock.tla +8 -0
  531. package/pstack/skills/statechart/scripts/test/corpus/UserNoDeadlock/chart.mmd +22 -0
  532. package/pstack/skills/statechart/scripts/test/corpus/UserNoDeadlock/graph.dot +16 -0
  533. package/pstack/skills/statechart/scripts/test/corpus/UserNoDeadlock/report.md +15 -0
  534. package/pstack/skills/statechart/scripts/test/corpus/UserNoDeadlock/sany.out +2 -0
  535. package/pstack/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-1.exit +1 -0
  536. package/pstack/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-1.out +56 -0
  537. package/pstack/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-2.exit +1 -0
  538. package/pstack/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-2.out +77 -0
  539. package/pstack/skills/statechart/scripts/test/corpus.test.ts +403 -0
  540. package/pstack/skills/statechart/scripts/test/differential.test.ts +565 -0
  541. package/pstack/skills/statechart/scripts/test/grid/Grid.cfg +2 -0
  542. package/pstack/skills/statechart/scripts/test/grid/Grid.tla +9 -0
  543. package/pstack/skills/statechart/scripts/test/grid/sany.out +2 -0
  544. package/pstack/skills/statechart/scripts/test/java.ts +63 -0
  545. package/pstack/skills/statechart/scripts/test/labels.ts +643 -0
  546. package/pstack/skills/statechart/scripts/test/messages.test.ts +212 -0
  547. package/pstack/skills/statechart/scripts/test/pipeline.test.ts +270 -0
  548. package/pstack/skills/statechart/scripts/test/plain-tlc.test.ts +255 -0
  549. package/pstack/skills/statechart/scripts/test/render.test.ts +81 -0
  550. package/pstack/skills/statechart/scripts/test/tlc-out.test.ts +90 -0
  551. package/pstack/skills/statechart/scripts/test/tlc.ts +158 -0
  552. package/pstack/skills/statechart/scripts/tsconfig.json +11 -0
  553. package/pstack/skills/statechart/scripts/worker.ts +35 -0
  554. package/pstack/skills/swarm/SKILL.md +47 -0
  555. package/pstack/skills/tdd/SKILL.md +42 -0
  556. package/pstack/skills/teach/SKILL.md +21 -0
  557. package/pstack/skills/technical-writing/SKILL.md +106 -0
  558. package/pstack/skills/thermo-nuclear-code-quality-review/SKILL.md +192 -0
  559. package/pstack/skills/thermo-nuclear-review/SKILL.md +51 -0
  560. package/pstack/skills/thermos/SKILL.md +21 -0
  561. package/pstack/skills/typescript-best-practices/SKILL.md +31 -0
  562. package/pstack/skills/typescript-best-practices/references/patterns.md +328 -0
  563. package/pstack/skills/unslop/SKILL.md +62 -0
  564. package/pstack/skills/what-did-i-get-done/SKILL.md +31 -0
  565. package/pstack/skills/why/SKILL.md +105 -0
  566. package/pstack/skills/why/references/epistemics.md +71 -0
  567. package/pstack/skills/why/references/investigator-prompt.md +84 -0
  568. package/pstack/skills/why/references/source-playbook.md +17 -0
  569. package/pstack/skills/why/references/sources/code-archaeology.md +51 -0
  570. package/pstack/skills/why/references/sources/databricks.md +70 -0
  571. package/pstack/skills/why/references/sources/datadog.md +97 -0
  572. package/pstack/skills/why/references/sources/incident-postmortem.md +5 -0
  573. package/pstack/skills/why/references/sources/linear.md +48 -0
  574. package/pstack/skills/why/references/sources/notion.md +55 -0
  575. package/pstack/skills/why/references/sources/sentry.md +66 -0
  576. package/pstack/skills/why/references/sources/slack.md +17 -0
  577. package/pstack/skills/why/references/synthesizer-prompt.md +129 -0
  578. package/src/accounts.ts +527 -0
  579. package/src/bash-timeout.ts +63 -0
  580. package/src/bridge-trim.ts +109 -0
  581. package/src/brief.ts +280 -0
  582. package/src/cards.ts +65 -0
  583. package/src/child.ts +570 -0
  584. package/src/failures.ts +73 -0
  585. package/src/models.ts +1249 -0
  586. package/src/plan.ts +252 -0
  587. package/src/resources.ts +30 -0
  588. package/src/results.ts +92 -0
  589. package/src/resume.ts +143 -0
  590. package/src/session.ts +70 -0
  591. package/src/state.ts +124 -0
  592. package/src/t3-http.ts +140 -0
  593. package/src/t3-json.ts +50 -0
  594. package/src/t3-mcp.ts +188 -0
  595. package/src/tasks.ts +163 -0
  596. package/src/transcript.ts +17 -0
  597. package/src/usage.ts +145 -0
  598. package/README.md +0 -3
package/src/models.ts ADDED
@@ -0,0 +1,1249 @@
1
+ import { readFileSync } from "node:fs";
2
+
3
+ import { Type } from "@earendil-works/pi-ai";
4
+ import type { Static, UserMessage } from "@earendil-works/pi-ai";
5
+ import { defineTool } from "@earendil-works/pi-coding-agent";
6
+ import type {
7
+ ExtensionAPI,
8
+ ExtensionContext,
9
+ ExtensionToolContext,
10
+ } from "@earendil-works/pi-coding-agent";
11
+ import { Value } from "typebox/value";
12
+
13
+ import {
14
+ family,
15
+ parseEntry,
16
+ parseSheet,
17
+ } from "../pstack/skills/setup-pstack/scripts/t3-sheet.mjs";
18
+ import {
19
+ familyAvailable,
20
+ readAccounts,
21
+ registerAccounts,
22
+ settleChildren,
23
+ unavailableReason,
24
+ } from "./accounts.ts";
25
+ import {
26
+ APPROVAL_LINE,
27
+ briefProblems,
28
+ parseBrief,
29
+ PSTACK_COMMAND,
30
+ sessionBrief,
31
+ } from "./brief.ts";
32
+ import { policyPath } from "./resources.ts";
33
+ import { modelSheetPath } from "./session.ts";
34
+ import { t3Json, t3Text } from "./t3-json.ts";
35
+
36
+ const OptionValueSchema = Type.Union([Type.String(), Type.Boolean()]);
37
+
38
+ const CatalogOptionSchema = Type.Object({
39
+ id: Type.String(),
40
+ values: Type.Array(OptionValueSchema),
41
+ });
42
+
43
+ const CatalogModelSchema = Type.Object({
44
+ id: Type.String(),
45
+ options: Type.Optional(Type.Array(CatalogOptionSchema)),
46
+ });
47
+
48
+ const CatalogProviderSchema = Type.Object({
49
+ canRunChildTask: Type.Boolean(),
50
+ canRunCrossProviderChildTask: Type.Optional(Type.Boolean()),
51
+ models: Type.Array(CatalogModelSchema),
52
+ providerInstanceId: Type.String(),
53
+ });
54
+
55
+ const CatalogSchema = Type.Object({
56
+ inheritedModel: Type.Union([Type.String(), Type.Null()]),
57
+ inheritedProviderInstanceId: Type.Union([Type.String(), Type.Null()]),
58
+ providers: Type.Array(CatalogProviderSchema),
59
+ });
60
+
61
+ const ComplexitySchema = Type.Union([
62
+ Type.Literal("groundwork"),
63
+ Type.Literal("bounded"),
64
+ Type.Literal("general"),
65
+ ]);
66
+
67
+ const SizesSchema = Type.Object({
68
+ bounded: Type.String(),
69
+ general: Type.String(),
70
+ groundwork: Type.String(),
71
+ });
72
+
73
+ const GuardedWordsSchema = Type.Array(Type.String(), { minItems: 1 });
74
+
75
+ const JobTargetSchema = Type.Object({
76
+ model: Type.String(),
77
+ reasoning: Type.String(),
78
+ });
79
+
80
+ const JobSchema = Type.Union([
81
+ Type.Object({ M: JobTargetSchema, S: JobTargetSchema }),
82
+ Type.Object({ panel: Type.Array(JobTargetSchema, { minItems: 2 }) }),
83
+ ]);
84
+
85
+ const PolicySchema = Type.Object({
86
+ briefs: Type.Object({
87
+ gpt: Type.Object({
88
+ diskMb: Type.Number(),
89
+ family: Type.String(),
90
+ minutes: Type.Number(),
91
+ size: Type.String(),
92
+ }),
93
+ noWrites: Type.Array(Type.String()),
94
+ redBeforeGreen: Type.Array(Type.String()),
95
+ sizes: Type.Record(
96
+ Type.String(),
97
+ Type.Object({ files: Type.Number(), minutes: Type.Number() })
98
+ ),
99
+ }),
100
+ jobs: Type.Record(Type.String(), JobSchema),
101
+ roles: Type.Array(
102
+ Type.Object({
103
+ alias: Type.Optional(Type.String()),
104
+ role: Type.String(),
105
+ skill: Type.String(),
106
+ tier: Type.Union([Type.Literal("single"), Type.Literal("panel")]),
107
+ })
108
+ ),
109
+ routing: Type.Object({
110
+ aboveHigh: Type.Array(
111
+ Type.Object({ level: Type.String(), words: GuardedWordsSchema })
112
+ ),
113
+ approval: Type.Record(Type.String(), Type.Array(Type.String())),
114
+ families: Type.Record(Type.String(), SizesSchema),
115
+ fast: Type.Object({
116
+ options: Type.Array(Type.String()),
117
+ words: GuardedWordsSchema,
118
+ }),
119
+ levels: Type.Array(Type.String()),
120
+ panel: Type.Array(Type.String(), { minItems: 2 }),
121
+ reasoning: SizesSchema,
122
+ reserved: Type.Array(
123
+ Type.Object({ model: Type.String(), words: GuardedWordsSchema })
124
+ ),
125
+ }),
126
+ });
127
+
128
+ type CatalogOption = Static<typeof CatalogOptionSchema>;
129
+
130
+ type CatalogModel = Static<typeof CatalogModelSchema>;
131
+
132
+ type CatalogProvider = Static<typeof CatalogProviderSchema>;
133
+
134
+ type Catalog = Static<typeof CatalogSchema>;
135
+
136
+ type Complexity = Static<typeof ComplexitySchema>;
137
+
138
+ type Policy = Static<typeof PolicySchema>;
139
+
140
+ type Role = Policy["roles"][number];
141
+
142
+ type OptionValue = Static<typeof OptionValueSchema>;
143
+
144
+ type TargetOptions = Readonly<Record<string, OptionValue>>;
145
+
146
+ const TargetSchema = Type.Object({
147
+ model: Type.String(),
148
+ options: Type.Record(Type.String(), OptionValueSchema),
149
+ providerInstanceId: Type.String(),
150
+ });
151
+
152
+ type Target = Static<typeof TargetSchema>;
153
+
154
+ type Entry = Target | null;
155
+
156
+ interface ResolveContext {
157
+ readonly available: (modelFamily: string) => boolean;
158
+ readonly catalog: Catalog;
159
+ readonly notes: string[];
160
+ readonly policy: Policy;
161
+ }
162
+
163
+ const ResolutionSchema = Type.Union([
164
+ Type.Object({
165
+ kind: Type.Literal("targets"),
166
+ notes: Type.Array(Type.String()),
167
+ role: Type.String(),
168
+ targets: Type.Array(TargetSchema),
169
+ }),
170
+ Type.Object({
171
+ kind: Type.Literal("inherit-parent"),
172
+ notes: Type.Array(Type.String()),
173
+ role: Type.String(),
174
+ }),
175
+ Type.Object({
176
+ kind: Type.Literal("blocked"),
177
+ notes: Type.Array(Type.String()),
178
+ reason: Type.String(),
179
+ role: Type.String(),
180
+ }),
181
+ ]);
182
+
183
+ type Resolution = Static<typeof ResolutionSchema>;
184
+
185
+ const ORCHESTRATOR_CAPABILITIES_TOOLS = [
186
+ "mcp__t3-code__orchestrator_capabilities",
187
+ "mcp__t3__orchestrator_capabilities",
188
+ ] as const;
189
+
190
+ const RESOLVED_ENTRY = "t3-pstack-resolved";
191
+
192
+ const DELEGATE_TOOLS: ReadonlySet<string> = new Set([
193
+ "mcp__t3-code__delegate_task",
194
+ "mcp__t3__delegate_task",
195
+ ]);
196
+
197
+ const SIZE_FALLBACK: Readonly<Record<Complexity, readonly Complexity[]>> = {
198
+ bounded: ["bounded", "groundwork", "general"],
199
+ general: ["general", "bounded", "groundwork"],
200
+ groundwork: ["groundwork", "bounded", "general"],
201
+ };
202
+
203
+ const lastSegment = (model: string): string => model.split("/").pop() ?? model;
204
+
205
+ const describe = (target: Target): string => {
206
+ const options = Object.entries(target.options)
207
+ .map(([id, value]) => ` ${id}=${value}`)
208
+ .join("");
209
+
210
+ return `${target.providerInstanceId}/${target.model}${options}`;
211
+ };
212
+
213
+ const runnableProviders = (catalog: Catalog): CatalogProvider[] => {
214
+ const runnable = catalog.providers.filter(
215
+ (provider) =>
216
+ provider.canRunChildTask &&
217
+ (provider.canRunCrossProviderChildTask !== false ||
218
+ provider.providerInstanceId === catalog.inheritedProviderInstanceId)
219
+ );
220
+
221
+ const rank = (provider: CatalogProvider): number =>
222
+ provider.providerInstanceId === catalog.inheritedProviderInstanceId ? 0 : 1;
223
+
224
+ return runnable.toSorted((left, right) => rank(left) - rank(right));
225
+ };
226
+
227
+ const optionValues = (option: CatalogOption): readonly string[] =>
228
+ option.values.map(String);
229
+
230
+ const isSwitch = (option: CatalogOption): boolean =>
231
+ option.values.every((value) => Value.Check(Type.Boolean(), value));
232
+
233
+ const translateOptions = (
234
+ wanted: TargetOptions,
235
+ model: CatalogModel,
236
+ notes: string[]
237
+ ): TargetOptions => {
238
+ const known = model.options ?? [];
239
+ const translated = new Map<string, OptionValue>();
240
+
241
+ for (const [id, wantedValue] of Object.entries(wanted)) {
242
+ const value = String(wantedValue);
243
+
244
+ const sameId = known.find(
245
+ (option) => option.id === id && optionValues(option).includes(value)
246
+ );
247
+
248
+ const sameValue = known.find(
249
+ (option) => !isSwitch(option) && optionValues(option).includes(value)
250
+ );
251
+
252
+ const match = sameId ?? sameValue;
253
+
254
+ if (match === undefined) {
255
+ notes.push(`${model.id} has no option that accepts ${id}=${value}`);
256
+ } else {
257
+ translated.set(
258
+ match.id,
259
+ match.values.find((choice) => String(choice) === value) ?? value
260
+ );
261
+ }
262
+ }
263
+
264
+ return Object.fromEntries(translated);
265
+ };
266
+
267
+ const placeEntry = (
268
+ entry: Target,
269
+ catalog: Catalog,
270
+ notes: string[]
271
+ ): Target | undefined => {
272
+ const providers = runnableProviders(catalog);
273
+
274
+ const exact = providers.find(
275
+ (provider) => provider.providerInstanceId === entry.providerInstanceId
276
+ );
277
+
278
+ const ordered = exact === undefined ? providers : [exact, ...providers];
279
+
280
+ for (const provider of ordered) {
281
+ const model =
282
+ provider.models.find((candidate) => candidate.id === entry.model) ??
283
+ provider.models.find(
284
+ (candidate) => lastSegment(candidate.id) === lastSegment(entry.model)
285
+ );
286
+
287
+ if (model !== undefined) {
288
+ return {
289
+ model: model.id,
290
+ options: translateOptions(entry.options, model, notes),
291
+ providerInstanceId: provider.providerInstanceId,
292
+ };
293
+ }
294
+ }
295
+
296
+ return undefined;
297
+ };
298
+
299
+ const placeRouted = (
300
+ modelFamily: string,
301
+ complexity: Complexity,
302
+ {
303
+ catalog,
304
+ notes,
305
+ policy,
306
+ }: { catalog: Catalog; notes: string[]; policy: Policy }
307
+ ): Target | undefined => {
308
+ const sizes = policy.routing.families[modelFamily];
309
+
310
+ if (sizes === undefined) {
311
+ return undefined;
312
+ }
313
+
314
+ for (const size of SIZE_FALLBACK[complexity]) {
315
+ const placed = placeEntry(
316
+ {
317
+ model: sizes[size],
318
+ options: { reasoning: policy.routing.reasoning[complexity] },
319
+ providerInstanceId: catalog.inheritedProviderInstanceId ?? "",
320
+ },
321
+ catalog,
322
+ notes
323
+ );
324
+
325
+ if (placed !== undefined) {
326
+ if (size !== complexity) {
327
+ notes.push(
328
+ `${sizes[complexity]} cannot run here, so ${modelFamily} ${complexity} work uses ${placed.model}`
329
+ );
330
+ }
331
+
332
+ return placed;
333
+ }
334
+ }
335
+
336
+ notes.push(`no ${modelFamily} model can run here`);
337
+
338
+ return undefined;
339
+ };
340
+
341
+ const withJobReasoning = (
342
+ entry: Target,
343
+ complexity: Complexity,
344
+ policy: Policy
345
+ ): Target => ({
346
+ ...entry,
347
+ options: {
348
+ reasoning: policy.routing.reasoning[complexity],
349
+ ...entry.options,
350
+ },
351
+ });
352
+
353
+ const sheetEntries = (sheet: string, role: Role): Entry[] | undefined => {
354
+ const value = parseSheet(sheet).find(
355
+ (line: { key?: string }) =>
356
+ line.key === role.role || line.key === role.alias
357
+ )?.value;
358
+
359
+ return value === undefined
360
+ ? undefined
361
+ : String(value).split(",").map(parseEntry);
362
+ };
363
+
364
+ const resolveSingle = (
365
+ role: Role,
366
+ explicit: Entry,
367
+ complexity: Complexity,
368
+ { available, catalog, notes, policy }: ResolveContext
369
+ ): Resolution => {
370
+ if (explicit !== null && !available(family(explicit.model))) {
371
+ notes.push(
372
+ `${describe(explicit)} from the model sheet is on an exhausted account`
373
+ );
374
+ }
375
+
376
+ if (explicit !== null && available(family(explicit.model))) {
377
+ const placed = placeEntry(
378
+ withJobReasoning(explicit, complexity, policy),
379
+ catalog,
380
+ notes
381
+ );
382
+
383
+ if (placed !== undefined) {
384
+ notes.push("the model sheet names this target");
385
+
386
+ return { kind: "targets", notes, role: role.role, targets: [placed] };
387
+ }
388
+
389
+ notes.push(`${describe(explicit)} from the model sheet cannot run here`);
390
+ }
391
+
392
+ if (catalog.inheritedModel === null) {
393
+ return { kind: "inherit-parent", notes, role: role.role };
394
+ }
395
+
396
+ const parentFamily = family(catalog.inheritedModel);
397
+
398
+ const familyOrder = [
399
+ parentFamily,
400
+ ...policy.routing.panel.filter((name) => name !== parentFamily),
401
+ ].filter((name) => {
402
+ const open = available(name);
403
+
404
+ if (!open) {
405
+ notes.push(`${name} is on an exhausted account`);
406
+ }
407
+
408
+ return open;
409
+ });
410
+
411
+ const routed = familyOrder
412
+ .values()
413
+ .map((name) => placeRouted(name, complexity, { catalog, notes, policy }))
414
+ .find((target) => target !== undefined);
415
+
416
+ if (routed === undefined && !available(parentFamily)) {
417
+ return {
418
+ kind: "blocked",
419
+ notes,
420
+ reason: `Every model family that can run here is on an exhausted account. Wait for a reset or for /pstack-recovered.`,
421
+ role: role.role,
422
+ };
423
+ }
424
+
425
+ if (routed === undefined) {
426
+ notes.push("the role runs on the parent model");
427
+
428
+ return { kind: "inherit-parent", notes, role: role.role };
429
+ }
430
+
431
+ return { kind: "targets", notes, role: role.role, targets: [routed] };
432
+ };
433
+
434
+ const resolvePanel = (
435
+ role: Role,
436
+ explicit: readonly Entry[],
437
+ complexity: Complexity,
438
+ { available, catalog, notes, policy }: ResolveContext
439
+ ): Resolution => {
440
+ const targets: Target[] = [];
441
+
442
+ const families = (): Set<string> =>
443
+ new Set(targets.map((target) => family(target.model)));
444
+
445
+ const seat = (target: Target | undefined): void => {
446
+ if (
447
+ target !== undefined &&
448
+ !targets.some((seated) => describe(seated) === describe(target))
449
+ ) {
450
+ targets.push(target);
451
+ }
452
+ };
453
+
454
+ for (const entry of explicit) {
455
+ seat(
456
+ entry === null || !available(family(entry.model))
457
+ ? undefined
458
+ : placeEntry(
459
+ withJobReasoning(entry, complexity, policy),
460
+ catalog,
461
+ notes
462
+ )
463
+ );
464
+ }
465
+
466
+ for (const modelFamily of policy.routing.panel.filter(available)) {
467
+ if (explicit.length === 0 || families().size < 2) {
468
+ const placed = families().has(modelFamily)
469
+ ? undefined
470
+ : placeRouted(modelFamily, complexity, { catalog, notes, policy });
471
+
472
+ seat(placed);
473
+ }
474
+ }
475
+
476
+ if (families().size < 2) {
477
+ return {
478
+ kind: "blocked",
479
+ notes,
480
+ reason: `BLOCKED: independent review. The panel needs two model families that can run on this T3, and found ${[...families()].join(", ") || "none"}.`,
481
+ role: role.role,
482
+ };
483
+ }
484
+
485
+ return { kind: "targets", notes, role: role.role, targets };
486
+ };
487
+
488
+ const findRole = (policy: Policy, roleName: string): Role => {
489
+ const role = policy.roles.find(
490
+ (candidate) => candidate.role === roleName || candidate.alias === roleName
491
+ );
492
+
493
+ if (role === undefined) {
494
+ throw new Error(
495
+ `"${roleName}" is not a pstack role. Roles: ${policy.roles.map((candidate) => candidate.role).join("; ")}.`
496
+ );
497
+ }
498
+
499
+ return role;
500
+ };
501
+
502
+ export type JobSize = "S" | "M" | "L";
503
+
504
+ const tierOf = (policy: Policy, model: string): Complexity | undefined => {
505
+ const sizes = policy.routing.families[family(model)];
506
+
507
+ // SAFETY: SIZE_FALLBACK is keyed by every Complexity value.
508
+ return (Object.keys(SIZE_FALLBACK) as Complexity[]).find(
509
+ (size) => sizes?.[size] === model
510
+ );
511
+ };
512
+
513
+ const jobSpec = (policy: Policy, job: string) => {
514
+ const spec = policy.jobs[job];
515
+
516
+ if (spec === undefined) {
517
+ throw new Error(
518
+ `"${job}" is not a job type. Jobs: ${Object.keys(policy.jobs).join(", ")}.`
519
+ );
520
+ }
521
+
522
+ return spec;
523
+ };
524
+
525
+ const resolvePanelJob = (
526
+ role: Role,
527
+ job: string,
528
+ panel: readonly { model: string; reasoning: string }[],
529
+ { available, catalog, notes }: ResolveContext
530
+ ): Resolution => {
531
+ const targets: Target[] = [];
532
+
533
+ for (const seat of panel) {
534
+ if (available(family(seat.model))) {
535
+ const placed = placeEntry(
536
+ {
537
+ model: seat.model,
538
+ options: { reasoning: seat.reasoning },
539
+ providerInstanceId: catalog.inheritedProviderInstanceId ?? "",
540
+ },
541
+ catalog,
542
+ notes
543
+ );
544
+
545
+ if (placed !== undefined) {
546
+ targets.push(placed);
547
+ }
548
+ } else {
549
+ notes.push(`${family(seat.model)} is on an exhausted account`);
550
+ }
551
+ }
552
+
553
+ if (new Set(targets.map((target) => family(target.model))).size < 2) {
554
+ return {
555
+ kind: "blocked",
556
+ notes,
557
+ reason: `BLOCKED: independent review. The ${job} panel needs two model families that can run here.`,
558
+ role: role.role,
559
+ };
560
+ }
561
+
562
+ return { kind: "targets", notes, role: role.role, targets };
563
+ };
564
+
565
+ // The routing table: a job type and size pick the tier, model and reasoning.
566
+ // When that model's family is out, the same tier in the next family takes it,
567
+ // except that GPT only ever takes size S work.
568
+ const resolveJob = (
569
+ role: Role,
570
+ job: string,
571
+ size: JobSize | undefined,
572
+ explicit: readonly Entry[],
573
+ { available, catalog, notes, policy }: ResolveContext
574
+ ): Resolution => {
575
+ const spec = jobSpec(policy, job);
576
+
577
+ if ("panel" in spec) {
578
+ if (explicit.some((entry) => entry !== null)) {
579
+ return resolvePanel(role, explicit, "general", {
580
+ available,
581
+ catalog,
582
+ notes,
583
+ policy,
584
+ });
585
+ }
586
+
587
+ return resolvePanelJob(role, job, spec.panel, {
588
+ available,
589
+ catalog,
590
+ notes,
591
+ policy,
592
+ });
593
+ }
594
+
595
+ if (size === "L") {
596
+ throw new Error(
597
+ "Size L is too large to delegate: split the job into S or M tasks, or do it yourself."
598
+ );
599
+ }
600
+
601
+ if (size === undefined) {
602
+ throw new Error(`Job "${job}" needs a size: S or M.`);
603
+ }
604
+
605
+ const wanted = spec[size];
606
+ const sheetEntry = explicit[0] ?? null;
607
+
608
+ if (sheetEntry !== null && available(family(sheetEntry.model))) {
609
+ const placed = placeEntry(
610
+ {
611
+ ...sheetEntry,
612
+ options: { reasoning: wanted.reasoning, ...sheetEntry.options },
613
+ },
614
+ catalog,
615
+ notes
616
+ );
617
+
618
+ if (placed !== undefined) {
619
+ notes.push("the model sheet names this target");
620
+
621
+ return { kind: "targets", notes, role: role.role, targets: [placed] };
622
+ }
623
+ }
624
+
625
+ const wantedFamily = family(wanted.model);
626
+ const tier = tierOf(policy, wanted.model) ?? "bounded";
627
+ const { gpt } = policy.briefs;
628
+
629
+ const families = [
630
+ wantedFamily,
631
+ ...policy.routing.panel.filter((name) => name !== wantedFamily),
632
+ ].filter((name) => name !== gpt.family || size === gpt.size);
633
+
634
+ for (const name of families) {
635
+ if (available(name)) {
636
+ const model =
637
+ name === wantedFamily
638
+ ? wanted.model
639
+ : policy.routing.families[name]?.[tier];
640
+
641
+ const placed =
642
+ model === undefined
643
+ ? undefined
644
+ : placeEntry(
645
+ {
646
+ model,
647
+ options: { reasoning: wanted.reasoning },
648
+ providerInstanceId: catalog.inheritedProviderInstanceId ?? "",
649
+ },
650
+ catalog,
651
+ notes
652
+ );
653
+
654
+ if (placed !== undefined) {
655
+ if (name !== wantedFamily) {
656
+ notes.push(
657
+ `${wanted.model} is unavailable, so this ${job} ${size} job runs on ${placed.model}`
658
+ );
659
+ }
660
+
661
+ return { kind: "targets", notes, role: role.role, targets: [placed] };
662
+ }
663
+ } else {
664
+ notes.push(`${name} is on an exhausted account`);
665
+ }
666
+ }
667
+
668
+ return {
669
+ kind: "blocked",
670
+ notes,
671
+ reason: `No family that can take ${job} ${size} work is available. Wait for a reset or for /pstack-recovered.`,
672
+ role: role.role,
673
+ };
674
+ };
675
+
676
+ const resolveRole = (
677
+ roleName: string,
678
+ complexity: Complexity,
679
+ {
680
+ available,
681
+ catalog,
682
+ job,
683
+ policy,
684
+ sheet,
685
+ size,
686
+ }: {
687
+ available: (modelFamily: string) => boolean;
688
+ catalog: Catalog;
689
+ job?: string | undefined;
690
+ policy: Policy;
691
+ sheet: string;
692
+ size?: JobSize | undefined;
693
+ }
694
+ ): Resolution => {
695
+ const role = findRole(policy, roleName);
696
+ const notes: string[] = [];
697
+ const configured = sheetEntries(sheet, role) ?? [];
698
+ const context = { available, catalog, notes, policy };
699
+
700
+ if (job !== undefined) {
701
+ return resolveJob(role, job, size, configured, context);
702
+ }
703
+
704
+ if (role.tier === "panel") {
705
+ return resolvePanel(role, configured, complexity, context);
706
+ }
707
+
708
+ return resolveSingle(role, configured[0] ?? null, complexity, context);
709
+ };
710
+
711
+ const readPolicy = (): Policy => {
712
+ const policy = JSON.parse(readFileSync(policyPath(), "utf-8"));
713
+
714
+ if (!Value.Check(PolicySchema, policy)) {
715
+ throw new TypeError("models.json does not have the expected shape.");
716
+ }
717
+
718
+ return policy;
719
+ };
720
+
721
+ const readSheet = (): string => {
722
+ try {
723
+ return readFileSync(modelSheetPath(), "utf-8");
724
+ } catch {
725
+ return "";
726
+ }
727
+ };
728
+
729
+ const readCatalog = async (ctx: ExtensionToolContext): Promise<Catalog> => {
730
+ const name = ORCHESTRATOR_CAPABILITIES_TOOLS.find((candidate) =>
731
+ ctx.tools.some((tool) => tool.name === candidate)
732
+ );
733
+
734
+ if (name === undefined) {
735
+ throw new Error(
736
+ "T3's orchestrator_capabilities tool is not available in this session."
737
+ );
738
+ }
739
+
740
+ const outcome = await ctx.executeTool(name, {});
741
+
742
+ if (outcome.isError) {
743
+ throw new TypeError(
744
+ `orchestrator_capabilities failed: ${t3Text(outcome.result)}`
745
+ );
746
+ }
747
+
748
+ const catalog = t3Json(CatalogSchema, outcome.result);
749
+
750
+ if (catalog === undefined) {
751
+ throw new TypeError(
752
+ "orchestrator_capabilities did not return the expected shape."
753
+ );
754
+ }
755
+
756
+ return catalog;
757
+ };
758
+
759
+ const TextPartSchema = Type.Object({ text: Type.String() });
760
+
761
+ const partText = (part: string | UserMessage["content"][number]): string => {
762
+ if (Value.Check(Type.String(), part)) {
763
+ return part;
764
+ }
765
+
766
+ return Value.Check(TextPartSchema, part) ? part.text : "";
767
+ };
768
+
769
+ const textOf = (content: UserMessage["content"]): string =>
770
+ [content].flat().map(partText).join(" ");
771
+
772
+ const userWords = (ctx: ExtensionContext): string =>
773
+ ctx.sessionManager
774
+ .getBranch()
775
+ .map((entry) =>
776
+ entry.type === "message" && entry.message.role === "user"
777
+ ? textOf(entry.message.content)
778
+ : ""
779
+ )
780
+ .join(" ")
781
+ .toLowerCase();
782
+
783
+ const sheetText = (): string => readSheet().toLowerCase();
784
+
785
+ const RequestedTargetSchema = Type.Object({
786
+ model: Type.String(),
787
+ options: Type.Optional(
788
+ Type.Union([
789
+ Type.Array(
790
+ Type.Object({
791
+ id: Type.String(),
792
+ value: Type.Union([Type.String(), Type.Boolean()]),
793
+ })
794
+ ),
795
+ Type.Record(Type.String(), Type.Union([Type.String(), Type.Boolean()])),
796
+ ])
797
+ ),
798
+ providerInstanceId: Type.Optional(Type.Unknown()),
799
+ });
800
+
801
+ const requestedOptions = (
802
+ options: Static<typeof RequestedTargetSchema>["options"]
803
+ ): [string, string][] => {
804
+ if (options === undefined) {
805
+ return [];
806
+ }
807
+
808
+ if (Array.isArray(options)) {
809
+ return options.map((option) => [option.id, String(option.value)]);
810
+ }
811
+
812
+ return Object.entries(options).map(([id, value]) => [id, String(value)]);
813
+ };
814
+
815
+ const allowedBy = (
816
+ words: readonly string[],
817
+ sheetMention: string,
818
+ { sheet, user }: { sheet: string; user: string }
819
+ ): boolean =>
820
+ sheet.includes(sheetMention.toLowerCase()) ||
821
+ words.some((word) => user.includes(word.toLowerCase()));
822
+
823
+ // The user's latest message, if it is exactly an approval line such as
824
+ // "allow xhigh", unlocks those reasoning levels until their next message. A
825
+ // delegated child never unlocks them: its user messages come from the parent.
826
+ const approvedLevels = (
827
+ ctx: ExtensionContext,
828
+ policy: Policy
829
+ ): readonly string[] => {
830
+ if (sessionBrief(ctx) !== undefined) {
831
+ return [];
832
+ }
833
+
834
+ const latest = ctx.sessionManager
835
+ .getBranch()
836
+ .findLast(
837
+ (entry) => entry.type === "message" && entry.message.role === "user"
838
+ );
839
+
840
+ if (latest?.type !== "message" || latest.message.role !== "user") {
841
+ return [];
842
+ }
843
+
844
+ const said = textOf(latest.message.content)
845
+ .replaceAll(/<!--[\s\S]*?-->/gu, "")
846
+ .replaceAll(/<t3_context[\s\S]*?<\/t3_context>/gu, "")
847
+ .trim()
848
+ .toLowerCase()
849
+ .replace(/[.!]+$/u, "");
850
+
851
+ return policy.routing.approval[said] ?? [];
852
+ };
853
+
854
+ const reasoningOf = (
855
+ options: TargetOptions | [string, string][]
856
+ ): string | undefined => {
857
+ const pairs = Array.isArray(options) ? options : Object.entries(options);
858
+
859
+ const reasoning = pairs.find(([id]) =>
860
+ /thinking|effort|reasoning/iu.test(id)
861
+ )?.[1];
862
+
863
+ return reasoning === undefined ? undefined : String(reasoning);
864
+ };
865
+
866
+ const routingViolation = (
867
+ target: Static<typeof RequestedTargetSchema>,
868
+ policy: Policy,
869
+ allow: { approved: readonly string[]; sheet: string; user: string }
870
+ ): string | undefined => {
871
+ const model = lastSegment(target.model);
872
+
873
+ const reserved = policy.routing.reserved.find(
874
+ (entry) => entry.model === model
875
+ );
876
+
877
+ if (reserved !== undefined && !allowedBy(reserved.words, model, allow)) {
878
+ return `${model} is reserved for work where the user asked for it by name. Use pstack_model, or ask the user.`;
879
+ }
880
+
881
+ for (const [id, value] of requestedOptions(target.options)) {
882
+ if (
883
+ policy.routing.aboveHigh.some((entry) => entry.level === value) &&
884
+ !allow.approved.includes(value)
885
+ ) {
886
+ return `Reasoning above high (${id}=${value}) needs the user to send "allow xhigh" as their message in this chat. Use high or lower, or ask the user.`;
887
+ }
888
+
889
+ const fast =
890
+ policy.routing.fast.options.includes(id) &&
891
+ value !== "false" &&
892
+ value !== "default";
893
+
894
+ if (
895
+ fast &&
896
+ !allowedBy(policy.routing.fast.words, `${id}=${value}`, allow)
897
+ ) {
898
+ return `${id}=${value} is a speed option, and standard speed applies unless the user asks for fast mode.`;
899
+ }
900
+ }
901
+
902
+ return undefined;
903
+ };
904
+
905
+ const ComplexityOrJob = Type.Object({
906
+ complexity: Type.Optional(ComplexitySchema),
907
+ job: Type.Optional(
908
+ Type.String({
909
+ description:
910
+ "The job type from the routing table: mechanical, check, research, implement, hard, review, or design.",
911
+ })
912
+ ),
913
+ role: Type.String({ description: "The pstack role name.", minLength: 1 }),
914
+ size: Type.Optional(
915
+ Type.Union([Type.Literal("S"), Type.Literal("M"), Type.Literal("L")], {
916
+ description:
917
+ "S: 30 min or less and 5 files or fewer. M: 90 min or less and 15 files or fewer. L is refused: split it.",
918
+ })
919
+ ),
920
+ });
921
+
922
+ const modelTool = (pi: ExtensionAPI) =>
923
+ defineTool({
924
+ annotations: { readOnlyHint: true },
925
+ description:
926
+ "Resolve the delegate_task target for a pstack role. Pass the role name with the job and size from the routing table, or the complexity when there is no job. Pass each returned target as delegate_task's target. kind inherit-parent means omit target, and kind blocked means the role cannot run.",
927
+ execute: async (_toolCallId, params, _signal, _onUpdate, ctx) => {
928
+ await settleChildren(pi, ctx);
929
+
930
+ const accounts = readAccounts(ctx);
931
+
932
+ const resolution = resolveRole(
933
+ params.role,
934
+ params.complexity ?? "general",
935
+ {
936
+ available: (modelFamily) => familyAvailable(accounts, modelFamily),
937
+ catalog: await readCatalog(ctx),
938
+ job: params.job,
939
+ policy: readPolicy(),
940
+ sheet: readSheet(),
941
+ size: params.size,
942
+ }
943
+ );
944
+
945
+ if (resolution.kind === "targets") {
946
+ pi.appendEntry(RESOLVED_ENTRY, {
947
+ targets: resolution.targets.map((target) => ({
948
+ model: target.model,
949
+ options: target.options,
950
+ providerInstanceId: target.providerInstanceId,
951
+ })),
952
+ });
953
+ }
954
+
955
+ return {
956
+ content: [{ text: JSON.stringify(resolution, null, 2), type: "text" }],
957
+ details: resolution,
958
+ structuredContent: resolution,
959
+ };
960
+ },
961
+ label: "Pstack model",
962
+ name: "pstack_model",
963
+ outputSchema: ResolutionSchema,
964
+ parameters: ComplexityOrJob,
965
+ promptSnippet: "Resolve the delegate_task target for a pstack role.",
966
+ });
967
+
968
+ const ResolvedSchema = Type.Object({
969
+ targets: Type.Array(
970
+ Type.Object({
971
+ model: Type.String(),
972
+ options: Type.Optional(Type.Record(Type.String(), OptionValueSchema)),
973
+ providerInstanceId: Type.String(),
974
+ })
975
+ ),
976
+ });
977
+
978
+ // The reasoning levels pstack_model returned for this target, or undefined
979
+ // when it never returned the target.
980
+ const resolvedReasoning = (
981
+ ctx: ExtensionContext,
982
+ target: Static<typeof RequestedTargetSchema>
983
+ ): (string | undefined)[] | undefined => {
984
+ const matches = ctx.sessionManager
985
+ .getBranch()
986
+ .flatMap((entry) =>
987
+ entry.type === "custom" &&
988
+ entry.customType === RESOLVED_ENTRY &&
989
+ Value.Check(ResolvedSchema, entry.data)
990
+ ? entry.data.targets.filter(
991
+ (resolved) =>
992
+ resolved.model === target.model &&
993
+ resolved.providerInstanceId === target.providerInstanceId
994
+ )
995
+ : []
996
+ );
997
+
998
+ return matches.length === 0
999
+ ? undefined
1000
+ : matches.map((resolved) => reasoningOf(resolved.options ?? {}));
1001
+ };
1002
+
1003
+ const namedByUser = (
1004
+ target: Static<typeof RequestedTargetSchema>,
1005
+ policy: Policy,
1006
+ allow: { sheet: string; user: string }
1007
+ ): boolean => {
1008
+ const model = lastSegment(target.model).toLowerCase();
1009
+
1010
+ const words = [
1011
+ model,
1012
+ ...(policy.routing.reserved.find((entry) => entry.model === model)?.words ??
1013
+ []),
1014
+ ];
1015
+
1016
+ return allowedBy(words, model, allow);
1017
+ };
1018
+
1019
+ const aboveResolved = (
1020
+ requested: string | undefined,
1021
+ resolved: readonly (string | undefined)[],
1022
+ policy: Policy
1023
+ ): string | undefined => {
1024
+ if (requested === undefined || resolved.includes(undefined)) {
1025
+ return undefined;
1026
+ }
1027
+
1028
+ const rank = (level: string | undefined) =>
1029
+ level === undefined ? -1 : policy.routing.levels.indexOf(level);
1030
+
1031
+ let [ceiling] = resolved;
1032
+
1033
+ for (const level of resolved) {
1034
+ if (rank(level) > rank(ceiling)) {
1035
+ ceiling = level;
1036
+ }
1037
+ }
1038
+
1039
+ return rank(requested) > rank(ceiling) ? ceiling : undefined;
1040
+ };
1041
+
1042
+ const targetProblems = (
1043
+ target: Static<typeof RequestedTargetSchema>,
1044
+ ctx: ExtensionContext,
1045
+ policy: Policy,
1046
+ allow: { approved: readonly string[]; sheet: string; user: string }
1047
+ ): string | undefined => {
1048
+ const unavailable = unavailableReason(
1049
+ readAccounts(ctx),
1050
+ family(target.model)
1051
+ );
1052
+
1053
+ if (unavailable !== undefined) {
1054
+ return unavailable;
1055
+ }
1056
+
1057
+ const violation = routingViolation(target, policy, allow);
1058
+
1059
+ if (violation !== undefined) {
1060
+ return violation;
1061
+ }
1062
+
1063
+ const resolved = resolvedReasoning(ctx, target);
1064
+
1065
+ if (resolved === undefined) {
1066
+ return namedByUser(target, policy, allow)
1067
+ ? undefined
1068
+ : `${target.providerInstanceId}/${target.model} did not come from pstack_model, and the user did not name it. Call pstack_model for the job, or omit target to run on the parent model.`;
1069
+ }
1070
+
1071
+ const requested = reasoningOf(requestedOptions(target.options));
1072
+ const ceiling = aboveResolved(requested, resolved, policy);
1073
+
1074
+ if (ceiling !== undefined && !allow.approved.includes(requested ?? "")) {
1075
+ return `Reasoning ${requested} is above what pstack_model returned for this job (${ceiling}). Use ${ceiling} or lower, or ask the user to send "allow xhigh".`;
1076
+ }
1077
+
1078
+ return undefined;
1079
+ };
1080
+
1081
+ const DelegateArgsSchema = Type.Object({
1082
+ isolation: Type.Optional(Type.Union([Type.String(), Type.Null()])),
1083
+ mode: Type.Optional(Type.Union([Type.String(), Type.Null()])),
1084
+ task: Type.String(),
1085
+ });
1086
+
1087
+ // GPT drifts on long or open work and leaves files behind, so it only gets
1088
+ // small, bounded jobs in a worktree of its own.
1089
+ const gptProblems = (
1090
+ args: Static<typeof DelegateArgsSchema>,
1091
+ policy: Policy
1092
+ ): string[] => {
1093
+ const rules = policy.briefs.gpt;
1094
+ const brief = parseBrief(args.task);
1095
+ const problems: string[] = [];
1096
+
1097
+ if (args.isolation !== "worktree") {
1098
+ problems.push(
1099
+ 'GPT work runs in its own checkout: set isolation: "worktree".'
1100
+ );
1101
+ }
1102
+
1103
+ if (args.mode === "wait") {
1104
+ problems.push('GPT work runs with mode: "async".');
1105
+ }
1106
+
1107
+ if (brief === undefined) {
1108
+ return problems;
1109
+ }
1110
+
1111
+ if (brief.size !== undefined && brief.size !== rules.size) {
1112
+ problems.push(
1113
+ `GPT takes only size ${rules.size} work. Route this job with pstack_model.`
1114
+ );
1115
+ }
1116
+
1117
+ if (brief.minutes !== undefined && brief.minutes > rules.minutes) {
1118
+ problems.push(`GPT work allows at most ${rules.minutes} min.`);
1119
+ }
1120
+
1121
+ if (brief.diskMb !== undefined && brief.diskMb > rules.diskMb) {
1122
+ problems.push(`GPT work allows at most ${rules.diskMb} MB of disk.`);
1123
+ }
1124
+
1125
+ if (
1126
+ brief.files.some((file) => file.startsWith("/") || file.startsWith("~"))
1127
+ ) {
1128
+ problems.push(
1129
+ 'GPT file paths in "Files you may write" must be relative to its worktree.'
1130
+ );
1131
+ }
1132
+
1133
+ return problems;
1134
+ };
1135
+
1136
+ const SEND_TOOLS: ReadonlySet<string> = new Set([
1137
+ "mcp__t3-code__t3_thread_send",
1138
+ "mcp__t3__t3_thread_send",
1139
+ ]);
1140
+
1141
+ const policyFamilies = (): readonly string[] =>
1142
+ Object.keys(readPolicy().routing.families);
1143
+
1144
+ const TargetInputSchema = Type.Object({ target: RequestedTargetSchema });
1145
+
1146
+ const SendInputSchema = Type.Object({ message: Type.String() });
1147
+
1148
+ const requestedFamily = (
1149
+ requested: Static<typeof RequestedTargetSchema> | undefined,
1150
+ ctx: ExtensionContext
1151
+ ): string | undefined => {
1152
+ if (requested !== undefined) {
1153
+ return family(requested.model);
1154
+ }
1155
+
1156
+ return ctx.model === undefined ? undefined : family(ctx.model.id);
1157
+ };
1158
+
1159
+ interface DelegateRequest {
1160
+ readonly args: Static<typeof DelegateArgsSchema> | undefined;
1161
+ readonly requested: Static<typeof RequestedTargetSchema> | undefined;
1162
+ }
1163
+
1164
+ const delegateProblems = (
1165
+ { args, requested }: DelegateRequest,
1166
+ ctx: ExtensionContext
1167
+ ): string[] => {
1168
+ const policy = readPolicy();
1169
+
1170
+ const allow = {
1171
+ approved: approvedLevels(ctx, policy),
1172
+ sheet: sheetText(),
1173
+ user: userWords(ctx),
1174
+ };
1175
+
1176
+ const problems: string[] = [];
1177
+
1178
+ if (requested !== undefined) {
1179
+ const problem = targetProblems(requested, ctx, policy, allow);
1180
+
1181
+ if (problem !== undefined) {
1182
+ problems.push(problem);
1183
+ }
1184
+ }
1185
+
1186
+ if (args === undefined) {
1187
+ return [...problems, "delegate_task needs a task brief."];
1188
+ }
1189
+
1190
+ problems.push(
1191
+ ...briefProblems(args.task, {
1192
+ jobs: Object.keys(policy.jobs),
1193
+ noWrites: policy.briefs.noWrites,
1194
+ sizes: policy.briefs.sizes,
1195
+ })
1196
+ );
1197
+
1198
+ const childFamily = requestedFamily(requested, ctx);
1199
+
1200
+ if (childFamily === policy.briefs.gpt.family) {
1201
+ problems.push(...gptProblems(args, policy));
1202
+ }
1203
+
1204
+ return problems;
1205
+ };
1206
+
1207
+ export const registerModelRouting = (pi: ExtensionAPI): void => {
1208
+ pi.registerTool(modelTool(pi));
1209
+ registerAccounts(pi, policyFamilies);
1210
+
1211
+ pi.on("tool_call", (event, ctx) => {
1212
+ const { input } = event;
1213
+
1214
+ if (SEND_TOOLS.has(event.toolName)) {
1215
+ const message = Value.Check(SendInputSchema, input) ? input.message : "";
1216
+
1217
+ if (APPROVAL_LINE.test(message) || PSTACK_COMMAND.test(message)) {
1218
+ return {
1219
+ block: true,
1220
+ reason:
1221
+ 'A message to a child cannot carry the user\'s approval ("allow xhigh") or /pstack- commands.',
1222
+ };
1223
+ }
1224
+
1225
+ return;
1226
+ }
1227
+
1228
+ if (!DELEGATE_TOOLS.has(event.toolName)) {
1229
+ return;
1230
+ }
1231
+
1232
+ const problems = delegateProblems(
1233
+ {
1234
+ args: Value.Check(DelegateArgsSchema, input) ? input : undefined,
1235
+ requested: Value.Check(TargetInputSchema, input)
1236
+ ? input.target
1237
+ : undefined,
1238
+ },
1239
+ ctx
1240
+ );
1241
+
1242
+ if (problems.length > 0) {
1243
+ return {
1244
+ block: true,
1245
+ reason: `delegate_task refused. Fix all of these and call it again:\n- ${problems.join("\n- ")}`,
1246
+ };
1247
+ }
1248
+ });
1249
+ };