@justjoshn/pi-pstack 0.0.0-stage → 0.15.36-pi.11
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 +79 -0
- package/LICENSE +21 -0
- package/README.md +100 -2
- package/agents/ci-watcher.md +28 -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 +83 -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 +254 -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/docs/parity-status.md +113 -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 +57 -0
- package/src/index.ts +138 -0
- package/src/loop.ts +238 -0
- package/src/mode.ts +180 -0
- package/src/modes.ts +8 -0
- package/src/path-skills.ts +104 -0
- package/src/paths.ts +90 -0
- package/src/pi-command.ts +12 -0
- package/src/plan.ts +226 -0
- package/src/readonly-shell.ts +107 -0
- package/src/rule.ts +56 -0
- package/src/sections.ts +136 -0
- package/src/subscriptions/cron.ts +75 -0
- package/src/subscriptions/durable-store.ts +531 -0
- package/src/subscriptions/durable-types.ts +69 -0
- package/src/subscriptions/ensure-supervisor.ts +67 -0
- package/src/subscriptions/github.ts +149 -0
- package/src/subscriptions/index.ts +575 -0
- package/src/subscriptions/supervisor-main.ts +134 -0
- package/src/subscriptions/supervisor.ts +325 -0
- package/src/subscriptions/webhook.ts +270 -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 +147 -0
- package/src/task/progress.ts +112 -0
- package/src/task/records.ts +230 -0
- package/src/task/registry.ts +81 -0
- package/src/task/runner.ts +459 -0
- package/src/task/status.ts +170 -0
- package/src/task/stop.ts +100 -0
- package/src/task/tool.ts +560 -0
- package/src/task/worktree.ts +69 -0
- package/src/todo.ts +127 -0
- package/src/visualize.ts +244 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { isAbsolute, join, resolve } from 'node:path';
|
|
5
|
+
import { StringDecoder } from 'node:string_decoder';
|
|
6
|
+
|
|
7
|
+
import type { ImageContent, Usage as ProviderUsage } from '@earendil-works/pi-ai';
|
|
8
|
+
import { detectSupportedImageMimeTypeFromFile } from '@earendil-works/pi-coding-agent';
|
|
9
|
+
import { PACKAGE_ROOT } from '../paths.ts';
|
|
10
|
+
import type { ModelSpec } from './models.ts';
|
|
11
|
+
|
|
12
|
+
// TodoWrite only changes the child's own todo list, so a readonly reviewer can still keep one. The child replaces
|
|
13
|
+
// bash with a sandboxed read-only shell (readonly-shell.ts).
|
|
14
|
+
const READONLY_TOOLS = 'read,grep,find,ls,bash,TodoWrite';
|
|
15
|
+
const AGENT_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,126}[A-Za-z0-9]$/;
|
|
16
|
+
export const KILL_GRACE_MS = 3_000;
|
|
17
|
+
// Dialogs block a run until answered. A subagent has nobody to ask, so its owner dismisses them.
|
|
18
|
+
const DIALOG_METHODS = new Set(['select', 'confirm', 'input', 'editor']);
|
|
19
|
+
|
|
20
|
+
/** Provider usage, plus whether `cost.total` was reported by the provider rather than priced locally. */
|
|
21
|
+
export interface Usage extends ProviderUsage {
|
|
22
|
+
cost: ProviderUsage['cost'] & { totalFromProvider?: boolean | undefined };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ChildArgsOptions {
|
|
26
|
+
sessionDir: string;
|
|
27
|
+
agentId: string;
|
|
28
|
+
model?: ModelSpec;
|
|
29
|
+
readonly?: boolean;
|
|
30
|
+
/** Tools to add back to the loadout Pi restores from the transcript (records.ts `readonlyLaunchRestores`). */
|
|
31
|
+
restoreTools?: readonly string[];
|
|
32
|
+
/** The parent's project trust, so the child loads the same project resources (`ctx.isProjectTrusted()`). */
|
|
33
|
+
trusted?: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Argv for one `pi --mode rpc` subagent process. Its prompts travel as RPC commands on stdin, never in argv. */
|
|
37
|
+
export function childArgs(options: ChildArgsOptions): string[] {
|
|
38
|
+
const model = options.model === undefined ? [] : ['--model', `${options.model.provider}/${options.model.id}`, ...(options.model.thinking === undefined ? [] : ['--thinking', options.model.thinking])];
|
|
39
|
+
return [
|
|
40
|
+
'--mode',
|
|
41
|
+
'rpc',
|
|
42
|
+
'--session-dir',
|
|
43
|
+
options.sessionDir,
|
|
44
|
+
'--session-id',
|
|
45
|
+
options.agentId,
|
|
46
|
+
'-e',
|
|
47
|
+
PACKAGE_ROOT,
|
|
48
|
+
...(options.trusted === undefined ? [] : [options.trusted ? '--approve' : '--no-approve']),
|
|
49
|
+
...model,
|
|
50
|
+
...(options.readonly === true ? ['--tools', READONLY_TOOLS, '--no-mcp'] : []),
|
|
51
|
+
...(options.readonly !== true && (options.restoreTools ?? []).length > 0 ? ['--tools', (options.restoreTools ?? []).map((name) => `+${name}`).join(',')] : []),
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function validateAgentId(id: string): string {
|
|
56
|
+
if (!AGENT_ID.test(id)) throw new Error(`"${id.slice(0, 80)}" is not a valid agent ID.`);
|
|
57
|
+
return id;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Absolute paths of files to attach: `~` expands as in Pi's read paths, and each must be an existing file. */
|
|
61
|
+
export function resolveAttachments(paths: readonly string[], cwd: string, home: string = homedir()): string[] {
|
|
62
|
+
return paths.map((path) => {
|
|
63
|
+
const expanded = path === '~' || path.startsWith('~/') ? join(home, path.slice(1)) : path;
|
|
64
|
+
const absolute = isAbsolute(expanded) ? expanded : resolve(cwd, expanded);
|
|
65
|
+
if (!existsSync(absolute)) throw new Error(`file_attachments: ${absolute} does not exist`);
|
|
66
|
+
if (!statSync(absolute).isFile()) throw new Error(`file_attachments: ${absolute} is not a file`);
|
|
67
|
+
return absolute;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface ChildInput {
|
|
72
|
+
text: string;
|
|
73
|
+
images: ImageContent[];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const VIDEO = /\.(?:mp4|m4v|mov|webm|avi|mkv)$/i;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The first message Pi builds from piped input and `@file` arguments, which RPC mode does not accept: the trimmed
|
|
80
|
+
* prompt, then each non-empty text file in a <file> block, and each image as an attachment with an empty <file> block.
|
|
81
|
+
*/
|
|
82
|
+
export async function withAttachments(prompt: string, attachments: readonly string[]): Promise<ChildInput> {
|
|
83
|
+
let text = prompt.trim();
|
|
84
|
+
const images: ImageContent[] = [];
|
|
85
|
+
for (const path of attachments) {
|
|
86
|
+
const bytes = readFileSync(path);
|
|
87
|
+
if (bytes.length === 0) continue;
|
|
88
|
+
// Pi model inputs have no video type. Name the file instead of feeding binary bytes to the text parser.
|
|
89
|
+
if (VIDEO.test(path)) {
|
|
90
|
+
text += `<file name="${path}">[video attachment; this host cannot send video to the model, open the path with a media tool]</file>\n`;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const mimeType = await detectSupportedImageMimeTypeFromFile(path);
|
|
94
|
+
if (mimeType === null) {
|
|
95
|
+
text += `<file name="${path}">\n${bytes.toString('utf8').replace(/^\uFEFF/, '')}\n</file>\n`;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
images.push({ type: 'image', mimeType, data: bytes.toString('base64') });
|
|
99
|
+
text += `<file name="${path}"></file>\n`;
|
|
100
|
+
}
|
|
101
|
+
return { text, images };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface ChildOptions {
|
|
105
|
+
command: readonly string[];
|
|
106
|
+
args: readonly string[];
|
|
107
|
+
prompt: string;
|
|
108
|
+
images?: readonly ImageContent[];
|
|
109
|
+
cwd: string;
|
|
110
|
+
env: NodeJS.ProcessEnv;
|
|
111
|
+
signal?: AbortSignal;
|
|
112
|
+
onEvent?: (event: { type: string } & Record<string, unknown>) => void;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface ChildOutcome {
|
|
116
|
+
finalText: string;
|
|
117
|
+
usage: Usage;
|
|
118
|
+
failure?: string;
|
|
119
|
+
stderr: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface ChildHandle {
|
|
123
|
+
done: Promise<ChildOutcome>;
|
|
124
|
+
/** Ends the child and its process group now: session shutdown or an aborted foreground call. */
|
|
125
|
+
kill: () => void;
|
|
126
|
+
/** stop_agent: aborts the run over RPC so the transcript records it, then kills the group if it outlives the grace period. */
|
|
127
|
+
stop: () => void;
|
|
128
|
+
/** Queues a message into the running turn (a new turn if the run just ended); rejects once the child is closing. */
|
|
129
|
+
steer: (text: string, images: readonly ImageContent[]) => Promise<void>;
|
|
130
|
+
pid: number | undefined;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export const zeroUsage = (): Usage => ({ input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0, totalFromProvider: true } });
|
|
134
|
+
|
|
135
|
+
export function addUsage(left: Usage, right: Usage): Usage {
|
|
136
|
+
return {
|
|
137
|
+
input: left.input + right.input,
|
|
138
|
+
output: left.output + right.output,
|
|
139
|
+
cacheRead: left.cacheRead + right.cacheRead,
|
|
140
|
+
cacheWrite: left.cacheWrite + right.cacheWrite,
|
|
141
|
+
totalTokens: left.totalTokens + right.totalTokens,
|
|
142
|
+
cost: {
|
|
143
|
+
input: left.cost.input + right.cost.input,
|
|
144
|
+
output: left.cost.output + right.cost.output,
|
|
145
|
+
cacheRead: left.cost.cacheRead + right.cost.cacheRead,
|
|
146
|
+
cacheWrite: left.cost.cacheWrite + right.cost.cacheWrite,
|
|
147
|
+
total: left.cost.total + right.cost.total,
|
|
148
|
+
totalFromProvider: left.cost.totalFromProvider === true && right.cost.totalFromProvider === true,
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
interface AssistantRecord {
|
|
154
|
+
text: string;
|
|
155
|
+
stopReason?: string;
|
|
156
|
+
errorMessage?: string;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Usage a JSON-mode event adds to the child's session totals, counted the way Pi's own session stats count it:
|
|
161
|
+
* assistant replies, tool results that carry nested usage (such as a grandchild subagent), and compactions.
|
|
162
|
+
*/
|
|
163
|
+
function usageOf(event: Record<string, unknown>): Usage | undefined {
|
|
164
|
+
if (event['type'] === 'compaction_end') return (event['result'] as { usage?: Usage } | undefined)?.usage;
|
|
165
|
+
const message = event['message'] as { role?: string; usage?: Usage } | undefined;
|
|
166
|
+
if (event['type'] !== 'message_end' || (message?.role !== 'assistant' && message?.role !== 'toolResult')) return undefined;
|
|
167
|
+
return message.usage;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function readAssistant(event: Record<string, unknown>): AssistantRecord | undefined {
|
|
171
|
+
const message = event['message'] as { role?: string; content?: { type: string; text?: string }[]; stopReason?: string; errorMessage?: string } | undefined;
|
|
172
|
+
if (event['type'] !== 'message_end' || message?.role !== 'assistant') return undefined;
|
|
173
|
+
const text = (message.content ?? [])
|
|
174
|
+
.filter((part) => part.type === 'text')
|
|
175
|
+
.map((part) => part.text ?? '')
|
|
176
|
+
.join('');
|
|
177
|
+
return {
|
|
178
|
+
text,
|
|
179
|
+
...(message.stopReason === undefined ? {} : { stopReason: message.stopReason }),
|
|
180
|
+
...(message.errorMessage === undefined ? {} : { errorMessage: message.errorMessage }),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function readUser(event: Record<string, unknown>): { text: string; images: ImageContent[] } | undefined {
|
|
185
|
+
if (event['type'] !== 'message_end') return undefined;
|
|
186
|
+
const message = event['message'] as { role?: string; content?: unknown } | undefined;
|
|
187
|
+
if (message?.role !== 'user') return undefined;
|
|
188
|
+
if (typeof message.content === 'string') return { text: message.content, images: [] };
|
|
189
|
+
if (!Array.isArray(message.content)) return undefined;
|
|
190
|
+
const text: string[] = [];
|
|
191
|
+
const images: ImageContent[] = [];
|
|
192
|
+
for (const part of message.content as { type?: string; text?: string; data?: string; mimeType?: string }[]) {
|
|
193
|
+
if (part.type === 'text') text.push(part.text ?? '');
|
|
194
|
+
if (part.type === 'image' && typeof part.data === 'string' && typeof part.mimeType === 'string') images.push({ type: 'image', data: part.data, mimeType: part.mimeType });
|
|
195
|
+
}
|
|
196
|
+
return { text: text.join(''), images };
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const sameImages = (left: readonly ImageContent[], right: readonly ImageContent[]): boolean => left.length === right.length && left.every((image, index) => image.data === right[index]?.data && image.mimeType === right[index]?.mimeType);
|
|
200
|
+
/** A steering input this runner accepted, kept until Pi stores it as a user message. */
|
|
201
|
+
export interface AcceptedSteer {
|
|
202
|
+
text: string;
|
|
203
|
+
images: readonly ImageContent[];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Rebuilds messages from a queue drain. Only steering entries were sent by this runner, so only they may reclaim a
|
|
208
|
+
* recorded image. Each recorded steer is used once, which keeps two identical texts with different images in order.
|
|
209
|
+
*/
|
|
210
|
+
export function recoverDrained(drained: readonly { queue: 'steering' | 'followUp'; text: string }[], accepted: readonly AcceptedSteer[]): AcceptedSteer[] {
|
|
211
|
+
const unused = [...accepted];
|
|
212
|
+
return drained.map(({ queue, text }) => {
|
|
213
|
+
if (queue === 'followUp') return { text, images: [] };
|
|
214
|
+
const exact = unused.findIndex((entry) => entry.text === text);
|
|
215
|
+
const [entry] = unused.splice(exact === -1 ? 0 : exact, 1);
|
|
216
|
+
return { text, images: entry?.images ?? [] };
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function lineReader(onLine: (line: string) => void): (chunk: Buffer) => void {
|
|
221
|
+
const decoder = new StringDecoder('utf8');
|
|
222
|
+
let buffer = '';
|
|
223
|
+
return (chunk) => {
|
|
224
|
+
buffer += decoder.write(chunk);
|
|
225
|
+
for (let index = buffer.indexOf('\n'); index !== -1; index = buffer.indexOf('\n')) {
|
|
226
|
+
const line = buffer.slice(0, index).trim();
|
|
227
|
+
buffer = buffer.slice(index + 1);
|
|
228
|
+
if (line !== '') onLine(line);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** RPC mode reserves stdout for protocol records, but a child extension can still print there; such a line must not crash the parent. */
|
|
234
|
+
function parseEvent(line: string): ({ type: string } & Record<string, unknown>) | undefined {
|
|
235
|
+
try {
|
|
236
|
+
const value: unknown = JSON.parse(line);
|
|
237
|
+
return typeof value === 'object' && value !== null && typeof (value as { type?: unknown }).type === 'string' ? (value as { type: string } & Record<string, unknown>) : undefined;
|
|
238
|
+
} catch (error) {
|
|
239
|
+
if (error instanceof SyntaxError) return undefined;
|
|
240
|
+
throw error;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** Signals the child's whole process group. A group that is already gone (ESRCH) or not ours (EPERM) is left alone. */
|
|
245
|
+
export function signalGroup(pid: number, signal: NodeJS.Signals): void {
|
|
246
|
+
try {
|
|
247
|
+
process.kill(-pid, signal);
|
|
248
|
+
} catch (error) {
|
|
249
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
250
|
+
if (code !== 'ESRCH' && code !== 'EPERM') throw error;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function killGroup(pid: number | undefined): void {
|
|
255
|
+
if (pid === undefined) return;
|
|
256
|
+
signalGroup(pid, 'SIGTERM');
|
|
257
|
+
setTimeout(() => signalGroup(pid, 'SIGKILL'), KILL_GRACE_MS).unref();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
interface ChildState {
|
|
261
|
+
usage: Usage;
|
|
262
|
+
stderr: string;
|
|
263
|
+
aborted: boolean;
|
|
264
|
+
stopped: boolean;
|
|
265
|
+
/** Why Pi refused the first prompt. */
|
|
266
|
+
refused?: string;
|
|
267
|
+
/** The recovery after a steer stranded at settlement could not continue the run. */
|
|
268
|
+
recoveryFailed?: string;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function outcomeOf(last: AssistantRecord | undefined, state: ChildState, code: number | null): ChildOutcome {
|
|
272
|
+
const base = { finalText: last?.text ?? '', usage: state.usage, stderr: state.stderr };
|
|
273
|
+
if (state.aborted) return { ...base, failure: 'Subagent was aborted' };
|
|
274
|
+
if (state.stopped) return { ...base, failure: 'Subagent was stopped with stop_agent' };
|
|
275
|
+
if (state.refused !== undefined) return { ...base, failure: state.refused };
|
|
276
|
+
if (state.recoveryFailed !== undefined) return { ...base, failure: state.recoveryFailed };
|
|
277
|
+
if (last?.stopReason === 'error' || last?.stopReason === 'aborted') return { ...base, failure: last.errorMessage ?? `subagent stopped: ${last.stopReason}` };
|
|
278
|
+
if (code !== 0) return { ...base, failure: `pi exited with code ${code}: ${state.stderr.trim().split('\n').at(-1) ?? ''}`.trim() };
|
|
279
|
+
return base;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
interface RpcResponse {
|
|
283
|
+
id?: string;
|
|
284
|
+
success: boolean;
|
|
285
|
+
error?: string;
|
|
286
|
+
data?: { disposition?: string; steering?: string[]; followUp?: string[] };
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Runs one `pi --mode rpc` child in its own process group, so abort and shutdown can stop it and everything it started.
|
|
291
|
+
* The child stays open while its run is active or a command awaits its response, so a steer always lands in a run;
|
|
292
|
+
* once the run settles with nothing outstanding, closing stdin makes Pi save the session and exit.
|
|
293
|
+
* Pi's `RpcClient` cannot start or end this child (no detached spawn, stdin close, `extension_ui_response`, or exit
|
|
294
|
+
* code); docs/native-gaps.md records each missing mechanism.
|
|
295
|
+
*/
|
|
296
|
+
export function startChild(options: ChildOptions): ChildHandle {
|
|
297
|
+
const [command, ...prefix] = options.command;
|
|
298
|
+
if (command === undefined) throw new Error('startChild needs a command');
|
|
299
|
+
const child = spawn(command, [...prefix, ...options.args], { cwd: options.cwd, env: options.env, stdio: ['pipe', 'pipe', 'pipe'], detached: true });
|
|
300
|
+
const state: ChildState = { usage: zeroUsage(), stderr: '', aborted: false, stopped: false };
|
|
301
|
+
let last: AssistantRecord | undefined;
|
|
302
|
+
let open = true;
|
|
303
|
+
let idle = true;
|
|
304
|
+
let steering: AcceptedSteer[] = [];
|
|
305
|
+
let recoveryRounds = 0;
|
|
306
|
+
let nextId = 0;
|
|
307
|
+
let grace: ReturnType<typeof setTimeout> | undefined;
|
|
308
|
+
const waiting = new Map<string, (response: RpcResponse) => void>();
|
|
309
|
+
|
|
310
|
+
const write = (record: Record<string, unknown>) => {
|
|
311
|
+
if (open) child.stdin.write(`${JSON.stringify(record)}\n`);
|
|
312
|
+
};
|
|
313
|
+
const close = () => {
|
|
314
|
+
if (!open) return;
|
|
315
|
+
open = false;
|
|
316
|
+
child.stdin.end();
|
|
317
|
+
};
|
|
318
|
+
const request = (record: Record<string, unknown>, onResponse: (response: RpcResponse) => void) => {
|
|
319
|
+
const id = `pstack-${nextId++}`;
|
|
320
|
+
waiting.set(id, onResponse);
|
|
321
|
+
write({ ...record, id });
|
|
322
|
+
};
|
|
323
|
+
const prompt = (text: string, images: readonly ImageContent[], onResponse: (response: RpcResponse) => void, streamingBehavior?: 'steer') =>
|
|
324
|
+
request({ type: 'prompt', message: text, ...(images.length === 0 ? {} : { images }), ...(streamingBehavior === undefined ? {} : { streamingBehavior }) }, (response) => {
|
|
325
|
+
if (response.data?.disposition === 'started') idle = false;
|
|
326
|
+
onResponse(response);
|
|
327
|
+
});
|
|
328
|
+
// A steer can reach Pi just as its run ends and stay queued with no run to take it. Draining that queue is the
|
|
329
|
+
// only native way to continue it, and the drain returns text only, so each drained message gets its recorded
|
|
330
|
+
// attachments back and keeps its own message boundary.
|
|
331
|
+
const closeWhenSettled = () => {
|
|
332
|
+
if (!open || !idle || waiting.size > 0) return;
|
|
333
|
+
if (state.stopped || steering.length === 0) return close();
|
|
334
|
+
if (recoveryRounds >= 3) {
|
|
335
|
+
state.recoveryFailed = `A steering message stayed queued after ${recoveryRounds} resume attempts: ${steering.map((entry) => entry.text).join(' | ')}`;
|
|
336
|
+
steering = [];
|
|
337
|
+
return close();
|
|
338
|
+
}
|
|
339
|
+
recoveryRounds += 1;
|
|
340
|
+
const accepted = steering;
|
|
341
|
+
steering = [];
|
|
342
|
+
request({ type: 'clear_queue' }, (response) => {
|
|
343
|
+
const drained = [...(response.data?.steering ?? []).map((text) => ({ queue: 'steering' as const, text })), ...(response.data?.followUp ?? []).map((text) => ({ queue: 'followUp' as const, text }))];
|
|
344
|
+
if (drained.length === 0) return closeWhenSettled();
|
|
345
|
+
const recovered = recoverDrained(drained, accepted);
|
|
346
|
+
steering = recovered;
|
|
347
|
+
for (const [index, entry] of recovered.entries()) prompt(entry.text, entry.images, () => undefined, index === 0 ? undefined : 'steer');
|
|
348
|
+
});
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
const kill = () => {
|
|
352
|
+
state.aborted = true;
|
|
353
|
+
killGroup(child.pid);
|
|
354
|
+
};
|
|
355
|
+
const stop = () => {
|
|
356
|
+
if (state.stopped || state.aborted) return;
|
|
357
|
+
state.stopped = true;
|
|
358
|
+
request({ type: 'clear_queue' }, () => undefined);
|
|
359
|
+
request({ type: 'abort' }, () => undefined);
|
|
360
|
+
grace = setTimeout(() => killGroup(child.pid), KILL_GRACE_MS);
|
|
361
|
+
grace.unref();
|
|
362
|
+
};
|
|
363
|
+
const steer = (text: string, images: readonly ImageContent[]) =>
|
|
364
|
+
new Promise<void>((resolve, reject) => {
|
|
365
|
+
if (!open || state.stopped || state.aborted) return reject(new Error('The subagent has finished its run.'));
|
|
366
|
+
const entry = { text, images };
|
|
367
|
+
steering.push(entry);
|
|
368
|
+
prompt(
|
|
369
|
+
text,
|
|
370
|
+
images,
|
|
371
|
+
(response) => {
|
|
372
|
+
if (!response.success) {
|
|
373
|
+
steering = steering.filter((candidate) => candidate !== entry);
|
|
374
|
+
return reject(new Error(response.error ?? 'Pi refused the message.'));
|
|
375
|
+
}
|
|
376
|
+
if (response.data?.disposition === 'handled') steering = steering.filter((candidate) => candidate !== entry);
|
|
377
|
+
resolve();
|
|
378
|
+
},
|
|
379
|
+
'steer',
|
|
380
|
+
);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
const onRecord = (record: { type: string } & Record<string, unknown>) => {
|
|
384
|
+
if (record.type === 'response') {
|
|
385
|
+
const response = record as unknown as RpcResponse;
|
|
386
|
+
const onResponse = response.id === undefined ? undefined : waiting.get(response.id);
|
|
387
|
+
if (onResponse === undefined) return;
|
|
388
|
+
waiting.delete(response.id as string);
|
|
389
|
+
onResponse(response);
|
|
390
|
+
return closeWhenSettled();
|
|
391
|
+
}
|
|
392
|
+
if (record.type === 'extension_ui_request') {
|
|
393
|
+
if (DIALOG_METHODS.has(String(record['method']))) write({ type: 'extension_ui_response', id: record['id'], cancelled: true });
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
options.onEvent?.(record);
|
|
397
|
+
const user = readUser(record);
|
|
398
|
+
if (user !== undefined) {
|
|
399
|
+
const matchers = [
|
|
400
|
+
(entry: { text: string; images: readonly ImageContent[] }) => entry.text === user.text && sameImages(entry.images, user.images),
|
|
401
|
+
(entry: { text: string }) => entry.text === user.text,
|
|
402
|
+
(entry: { images: readonly ImageContent[] }) => entry.images.length > 0 && sameImages(entry.images, user.images),
|
|
403
|
+
];
|
|
404
|
+
let index = -1;
|
|
405
|
+
for (const matches of matchers) {
|
|
406
|
+
index = steering.findIndex(matches);
|
|
407
|
+
if (index !== -1) break;
|
|
408
|
+
}
|
|
409
|
+
if (index !== -1) {
|
|
410
|
+
steering.splice(index, 1);
|
|
411
|
+
recoveryRounds = 0;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (record.type === 'agent_start') idle = false;
|
|
415
|
+
const usage = usageOf(record);
|
|
416
|
+
if (usage !== undefined) state.usage = addUsage(state.usage, usage);
|
|
417
|
+
last = readAssistant(record) ?? last;
|
|
418
|
+
if (record.type === 'agent_settled') {
|
|
419
|
+
idle = true;
|
|
420
|
+
closeWhenSettled();
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
child.stdout.on(
|
|
425
|
+
'data',
|
|
426
|
+
lineReader((line) => {
|
|
427
|
+
const record = parseEvent(line);
|
|
428
|
+
if (record === undefined) state.stderr = `${state.stderr}${line}\n`.slice(-8_192);
|
|
429
|
+
else onRecord(record);
|
|
430
|
+
}),
|
|
431
|
+
);
|
|
432
|
+
child.stderr.on('data', (chunk: Buffer) => {
|
|
433
|
+
state.stderr = `${state.stderr}${chunk.toString('utf8')}`.slice(-8_192);
|
|
434
|
+
});
|
|
435
|
+
// A child that exits or is killed before it reads a large prompt closes the pipe. Unhandled, that EPIPE would be an
|
|
436
|
+
// uncaught exception in the parent, and interactive Pi exits on one; the child's exit already reports the failure.
|
|
437
|
+
child.stdin.on('error', (error: NodeJS.ErrnoException) => {
|
|
438
|
+
if (error.code !== 'EPIPE' && error.code !== 'ECONNRESET') state.stderr = `${state.stderr}stdin: ${error.message}\n`.slice(-8_192);
|
|
439
|
+
});
|
|
440
|
+
if (options.signal?.aborted) kill();
|
|
441
|
+
else options.signal?.addEventListener('abort', kill, { once: true });
|
|
442
|
+
if (state.aborted || (options.prompt.trim() === '' && (options.images ?? []).length === 0)) close();
|
|
443
|
+
else
|
|
444
|
+
prompt(options.prompt, options.images ?? [], (response) => {
|
|
445
|
+
if (!response.success) state.refused = response.error ?? 'Pi refused the prompt.';
|
|
446
|
+
});
|
|
447
|
+
const done = new Promise<ChildOutcome>((resolveDone) => {
|
|
448
|
+
child.on('error', (error) => resolveDone({ finalText: '', usage: state.usage, stderr: state.stderr, failure: `could not start pi: ${error.message}` }));
|
|
449
|
+
child.on('close', (code) => {
|
|
450
|
+
open = false;
|
|
451
|
+
clearTimeout(grace);
|
|
452
|
+
options.signal?.removeEventListener('abort', kill);
|
|
453
|
+
resolveDone(outcomeOf(last, state, code));
|
|
454
|
+
for (const onResponse of waiting.values()) onResponse({ success: false, error: 'The subagent exited.' });
|
|
455
|
+
waiting.clear();
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
return { done, kill, stop, steer, pid: child.pid };
|
|
459
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { closeSync, existsSync, openSync, readSync, statSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
5
|
+
import { Type } from 'typebox';
|
|
6
|
+
import { subagentDir } from '../paths.ts';
|
|
7
|
+
import type { ModelSpec } from './models.ts';
|
|
8
|
+
import { readRecord, recordIds, runningPid, transcriptFor } from './records.ts';
|
|
9
|
+
import { validateAgentId } from './runner.ts';
|
|
10
|
+
|
|
11
|
+
const LIST_LIMIT = 20;
|
|
12
|
+
const TEXT_LIMIT = 500;
|
|
13
|
+
const FIRST_READ_BYTES = 64 * 1024;
|
|
14
|
+
// A transcript can grow to hundreds of megabytes; status reads only its tail.
|
|
15
|
+
const TAIL_LIMIT_BYTES = 4 * 1024 * 1024;
|
|
16
|
+
|
|
17
|
+
export interface AgentStatus {
|
|
18
|
+
agentId: string;
|
|
19
|
+
state: 'running' | 'idle' | 'missing';
|
|
20
|
+
pid?: number;
|
|
21
|
+
type?: string;
|
|
22
|
+
model?: string;
|
|
23
|
+
readonly?: boolean;
|
|
24
|
+
directory?: string;
|
|
25
|
+
branch?: string;
|
|
26
|
+
forkedFrom?: string;
|
|
27
|
+
createdAt?: string;
|
|
28
|
+
updatedAt?: string;
|
|
29
|
+
transcript?: string;
|
|
30
|
+
lastText?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const modelName = (model: ModelSpec | undefined) => (model === undefined ? "Pi's default model" : `${model.provider}/${model.id}${model.thinking === undefined ? '' : `:${model.thinking}`}`);
|
|
34
|
+
|
|
35
|
+
function truncate(text: string): string {
|
|
36
|
+
const flat = text.trim();
|
|
37
|
+
return flat.length > TEXT_LIMIT ? `${flat.slice(0, TEXT_LIMIT)}…` : flat;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readTail(path: string, size: number, bytes: number): string {
|
|
41
|
+
const length = Math.min(size, bytes);
|
|
42
|
+
const buffer = Buffer.alloc(length);
|
|
43
|
+
const fd = openSync(path, 'r');
|
|
44
|
+
try {
|
|
45
|
+
readSync(fd, buffer, 0, length, size - length);
|
|
46
|
+
} finally {
|
|
47
|
+
closeSync(fd);
|
|
48
|
+
}
|
|
49
|
+
return buffer.toString('utf8');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function assistantTextOf(line: string): string | undefined {
|
|
53
|
+
let entry: { type?: unknown; message?: { role?: unknown; content?: unknown } };
|
|
54
|
+
try {
|
|
55
|
+
entry = JSON.parse(line) as typeof entry;
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (error instanceof SyntaxError) return undefined;
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
if (entry.type !== 'message' || entry.message?.role !== 'assistant' || !Array.isArray(entry.message.content)) return undefined;
|
|
61
|
+
const text = (entry.message.content as { type?: unknown; text?: unknown }[])
|
|
62
|
+
.filter((part) => part.type === 'text' && typeof part.text === 'string')
|
|
63
|
+
.map((part) => part.text as string)
|
|
64
|
+
.join('');
|
|
65
|
+
return text.trim() === '' ? undefined : truncate(text);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** The text of the last assistant message in a Pi session file, scanning back from the end through at most its last 4 MiB. */
|
|
69
|
+
export function lastAssistantText(transcript: string): string | undefined {
|
|
70
|
+
const { size } = statSync(transcript);
|
|
71
|
+
for (let bytes = FIRST_READ_BYTES; ; bytes *= 4) {
|
|
72
|
+
const lines = readTail(transcript, size, bytes).split('\n');
|
|
73
|
+
// The first line of a partial read is cut off.
|
|
74
|
+
if (bytes < size) lines.shift();
|
|
75
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
76
|
+
const text = assistantTextOf(lines[index]?.trim() ?? '');
|
|
77
|
+
if (text !== undefined) return text;
|
|
78
|
+
}
|
|
79
|
+
if (bytes >= size || bytes >= TAIL_LIMIT_BYTES) return undefined;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** One agent's state from its record, run lock, and transcript. Reads files only; never starts anything. */
|
|
84
|
+
export function agentStatus(dir: string, agentId: string): AgentStatus {
|
|
85
|
+
const record = readRecord(dir, agentId);
|
|
86
|
+
const transcript = transcriptFor(dir, agentId);
|
|
87
|
+
if (record === undefined && transcript === undefined) return { agentId, state: 'missing' };
|
|
88
|
+
const pid = runningPid(dir, agentId);
|
|
89
|
+
const updated = transcript ?? join(dir, `${agentId}.json`);
|
|
90
|
+
const lastText = transcript === undefined ? undefined : lastAssistantText(transcript);
|
|
91
|
+
return {
|
|
92
|
+
agentId,
|
|
93
|
+
state: pid === undefined ? 'idle' : 'running',
|
|
94
|
+
...(pid === undefined ? {} : { pid }),
|
|
95
|
+
...(record === undefined
|
|
96
|
+
? {}
|
|
97
|
+
: {
|
|
98
|
+
type: record.type,
|
|
99
|
+
model: modelName(record.model),
|
|
100
|
+
readonly: record.readonly,
|
|
101
|
+
directory: record.worktree?.cwd ?? record.cwd,
|
|
102
|
+
createdAt: record.createdAt,
|
|
103
|
+
...(record.worktree === undefined ? {} : { branch: record.worktree.branch }),
|
|
104
|
+
...(record.forkedFrom === undefined ? {} : { forkedFrom: record.forkedFrom }),
|
|
105
|
+
}),
|
|
106
|
+
...(existsSync(updated) ? { updatedAt: statSync(updated).mtime.toISOString() } : {}),
|
|
107
|
+
...(transcript === undefined ? {} : { transcript }),
|
|
108
|
+
...(lastText === undefined ? {} : { lastText }),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Agents with a record in `dir`, newest first, at most `limit`, and how many there are in all. */
|
|
113
|
+
export function listAgentStatuses(dir: string, limit: number = LIST_LIMIT): { agents: AgentStatus[]; total: number } {
|
|
114
|
+
const records = recordIds(dir).flatMap((agentId) => {
|
|
115
|
+
try {
|
|
116
|
+
const record = readRecord(dir, agentId);
|
|
117
|
+
return record === undefined ? [] : [record];
|
|
118
|
+
} catch {
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
const newest = records.toSorted((left, right) => right.createdAt.localeCompare(left.createdAt)).slice(0, limit);
|
|
123
|
+
return { agents: newest.map((record) => agentStatus(dir, record.agentId)), total: records.length };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function statusText(status: AgentStatus): string {
|
|
127
|
+
if (status.state === 'missing') return `Agent ${status.agentId}: missing (no record or transcript in this workspace)`;
|
|
128
|
+
const fields: [string, string | undefined][] = [
|
|
129
|
+
['state', status.state === 'running' ? `running (pid ${status.pid})` : 'idle'],
|
|
130
|
+
['type', status.type === undefined ? undefined : `${status.type}${status.readonly === true ? ' (readonly)' : ''}`],
|
|
131
|
+
['model', status.model],
|
|
132
|
+
['directory', status.directory],
|
|
133
|
+
['branch', status.branch],
|
|
134
|
+
['forked from', status.forkedFrom],
|
|
135
|
+
['created', status.createdAt],
|
|
136
|
+
['updated', status.updatedAt],
|
|
137
|
+
['transcript', status.transcript],
|
|
138
|
+
];
|
|
139
|
+
const lines = fields.flatMap(([name, value]) => (value === undefined ? [] : [` ${name}: ${value}`]));
|
|
140
|
+
const last = status.lastText === undefined ? [] : [' last response:', ...status.lastText.split('\n').map((line) => ` ${line}`)];
|
|
141
|
+
return [`Agent ${status.agentId}`, ...lines, ...last].join('\n');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export const AgentStatusParams = Type.Object({
|
|
145
|
+
agent_id: Type.Optional(Type.String({ description: 'Agent ID from an earlier Task call in this workspace. Omit it to list the most recent agents, newest first.' })),
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const DESCRIPTION =
|
|
149
|
+
'Read-only status of subagents in this workspace: running or idle, type, model, directory, worktree branch, created and updated times, and the last response. This is the way to check on a worker; it never starts, messages, or resumes anything. Task resume would message a running agent or restart an idle one instead.';
|
|
150
|
+
|
|
151
|
+
export function registerAgentStatus(pi: ExtensionAPI): void {
|
|
152
|
+
pi.registerTool({
|
|
153
|
+
name: 'agent_status',
|
|
154
|
+
label: 'Agent status',
|
|
155
|
+
description: DESCRIPTION,
|
|
156
|
+
promptSnippet: 'Check subagents read-only (running or idle, last response) without restarting them',
|
|
157
|
+
parameters: AgentStatusParams,
|
|
158
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
159
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
160
|
+
const dir = subagentDir(ctx.cwd);
|
|
161
|
+
if (params.agent_id !== undefined) {
|
|
162
|
+
const status = agentStatus(dir, validateAgentId(params.agent_id));
|
|
163
|
+
return { content: [{ type: 'text', text: statusText(status) }], details: { agents: [status], total: status.state === 'missing' ? 0 : 1 } };
|
|
164
|
+
}
|
|
165
|
+
const { agents, total } = listAgentStatuses(dir);
|
|
166
|
+
const header = total === 0 ? 'No subagents in this workspace yet.' : `${total} subagent${total === 1 ? '' : 's'} in this workspace${total > agents.length ? `; the ${agents.length} newest` : ''}:`;
|
|
167
|
+
return { content: [{ type: 'text', text: [header, ...agents.map(statusText)].join('\n\n') }], details: { agents, total } };
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
}
|