@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
|
@@ -0,0 +1,365 @@
|
|
|
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 } 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
|
+
export interface ChildArgsOptions {
|
|
21
|
+
sessionDir: string;
|
|
22
|
+
agentId: string;
|
|
23
|
+
model?: ModelSpec;
|
|
24
|
+
readonly?: boolean;
|
|
25
|
+
/** Tools to add back to the loadout Pi restores from the transcript (records.ts `readonlyLaunchRestores`). */
|
|
26
|
+
restoreTools?: readonly string[];
|
|
27
|
+
/** The parent's project trust, so the child loads the same project resources (`ctx.isProjectTrusted()`). */
|
|
28
|
+
trusted?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Argv for one `pi --mode rpc` subagent process. Its prompts travel as RPC commands on stdin, never in argv. */
|
|
32
|
+
export function childArgs(options: ChildArgsOptions): string[] {
|
|
33
|
+
const model = options.model === undefined ? [] : ['--model', `${options.model.provider}/${options.model.id}`, ...(options.model.thinking === undefined ? [] : ['--thinking', options.model.thinking])];
|
|
34
|
+
return [
|
|
35
|
+
'--mode',
|
|
36
|
+
'rpc',
|
|
37
|
+
'--session-dir',
|
|
38
|
+
options.sessionDir,
|
|
39
|
+
'--session-id',
|
|
40
|
+
options.agentId,
|
|
41
|
+
'-e',
|
|
42
|
+
PACKAGE_ROOT,
|
|
43
|
+
...(options.trusted === undefined ? [] : [options.trusted ? '--approve' : '--no-approve']),
|
|
44
|
+
...model,
|
|
45
|
+
...(options.readonly === true ? ['--tools', READONLY_TOOLS, '--no-mcp'] : []),
|
|
46
|
+
...(options.readonly !== true && (options.restoreTools ?? []).length > 0 ? ['--tools', (options.restoreTools ?? []).map((name) => `+${name}`).join(',')] : []),
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function validateAgentId(id: string): string {
|
|
51
|
+
if (!AGENT_ID.test(id)) throw new Error(`"${id.slice(0, 80)}" is not a valid agent ID.`);
|
|
52
|
+
return id;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Absolute paths of files to attach: `~` expands as in Pi's read paths, and each must be an existing file. */
|
|
56
|
+
export function resolveAttachments(paths: readonly string[], cwd: string, home: string = homedir()): string[] {
|
|
57
|
+
return paths.map((path) => {
|
|
58
|
+
const expanded = path === '~' || path.startsWith('~/') ? join(home, path.slice(1)) : path;
|
|
59
|
+
const absolute = isAbsolute(expanded) ? expanded : resolve(cwd, expanded);
|
|
60
|
+
if (!existsSync(absolute)) throw new Error(`file_attachments: ${absolute} does not exist`);
|
|
61
|
+
if (!statSync(absolute).isFile()) throw new Error(`file_attachments: ${absolute} is not a file`);
|
|
62
|
+
return absolute;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface ChildInput {
|
|
67
|
+
text: string;
|
|
68
|
+
images: ImageContent[];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The first message Pi builds from piped input and `@file` arguments, which RPC mode does not accept: the trimmed
|
|
73
|
+
* prompt, then each non-empty text file in a <file> block, and each image as an attachment with an empty <file> block.
|
|
74
|
+
*/
|
|
75
|
+
export async function withAttachments(prompt: string, attachments: readonly string[]): Promise<ChildInput> {
|
|
76
|
+
let text = prompt.trim();
|
|
77
|
+
const images: ImageContent[] = [];
|
|
78
|
+
for (const path of attachments) {
|
|
79
|
+
const bytes = readFileSync(path);
|
|
80
|
+
if (bytes.length === 0) continue;
|
|
81
|
+
const mimeType = await detectSupportedImageMimeTypeFromFile(path);
|
|
82
|
+
if (mimeType === null) {
|
|
83
|
+
text += `<file name="${path}">\n${bytes.toString('utf8').replace(/^\uFEFF/, '')}\n</file>\n`;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
images.push({ type: 'image', mimeType, data: bytes.toString('base64') });
|
|
87
|
+
text += `<file name="${path}"></file>\n`;
|
|
88
|
+
}
|
|
89
|
+
return { text, images };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface ChildOptions {
|
|
93
|
+
command: readonly string[];
|
|
94
|
+
args: readonly string[];
|
|
95
|
+
prompt: string;
|
|
96
|
+
images?: readonly ImageContent[];
|
|
97
|
+
cwd: string;
|
|
98
|
+
env: NodeJS.ProcessEnv;
|
|
99
|
+
signal?: AbortSignal;
|
|
100
|
+
onEvent?: (event: { type: string } & Record<string, unknown>) => void;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface ChildOutcome {
|
|
104
|
+
finalText: string;
|
|
105
|
+
usage: Usage;
|
|
106
|
+
failure?: string;
|
|
107
|
+
stderr: string;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface ChildHandle {
|
|
111
|
+
done: Promise<ChildOutcome>;
|
|
112
|
+
/** Ends the child and its process group now: session shutdown or an aborted foreground call. */
|
|
113
|
+
kill: () => void;
|
|
114
|
+
/** stop_agent: aborts the run over RPC so the transcript records it, then kills the group if it outlives the grace period. */
|
|
115
|
+
stop: () => void;
|
|
116
|
+
/** Queues a message into the running turn (a new turn if the run just ended); rejects once the child is closing. */
|
|
117
|
+
steer: (text: string, images: readonly ImageContent[]) => Promise<void>;
|
|
118
|
+
pid: number | undefined;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
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 } });
|
|
122
|
+
|
|
123
|
+
export function addUsage(left: Usage, right: Usage): Usage {
|
|
124
|
+
return {
|
|
125
|
+
input: left.input + right.input,
|
|
126
|
+
output: left.output + right.output,
|
|
127
|
+
cacheRead: left.cacheRead + right.cacheRead,
|
|
128
|
+
cacheWrite: left.cacheWrite + right.cacheWrite,
|
|
129
|
+
totalTokens: left.totalTokens + right.totalTokens,
|
|
130
|
+
cost: {
|
|
131
|
+
input: left.cost.input + right.cost.input,
|
|
132
|
+
output: left.cost.output + right.cost.output,
|
|
133
|
+
cacheRead: left.cost.cacheRead + right.cost.cacheRead,
|
|
134
|
+
cacheWrite: left.cost.cacheWrite + right.cost.cacheWrite,
|
|
135
|
+
total: left.cost.total + right.cost.total,
|
|
136
|
+
totalFromProvider: left.cost.totalFromProvider === true && right.cost.totalFromProvider === true,
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
interface AssistantRecord {
|
|
142
|
+
text: string;
|
|
143
|
+
stopReason?: string;
|
|
144
|
+
errorMessage?: string;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Usage a JSON-mode event adds to the child's session totals, counted the way Pi's own session stats count it:
|
|
149
|
+
* assistant replies, tool results that carry nested usage (such as a grandchild subagent), and compactions.
|
|
150
|
+
*/
|
|
151
|
+
function usageOf(event: Record<string, unknown>): Usage | undefined {
|
|
152
|
+
if (event['type'] === 'compaction_end') return (event['result'] as { usage?: Usage } | undefined)?.usage;
|
|
153
|
+
const message = event['message'] as { role?: string; usage?: Usage } | undefined;
|
|
154
|
+
if (event['type'] !== 'message_end' || (message?.role !== 'assistant' && message?.role !== 'toolResult')) return undefined;
|
|
155
|
+
return message.usage;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function readAssistant(event: Record<string, unknown>): AssistantRecord | undefined {
|
|
159
|
+
const message = event['message'] as { role?: string; content?: { type: string; text?: string }[]; stopReason?: string; errorMessage?: string } | undefined;
|
|
160
|
+
if (event['type'] !== 'message_end' || message?.role !== 'assistant') return undefined;
|
|
161
|
+
const text = (message.content ?? [])
|
|
162
|
+
.filter((part) => part.type === 'text')
|
|
163
|
+
.map((part) => part.text ?? '')
|
|
164
|
+
.join('');
|
|
165
|
+
return {
|
|
166
|
+
text,
|
|
167
|
+
...(message.stopReason === undefined ? {} : { stopReason: message.stopReason }),
|
|
168
|
+
...(message.errorMessage === undefined ? {} : { errorMessage: message.errorMessage }),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function lineReader(onLine: (line: string) => void): (chunk: Buffer) => void {
|
|
173
|
+
const decoder = new StringDecoder('utf8');
|
|
174
|
+
let buffer = '';
|
|
175
|
+
return (chunk) => {
|
|
176
|
+
buffer += decoder.write(chunk);
|
|
177
|
+
for (let index = buffer.indexOf('\n'); index !== -1; index = buffer.indexOf('\n')) {
|
|
178
|
+
const line = buffer.slice(0, index).trim();
|
|
179
|
+
buffer = buffer.slice(index + 1);
|
|
180
|
+
if (line !== '') onLine(line);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** RPC mode reserves stdout for protocol records, but a child extension can still print there; such a line must not crash the parent. */
|
|
186
|
+
function parseEvent(line: string): ({ type: string } & Record<string, unknown>) | undefined {
|
|
187
|
+
try {
|
|
188
|
+
const value: unknown = JSON.parse(line);
|
|
189
|
+
return typeof value === 'object' && value !== null && typeof (value as { type?: unknown }).type === 'string' ? (value as { type: string } & Record<string, unknown>) : undefined;
|
|
190
|
+
} catch (error) {
|
|
191
|
+
if (error instanceof SyntaxError) return undefined;
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** Signals the child's whole process group. A group that is already gone (ESRCH) or not ours (EPERM) is left alone. */
|
|
197
|
+
export function signalGroup(pid: number, signal: NodeJS.Signals): void {
|
|
198
|
+
try {
|
|
199
|
+
process.kill(-pid, signal);
|
|
200
|
+
} catch (error) {
|
|
201
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
202
|
+
if (code !== 'ESRCH' && code !== 'EPERM') throw error;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function killGroup(pid: number | undefined): void {
|
|
207
|
+
if (pid === undefined) return;
|
|
208
|
+
signalGroup(pid, 'SIGTERM');
|
|
209
|
+
setTimeout(() => signalGroup(pid, 'SIGKILL'), KILL_GRACE_MS).unref();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
interface ChildState {
|
|
213
|
+
usage: Usage;
|
|
214
|
+
stderr: string;
|
|
215
|
+
aborted: boolean;
|
|
216
|
+
stopped: boolean;
|
|
217
|
+
/** Why Pi refused the first prompt. */
|
|
218
|
+
refused?: string;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function outcomeOf(last: AssistantRecord | undefined, state: ChildState, code: number | null): ChildOutcome {
|
|
222
|
+
const base = { finalText: last?.text ?? '', usage: state.usage, stderr: state.stderr };
|
|
223
|
+
if (state.aborted) return { ...base, failure: 'Subagent was aborted' };
|
|
224
|
+
if (state.stopped) return { ...base, failure: 'Subagent was stopped with stop_agent' };
|
|
225
|
+
if (state.refused !== undefined) return { ...base, failure: state.refused };
|
|
226
|
+
if (last?.stopReason === 'error' || last?.stopReason === 'aborted') return { ...base, failure: last.errorMessage ?? `subagent stopped: ${last.stopReason}` };
|
|
227
|
+
if (code !== 0) return { ...base, failure: `pi exited with code ${code}: ${state.stderr.trim().split('\n').at(-1) ?? ''}`.trim() };
|
|
228
|
+
return base;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
interface RpcResponse {
|
|
232
|
+
id?: string;
|
|
233
|
+
success: boolean;
|
|
234
|
+
error?: string;
|
|
235
|
+
data?: { disposition?: string; steering?: string[]; followUp?: string[] };
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Runs one `pi --mode rpc` child in its own process group, so abort and shutdown can stop it and everything it started.
|
|
240
|
+
* The child stays open while its run is active or a command awaits its response, so a steer always lands in a run;
|
|
241
|
+
* once the run settles with nothing outstanding, closing stdin makes Pi save the session and exit.
|
|
242
|
+
* Pi's `RpcClient` cannot start or end this child (no detached spawn, stdin close, `extension_ui_response`, or exit
|
|
243
|
+
* code); docs/native-gaps.md records each missing mechanism.
|
|
244
|
+
*/
|
|
245
|
+
export function startChild(options: ChildOptions): ChildHandle {
|
|
246
|
+
const [command, ...prefix] = options.command;
|
|
247
|
+
if (command === undefined) throw new Error('startChild needs a command');
|
|
248
|
+
const child = spawn(command, [...prefix, ...options.args], { cwd: options.cwd, env: options.env, stdio: ['pipe', 'pipe', 'pipe'], detached: true });
|
|
249
|
+
const state: ChildState = { usage: zeroUsage(), stderr: '', aborted: false, stopped: false };
|
|
250
|
+
let last: AssistantRecord | undefined;
|
|
251
|
+
let open = true;
|
|
252
|
+
let idle = true;
|
|
253
|
+
let steered = false;
|
|
254
|
+
let nextId = 0;
|
|
255
|
+
let grace: ReturnType<typeof setTimeout> | undefined;
|
|
256
|
+
const waiting = new Map<string, (response: RpcResponse) => void>();
|
|
257
|
+
|
|
258
|
+
const write = (record: Record<string, unknown>) => {
|
|
259
|
+
if (open) child.stdin.write(`${JSON.stringify(record)}\n`);
|
|
260
|
+
};
|
|
261
|
+
const close = () => {
|
|
262
|
+
if (!open) return;
|
|
263
|
+
open = false;
|
|
264
|
+
child.stdin.end();
|
|
265
|
+
};
|
|
266
|
+
const request = (record: Record<string, unknown>, onResponse: (response: RpcResponse) => void) => {
|
|
267
|
+
const id = `pstack-${nextId++}`;
|
|
268
|
+
waiting.set(id, onResponse);
|
|
269
|
+
write({ ...record, id });
|
|
270
|
+
};
|
|
271
|
+
const prompt = (text: string, images: readonly ImageContent[], onResponse: (response: RpcResponse) => void, streamingBehavior?: 'steer') =>
|
|
272
|
+
request({ type: 'prompt', message: text, ...(images.length === 0 ? {} : { images }), ...(streamingBehavior === undefined ? {} : { streamingBehavior }) }, (response) => {
|
|
273
|
+
if (response.data?.disposition === 'started') idle = false;
|
|
274
|
+
onResponse(response);
|
|
275
|
+
});
|
|
276
|
+
// A steer can reach Pi just as its run ends and stay queued with no run to take it, so it goes out as a new prompt.
|
|
277
|
+
const closeWhenSettled = () => {
|
|
278
|
+
if (!open || !idle || waiting.size > 0) return;
|
|
279
|
+
if (!steered || state.stopped) return close();
|
|
280
|
+
steered = false;
|
|
281
|
+
request({ type: 'clear_queue' }, (response) => {
|
|
282
|
+
const left = [...(response.data?.steering ?? []), ...(response.data?.followUp ?? [])];
|
|
283
|
+
if (left.length > 0) prompt(left.join('\n\n'), [], () => undefined);
|
|
284
|
+
});
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const kill = () => {
|
|
288
|
+
state.aborted = true;
|
|
289
|
+
killGroup(child.pid);
|
|
290
|
+
};
|
|
291
|
+
const stop = () => {
|
|
292
|
+
if (state.stopped || state.aborted) return;
|
|
293
|
+
state.stopped = true;
|
|
294
|
+
request({ type: 'clear_queue' }, () => undefined);
|
|
295
|
+
request({ type: 'abort' }, () => undefined);
|
|
296
|
+
grace = setTimeout(() => killGroup(child.pid), KILL_GRACE_MS);
|
|
297
|
+
grace.unref();
|
|
298
|
+
};
|
|
299
|
+
const steer = (text: string, images: readonly ImageContent[]) =>
|
|
300
|
+
new Promise<void>((resolve, reject) => {
|
|
301
|
+
if (!open || state.stopped || state.aborted) return reject(new Error('The subagent has finished its run.'));
|
|
302
|
+
steered = true;
|
|
303
|
+
prompt(text, images, (response) => (response.success ? resolve() : reject(new Error(response.error ?? 'Pi refused the message.'))), 'steer');
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
const onRecord = (record: { type: string } & Record<string, unknown>) => {
|
|
307
|
+
if (record.type === 'response') {
|
|
308
|
+
const response = record as unknown as RpcResponse;
|
|
309
|
+
const onResponse = response.id === undefined ? undefined : waiting.get(response.id);
|
|
310
|
+
if (onResponse === undefined) return;
|
|
311
|
+
waiting.delete(response.id as string);
|
|
312
|
+
onResponse(response);
|
|
313
|
+
return closeWhenSettled();
|
|
314
|
+
}
|
|
315
|
+
if (record.type === 'extension_ui_request') {
|
|
316
|
+
if (DIALOG_METHODS.has(String(record['method']))) write({ type: 'extension_ui_response', id: record['id'], cancelled: true });
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
options.onEvent?.(record);
|
|
320
|
+
if (record.type === 'agent_start') idle = false;
|
|
321
|
+
const usage = usageOf(record);
|
|
322
|
+
if (usage !== undefined) state.usage = addUsage(state.usage, usage);
|
|
323
|
+
last = readAssistant(record) ?? last;
|
|
324
|
+
if (record.type === 'agent_settled') {
|
|
325
|
+
idle = true;
|
|
326
|
+
closeWhenSettled();
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
child.stdout.on(
|
|
331
|
+
'data',
|
|
332
|
+
lineReader((line) => {
|
|
333
|
+
const record = parseEvent(line);
|
|
334
|
+
if (record === undefined) state.stderr = `${state.stderr}${line}\n`.slice(-8_192);
|
|
335
|
+
else onRecord(record);
|
|
336
|
+
}),
|
|
337
|
+
);
|
|
338
|
+
child.stderr.on('data', (chunk: Buffer) => {
|
|
339
|
+
state.stderr = `${state.stderr}${chunk.toString('utf8')}`.slice(-8_192);
|
|
340
|
+
});
|
|
341
|
+
// A child that exits or is killed before it reads a large prompt closes the pipe. Unhandled, that EPIPE would be an
|
|
342
|
+
// uncaught exception in the parent, and interactive Pi exits on one; the child's exit already reports the failure.
|
|
343
|
+
child.stdin.on('error', (error: NodeJS.ErrnoException) => {
|
|
344
|
+
if (error.code !== 'EPIPE' && error.code !== 'ECONNRESET') state.stderr = `${state.stderr}stdin: ${error.message}\n`.slice(-8_192);
|
|
345
|
+
});
|
|
346
|
+
if (options.signal?.aborted) kill();
|
|
347
|
+
else options.signal?.addEventListener('abort', kill, { once: true });
|
|
348
|
+
if (state.aborted || (options.prompt.trim() === '' && (options.images ?? []).length === 0)) close();
|
|
349
|
+
else
|
|
350
|
+
prompt(options.prompt, options.images ?? [], (response) => {
|
|
351
|
+
if (!response.success) state.refused = response.error ?? 'Pi refused the prompt.';
|
|
352
|
+
});
|
|
353
|
+
const done = new Promise<ChildOutcome>((resolveDone) => {
|
|
354
|
+
child.on('error', (error) => resolveDone({ finalText: '', usage: state.usage, stderr: state.stderr, failure: `could not start pi: ${error.message}` }));
|
|
355
|
+
child.on('close', (code) => {
|
|
356
|
+
open = false;
|
|
357
|
+
clearTimeout(grace);
|
|
358
|
+
options.signal?.removeEventListener('abort', kill);
|
|
359
|
+
resolveDone(outcomeOf(last, state, code));
|
|
360
|
+
for (const onResponse of waiting.values()) onResponse({ success: false, error: 'The subagent exited.' });
|
|
361
|
+
waiting.clear();
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
return { done, kill, stop, steer, pid: child.pid };
|
|
365
|
+
}
|
|
@@ -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
|
+
}
|
package/src/task/stop.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { statSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
|
|
5
|
+
import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
6
|
+
import { Type } from 'typebox';
|
|
7
|
+
import { subagentDir } from '../paths.ts';
|
|
8
|
+
import { type ChildHandle, KILL_GRACE_MS, signalGroup, validateAgentId } from './runner.ts';
|
|
9
|
+
import { agentStatus } from './status.ts';
|
|
10
|
+
|
|
11
|
+
// A subagent starts a moment before its owner writes its pid into the run lock.
|
|
12
|
+
const LOCK_AFTER_START_MS = 3_000;
|
|
13
|
+
const POLL_MS = 100;
|
|
14
|
+
|
|
15
|
+
function processStart(pid: number): number | undefined {
|
|
16
|
+
try {
|
|
17
|
+
const started = Date.parse(execFileSync('ps', ['-o', 'lstart=', '-p', String(pid)], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim());
|
|
18
|
+
return Number.isNaN(started) ? undefined : started;
|
|
19
|
+
} catch {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Whether the run lock's pid is the subagent process: one this user may signal that started just before the lock named
|
|
26
|
+
* it. That refuses a lock naming its owner while the owner prepares the launch, and a pid reused after a crash.
|
|
27
|
+
*/
|
|
28
|
+
function isLockedChild(lockPath: string, pid: number): boolean {
|
|
29
|
+
try {
|
|
30
|
+
process.kill(pid, 0);
|
|
31
|
+
} catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
const started = processStart(pid);
|
|
35
|
+
const named = statSync(lockPath).mtimeMs;
|
|
36
|
+
return started !== undefined && started <= named && started >= named - LOCK_AFTER_START_MS;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const alive = (pid: number) => {
|
|
40
|
+
try {
|
|
41
|
+
process.kill(pid, 0);
|
|
42
|
+
return true;
|
|
43
|
+
} catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
async function exited(pid: number, withinMs: number): Promise<boolean> {
|
|
49
|
+
const deadline = Date.now() + withinMs;
|
|
50
|
+
while (alive(pid) && Date.now() < deadline) await new Promise((resolve) => setTimeout(resolve, POLL_MS));
|
|
51
|
+
return !alive(pid);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Stops the subagent another Pi process runs: SIGTERM to its process group, then SIGKILL after the grace period. */
|
|
55
|
+
async function stopElsewhere(agentId: string, lockPath: string, pid: number): Promise<string> {
|
|
56
|
+
if (!isLockedChild(lockPath, pid))
|
|
57
|
+
return `Agent ${agentId}'s run lock names pid ${pid}, which is not a subagent process this user can stop (its owner may still be starting it, or the lock is stale). Nothing was signalled; check again with agent_status.`;
|
|
58
|
+
signalGroup(pid, 'SIGTERM');
|
|
59
|
+
if (await exited(pid, KILL_GRACE_MS)) return `Stopped agent ${agentId}: another Pi process ran it (pid ${pid}), so it got SIGTERM and has exited. That process reports the stop as the agent's result.`;
|
|
60
|
+
signalGroup(pid, 'SIGKILL');
|
|
61
|
+
const gone = await exited(pid, KILL_GRACE_MS);
|
|
62
|
+
return `Agent ${agentId} (pid ${pid}, run by another Pi process) ignored SIGTERM, so it got SIGKILL${gone ? ' and has exited' : ' and has not exited yet'}.`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface StopAgentOptions {
|
|
66
|
+
/** A child this process runs, if any. */
|
|
67
|
+
running: (agentId: string) => { handle: ChildHandle } | undefined;
|
|
68
|
+
depth: number;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const DESCRIPTION =
|
|
72
|
+
'Stop a running subagent: abort its run and end its process. Its result (the completion notification of a background agent, or the waiting Task result of a foreground one) reports the stop. An agent that is not running is left alone. Resume a stopped agent with Task resume.';
|
|
73
|
+
|
|
74
|
+
export function registerStopAgent(pi: ExtensionAPI, options: StopAgentOptions): void {
|
|
75
|
+
pi.registerTool({
|
|
76
|
+
name: 'stop_agent',
|
|
77
|
+
label: 'Stop agent',
|
|
78
|
+
description: DESCRIPTION,
|
|
79
|
+
promptSnippet: 'Stop a running subagent by agent ID',
|
|
80
|
+
parameters: Type.Object({ agent_id: Type.String({ description: 'Agent ID from an earlier Task call in this workspace.' }) }),
|
|
81
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
82
|
+
// Nesting stops at the subagent of a subagent, which has no subagents to stop.
|
|
83
|
+
defaultActive: options.depth < 2,
|
|
84
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
85
|
+
const agentId = validateAgentId(params.agent_id);
|
|
86
|
+
const owned = options.running(agentId);
|
|
87
|
+
if (owned !== undefined) {
|
|
88
|
+
owned.handle.stop();
|
|
89
|
+
await owned.handle.done;
|
|
90
|
+
return { content: [{ type: 'text', text: `Stopped agent ${agentId}: its run was aborted and its process has exited. Its result reports the stop; resume it with Task resume.` }], details: { agentId, stopped: true } };
|
|
91
|
+
}
|
|
92
|
+
const dir = subagentDir(ctx.cwd);
|
|
93
|
+
const status = agentStatus(dir, agentId);
|
|
94
|
+
if (status.state === 'missing') throw new Error(`Unknown agent ID ${agentId}. stop_agent needs an agent ID returned by an earlier Task call in this workspace.`);
|
|
95
|
+
if (status.state === 'idle' || status.pid === undefined) return { content: [{ type: 'text', text: `Agent ${agentId} is not running, so there is nothing to stop.` }], details: { agentId, stopped: false } };
|
|
96
|
+
const text = await stopElsewhere(agentId, join(dir, `${agentId}.lock`), status.pid);
|
|
97
|
+
return { content: [{ type: 'text', text }], details: { agentId, stopped: !alive(status.pid), pid: status.pid } };
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|