@justjoshn/pi-pstack 0.0.0-stage → 0.15.36-pi.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/LICENSE +21 -0
- package/README.md +98 -2
- package/agents/ci-watcher.md +27 -0
- package/agents/comment-sicko.md +32 -0
- package/agents/poteto-agent.md +9 -0
- package/agents/thermo-nuclear-code-quality-review.md +23 -0
- package/assets/logo.png +0 -0
- package/automations/benny/FOR_AGENTS.md +82 -0
- package/automations/benny/README.md +20 -0
- package/automations/benny/skills/reproduce-and-fix-issues/SKILL.md +310 -0
- package/automations/benny/skills/reproduce-and-fix-issues/references/control-adapter.md +169 -0
- package/automations/benny/skills/reproduce-and-fix-issues/references/feature-map.example.md +205 -0
- package/automations/benny/skills/reproduce-and-fix-issues/references/verify-existing-fix.md +93 -0
- package/automations/benny/skills/setup-benny/SKILL.md +253 -0
- package/automations/benny/skills/triage-issue-reports/SKILL.md +240 -0
- package/automations/benny/skills/triage-issue-reports/references/routing.example.md +61 -0
- package/automations/benny/templates/configuration.example.yaml +113 -0
- package/automations/benny/templates/reproduce-automation-prompt.md +49 -0
- package/automations/benny/templates/triage-automation-prompt.md +53 -0
- package/bin/pstack-routines-supervisor +9 -0
- package/docs/guide/01-setup.md +67 -0
- package/docs/guide/02-poteto-mode.md +139 -0
- package/docs/guide/03-understand.md +79 -0
- package/docs/guide/04-design.md +133 -0
- package/docs/guide/05-build-and-clean.md +83 -0
- package/docs/guide/06-verify-and-ship.md +162 -0
- package/docs/guide/07-overnight.md +122 -0
- package/docs/guide/08-principles.md +72 -0
- package/docs/guide/09-make-it-yours.md +100 -0
- package/docs/guide/10-recipes-and-pitfalls.md +182 -0
- package/docs/guide/README.md +38 -0
- package/docs/guide/images/design.jpg +0 -0
- package/docs/guide/images/overnight.jpg +0 -0
- package/docs/guide/images/recipes.jpg +0 -0
- package/docs/guide/images/router.jpg +0 -0
- package/docs/guide/images/understanding.jpg +0 -0
- package/docs/guide/images/verification.jpg +0 -0
- package/docs/native-gaps.md +73 -0
- package/docs/parity-reverse-engineering.md +94 -0
- package/licenses/cursor-team-kit.LICENSE +21 -0
- package/licenses/pstack.LICENSE +21 -0
- package/package.json +86 -4
- package/packaging/install-supervisor-unit.sh +164 -0
- package/packaging/launchd/com.pstack.routines-supervisor.plist.example +24 -0
- package/packaging/systemd/pstack-routines-supervisor.service.example +15 -0
- package/skills/architect/SKILL.md +79 -0
- package/skills/architect/references/design-red-flags.md +57 -0
- package/skills/architect/references/rationale-template.md +35 -0
- package/skills/architect/references/runner-prompt.md +20 -0
- package/skills/arena/SKILL.md +48 -0
- package/skills/automate-me/SKILL.md +104 -0
- package/skills/benchmark-checklist/SKILL.md +39 -0
- package/skills/blast-radius/SKILL.md +50 -0
- package/skills/bro/SKILL.md +7 -0
- package/skills/check-compiler-errors/SKILL.md +23 -0
- package/skills/control-cli/SKILL.md +109 -0
- package/skills/control-ui/SKILL.md +109 -0
- package/skills/correct/SKILL.md +32 -0
- package/skills/create-formal-verification-skill/SKILL.md +43 -0
- package/skills/create-skill/SKILL.md +548 -0
- package/skills/create-verification-skill/SKILL.md +44 -0
- package/skills/create-verification-skill/references/feature-map-example/README.md +47 -0
- package/skills/create-verification-skill/references/feature-map-example/create-note.md +39 -0
- package/skills/create-verification-skill/references/feature-map-example/search.md +45 -0
- package/skills/deslop/SKILL.md +22 -0
- package/skills/figure-it-out/SKILL.md +52 -0
- package/skills/fix-ci/SKILL.md +29 -0
- package/skills/fix-merge-conflicts/SKILL.md +32 -0
- package/skills/get-pr-comments/SKILL.md +23 -0
- package/skills/how/SKILL.md +36 -0
- package/skills/how/references/explainer-prompt.md +55 -0
- package/skills/how/references/explorer-prompt.md +35 -0
- package/skills/in-your-own-words/SKILL.md +7 -0
- package/skills/interrogate/SKILL.md +31 -0
- package/skills/ketchup/SKILL.md +43 -0
- package/skills/ketchup-video/SKILL.md +29 -0
- package/skills/loop-on-ci/SKILL.md +50 -0
- package/skills/maintain-formal-verification-skill/SKILL.md +58 -0
- package/skills/maintain-verification-skill/SKILL.md +39 -0
- package/skills/make-bot-ui/SKILL.md +104 -0
- package/skills/make-pr-easy-to-review/SKILL.md +59 -0
- package/skills/new-branch-and-pr/SKILL.md +29 -0
- package/skills/no-comments/SKILL.md +24 -0
- package/skills/no-inline-imports/SKILL.md +12 -0
- package/skills/poteto-help/SKILL.md +161 -0
- package/skills/poteto-help/references/prompting.md +51 -0
- package/skills/poteto-help/references/recipes.md +51 -0
- package/skills/poteto-mode/SKILL.md +151 -0
- package/skills/poteto-mode/playbooks/authoring-a-skill.md +12 -0
- package/skills/poteto-mode/playbooks/autonomous-run.md +13 -0
- package/skills/poteto-mode/playbooks/autopilot-full.md +25 -0
- package/skills/poteto-mode/playbooks/autopilot-stack.md +8 -0
- package/skills/poteto-mode/playbooks/babysit.md +23 -0
- package/skills/poteto-mode/playbooks/bug-fix.md +15 -0
- package/skills/poteto-mode/playbooks/eval.md +25 -0
- package/skills/poteto-mode/playbooks/feature.md +21 -0
- package/skills/poteto-mode/playbooks/hillclimb.md +21 -0
- package/skills/poteto-mode/playbooks/investigation.md +14 -0
- package/skills/poteto-mode/playbooks/multi-phase-plan.md +155 -0
- package/skills/poteto-mode/playbooks/opening-a-pr.md +34 -0
- package/skills/poteto-mode/playbooks/orchestrate.md +25 -0
- package/skills/poteto-mode/playbooks/pause-safely.md +10 -0
- package/skills/poteto-mode/playbooks/perf-issue.md +25 -0
- package/skills/poteto-mode/playbooks/prototype.md +14 -0
- package/skills/poteto-mode/playbooks/refactoring.md +16 -0
- package/skills/poteto-mode/playbooks/runtime-forensics.md +11 -0
- package/skills/poteto-mode/playbooks/session-pickup.md +11 -0
- package/skills/poteto-mode/playbooks/shipping.md +12 -0
- package/skills/poteto-mode/playbooks/trace-forensics.md +14 -0
- package/skills/poteto-mode/playbooks/visual-parity.md +11 -0
- package/skills/poteto-mode/playbooks/worktree-cleanup.md +12 -0
- package/skills/poteto-mode/references/bugbot-triage.md +142 -0
- package/skills/poteto-mode/scripts/bootstrap.ts +62 -0
- package/skills/poteto-mode/scripts/bun.lock +67 -0
- package/skills/poteto-mode/scripts/check-plan.mjs +205 -0
- package/skills/poteto-mode/scripts/check-plan.test.ts +110 -0
- package/skills/poteto-mode/scripts/package.json +16 -0
- package/skills/poteto-mode/scripts/watch-pr/cli.test.ts +224 -0
- package/skills/poteto-mode/scripts/watch-pr/cli.ts +223 -0
- package/skills/poteto-mode/scripts/watch-pr/fakes.test-helper.ts +129 -0
- package/skills/poteto-mode/scripts/watch-pr/github.test.ts +498 -0
- package/skills/poteto-mode/scripts/watch-pr/github.ts +726 -0
- package/skills/poteto-mode/scripts/watch-pr/policy.test.ts +482 -0
- package/skills/poteto-mode/scripts/watch-pr/policy.ts +842 -0
- package/skills/poteto-mode/scripts/watch-pr/render.ts +169 -0
- package/skills/poteto-mode/scripts/watch-pr/tsconfig.json +13 -0
- package/skills/poteto-mode/scripts/watch-pr/types.compile.ts +93 -0
- package/skills/poteto-mode/scripts/watch-pr/types.ts +414 -0
- package/skills/poteto-mode/scripts/watch-pr/watch-pr +6 -0
- package/skills/poteto-mode/scripts/worktree-audit.sh +156 -0
- package/skills/pr-review-canvas/SKILL.md +176 -0
- package/skills/pr-review-canvas/renderer.js +170 -0
- package/skills/pr-review-canvas/styles.css +96 -0
- package/skills/pr-review-canvas/template.html +18 -0
- package/skills/principle-attack-the-premise/SKILL.md +21 -0
- package/skills/principle-boundary-discipline/SKILL.md +34 -0
- package/skills/principle-build-the-lever/SKILL.md +23 -0
- package/skills/principle-encode-lessons-in-structure/SKILL.md +11 -0
- package/skills/principle-exhaust-the-design-space/SKILL.md +9 -0
- package/skills/principle-experience-first/SKILL.md +19 -0
- package/skills/principle-explain-the-number/SKILL.md +18 -0
- package/skills/principle-fix-root-causes/SKILL.md +21 -0
- package/skills/principle-foundational-thinking/SKILL.md +21 -0
- package/skills/principle-guard-the-context-window/SKILL.md +12 -0
- package/skills/principle-laziness-protocol/SKILL.md +10 -0
- package/skills/principle-make-operations-idempotent/SKILL.md +22 -0
- package/skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md +14 -0
- package/skills/principle-minimize-reader-load/SKILL.md +18 -0
- package/skills/principle-model-the-domain/SKILL.md +24 -0
- package/skills/principle-never-block-on-the-human/SKILL.md +15 -0
- package/skills/principle-outcome-oriented-execution/SKILL.md +21 -0
- package/skills/principle-prove-it-works/SKILL.md +22 -0
- package/skills/principle-redesign-from-first-principles/SKILL.md +16 -0
- package/skills/principle-separate-before-serializing-shared-state/SKILL.md +16 -0
- package/skills/principle-sequence-verifiable-units/SKILL.md +17 -0
- package/skills/principle-subtract-before-you-add/SKILL.md +18 -0
- package/skills/principle-test-behavior-not-implementation/SKILL.md +20 -0
- package/skills/principle-type-system-discipline/SKILL.md +13 -0
- package/skills/recall/SKILL.md +35 -0
- package/skills/reflect/SKILL.md +69 -0
- package/skills/reflect/references/divergent-reviewer.md +38 -0
- package/skills/reflect/references/judgment-reviewer.md +37 -0
- package/skills/reflect/references/synthesizer.md +56 -0
- package/skills/reflect/references/tooling-reviewer.md +48 -0
- package/skills/review-and-ship/SKILL.md +41 -0
- package/skills/run-smoke-tests/SKILL.md +42 -0
- package/skills/setup-pstack/SKILL.md +74 -0
- package/skills/sharpen/SKILL.md +16 -0
- package/skills/show-me-your-work/SKILL.md +82 -0
- package/skills/show-me-your-work/references/decision-log-template.tsv +1 -0
- package/skills/show-me-your-work/scripts/log.sh +42 -0
- package/skills/statechart/SKILL.md +82 -0
- package/skills/statechart/references/render.md +93 -0
- package/skills/statechart/scripts/backends/cfg.ts +33 -0
- package/skills/statechart/scripts/backends/mermaid.ts +201 -0
- package/skills/statechart/scripts/backends/plain-text.ts +72 -0
- package/skills/statechart/scripts/backends/report.ts +177 -0
- package/skills/statechart/scripts/frontends/config.ts +276 -0
- package/skills/statechart/scripts/frontends/dot.ts +74 -0
- package/skills/statechart/scripts/frontends/marks.ts +93 -0
- package/skills/statechart/scripts/frontends/messages.ts +52 -0
- package/skills/statechart/scripts/frontends/spec.ts +114 -0
- package/skills/statechart/scripts/frontends/trace.ts +24 -0
- package/skills/statechart/scripts/frontends/value.ts +166 -0
- package/skills/statechart/scripts/frontends/verdict.ts +40 -0
- package/skills/statechart/scripts/frontends/view.ts +119 -0
- package/skills/statechart/scripts/ir.ts +547 -0
- package/skills/statechart/scripts/package.json +11 -0
- package/skills/statechart/scripts/passes/annotate.ts +128 -0
- package/skills/statechart/scripts/passes/label.ts +269 -0
- package/skills/statechart/scripts/passes/lift.ts +85 -0
- package/skills/statechart/scripts/passes/loop-check.ts +68 -0
- package/skills/statechart/scripts/passes/paths.ts +60 -0
- package/skills/statechart/scripts/passes/reach.ts +135 -0
- package/skills/statechart/scripts/passes/region-check.ts +97 -0
- package/skills/statechart/scripts/passes/regions.ts +295 -0
- package/skills/statechart/scripts/pipeline.ts +76 -0
- package/skills/statechart/scripts/run.ts +481 -0
- package/skills/statechart/scripts/statechart +29 -0
- package/skills/statechart/scripts/statechart.ts +164 -0
- package/skills/statechart/scripts/test/ConfigOracle.java +63 -0
- package/skills/statechart/scripts/test/chart.test.ts +1210 -0
- package/skills/statechart/scripts/test/charts/Braces.mmd +7 -0
- package/skills/statechart/scripts/test/charts/Escapes.mmd +11 -0
- package/skills/statechart/scripts/test/charts/Phases.mmd +29 -0
- package/skills/statechart/scripts/test/cli.test.ts +1314 -0
- package/skills/statechart/scripts/test/config-fuzz.test.ts +263 -0
- package/skills/statechart/scripts/test/corpus/Counter/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/Counter/Counter.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/Counter/Counter.tla +10 -0
- package/skills/statechart/scripts/test/corpus/Counter/chart.mmd +9 -0
- package/skills/statechart/scripts/test/corpus/Counter/graph.dot +16 -0
- package/skills/statechart/scripts/test/corpus/Counter/report.md +7 -0
- package/skills/statechart/scripts/test/corpus/Counter/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/Counter/verdict-1.out +49 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/ChartRun.out +60 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/CounterAction.cfg +4 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/CounterAction.tla +22 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/chart.mmd +26 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/graph.dot +19 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/report.md +20 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/verdict-1.out +56 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/verdict-2.out +82 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/verdict-3.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/ChartRun.out +59 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/CounterDeadlock.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/CounterDeadlock.tla +11 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/chart.mmd +22 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/graph.dot +16 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/report.md +17 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-1.out +56 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-2.out +77 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/ChartRun.out +69 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/CounterFan.cfg +2 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/CounterFan.tla +11 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/chart.mmd +85 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/graph.dot +70 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/report.md +12 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/verdict-1.out +67 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/verdict-2.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/ChartRun.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/ChartRun.out +85 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/CounterGuard.cfg +6 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/CounterGuard.tla +13 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/chart.mmd +5 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/graph.dot +10 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/report.md +31 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/verdict-1.out +64 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/verdict-2.out +77 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/ChartRun.out +55 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/CounterInitPast.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/CounterInitPast.tla +10 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/chart.mmd +12 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/graph.dot +6 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/report.md +12 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/verdict-1.out +33 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/verdict-2.out +54 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/ChartRun.out +54 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/CounterInitPastHolds.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/CounterInitPastHolds.tla +10 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/chart.mmd +1 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/graph.dot +6 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/report.md +7 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/verdict-1.out +46 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/ChartRun.out +59 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/CounterInstance.cfg +2 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/CounterInstance.tla +10 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/CounterSteps.tla +6 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/chart.mmd +17 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/graph.dot +15 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/report.md +14 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/sany.out +3 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/verdict-1.out +78 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/ChartRun.out +59 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/CounterJump.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/CounterJump.tla +19 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/chart.mmd +26 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/graph.dot +22 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/report.md +12 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/verdict-1.out +58 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/verdict-2.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/CounterLoop.cfg +2 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/CounterLoop.tla +11 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/chart.mmd +17 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/graph.dot +15 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/report.md +14 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/verdict-1.out +76 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/ChartRun.out +59 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/CounterOrder.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/CounterOrder.tla +11 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/chart.mmd +19 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/graph.dot +10 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/report.md +15 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/verdict-1.out +56 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/verdict-2.out +67 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/ChartRun.out +62 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/CounterRules.cfg +6 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/CounterRules.tla +24 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/Moves.tla +5 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/chart.mmd +22 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/graph.dot +10 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/report.md +23 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/sany.out +3 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/verdict-1.out +58 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/verdict-2.out +66 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/verdict-3.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/verdict-3.out +74 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/verdict-4.out +59 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/ChartRun.out +58 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/CounterStart.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/CounterStart.tla +15 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/chart.mmd +18 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/graph.dot +13 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/report.md +11 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/verdict-1.out +33 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/verdict-2.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterStop/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterStop/CounterStop.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/CounterStop/CounterStop.tla +15 -0
- package/skills/statechart/scripts/test/corpus/CounterStop/chart.mmd +7 -0
- package/skills/statechart/scripts/test/corpus/CounterStop/graph.dot +13 -0
- package/skills/statechart/scripts/test/corpus/CounterStop/report.md +6 -0
- package/skills/statechart/scripts/test/corpus/CounterStop/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterStop/verdict-1.out +49 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/ChartRun.out +61 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/CounterTie.cfg +4 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/CounterTie.tla +14 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/chart.mmd +30 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/graph.dot +19 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/report.md +27 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/verdict-1.out +56 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/verdict-2.out +64 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/verdict-3.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/verdict-3.out +87 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/verdict-4.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/ChartRun.out +60 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/CounterTieInGraph.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/CounterTieInGraph.tla +12 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/chart.mmd +23 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/graph.dot +19 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/report.md +11 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/verdict-1.out +56 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/verdict-2.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterView/ChartRun.out +61 -0
- package/skills/statechart/scripts/test/corpus/CounterView/CounterView.cfg +4 -0
- package/skills/statechart/scripts/test/corpus/CounterView/CounterView.tla +14 -0
- package/skills/statechart/scripts/test/corpus/CounterView/chart.mmd +23 -0
- package/skills/statechart/scripts/test/corpus/CounterView/graph.dot +19 -0
- package/skills/statechart/scripts/test/corpus/CounterView/report.md +27 -0
- package/skills/statechart/scripts/test/corpus/CounterView/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterView/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterView/verdict-1.out +56 -0
- package/skills/statechart/scripts/test/corpus/CounterView/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterView/verdict-2.out +64 -0
- package/skills/statechart/scripts/test/corpus/CounterView/verdict-3.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterView/verdict-3.out +87 -0
- package/skills/statechart/scripts/test/corpus/CounterView/verdict-4.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterView/view.mjs +1 -0
- package/skills/statechart/scripts/test/corpus/DieHard/ChartRun.out +59 -0
- package/skills/statechart/scripts/test/corpus/DieHard/DieHard.cfg +4 -0
- package/skills/statechart/scripts/test/corpus/DieHard/DieHard.tla +38 -0
- package/skills/statechart/scripts/test/corpus/DieHard/chart.mmd +92 -0
- package/skills/statechart/scripts/test/corpus/DieHard/graph.dot +126 -0
- package/skills/statechart/scripts/test/corpus/DieHard/report.md +17 -0
- package/skills/statechart/scripts/test/corpus/DieHard/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/DieHard/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/DieHard/verdict-1.out +91 -0
- package/skills/statechart/scripts/test/corpus/DieHard/verdict-2.out +57 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/ChartRun.out +61 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/FirstRule.cfg +6 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/FirstRule.tla +11 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/chart.mmd +22 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/graph.dot +16 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/report.md +25 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/verdict-1.out +56 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/verdict-2.out +64 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/verdict-3.exit +1 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/verdict-3.out +64 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/verdict-4.exit +1 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/verdict-4.out +77 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/HiddenClock.cfg +4 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/HiddenClock.tla +11 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/chart.mmd +13 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/graph.dot +12 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/report.md +11 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/verdict-1.out +72 -0
- package/skills/statechart/scripts/test/corpus/Login/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/Login/Login.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/Login/Login.tla +62 -0
- package/skills/statechart/scripts/test/corpus/Login/chart.mmd +27 -0
- package/skills/statechart/scripts/test/corpus/Login/graph.dot +40 -0
- package/skills/statechart/scripts/test/corpus/Login/report.md +7 -0
- package/skills/statechart/scripts/test/corpus/Login/sany.out +1 -0
- package/skills/statechart/scripts/test/corpus/Login/verdict-1.out +47 -0
- package/skills/statechart/scripts/test/corpus/Login/view.mjs +1 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/LoginGuarded.cfg +2 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/LoginGuarded.tla +64 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/chart.mmd +28 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/graph.dot +37 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/report.md +8 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/sany.out +1 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/verdict-1.out +47 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/view.mjs +1 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/ChartRun.out +60 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/LoginParallel.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/LoginParallel.tla +64 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/chart.mmd +44 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/graph.dot +58 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/report.md +17 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/sany.out +1 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/verdict-1.out +83 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/verdict-2.out +57 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/view.mjs +1 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/ChartRun.out +60 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/MediaPlayer.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/MediaPlayer.tla +103 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/chart.mmd +43 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/graph.dot +93 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/report.md +14 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/sany.out +1 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/verdict-1.out +59 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/verdict-2.out +72 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/view.mjs +3 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/MediaPlayerFixed.cfg +2 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/MediaPlayerFixed.tla +100 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/chart.mmd +31 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/graph.dot +85 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/report.md +9 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/sany.out +1 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/verdict-1.out +47 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/view.mjs +3 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/ChartRun.out +59 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/MediaPlayer.tla +103 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/MediaPlayerProps.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/MediaPlayerProps.tla +6 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/chart.mmd +42 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/graph.dot +93 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/report.md +19 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-1.out +61 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-2.out +59 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-3.out +61 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-4.exit +1 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-4.out +66 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-5.exit +1 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-5.out +58 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-6.out +49 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/view.mjs +3 -0
- package/skills/statechart/scripts/test/corpus/PickWorker/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/PickWorker/PickWorker.cfg +6 -0
- package/skills/statechart/scripts/test/corpus/PickWorker/PickWorker.tla +11 -0
- package/skills/statechart/scripts/test/corpus/PickWorker/chart.mmd +5 -0
- package/skills/statechart/scripts/test/corpus/PickWorker/graph.dot +11 -0
- package/skills/statechart/scripts/test/corpus/PickWorker/report.md +7 -0
- package/skills/statechart/scripts/test/corpus/PickWorker/sany.out +5 -0
- package/skills/statechart/scripts/test/corpus/PickWorker/verdict-1.out +70 -0
- package/skills/statechart/scripts/test/corpus/Shadow/ChartRun.out +61 -0
- package/skills/statechart/scripts/test/corpus/Shadow/Shadow.cfg +4 -0
- package/skills/statechart/scripts/test/corpus/Shadow/Shadow.tla +11 -0
- package/skills/statechart/scripts/test/corpus/Shadow/ShadowLib.tla +6 -0
- package/skills/statechart/scripts/test/corpus/Shadow/ShadowSub.tla +3 -0
- package/skills/statechart/scripts/test/corpus/Shadow/chart.mmd +9 -0
- package/skills/statechart/scripts/test/corpus/Shadow/graph.dot +16 -0
- package/skills/statechart/scripts/test/corpus/Shadow/report.md +8 -0
- package/skills/statechart/scripts/test/corpus/Shadow/sany.out +4 -0
- package/skills/statechart/scripts/test/corpus/Shadow/verdict-1.out +65 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/ChartRun.out +59 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/SpacedNames.cfg +2 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/SpacedNames.tla +9 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/chart.mmd +23 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/graph.dot +17 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/report.md +15 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/sany.out +1 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/verdict-1.out +65 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/verdict-2.out +75 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/ChartRun.out +69 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/TwoPhase.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/TwoPhase.tla +75 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/chart.mmd +60 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/graph.dot +297 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/report.md +20 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/sany.out +1 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/verdict-1.out +95 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/verdict-2.out +57 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/view.mjs +1 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/TwoPhaseFixed.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/TwoPhaseFixed.tla +75 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/chart.mmd +37 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/graph.dot +223 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/report.md +11 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/sany.out +1 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/verdict-1.out +47 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/view.mjs +1 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/ChartRun.exit +1 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/ChartRun.out +75 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/TypeGuard.cfg +5 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/TypeGuard.tla +11 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/chart.mmd +18 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/graph.dot +14 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/report.md +29 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/verdict-1.out +64 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/verdict-2.out +75 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/ChartRun.out +58 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/UserNoDeadlock.cfg +2 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/UserNoDeadlock.tla +8 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/chart.mmd +22 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/graph.dot +16 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/report.md +15 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-1.out +56 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-2.out +77 -0
- package/skills/statechart/scripts/test/corpus.test.ts +403 -0
- package/skills/statechart/scripts/test/differential.test.ts +565 -0
- package/skills/statechart/scripts/test/grid/Grid.cfg +2 -0
- package/skills/statechart/scripts/test/grid/Grid.tla +9 -0
- package/skills/statechart/scripts/test/grid/sany.out +2 -0
- package/skills/statechart/scripts/test/java.ts +63 -0
- package/skills/statechart/scripts/test/labels.ts +643 -0
- package/skills/statechart/scripts/test/messages.test.ts +212 -0
- package/skills/statechart/scripts/test/pipeline.test.ts +270 -0
- package/skills/statechart/scripts/test/plain-tlc.test.ts +255 -0
- package/skills/statechart/scripts/test/render.test.ts +81 -0
- package/skills/statechart/scripts/test/tlc-out.test.ts +90 -0
- package/skills/statechart/scripts/test/tlc.ts +158 -0
- package/skills/statechart/scripts/tsconfig.json +11 -0
- package/skills/statechart/scripts/worker.ts +35 -0
- package/skills/swarm/SKILL.md +41 -0
- package/skills/tdd/SKILL.md +42 -0
- package/skills/teach/SKILL.md +21 -0
- package/skills/technical-writing/SKILL.md +106 -0
- package/skills/thermo-nuclear-code-quality-review/SKILL.md +192 -0
- package/skills/typescript-best-practices/SKILL.md +32 -0
- package/skills/typescript-best-practices/references/patterns.md +328 -0
- package/skills/typescript-exhaustive-switch/SKILL.md +10 -0
- package/skills/unslop/SKILL.md +62 -0
- package/skills/verify-this/SKILL.md +74 -0
- package/skills/weekly-review/SKILL.md +32 -0
- package/skills/what-did-i-get-done/SKILL.md +31 -0
- package/skills/why/SKILL.md +98 -0
- package/skills/why/references/epistemics.md +71 -0
- package/skills/why/references/investigator-prompt.md +84 -0
- package/skills/why/references/source-playbook.md +17 -0
- package/skills/why/references/sources/code-archaeology.md +51 -0
- package/skills/why/references/sources/databricks.md +70 -0
- package/skills/why/references/sources/datadog.md +97 -0
- package/skills/why/references/sources/incident-postmortem.md +5 -0
- package/skills/why/references/sources/linear.md +48 -0
- package/skills/why/references/sources/notion.md +55 -0
- package/skills/why/references/sources/sentry.md +66 -0
- package/skills/why/references/sources/slack.md +17 -0
- package/skills/why/references/synthesizer-prompt.md +129 -0
- package/skills/workflow-from-chats/SKILL.md +50 -0
- package/src/aliases.ts +64 -0
- package/src/ask.ts +131 -0
- package/src/autocomplete.ts +21 -0
- package/src/child-env.ts +44 -0
- package/src/index.ts +123 -0
- package/src/loop.ts +189 -0
- package/src/mode.ts +156 -0
- package/src/modes.ts +8 -0
- package/src/paths.ts +85 -0
- package/src/pi-command.ts +12 -0
- package/src/plan.ts +141 -0
- package/src/readonly-shell.ts +107 -0
- package/src/rule.ts +56 -0
- package/src/sections.ts +118 -0
- package/src/subscriptions/cron.ts +75 -0
- package/src/subscriptions/durable-store.ts +482 -0
- package/src/subscriptions/durable-types.ts +41 -0
- package/src/subscriptions/ensure-supervisor.ts +67 -0
- package/src/subscriptions/github.ts +149 -0
- package/src/subscriptions/index.ts +507 -0
- package/src/subscriptions/supervisor-main.ts +88 -0
- package/src/subscriptions/supervisor.ts +271 -0
- package/src/subscriptions/webhook.ts +222 -0
- package/src/task/agents.ts +55 -0
- package/src/task/card.ts +61 -0
- package/src/task/format.ts +88 -0
- package/src/task/models.ts +140 -0
- package/src/task/records.ts +227 -0
- package/src/task/registry.ts +77 -0
- package/src/task/runner.ts +365 -0
- package/src/task/status.ts +170 -0
- package/src/task/stop.ts +100 -0
- package/src/task/tool.ts +488 -0
- package/src/task/worktree.ts +67 -0
- package/src/todo.ts +121 -0
- package/src/visualize.ts +244 -0
package/src/task/card.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { AgentToolResult } from '@earendil-works/pi-agent-core';
|
|
2
|
+
import { Text } from '@earendil-works/pi-tui';
|
|
3
|
+
|
|
4
|
+
const COLLAPSED_LINES = 10;
|
|
5
|
+
|
|
6
|
+
interface CardDetails {
|
|
7
|
+
subagentType: string;
|
|
8
|
+
model: { provider: string; id: string; thinking?: string } | null;
|
|
9
|
+
worktree?: { branch: string } | null;
|
|
10
|
+
description?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function isCardDetails(details: unknown): details is CardDetails {
|
|
14
|
+
return typeof details === 'object' && details !== null && 'subagentType' in details && 'model' in details;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Heads the Task result with the Task description and the model that ran. */
|
|
18
|
+
export function taskCardText(result: Pick<AgentToolResult<unknown>, 'content' | 'details'>, expanded: boolean): string {
|
|
19
|
+
const text = result.content.map((part) => (part.type === 'text' ? part.text : '')).join('\n');
|
|
20
|
+
const lines = text.split('\n');
|
|
21
|
+
const body = expanded || lines.length <= COLLAPSED_LINES ? lines : [...lines.slice(0, COLLAPSED_LINES), `… ${lines.length - COLLAPSED_LINES} more lines`];
|
|
22
|
+
if (!isCardDetails(result.details)) return body.join('\n');
|
|
23
|
+
const { model, subagentType, worktree, description } = result.details;
|
|
24
|
+
const modelName = model === null ? "Pi's default model" : `${model.provider}/${model.id}${model.thinking === undefined ? '' : `:${model.thinking}`}`;
|
|
25
|
+
const branch = worktree === undefined || worktree === null ? '' : ` · branch ${worktree.branch}`;
|
|
26
|
+
const title = description === undefined || description.trim() === '' ? '' : `${description.trim()} · `;
|
|
27
|
+
return [`${title}${subagentType} · ${modelName}${branch}`, ...body].join('\n');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function renderTaskCard(result: AgentToolResult<unknown>, options: { expanded: boolean }): Text {
|
|
31
|
+
return new Text(taskCardText(result, options.expanded), 0, 0);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface NotificationCardDetails {
|
|
35
|
+
status: 'success' | 'error';
|
|
36
|
+
agentId: string;
|
|
37
|
+
title: string;
|
|
38
|
+
detail: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function isNotificationCardDetails(details: unknown): details is NotificationCardDetails {
|
|
42
|
+
const value = details as Partial<NotificationCardDetails> | null;
|
|
43
|
+
return typeof value === 'object' && value !== null && (value.status === 'success' || value.status === 'error') && typeof value.agentId === 'string' && typeof value.title === 'string' && typeof value.detail === 'string';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function taskNotificationCardText(message: { content: string | { type: string; text?: string }[]; details?: unknown }, expanded: boolean): string {
|
|
47
|
+
if (!isNotificationCardDetails(message.details)) {
|
|
48
|
+
const raw = typeof message.content === 'string' ? message.content : message.content.map((part) => (part.type === 'text' ? (part.text ?? '') : '')).join('\n');
|
|
49
|
+
const lines = raw.split('\n');
|
|
50
|
+
return (expanded || lines.length <= COLLAPSED_LINES ? lines : [...lines.slice(0, COLLAPSED_LINES), `… ${lines.length - COLLAPSED_LINES} more lines`]).join('\n');
|
|
51
|
+
}
|
|
52
|
+
const { title, status, agentId, detail } = message.details;
|
|
53
|
+
const lines = detail.split('\n');
|
|
54
|
+
const body = expanded || lines.length <= COLLAPSED_LINES ? lines : [...lines.slice(0, COLLAPSED_LINES), `… ${lines.length - COLLAPSED_LINES} more lines`];
|
|
55
|
+
const head = `${title.trim() === '' ? 'subagent' : title.trim()} · ${status} · agent ${agentId}`;
|
|
56
|
+
return [head, ...body].join('\n');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function renderTaskNotification(message: { content: string | { type: string; text?: string }[]; details?: unknown }, options: { expanded: boolean }): Text {
|
|
60
|
+
return new Text(taskNotificationCardText(message, options.expanded), 0, 0);
|
|
61
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Model-facing texts: a <response> block, an "Agent ID:" line that names `resume`, and a <task> notification block
|
|
2
|
+
// with the same fields.
|
|
3
|
+
import type { Usage } from '@earendil-works/pi-ai';
|
|
4
|
+
import { DEFAULT_MAX_BYTES, formatSize, truncateHead } from '@earendil-works/pi-coding-agent';
|
|
5
|
+
import type { Worktree } from './worktree.ts';
|
|
6
|
+
|
|
7
|
+
/** The first `limit` bytes, cut back to a UTF-8 character boundary (past 10xxxxxx continuation bytes). */
|
|
8
|
+
function headBytes(bytes: Buffer, limit: number): string {
|
|
9
|
+
let end = limit;
|
|
10
|
+
while (end > 0 && ((bytes[end] ?? 0) & 0xc0) === 0x80) end -= 1;
|
|
11
|
+
return bytes.subarray(0, end).toString('utf8');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Bounds a response with Pi's own tool-output limits (truncateHead: 2000 lines or 50KB). truncateHead keeps whole
|
|
16
|
+
* lines and returns nothing when the first line alone is too long, and a subagent's reply can be one long line, so
|
|
17
|
+
* that case keeps the line's first 50KB instead.
|
|
18
|
+
*/
|
|
19
|
+
export function bounded(text: string, transcript: string | undefined): string {
|
|
20
|
+
const result = truncateHead(text);
|
|
21
|
+
if (!result.truncated) return text;
|
|
22
|
+
const where = `the full response is in ${transcript ?? 'the subagent transcript'}`;
|
|
23
|
+
if (result.firstLineExceedsLimit) {
|
|
24
|
+
const head = headBytes(Buffer.from(text, 'utf8'), DEFAULT_MAX_BYTES);
|
|
25
|
+
return `${head}\n[truncated: showing ${formatSize(Buffer.byteLength(head, 'utf8'))} of ${formatSize(result.totalBytes)}; ${where}]`;
|
|
26
|
+
}
|
|
27
|
+
const size = result.truncatedBy === 'bytes' ? ` (${formatSize(result.outputBytes)} of ${formatSize(result.totalBytes)})` : '';
|
|
28
|
+
return `${result.content}\n[truncated: showing ${result.outputLines} of ${result.totalLines} lines${size}; ${where}]`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const agentIdLine = (agentId: string) => `Agent ID: ${agentId} (pass it as \`resume\` to send a follow-up after it completes)`;
|
|
32
|
+
const transcriptLine = (transcript: string | undefined) => (transcript === undefined ? [] : [`Transcript: ${transcript}`]);
|
|
33
|
+
|
|
34
|
+
export function foregroundText(agentId: string, response: string, transcript: string | undefined, notes: readonly string[] = []): string {
|
|
35
|
+
return ['This is the output of the subagent:', '', 'response:', '<response>', bounded(response, transcript), '</response>', '', agentIdLine(agentId), ...transcriptLine(transcript), ...notes].join('\n');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function backgroundText(agentId: string, transcript: string | undefined, notes: readonly string[] = []): string {
|
|
39
|
+
return [
|
|
40
|
+
'Subagent is running in the background. Its final response arrives automatically after your turn ends, so do not wait or poll for it. End your turn or work on something else.',
|
|
41
|
+
'',
|
|
42
|
+
agentIdLine(agentId),
|
|
43
|
+
...transcriptLine(transcript),
|
|
44
|
+
...notes,
|
|
45
|
+
].join('\n');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function steerText(agentId: string, notes: readonly string[] = []): string {
|
|
49
|
+
return [
|
|
50
|
+
`Sent to agent ${agentId} while it runs: it reads the message after its current step. Its final response still arrives as its launch said, as a completion notification for a background agent or as the waiting Task result for a foreground one, so do not wait or poll for it.`,
|
|
51
|
+
...notes,
|
|
52
|
+
].join('\n');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function worktreeLine(worktree: Worktree): string {
|
|
56
|
+
return `Worktree: ${worktree.path} on branch ${worktree.branch}, from ${worktree.base} at ${worktree.commit}. Merge ${worktree.branch} to take the subagent's commits.`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Opens a cloud agent's first prompt, since nothing else tells the child that the parent merges from its branch. */
|
|
60
|
+
export function worktreePreface(worktree: Worktree, prompt: string): string {
|
|
61
|
+
const where = worktree.cwd === worktree.path ? worktree.path : `${worktree.path} (working directory ${worktree.cwd})`;
|
|
62
|
+
return `You are running in an isolated git worktree at ${where} on branch ${worktree.branch}, created from ${worktree.base} at ${worktree.commit}. Uncommitted changes in the parent's checkout are not here. Commit your changes to ${worktree.branch} before you finish, because the parent agent merges from that branch.\n\n${prompt}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface NotificationFields {
|
|
66
|
+
status: 'success' | 'error';
|
|
67
|
+
agentId: string;
|
|
68
|
+
title: string;
|
|
69
|
+
toolCallId: string;
|
|
70
|
+
detail: string;
|
|
71
|
+
/** What the background child spent. It stays in the notification details, because Pi gives extensions no way to add it to session totals. */
|
|
72
|
+
usage?: Usage;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function notificationText(fields: NotificationFields): string {
|
|
76
|
+
return [
|
|
77
|
+
'The following task has finished. If you already handled it, ignore this notification and do not restate earlier responses.',
|
|
78
|
+
'',
|
|
79
|
+
'<task>',
|
|
80
|
+
'kind: subagent',
|
|
81
|
+
`status: ${fields.status}`,
|
|
82
|
+
`task_id: ${fields.agentId}`,
|
|
83
|
+
`title: ${fields.title}`,
|
|
84
|
+
`tool_call_id: ${fields.toolCallId}`,
|
|
85
|
+
`detail: ${fields.detail}`,
|
|
86
|
+
'</task>',
|
|
87
|
+
].join('\n');
|
|
88
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
export type Effort = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
2
|
+
|
|
3
|
+
export interface AvailableModel {
|
|
4
|
+
provider: string;
|
|
5
|
+
id: string;
|
|
6
|
+
reasoning: boolean;
|
|
7
|
+
/** Thinking levels Pi supports for the model (pi-ai `getSupportedThinkingLevels`). */
|
|
8
|
+
levels: readonly string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** A concrete child model. `thinking` absent means the child's own default for that model. */
|
|
12
|
+
export interface ModelSpec {
|
|
13
|
+
provider: string;
|
|
14
|
+
id: string;
|
|
15
|
+
thinking?: Effort;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const INHERIT = new Set(['', 'inherit', 'inherit-parent', 'auto', 'default']);
|
|
19
|
+
const EFFORTS = new Set<string>(['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max']);
|
|
20
|
+
const DASH_SLUG = /^(.+?)(?:-thinking)?(?:-(none|minimal|low|medium|high|xhigh|max))?(-fast)?$/;
|
|
21
|
+
|
|
22
|
+
const asEffort = (value: string): Effort | undefined => (EFFORTS.has(value) ? (value as Effort) : undefined);
|
|
23
|
+
|
|
24
|
+
/** A model as the allowed list names it, with its thinking levels when it has more than off. */
|
|
25
|
+
export function modelLabel(model: AvailableModel): string {
|
|
26
|
+
const levels = model.levels.filter((level) => level !== 'off').length > 0 ? ` (thinking: ${model.levels.join(', ')})` : '';
|
|
27
|
+
return `${model.provider}/${model.id}${levels}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function invalid(value: string, available: readonly AvailableModel[], reason = 'Model could not be resolved to a valid subagent model.'): Error {
|
|
31
|
+
return new Error(
|
|
32
|
+
[
|
|
33
|
+
`Invalid model selection "${value}". ${reason}`,
|
|
34
|
+
'Allowed model slugs:',
|
|
35
|
+
'- inherit',
|
|
36
|
+
...available.map((model) => `- ${modelLabel(model)}`),
|
|
37
|
+
'',
|
|
38
|
+
'Add a thinking level as <model>:<level>, for example claude-opus-5-5:xhigh, or as <model>[effort=<level>].',
|
|
39
|
+
'The `model` parameter is optional. If omitted, the subagent uses the same model as the parent agent.',
|
|
40
|
+
].join('\n'),
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
type Find = (reference: string) => AvailableModel | undefined;
|
|
45
|
+
|
|
46
|
+
/** A bare id that several providers offer means the parent chat's provider when it is one of them. */
|
|
47
|
+
function findModel(reference: string, available: readonly AvailableModel[], parentProvider: string | undefined): AvailableModel | undefined {
|
|
48
|
+
const slash = reference.indexOf('/');
|
|
49
|
+
if (slash !== -1) return available.find((model) => model.provider === reference.slice(0, slash) && model.id === reference.slice(slash + 1));
|
|
50
|
+
const matches = available.filter((model) => model.id === reference);
|
|
51
|
+
if (matches.length > 1) return matches.find((model) => model.provider === parentProvider) ?? failAmbiguous(reference, matches);
|
|
52
|
+
return matches[0];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function failAmbiguous(reference: string, matches: readonly AvailableModel[]): never {
|
|
56
|
+
throw new Error(`Model "${reference}" matches more than one provider: ${matches.map((model) => `${model.provider}/${model.id}`).join(', ')}. Use <provider>/<model-id>.`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Only listed levels are accepted, so a level the model does not support is refused instead of clamped by Pi. */
|
|
60
|
+
class UnsupportedLevel extends Error {}
|
|
61
|
+
|
|
62
|
+
function withThinking(model: AvailableModel, thinking: Effort | undefined): ModelSpec {
|
|
63
|
+
if (thinking === undefined) return { provider: model.provider, id: model.id };
|
|
64
|
+
if (!model.levels.includes(thinking)) throw new UnsupportedLevel(`${model.provider}/${model.id} does not support thinking level ${thinking}; it supports ${model.levels.join(', ')}.`);
|
|
65
|
+
return { provider: model.provider, id: model.id, thinking };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** A whole reference first, since model ids such as llama3:8b contain a colon; then a trailing :<effort>. */
|
|
69
|
+
function resolvePiSpec(value: string, find: Find): ModelSpec | undefined {
|
|
70
|
+
const whole = find(value);
|
|
71
|
+
if (whole !== undefined) return withThinking(whole, undefined);
|
|
72
|
+
const colon = value.lastIndexOf(':');
|
|
73
|
+
const level = colon === -1 ? undefined : asEffort(value.slice(colon + 1));
|
|
74
|
+
if (level === undefined) return undefined;
|
|
75
|
+
const model = find(value.slice(0, colon));
|
|
76
|
+
return model === undefined ? undefined : withThinking(model, level);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Legacy `<id>[-<effort>][-fast]` slugs: a Pi model whose own id ends in -fast wins, else the base id; the effort is the thinking level, and `none` is Pi's `off`. */
|
|
80
|
+
function resolveDashSlug(value: string, find: Find): ModelSpec | undefined {
|
|
81
|
+
const match = DASH_SLUG.exec(value);
|
|
82
|
+
const base = match?.[1];
|
|
83
|
+
const effort = match?.[2] === undefined ? undefined : asEffort(match[2] === 'none' ? 'off' : match[2]);
|
|
84
|
+
const fast = match?.[3] !== undefined;
|
|
85
|
+
if (base === undefined || (effort === undefined && !fast)) return undefined;
|
|
86
|
+
const model = (fast ? find(`${base}-fast`) : undefined) ?? find(base);
|
|
87
|
+
return model === undefined ? undefined : withThinking(model, effort);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
interface ModelParameters {
|
|
91
|
+
effort?: Effort;
|
|
92
|
+
fast?: boolean;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const BRACKETED = /^(.+)\[([^\]]*)\]$/;
|
|
96
|
+
|
|
97
|
+
/** `id=value` pairs. Pi sets a context window per model, not per call, so `context` is accepted and has no effect. */
|
|
98
|
+
function parseModelParameters(text: string): ModelParameters | undefined {
|
|
99
|
+
let parsed: ModelParameters = {};
|
|
100
|
+
for (const pair of text
|
|
101
|
+
.split(',')
|
|
102
|
+
.map((part) => part.trim())
|
|
103
|
+
.filter((part) => part !== '')) {
|
|
104
|
+
const [key, value, ...rest] = pair.split('=').map((part) => part.trim());
|
|
105
|
+
if (value === undefined || value === '' || rest.length > 0) return undefined;
|
|
106
|
+
const effort = asEffort(value);
|
|
107
|
+
if (key === 'effort' && effort !== undefined) parsed = { ...parsed, effort };
|
|
108
|
+
else if (key === 'fast' && (value === 'true' || value === 'false')) parsed = { ...parsed, fast: value === 'true' };
|
|
109
|
+
else if (key !== 'context') return undefined;
|
|
110
|
+
}
|
|
111
|
+
return parsed;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** `<model>[effort=high,fast=false,context=300k]`, per-model parameters; `[]` is the standard variant. */
|
|
115
|
+
function resolveBracketed(value: string, find: Find): ModelSpec | undefined {
|
|
116
|
+
const match = BRACKETED.exec(value);
|
|
117
|
+
const base = match?.[1];
|
|
118
|
+
const parameters = parseModelParameters(match?.[2] ?? '');
|
|
119
|
+
if (base === undefined || parameters === undefined) return undefined;
|
|
120
|
+
const model = (parameters.fast === true ? find(`${base}-fast`) : undefined) ?? find(base);
|
|
121
|
+
return model === undefined ? undefined : withThinking(model, parameters.effort);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Resolves Task's `model`: aliases run on the parent, a listed model runs as asked, and anything else fails with the
|
|
126
|
+
* allowed list. Legacy slugs `<id>-<effort>[-fast]` still map to a Pi model plus thinking level.
|
|
127
|
+
*/
|
|
128
|
+
export function resolveSubagentModel(value: string | undefined, available: readonly AvailableModel[], parent: ModelSpec | undefined): ModelSpec | undefined {
|
|
129
|
+
const requested = (value ?? '').trim();
|
|
130
|
+
if (INHERIT.has(requested)) return parent;
|
|
131
|
+
try {
|
|
132
|
+
const find: Find = (reference) => findModel(reference, available, parent?.provider);
|
|
133
|
+
const resolved = resolveBracketed(requested, find) ?? resolvePiSpec(requested, find) ?? resolveDashSlug(requested, find);
|
|
134
|
+
if (resolved === undefined) throw invalid(requested, available);
|
|
135
|
+
return resolved;
|
|
136
|
+
} catch (error) {
|
|
137
|
+
if (error instanceof UnsupportedLevel) throw invalid(requested, available, error.message);
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { parseSessionEntries, SessionManager } from '@earendil-works/pi-coding-agent';
|
|
5
|
+
import type { ModelSpec } from './models.ts';
|
|
6
|
+
import type { Worktree } from './worktree.ts';
|
|
7
|
+
|
|
8
|
+
/** What resume needs to restart an agent the way it first ran. */
|
|
9
|
+
export interface AgentRecord {
|
|
10
|
+
agentId: string;
|
|
11
|
+
type: string;
|
|
12
|
+
model?: ModelSpec;
|
|
13
|
+
readonly: boolean;
|
|
14
|
+
/** The parent workspace the agent belongs to; a cloud agent runs in `worktree` instead. */
|
|
15
|
+
cwd: string;
|
|
16
|
+
createdAt: string;
|
|
17
|
+
/** 1 for a subagent of the main chat, 2 for a subagent of a subagent; absent in records written before it existed. */
|
|
18
|
+
depth?: number;
|
|
19
|
+
worktree?: Worktree;
|
|
20
|
+
/** The agent whose transcript this one started as a copy of (Task `fork`). */
|
|
21
|
+
forkedFrom?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function isWorktree(value: unknown): value is Worktree {
|
|
25
|
+
const worktree = value as Partial<Worktree> | null;
|
|
26
|
+
return typeof worktree === 'object' && worktree !== null && (['path', 'cwd', 'branch', 'base', 'commit'] as const).every((key) => typeof worktree[key] === 'string');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function isModel(value: unknown): value is ModelSpec {
|
|
30
|
+
const model = value as Partial<ModelSpec> | null;
|
|
31
|
+
return typeof model === 'object' && model !== null && typeof model.provider === 'string' && typeof model.id === 'string' && (model.thinking === undefined || typeof model.thinking === 'string');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function isRecord(value: unknown, agentId: string): value is AgentRecord {
|
|
35
|
+
const record = value as Partial<AgentRecord> | null;
|
|
36
|
+
return (
|
|
37
|
+
typeof record === 'object' &&
|
|
38
|
+
record !== null &&
|
|
39
|
+
!Array.isArray(record) &&
|
|
40
|
+
record.agentId === agentId &&
|
|
41
|
+
typeof record.type === 'string' &&
|
|
42
|
+
typeof record.readonly === 'boolean' &&
|
|
43
|
+
typeof record.cwd === 'string' &&
|
|
44
|
+
typeof record.createdAt === 'string' &&
|
|
45
|
+
(record.model === undefined || isModel(record.model)) &&
|
|
46
|
+
(record.depth === undefined || Number.isInteger(record.depth)) &&
|
|
47
|
+
(record.worktree === undefined || isWorktree(record.worktree)) &&
|
|
48
|
+
(record.forkedFrom === undefined || typeof record.forkedFrom === 'string')
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function writeRecord(dir: string, record: AgentRecord): void {
|
|
53
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
54
|
+
const path = join(dir, `${record.agentId}.json`);
|
|
55
|
+
const temporary = `${path}.${process.pid}.tmp`;
|
|
56
|
+
writeFileSync(temporary, `${JSON.stringify(record, null, 2)}\n`, { mode: 0o600 });
|
|
57
|
+
renameSync(temporary, path);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function readRecord(dir: string, agentId: string): AgentRecord | undefined {
|
|
61
|
+
const path = join(dir, `${agentId}.json`);
|
|
62
|
+
if (!existsSync(path)) return undefined;
|
|
63
|
+
const unreadable = new Error(`Agent record ${path} is unreadable; delete it and start a new agent.`);
|
|
64
|
+
let value: unknown;
|
|
65
|
+
try {
|
|
66
|
+
value = JSON.parse(readFileSync(path, 'utf8'));
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if (error instanceof SyntaxError) throw unreadable;
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
if (!isRecord(value, agentId)) throw unreadable;
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Pi names a session file `<timestamp>_<session id>.jsonl`; the agent ID is the session ID. */
|
|
76
|
+
export function transcriptFor(dir: string, agentId: string): string | undefined {
|
|
77
|
+
if (!existsSync(dir)) return undefined;
|
|
78
|
+
const file = readdirSync(dir).find((name) => name.endsWith(`_${agentId}.jsonl`));
|
|
79
|
+
return file === undefined ? undefined : join(dir, file);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** The working directory a Pi session file's header names, or undefined without a readable header. */
|
|
83
|
+
function sessionCwd(file: string): string | undefined {
|
|
84
|
+
const [header] = parseSessionEntries(readFileSync(file, 'utf8').split('\n', 1)[0] ?? '');
|
|
85
|
+
return header?.type === 'session' && typeof header.cwd === 'string' && header.cwd !== '' ? header.cwd : undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Starts `agentId`'s transcript as a copy of `sourceId`'s, through Pi's own session fork: a new session ID in the
|
|
90
|
+
* header, the source as its parent session, and the source's working directory, so `--session-id` finds it where the
|
|
91
|
+
* source ran. Returns the new transcript path.
|
|
92
|
+
*/
|
|
93
|
+
export function forkTranscript(dir: string, sourceId: string, agentId: string, turns?: number): string {
|
|
94
|
+
const source = transcriptFor(dir, sourceId);
|
|
95
|
+
if (source === undefined) throw new Error(`Agent ${sourceId} has no transcript to fork.`);
|
|
96
|
+
const cwd = sessionCwd(source);
|
|
97
|
+
if (cwd === undefined) throw new Error(`Agent ${sourceId}'s transcript ${source} has no session header, so it cannot be forked.`);
|
|
98
|
+
const fork = SessionManager.forkFrom(source, cwd, dir, { id: agentId });
|
|
99
|
+
const file = fork.getSessionFile();
|
|
100
|
+
if (file === undefined) throw new Error(`Pi did not write a transcript for the fork of agent ${sourceId}.`);
|
|
101
|
+
if (turns !== undefined) keepFirstTurns(fork, file, turns);
|
|
102
|
+
return file;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Cuts the copy's active branch just before its (turns + 1)th user message, so the fork opens at the end of turn `turns`.
|
|
107
|
+
* `SessionManager.createBranchedSession(leafId)` mints its own session ID and file name, so it cannot truncate the file
|
|
108
|
+
* `forkFrom(..., { id: agentId })` wrote under the agent's ID (docs/native-gaps.md).
|
|
109
|
+
*/
|
|
110
|
+
function keepFirstTurns(fork: SessionManager, file: string, turns: number): void {
|
|
111
|
+
const branch = fork.getBranch();
|
|
112
|
+
const cut = branch.filter((entry) => entry.type === 'message' && entry.message.role === 'user')[turns];
|
|
113
|
+
if (cut === undefined) return;
|
|
114
|
+
const kept = [fork.getHeader(), ...branch.slice(0, branch.indexOf(cut))];
|
|
115
|
+
writeFileSync(file, kept.map((entry) => `${JSON.stringify(entry)}\n`).join(''), { mode: 0o600 });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Tools a writable launch gives back: those a launch-only readonly run (plan mode) took from the agent's last writable
|
|
120
|
+
* loadout. Pi restores the tool loadout a session last recorded, so without them the agent would stay readonly.
|
|
121
|
+
*/
|
|
122
|
+
export function readonlyLaunchRestores(transcript: string): string[] {
|
|
123
|
+
const active = new Set<string>();
|
|
124
|
+
let writable: string[] = [];
|
|
125
|
+
for (const entry of SessionManager.open(transcript).getBranch()) {
|
|
126
|
+
if (entry.type !== 'message' || entry.message.role !== 'system') continue;
|
|
127
|
+
for (const tool of entry.message.toolsRemoved ?? []) active.delete(tool.name);
|
|
128
|
+
for (const tool of entry.message.toolsAdded ?? []) active.add(tool.name);
|
|
129
|
+
if (active.has('write') || active.has('edit')) writable = [...active];
|
|
130
|
+
}
|
|
131
|
+
return writable.filter((name) => !active.has(name));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** IDs of every agent with a record in `dir`. */
|
|
135
|
+
export function recordIds(dir: string): string[] {
|
|
136
|
+
if (!existsSync(dir)) return [];
|
|
137
|
+
return readdirSync(dir)
|
|
138
|
+
.filter((name) => name.endsWith('.json'))
|
|
139
|
+
.map((name) => name.slice(0, -'.json'.length));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function alive(pid: number): boolean {
|
|
143
|
+
try {
|
|
144
|
+
process.kill(pid, 0);
|
|
145
|
+
return true;
|
|
146
|
+
} catch (error) {
|
|
147
|
+
return (error as NodeJS.ErrnoException).code === 'EPERM';
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const isPid = (value: number) => Number.isInteger(value) && value > 0;
|
|
152
|
+
|
|
153
|
+
/** The live pid the agent's run lock names, or undefined when no live process holds it. */
|
|
154
|
+
export function runningPid(dir: string, agentId: string): number | undefined {
|
|
155
|
+
const holder = holderOf(join(dir, `${agentId}.lock`));
|
|
156
|
+
return holder !== undefined && isPid(holder) && alive(holder) ? holder : undefined;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** The pid a lock names: undefined when the file is gone, NaN when it holds no readable pid. */
|
|
160
|
+
function holderOf(path: string): number | undefined {
|
|
161
|
+
try {
|
|
162
|
+
return Number.parseInt(readFileSync(path, 'utf8'), 10);
|
|
163
|
+
} catch (error) {
|
|
164
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function createExclusive(path: string): boolean {
|
|
170
|
+
try {
|
|
171
|
+
writeFileSync(path, String(process.pid), { flag: 'wx', mode: 0o600 });
|
|
172
|
+
return true;
|
|
173
|
+
} catch (error) {
|
|
174
|
+
if ((error as NodeJS.ErrnoException).code === 'EEXIST') return false;
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function writeAtomically(path: string, text: string): void {
|
|
180
|
+
const temporary = `${path}.${process.pid}.tmp`;
|
|
181
|
+
writeFileSync(temporary, text, { mode: 0o600 });
|
|
182
|
+
renameSync(temporary, path);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const stillRunning = (agentId: string, holder: number | undefined, path: string) =>
|
|
186
|
+
new Error(`Agent ${agentId} is still running (pid ${holder !== undefined && isPid(holder) ? holder : 'unknown'}; lock ${path}). Wait for its completion before resuming it.`);
|
|
187
|
+
|
|
188
|
+
export interface RunLock {
|
|
189
|
+
/** Names the process that writes the transcript, so the lock stays held exactly as long as that process lives. */
|
|
190
|
+
holdFor: (pid: number) => void;
|
|
191
|
+
/** Removes the lock unless another holder has taken it over since. */
|
|
192
|
+
release: () => void;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Pi appends to a session file without a lock, so two processes on one agent ID would interleave its transcript.
|
|
197
|
+
* The lock file holds the pid of the process writing the transcript. A lock without a readable pid counts as held.
|
|
198
|
+
* A dead holder's lock is removed only if it still names that holder, then created again exclusively; two
|
|
199
|
+
* processes taking over the same stale lock in the narrow window between that re-read and the removal can both succeed.
|
|
200
|
+
*/
|
|
201
|
+
export function acquireRunLock(dir: string, agentId: string): RunLock {
|
|
202
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
203
|
+
const path = join(dir, `${agentId}.lock`);
|
|
204
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
205
|
+
if (createExclusive(path)) {
|
|
206
|
+
let owner = process.pid;
|
|
207
|
+
return {
|
|
208
|
+
holdFor: (pid) => {
|
|
209
|
+
writeAtomically(path, String(pid));
|
|
210
|
+
owner = pid;
|
|
211
|
+
},
|
|
212
|
+
// Best effort: a lock left behind names a pid that will be dead, so the next acquire takes it over.
|
|
213
|
+
release: () => {
|
|
214
|
+
try {
|
|
215
|
+
if (holderOf(path) === owner) rmSync(path, { force: true });
|
|
216
|
+
} catch (error) {
|
|
217
|
+
if (!['EACCES', 'EPERM', 'EROFS', 'EBUSY', 'EIO'].includes((error as NodeJS.ErrnoException).code ?? '')) throw error;
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
const holder = holderOf(path);
|
|
223
|
+
if (holder !== undefined && (!isPid(holder) || alive(holder))) throw stillRunning(agentId, holder, path);
|
|
224
|
+
if (holder !== undefined && holderOf(path) === holder) rmSync(path, { force: true });
|
|
225
|
+
}
|
|
226
|
+
throw stillRunning(agentId, holderOf(path), path);
|
|
227
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { AgentActivityOutcome, BoundaryResult, ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';
|
|
2
|
+
import { isOneShot } from '../modes.ts';
|
|
3
|
+
import { type NotificationFields, notificationText } from './format.ts';
|
|
4
|
+
import type { ChildHandle, ChildOutcome } from './runner.ts';
|
|
5
|
+
|
|
6
|
+
export const NOTIFICATION_TYPE = 'pstack/task';
|
|
7
|
+
|
|
8
|
+
interface Running {
|
|
9
|
+
settled: Promise<void>;
|
|
10
|
+
handle: ChildHandle;
|
|
11
|
+
/** How the child runs now, which can be stricter than its record (plan mode). */
|
|
12
|
+
readonly: boolean;
|
|
13
|
+
background: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface BackgroundNotice {
|
|
17
|
+
title: string;
|
|
18
|
+
toolCallId: string;
|
|
19
|
+
mode: ExtensionContext['mode'];
|
|
20
|
+
detailFor: (outcome: ChildOutcome) => Pick<NotificationFields, 'status' | 'detail' | 'usage'>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Every running child of this runtime, foreground and background, so one agent ID never has two writers here.
|
|
25
|
+
* Background completions become notices: a follow-up message in long-lived sessions, and a settle-time entry in
|
|
26
|
+
* one-shot print and JSON runs, which wait for them before exiting.
|
|
27
|
+
*/
|
|
28
|
+
export function createSubagentRegistry(pi: ExtensionAPI) {
|
|
29
|
+
const running = new Map<string, Running>();
|
|
30
|
+
const pending: NotificationFields[] = [];
|
|
31
|
+
let retired = false;
|
|
32
|
+
|
|
33
|
+
const deliver = (fields: NotificationFields, mode: ExtensionContext['mode']) => {
|
|
34
|
+
if (isOneShot(mode)) pending.push(fields);
|
|
35
|
+
else pi.sendMessage({ customType: NOTIFICATION_TYPE, content: notificationText(fields), display: true, details: fields }, { triggerTurn: true, deliverAs: 'followUp' });
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** Registers synchronously, before any await in the caller, so a sibling call in the same message sees it. */
|
|
39
|
+
const track = (agentId: string, handle: ChildHandle, release: () => void, readonly: boolean, notice?: BackgroundNotice) => {
|
|
40
|
+
const settled = handle.done.then((outcome) => {
|
|
41
|
+
running.delete(agentId);
|
|
42
|
+
release();
|
|
43
|
+
// Shutdown killed this child; the retired runtime's pi must not be touched.
|
|
44
|
+
if (retired || notice === undefined) return;
|
|
45
|
+
deliver({ ...notice.detailFor(outcome), agentId, title: notice.title, toolCallId: notice.toolCallId }, notice.mode);
|
|
46
|
+
});
|
|
47
|
+
running.set(agentId, { settled, handle, readonly, background: notice !== undefined });
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const backgroundRunning = () => [...running.values()].filter((entry) => entry.background);
|
|
51
|
+
|
|
52
|
+
/** An aborted run ends now: a one-shot run does not hold its exit for background subagents after Escape or a watchdog abort. */
|
|
53
|
+
const beforeSettle = async (ctx: ExtensionContext, outcome: AgentActivityOutcome): Promise<BoundaryResult | undefined> => {
|
|
54
|
+
if (!isOneShot(ctx.mode) || outcome === 'aborted' || (pending.length === 0 && backgroundRunning().length === 0)) return undefined;
|
|
55
|
+
if (pending.length === 0) await Promise.race(backgroundRunning().map((entry) => entry.settled));
|
|
56
|
+
const ready = pending.splice(0);
|
|
57
|
+
return { entries: ready.map((fields) => ({ type: 'custom_message' as const, customType: NOTIFICATION_TYPE, content: notificationText(fields), display: true, details: fields })), continue: true };
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const shutdown = (): number => {
|
|
61
|
+
retired = true;
|
|
62
|
+
const background = backgroundRunning().length;
|
|
63
|
+
for (const entry of running.values()) entry.handle.kill();
|
|
64
|
+
running.clear();
|
|
65
|
+
pending.splice(0);
|
|
66
|
+
return background;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
isRunning: (agentId: string) => running.has(agentId),
|
|
71
|
+
get: (agentId: string): Pick<Running, 'handle' | 'readonly'> | undefined => running.get(agentId),
|
|
72
|
+
hasBackgroundWork: () => backgroundRunning().length > 0,
|
|
73
|
+
track,
|
|
74
|
+
beforeSettle,
|
|
75
|
+
shutdown,
|
|
76
|
+
};
|
|
77
|
+
}
|