@justjoshn/pi-pstack 0.0.0-stage → 0.15.36-pi.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +95 -2
- package/agents/comment-sicko.md +32 -0
- package/agents/poteto-agent.md +9 -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/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 +67 -0
- package/licenses/cursor-team-kit.LICENSE +21 -0
- package/licenses/pstack.LICENSE +21 -0
- package/package.json +51 -4
- package/scripts/live-e2e.mjs +257 -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/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 +62 -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/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/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/no-comments/SKILL.md +24 -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/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/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/typescript-best-practices/SKILL.md +32 -0
- package/skills/typescript-best-practices/references/patterns.md +328 -0
- package/skills/unslop/SKILL.md +62 -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/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 +72 -0
- package/src/plan.ts +141 -0
- package/src/readonly-shell.ts +107 -0
- package/src/rule.ts +56 -0
- package/src/sections.ts +117 -0
- package/src/subscriptions/cron.ts +75 -0
- package/src/subscriptions/github.ts +149 -0
- package/src/subscriptions/index.ts +547 -0
- package/src/subscriptions/webhook.ts +209 -0
- package/src/task/agents.ts +55 -0
- package/src/task/card.ts +32 -0
- package/src/task/format.ts +88 -0
- package/src/task/models.ts +140 -0
- package/src/task/records.ts +232 -0
- package/src/task/registry.ts +77 -0
- package/src/task/runner.ts +370 -0
- package/src/task/status.ts +170 -0
- package/src/task/stop.ts +100 -0
- package/src/task/tool.ts +491 -0
- package/src/task/worktree.ts +67 -0
- package/src/todo.ts +122 -0
- package/src/visualize.ts +244 -0
- package/test/aliases.test.ts +57 -0
- package/test/ask.test.ts +85 -0
- package/test/autocomplete.test.ts +39 -0
- package/test/e2e/aliases.e2e.test.ts +81 -0
- package/test/e2e/ask.e2e.test.ts +135 -0
- package/test/e2e/harness.ts +179 -0
- package/test/e2e/host.e2e.test.ts +193 -0
- package/test/e2e/lifecycle.e2e.test.ts +99 -0
- package/test/e2e/mode.e2e.test.ts +160 -0
- package/test/e2e/package.e2e.test.ts +67 -0
- package/test/e2e/task.e2e.test.ts +734 -0
- package/test/e2e/todo.e2e.test.ts +59 -0
- package/test/fixtures/cursor-askquestion-calls.json +806 -0
- package/test/fixtures/fake-pi.mjs +96 -0
- package/test/fixtures/image-model.ts +16 -0
- package/test/fixtures/list-models.ts +15 -0
- package/test/fixtures/readonly-shell-exit.ts +17 -0
- package/test/fixtures/scripted-model.ts +113 -0
- package/test/loop.test.ts +209 -0
- package/test/mode.test.ts +143 -0
- package/test/plan.test.ts +126 -0
- package/test/readonly-shell-security.test.ts +84 -0
- package/test/readonly-shell.test.ts +44 -0
- package/test/records.test.ts +143 -0
- package/test/registry.test.ts +18 -0
- package/test/resources.test.ts +162 -0
- package/test/rule.test.ts +92 -0
- package/test/scripts.test.ts +182 -0
- package/test/sections.test.ts +56 -0
- package/test/subscriptions-cron.test.ts +60 -0
- package/test/subscriptions.test.ts +598 -0
- package/test/task-agents.test.ts +49 -0
- package/test/task-card.test.ts +34 -0
- package/test/task-fork.test.ts +233 -0
- package/test/task-format.test.ts +65 -0
- package/test/task-model.test.ts +141 -0
- package/test/task-runner.test.ts +259 -0
- package/test/task-schema.test.ts +50 -0
- package/test/task-status.test.ts +155 -0
- package/test/task-worktree.test.ts +106 -0
- package/test/todo.test.ts +74 -0
- package/test/visualize.test.ts +152 -0
- package/tsconfig.json +5 -0
- package/vitest.config.ts +16 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { createHash, randomBytes, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http';
|
|
4
|
+
import type { AddressInfo } from 'node:net';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
|
|
7
|
+
export const DEFAULT_ROUTINES_PORT = 47913;
|
|
8
|
+
export const MAX_BODY_BYTES = 64 * 1024;
|
|
9
|
+
const HOST = '127.0.0.1';
|
|
10
|
+
const KEY = /^[0-9a-f]{64}$/;
|
|
11
|
+
|
|
12
|
+
export function routineSlug(name: string): string {
|
|
13
|
+
const slug = name
|
|
14
|
+
.normalize('NFKD')
|
|
15
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
16
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
17
|
+
.toLowerCase()
|
|
18
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
19
|
+
.replace(/^-+|-+$/g, '');
|
|
20
|
+
if (slug === '') throw new Error(`Routine name "${name}" has no letters or digits to make a slug from.`);
|
|
21
|
+
return slug.slice(0, 64).replace(/-+$/, '');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function credentialFile(routinesDir: string, slug: string): string {
|
|
25
|
+
return join(routinesDir, slug, 'credentials.json');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function readKey(file: string): string | undefined {
|
|
29
|
+
try {
|
|
30
|
+
const key = (JSON.parse(readFileSync(file, 'utf8')) as { key?: unknown } | null)?.key;
|
|
31
|
+
return typeof key === 'string' && KEY.test(key) ? key : undefined;
|
|
32
|
+
} catch {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const errno = (error: unknown) => (typeof error === 'object' && error !== null && 'code' in error ? String((error as { code: unknown }).code) : undefined);
|
|
38
|
+
const pause = (ms: number) => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
39
|
+
|
|
40
|
+
/** The routine's sender key file, created with a fresh key unless a valid one is already there. Returns the path only. */
|
|
41
|
+
export function ensureCredentials(routinesDir: string, slug: string): string {
|
|
42
|
+
const file = credentialFile(routinesDir, slug);
|
|
43
|
+
mkdirSync(join(routinesDir, slug), { recursive: true, mode: 0o700 });
|
|
44
|
+
for (let attempt = 0; attempt < 5; attempt += 1) {
|
|
45
|
+
const key = readKey(file);
|
|
46
|
+
if (key !== undefined) {
|
|
47
|
+
chmodSync(file, 0o600);
|
|
48
|
+
return file;
|
|
49
|
+
}
|
|
50
|
+
if (!existsSync(file)) {
|
|
51
|
+
try {
|
|
52
|
+
writeFileSync(file, `${JSON.stringify({ key: randomBytes(32).toString('hex') })}\n`, { flag: 'wx', mode: 0o600 });
|
|
53
|
+
chmodSync(file, 0o600);
|
|
54
|
+
return file;
|
|
55
|
+
} catch (error) {
|
|
56
|
+
if (errno(error) !== 'EEXIST') throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (attempt < 4) pause(5);
|
|
60
|
+
}
|
|
61
|
+
if (readKey(file) !== undefined) {
|
|
62
|
+
chmodSync(file, 0o600);
|
|
63
|
+
return file;
|
|
64
|
+
}
|
|
65
|
+
writeFileSync(file, `${JSON.stringify({ key: randomBytes(32).toString('hex') })}\n`, { mode: 0o600 });
|
|
66
|
+
chmodSync(file, 0o600);
|
|
67
|
+
return file;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const digest = (text: string) => createHash('sha256').update(text).digest();
|
|
71
|
+
|
|
72
|
+
/** Constant-time: both sides are hashed first, so length differences do not leak either. */
|
|
73
|
+
export function keyMatches(presented: string | undefined, expected: string | undefined): boolean {
|
|
74
|
+
if (presented === undefined || expected === undefined) return false;
|
|
75
|
+
return timingSafeEqual(digest(presented), digest(expected));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function presentedKey(request: IncomingMessage): string | undefined {
|
|
79
|
+
const header = request.headers['x-automation-key'];
|
|
80
|
+
if (typeof header === 'string' && header !== '') return header.trim();
|
|
81
|
+
const bearer = /^Bearer\s+(\S+)\s*$/i.exec(request.headers.authorization ?? '');
|
|
82
|
+
return bearer?.[1];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface WebhookEvent {
|
|
86
|
+
headers: Record<string, string>;
|
|
87
|
+
bodyDigest: string;
|
|
88
|
+
body: string;
|
|
89
|
+
timestampMs: number;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** JSON whose `<` is escaped, so a body cannot close the surrounding tag; it still parses to the same value. */
|
|
93
|
+
const tagSafeJson = (value: unknown) => JSON.stringify(value, null, 2).replace(/</g, '\\u003c');
|
|
94
|
+
|
|
95
|
+
export function webhookEventBlock(event: WebhookEvent): string {
|
|
96
|
+
return ['<webhook_event>', tagSafeJson({ headers: event.headers, body_digest: event.bodyDigest, body: event.body, timestamp_ms: event.timestampMs }), '</webhook_event>'].join('\n');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface RoutineRoute {
|
|
100
|
+
slug: string;
|
|
101
|
+
credentialFile: string;
|
|
102
|
+
onEvent: (event: WebhookEvent) => void;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const reply = (response: ServerResponse, status: number, message: string) => {
|
|
106
|
+
response.writeHead(status, { 'content-type': 'application/json', connection: 'close' });
|
|
107
|
+
response.end(`${JSON.stringify(status === 200 ? { ok: true } : { error: message })}\n`);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/** One local listener for every routine of this process. Routes are looked up per request, so they can change while it runs. */
|
|
111
|
+
export class RoutineServer {
|
|
112
|
+
private server: Server | undefined;
|
|
113
|
+
private listening: Promise<number> | undefined;
|
|
114
|
+
readonly routes = new Map<string, RoutineRoute>();
|
|
115
|
+
private readonly port: number;
|
|
116
|
+
|
|
117
|
+
constructor(port: number) {
|
|
118
|
+
this.port = port;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Starts the listener once and resolves to its port. */
|
|
122
|
+
start(): Promise<number> {
|
|
123
|
+
this.listening ??= new Promise<number>((resolve, reject) => {
|
|
124
|
+
const server = createServer((request, response) => this.handle(request, response));
|
|
125
|
+
server.once('error', (error: NodeJS.ErrnoException) => {
|
|
126
|
+
this.listening = undefined;
|
|
127
|
+
this.server = undefined;
|
|
128
|
+
reject(new Error(error.code === 'EADDRINUSE' ? `Port ${this.port} on ${HOST} is in use (another Pi process may own the routines listener). Set PSTACK_ROUTINES_PORT to a free port.` : `Routines listener failed: ${error.message}`));
|
|
129
|
+
});
|
|
130
|
+
server.listen(this.port, HOST, () => {
|
|
131
|
+
server.unref();
|
|
132
|
+
resolve((server.address() as AddressInfo).port);
|
|
133
|
+
});
|
|
134
|
+
this.server = server;
|
|
135
|
+
});
|
|
136
|
+
return this.listening;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async url(slug: string): Promise<string> {
|
|
140
|
+
return `http://${HOST}:${await this.start()}/routines/${slug}`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
isListening(): boolean {
|
|
144
|
+
return this.server?.listening === true;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
close(): void {
|
|
148
|
+
this.server?.close();
|
|
149
|
+
this.server?.closeAllConnections();
|
|
150
|
+
this.server = undefined;
|
|
151
|
+
this.listening = undefined;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
private handle(request: IncomingMessage, response: ServerResponse): void {
|
|
155
|
+
const slug = /^\/routines\/([a-z0-9-]+)\/?$/.exec(new URL(request.url ?? '/', 'http://localhost').pathname)?.[1];
|
|
156
|
+
const route = slug === undefined ? undefined : this.routes.get(slug);
|
|
157
|
+
if (route === undefined) {
|
|
158
|
+
reply(response, 404, 'No such routine.');
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (request.method !== 'POST') {
|
|
162
|
+
response.setHeader('allow', 'POST');
|
|
163
|
+
reply(response, 405, 'Use POST.');
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (!keyMatches(presentedKey(request), readKey(route.credentialFile))) {
|
|
167
|
+
reply(response, 401, 'Wrong or missing sender key.');
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (Number(request.headers['content-length'] ?? 0) > MAX_BODY_BYTES) {
|
|
171
|
+
reply(response, 413, `Body over ${MAX_BODY_BYTES} bytes.`);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const chunks: Buffer[] = [];
|
|
175
|
+
let size = 0;
|
|
176
|
+
let done = false;
|
|
177
|
+
request.on('data', (chunk: Buffer) => {
|
|
178
|
+
if (done) return;
|
|
179
|
+
size += chunk.length;
|
|
180
|
+
if (size > MAX_BODY_BYTES) {
|
|
181
|
+
done = true;
|
|
182
|
+
reply(response, 413, `Body over ${MAX_BODY_BYTES} bytes.`);
|
|
183
|
+
request.resume();
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
chunks.push(chunk);
|
|
187
|
+
});
|
|
188
|
+
request.on('end', () => {
|
|
189
|
+
if (done) return;
|
|
190
|
+
done = true;
|
|
191
|
+
const raw = Buffer.concat(chunks);
|
|
192
|
+
const body = raw.toString('utf8');
|
|
193
|
+
let parsed: unknown;
|
|
194
|
+
try {
|
|
195
|
+
parsed = JSON.parse(body);
|
|
196
|
+
} catch {
|
|
197
|
+
parsed = undefined;
|
|
198
|
+
}
|
|
199
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) return reply(response, 400, 'Body must be a JSON object.');
|
|
200
|
+
const headers: Record<string, string> = {};
|
|
201
|
+
for (const name of ['content-type', 'user-agent'] as const) {
|
|
202
|
+
const header = request.headers[name];
|
|
203
|
+
if (typeof header === 'string') headers[name] = header;
|
|
204
|
+
}
|
|
205
|
+
route.onEvent({ headers, bodyDigest: createHash('sha256').update(raw).digest('hex'), body, timestampMs: Date.now() });
|
|
206
|
+
reply(response, 200, 'ok');
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { basename, join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { parseFrontmatter } from '@earendil-works/pi-coding-agent';
|
|
5
|
+
import { AGENTS_DIR } from '../paths.ts';
|
|
6
|
+
|
|
7
|
+
/** A subagent type from an agent file: name, description, model, readonly, is_background, prompt body. */
|
|
8
|
+
export interface AgentDefinition {
|
|
9
|
+
type: string;
|
|
10
|
+
description: string;
|
|
11
|
+
model?: string;
|
|
12
|
+
readonly: boolean;
|
|
13
|
+
background: boolean;
|
|
14
|
+
prompt: string;
|
|
15
|
+
file?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const GENERAL_PURPOSE: AgentDefinition = {
|
|
19
|
+
type: 'generalPurpose',
|
|
20
|
+
description: 'General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. Use when a search or task needs several steps of its own.',
|
|
21
|
+
readonly: false,
|
|
22
|
+
background: false,
|
|
23
|
+
prompt: '',
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function parseAgentFile(file: string): AgentDefinition {
|
|
27
|
+
const { frontmatter, body } = parseFrontmatter(readFileSync(file, 'utf8'));
|
|
28
|
+
const name = frontmatter['name'];
|
|
29
|
+
const description = frontmatter['description'];
|
|
30
|
+
const model = frontmatter['model'];
|
|
31
|
+
return {
|
|
32
|
+
type: typeof name === 'string' && name.trim() !== '' ? name.trim() : basename(file, '.md'),
|
|
33
|
+
description: typeof description === 'string' ? description.trim() : '',
|
|
34
|
+
...(typeof model === 'string' && model.trim() !== '' ? { model: model.trim() } : {}),
|
|
35
|
+
readonly: frontmatter['readonly'] === true,
|
|
36
|
+
background: frontmatter['is_background'] === true,
|
|
37
|
+
prompt: body.trim(),
|
|
38
|
+
file,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** generalPurpose first, then every `*.md` agent file in `dir` sorted by file name. */
|
|
43
|
+
export function loadAgentDefinitions(dir: string = AGENTS_DIR): AgentDefinition[] {
|
|
44
|
+
const files = readdirSync(dir)
|
|
45
|
+
.filter((name) => name.endsWith('.md'))
|
|
46
|
+
.toSorted();
|
|
47
|
+
return [GENERAL_PURPOSE, ...files.map((name) => parseAgentFile(join(dir, name)))];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function findAgent(agents: readonly AgentDefinition[], type: string | undefined): AgentDefinition {
|
|
51
|
+
const wanted = type ?? GENERAL_PURPOSE.type;
|
|
52
|
+
const agent = agents.find((candidate) => candidate.type === wanted);
|
|
53
|
+
if (agent) return agent;
|
|
54
|
+
throw new Error(`Unknown subagent_type "${wanted}". Available subagent types: ${agents.map((candidate) => candidate.type).join(', ')}.`);
|
|
55
|
+
}
|
package/src/task/card.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { AgentToolResult } from '@earendil-works/pi-agent-core';
|
|
2
|
+
import { Text } from '@earendil-works/pi-tui';
|
|
3
|
+
|
|
4
|
+
const COLLAPSED_LINES = 10;
|
|
5
|
+
|
|
6
|
+
interface CardDetails {
|
|
7
|
+
subagentType: string;
|
|
8
|
+
model: { provider: string; id: string; thinking?: string } | null;
|
|
9
|
+
worktree?: { branch: string } | null;
|
|
10
|
+
description?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function isCardDetails(details: unknown): details is CardDetails {
|
|
14
|
+
return typeof details === 'object' && details !== null && 'subagentType' in details && 'model' in details;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Heads the Task result with the Task description and the model that ran. */
|
|
18
|
+
export function taskCardText(result: Pick<AgentToolResult<unknown>, 'content' | 'details'>, expanded: boolean): string {
|
|
19
|
+
const text = result.content.map((part) => (part.type === 'text' ? part.text : '')).join('\n');
|
|
20
|
+
const lines = text.split('\n');
|
|
21
|
+
const body = expanded || lines.length <= COLLAPSED_LINES ? lines : [...lines.slice(0, COLLAPSED_LINES), `… ${lines.length - COLLAPSED_LINES} more lines`];
|
|
22
|
+
if (!isCardDetails(result.details)) return body.join('\n');
|
|
23
|
+
const { model, subagentType, worktree, description } = result.details;
|
|
24
|
+
const modelName = model === null ? "Pi's default model" : `${model.provider}/${model.id}${model.thinking === undefined ? '' : `:${model.thinking}`}`;
|
|
25
|
+
const branch = worktree === undefined || worktree === null ? '' : ` · branch ${worktree.branch}`;
|
|
26
|
+
const title = description === undefined || description.trim() === '' ? '' : `${description.trim()} · `;
|
|
27
|
+
return [`${title}${subagentType} · ${modelName}${branch}`, ...body].join('\n');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function renderTaskCard(result: AgentToolResult<unknown>, options: { expanded: boolean }): Text {
|
|
31
|
+
return new Text(taskCardText(result, options.expanded), 0, 0);
|
|
32
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Model-facing texts: a <response> block, an "Agent ID:" line that names `resume`, and a <task> notification block
|
|
2
|
+
// with the same fields.
|
|
3
|
+
import type { Usage } from '@earendil-works/pi-ai';
|
|
4
|
+
import { DEFAULT_MAX_BYTES, formatSize, truncateHead } from '@earendil-works/pi-coding-agent';
|
|
5
|
+
import type { Worktree } from './worktree.ts';
|
|
6
|
+
|
|
7
|
+
/** The first `limit` bytes, cut back to a UTF-8 character boundary (past 10xxxxxx continuation bytes). */
|
|
8
|
+
function headBytes(bytes: Buffer, limit: number): string {
|
|
9
|
+
let end = limit;
|
|
10
|
+
while (end > 0 && ((bytes[end] ?? 0) & 0xc0) === 0x80) end -= 1;
|
|
11
|
+
return bytes.subarray(0, end).toString('utf8');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Bounds a response with Pi's own tool-output limits (truncateHead: 2000 lines or 50KB). truncateHead keeps whole
|
|
16
|
+
* lines and returns nothing when the first line alone is too long, and a subagent's reply can be one long line, so
|
|
17
|
+
* that case keeps the line's first 50KB instead.
|
|
18
|
+
*/
|
|
19
|
+
export function bounded(text: string, transcript: string | undefined): string {
|
|
20
|
+
const result = truncateHead(text);
|
|
21
|
+
if (!result.truncated) return text;
|
|
22
|
+
const where = `the full response is in ${transcript ?? 'the subagent transcript'}`;
|
|
23
|
+
if (result.firstLineExceedsLimit) {
|
|
24
|
+
const head = headBytes(Buffer.from(text, 'utf8'), DEFAULT_MAX_BYTES);
|
|
25
|
+
return `${head}\n[truncated: showing ${formatSize(Buffer.byteLength(head, 'utf8'))} of ${formatSize(result.totalBytes)}; ${where}]`;
|
|
26
|
+
}
|
|
27
|
+
const size = result.truncatedBy === 'bytes' ? ` (${formatSize(result.outputBytes)} of ${formatSize(result.totalBytes)})` : '';
|
|
28
|
+
return `${result.content}\n[truncated: showing ${result.outputLines} of ${result.totalLines} lines${size}; ${where}]`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const agentIdLine = (agentId: string) => `Agent ID: ${agentId} (pass it as \`resume\` to send a follow-up after it completes)`;
|
|
32
|
+
const transcriptLine = (transcript: string | undefined) => (transcript === undefined ? [] : [`Transcript: ${transcript}`]);
|
|
33
|
+
|
|
34
|
+
export function foregroundText(agentId: string, response: string, transcript: string | undefined, notes: readonly string[] = []): string {
|
|
35
|
+
return ['This is the output of the subagent:', '', 'response:', '<response>', bounded(response, transcript), '</response>', '', agentIdLine(agentId), ...transcriptLine(transcript), ...notes].join('\n');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function backgroundText(agentId: string, transcript: string | undefined, notes: readonly string[] = []): string {
|
|
39
|
+
return [
|
|
40
|
+
'Subagent is running in the background. Its final response arrives automatically after your turn ends, so do not wait or poll for it. End your turn or work on something else.',
|
|
41
|
+
'',
|
|
42
|
+
agentIdLine(agentId),
|
|
43
|
+
...transcriptLine(transcript),
|
|
44
|
+
...notes,
|
|
45
|
+
].join('\n');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function steerText(agentId: string, notes: readonly string[] = []): string {
|
|
49
|
+
return [
|
|
50
|
+
`Sent to agent ${agentId} while it runs: it reads the message after its current step. Its final response still arrives as its launch said, as a completion notification for a background agent or as the waiting Task result for a foreground one, so do not wait or poll for it.`,
|
|
51
|
+
...notes,
|
|
52
|
+
].join('\n');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function worktreeLine(worktree: Worktree): string {
|
|
56
|
+
return `Worktree: ${worktree.path} on branch ${worktree.branch}, from ${worktree.base} at ${worktree.commit}. Merge ${worktree.branch} to take the subagent's commits.`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Opens a cloud agent's first prompt, since nothing else tells the child that the parent merges from its branch. */
|
|
60
|
+
export function worktreePreface(worktree: Worktree, prompt: string): string {
|
|
61
|
+
const where = worktree.cwd === worktree.path ? worktree.path : `${worktree.path} (working directory ${worktree.cwd})`;
|
|
62
|
+
return `You are running in an isolated git worktree at ${where} on branch ${worktree.branch}, created from ${worktree.base} at ${worktree.commit}. Uncommitted changes in the parent's checkout are not here. Commit your changes to ${worktree.branch} before you finish, because the parent agent merges from that branch.\n\n${prompt}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface NotificationFields {
|
|
66
|
+
status: 'success' | 'error';
|
|
67
|
+
agentId: string;
|
|
68
|
+
title: string;
|
|
69
|
+
toolCallId: string;
|
|
70
|
+
detail: string;
|
|
71
|
+
/** What the background child spent. It stays in the notification details, because Pi gives extensions no way to add it to session totals. */
|
|
72
|
+
usage?: Usage;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function notificationText(fields: NotificationFields): string {
|
|
76
|
+
return [
|
|
77
|
+
'The following task has finished. If you already handled it, ignore this notification and do not restate earlier responses.',
|
|
78
|
+
'',
|
|
79
|
+
'<task>',
|
|
80
|
+
'kind: subagent',
|
|
81
|
+
`status: ${fields.status}`,
|
|
82
|
+
`task_id: ${fields.agentId}`,
|
|
83
|
+
`title: ${fields.title}`,
|
|
84
|
+
`tool_call_id: ${fields.toolCallId}`,
|
|
85
|
+
`detail: ${fields.detail}`,
|
|
86
|
+
'</task>',
|
|
87
|
+
].join('\n');
|
|
88
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
export type Effort = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
2
|
+
|
|
3
|
+
export interface AvailableModel {
|
|
4
|
+
provider: string;
|
|
5
|
+
id: string;
|
|
6
|
+
reasoning: boolean;
|
|
7
|
+
/** Thinking levels Pi supports for the model (pi-ai `getSupportedThinkingLevels`). */
|
|
8
|
+
levels: readonly string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** A concrete child model. `thinking` absent means the child's own default for that model. */
|
|
12
|
+
export interface ModelSpec {
|
|
13
|
+
provider: string;
|
|
14
|
+
id: string;
|
|
15
|
+
thinking?: Effort;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const INHERIT = new Set(['', 'inherit', 'inherit-parent', 'auto', 'default']);
|
|
19
|
+
const EFFORTS = new Set<string>(['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max']);
|
|
20
|
+
const DASH_SLUG = /^(.+?)(?:-thinking)?(?:-(none|minimal|low|medium|high|xhigh|max))?(-fast)?$/;
|
|
21
|
+
|
|
22
|
+
const asEffort = (value: string): Effort | undefined => (EFFORTS.has(value) ? (value as Effort) : undefined);
|
|
23
|
+
|
|
24
|
+
/** A model as the allowed list names it, with its thinking levels when it has more than off. */
|
|
25
|
+
export function modelLabel(model: AvailableModel): string {
|
|
26
|
+
const levels = model.levels.filter((level) => level !== 'off').length > 0 ? ` (thinking: ${model.levels.join(', ')})` : '';
|
|
27
|
+
return `${model.provider}/${model.id}${levels}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function invalid(value: string, available: readonly AvailableModel[], reason = 'Model could not be resolved to a valid subagent model.'): Error {
|
|
31
|
+
return new Error(
|
|
32
|
+
[
|
|
33
|
+
`Invalid model selection "${value}". ${reason}`,
|
|
34
|
+
'Allowed model slugs:',
|
|
35
|
+
'- inherit',
|
|
36
|
+
...available.map((model) => `- ${modelLabel(model)}`),
|
|
37
|
+
'',
|
|
38
|
+
'Add a thinking level as <model>:<level>, for example claude-opus-5-5:xhigh, or as <model>[effort=<level>].',
|
|
39
|
+
'The `model` parameter is optional. If omitted, the subagent uses the same model as the parent agent.',
|
|
40
|
+
].join('\n'),
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
type Find = (reference: string) => AvailableModel | undefined;
|
|
45
|
+
|
|
46
|
+
/** A bare id that several providers offer means the parent chat's provider when it is one of them. */
|
|
47
|
+
function findModel(reference: string, available: readonly AvailableModel[], parentProvider: string | undefined): AvailableModel | undefined {
|
|
48
|
+
const slash = reference.indexOf('/');
|
|
49
|
+
if (slash !== -1) return available.find((model) => model.provider === reference.slice(0, slash) && model.id === reference.slice(slash + 1));
|
|
50
|
+
const matches = available.filter((model) => model.id === reference);
|
|
51
|
+
if (matches.length > 1) return matches.find((model) => model.provider === parentProvider) ?? failAmbiguous(reference, matches);
|
|
52
|
+
return matches[0];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function failAmbiguous(reference: string, matches: readonly AvailableModel[]): never {
|
|
56
|
+
throw new Error(`Model "${reference}" matches more than one provider: ${matches.map((model) => `${model.provider}/${model.id}`).join(', ')}. Use <provider>/<model-id>.`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Only listed levels are accepted, so a level the model does not support is refused instead of clamped by Pi. */
|
|
60
|
+
class UnsupportedLevel extends Error {}
|
|
61
|
+
|
|
62
|
+
function withThinking(model: AvailableModel, thinking: Effort | undefined): ModelSpec {
|
|
63
|
+
if (thinking === undefined) return { provider: model.provider, id: model.id };
|
|
64
|
+
if (!model.levels.includes(thinking)) throw new UnsupportedLevel(`${model.provider}/${model.id} does not support thinking level ${thinking}; it supports ${model.levels.join(', ')}.`);
|
|
65
|
+
return { provider: model.provider, id: model.id, thinking };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** A whole reference first, since model ids such as llama3:8b contain a colon; then a trailing :<effort>. */
|
|
69
|
+
function resolvePiSpec(value: string, find: Find): ModelSpec | undefined {
|
|
70
|
+
const whole = find(value);
|
|
71
|
+
if (whole !== undefined) return withThinking(whole, undefined);
|
|
72
|
+
const colon = value.lastIndexOf(':');
|
|
73
|
+
const level = colon === -1 ? undefined : asEffort(value.slice(colon + 1));
|
|
74
|
+
if (level === undefined) return undefined;
|
|
75
|
+
const model = find(value.slice(0, colon));
|
|
76
|
+
return model === undefined ? undefined : withThinking(model, level);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Legacy `<id>[-<effort>][-fast]` slugs: a Pi model whose own id ends in -fast wins, else the base id; the effort is the thinking level, and `none` is Pi's `off`. */
|
|
80
|
+
function resolveDashSlug(value: string, find: Find): ModelSpec | undefined {
|
|
81
|
+
const match = DASH_SLUG.exec(value);
|
|
82
|
+
const base = match?.[1];
|
|
83
|
+
const effort = match?.[2] === undefined ? undefined : asEffort(match[2] === 'none' ? 'off' : match[2]);
|
|
84
|
+
const fast = match?.[3] !== undefined;
|
|
85
|
+
if (base === undefined || (effort === undefined && !fast)) return undefined;
|
|
86
|
+
const model = (fast ? find(`${base}-fast`) : undefined) ?? find(base);
|
|
87
|
+
return model === undefined ? undefined : withThinking(model, effort);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
interface ModelParameters {
|
|
91
|
+
effort?: Effort;
|
|
92
|
+
fast?: boolean;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const BRACKETED = /^(.+)\[([^\]]*)\]$/;
|
|
96
|
+
|
|
97
|
+
/** `id=value` pairs. Pi sets a context window per model, not per call, so `context` is accepted and has no effect. */
|
|
98
|
+
function parseModelParameters(text: string): ModelParameters | undefined {
|
|
99
|
+
let parsed: ModelParameters = {};
|
|
100
|
+
for (const pair of text
|
|
101
|
+
.split(',')
|
|
102
|
+
.map((part) => part.trim())
|
|
103
|
+
.filter((part) => part !== '')) {
|
|
104
|
+
const [key, value, ...rest] = pair.split('=').map((part) => part.trim());
|
|
105
|
+
if (value === undefined || value === '' || rest.length > 0) return undefined;
|
|
106
|
+
const effort = asEffort(value);
|
|
107
|
+
if (key === 'effort' && effort !== undefined) parsed = { ...parsed, effort };
|
|
108
|
+
else if (key === 'fast' && (value === 'true' || value === 'false')) parsed = { ...parsed, fast: value === 'true' };
|
|
109
|
+
else if (key !== 'context') return undefined;
|
|
110
|
+
}
|
|
111
|
+
return parsed;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** `<model>[effort=high,fast=false,context=300k]`, per-model parameters; `[]` is the standard variant. */
|
|
115
|
+
function resolveBracketed(value: string, find: Find): ModelSpec | undefined {
|
|
116
|
+
const match = BRACKETED.exec(value);
|
|
117
|
+
const base = match?.[1];
|
|
118
|
+
const parameters = parseModelParameters(match?.[2] ?? '');
|
|
119
|
+
if (base === undefined || parameters === undefined) return undefined;
|
|
120
|
+
const model = (parameters.fast === true ? find(`${base}-fast`) : undefined) ?? find(base);
|
|
121
|
+
return model === undefined ? undefined : withThinking(model, parameters.effort);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Resolves Task's `model`: aliases run on the parent, a listed model runs as asked, and anything else fails with the
|
|
126
|
+
* allowed list. Legacy slugs `<id>-<effort>[-fast]` still map to a Pi model plus thinking level.
|
|
127
|
+
*/
|
|
128
|
+
export function resolveSubagentModel(value: string | undefined, available: readonly AvailableModel[], parent: ModelSpec | undefined): ModelSpec | undefined {
|
|
129
|
+
const requested = (value ?? '').trim();
|
|
130
|
+
if (INHERIT.has(requested)) return parent;
|
|
131
|
+
try {
|
|
132
|
+
const find: Find = (reference) => findModel(reference, available, parent?.provider);
|
|
133
|
+
const resolved = resolveBracketed(requested, find) ?? resolvePiSpec(requested, find) ?? resolveDashSlug(requested, find);
|
|
134
|
+
if (resolved === undefined) throw invalid(requested, available);
|
|
135
|
+
return resolved;
|
|
136
|
+
} catch (error) {
|
|
137
|
+
if (error instanceof UnsupportedLevel) throw invalid(requested, available, error.message);
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
}
|