@justjoshn/pi-pstack 0.0.0-stage → 0.15.36-pi.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +79 -0
- package/LICENSE +21 -0
- package/README.md +100 -2
- package/agents/ci-watcher.md +28 -0
- package/agents/comment-sicko.md +32 -0
- package/agents/poteto-agent.md +9 -0
- package/agents/thermo-nuclear-code-quality-review.md +23 -0
- package/assets/logo.png +0 -0
- package/automations/benny/FOR_AGENTS.md +83 -0
- package/automations/benny/README.md +20 -0
- package/automations/benny/skills/reproduce-and-fix-issues/SKILL.md +310 -0
- package/automations/benny/skills/reproduce-and-fix-issues/references/control-adapter.md +169 -0
- package/automations/benny/skills/reproduce-and-fix-issues/references/feature-map.example.md +205 -0
- package/automations/benny/skills/reproduce-and-fix-issues/references/verify-existing-fix.md +93 -0
- package/automations/benny/skills/setup-benny/SKILL.md +254 -0
- package/automations/benny/skills/triage-issue-reports/SKILL.md +240 -0
- package/automations/benny/skills/triage-issue-reports/references/routing.example.md +61 -0
- package/automations/benny/templates/configuration.example.yaml +113 -0
- package/automations/benny/templates/reproduce-automation-prompt.md +49 -0
- package/automations/benny/templates/triage-automation-prompt.md +53 -0
- package/bin/pstack-routines-supervisor +9 -0
- package/docs/guide/01-setup.md +67 -0
- package/docs/guide/02-poteto-mode.md +139 -0
- package/docs/guide/03-understand.md +79 -0
- package/docs/guide/04-design.md +133 -0
- package/docs/guide/05-build-and-clean.md +83 -0
- package/docs/guide/06-verify-and-ship.md +162 -0
- package/docs/guide/07-overnight.md +122 -0
- package/docs/guide/08-principles.md +72 -0
- package/docs/guide/09-make-it-yours.md +100 -0
- package/docs/guide/10-recipes-and-pitfalls.md +182 -0
- package/docs/guide/README.md +38 -0
- package/docs/guide/images/design.jpg +0 -0
- package/docs/guide/images/overnight.jpg +0 -0
- package/docs/guide/images/recipes.jpg +0 -0
- package/docs/guide/images/router.jpg +0 -0
- package/docs/guide/images/understanding.jpg +0 -0
- package/docs/guide/images/verification.jpg +0 -0
- package/docs/native-gaps.md +73 -0
- package/docs/parity-reverse-engineering.md +94 -0
- package/docs/parity-status.md +113 -0
- package/licenses/cursor-team-kit.LICENSE +21 -0
- package/licenses/pstack.LICENSE +21 -0
- package/package.json +86 -4
- package/packaging/install-supervisor-unit.sh +164 -0
- package/packaging/launchd/com.pstack.routines-supervisor.plist.example +24 -0
- package/packaging/systemd/pstack-routines-supervisor.service.example +15 -0
- package/skills/architect/SKILL.md +79 -0
- package/skills/architect/references/design-red-flags.md +57 -0
- package/skills/architect/references/rationale-template.md +35 -0
- package/skills/architect/references/runner-prompt.md +20 -0
- package/skills/arena/SKILL.md +48 -0
- package/skills/automate-me/SKILL.md +104 -0
- package/skills/benchmark-checklist/SKILL.md +39 -0
- package/skills/blast-radius/SKILL.md +50 -0
- package/skills/bro/SKILL.md +7 -0
- package/skills/check-compiler-errors/SKILL.md +23 -0
- package/skills/control-cli/SKILL.md +109 -0
- package/skills/control-ui/SKILL.md +109 -0
- package/skills/correct/SKILL.md +32 -0
- package/skills/create-formal-verification-skill/SKILL.md +43 -0
- package/skills/create-skill/SKILL.md +548 -0
- package/skills/create-verification-skill/SKILL.md +44 -0
- package/skills/create-verification-skill/references/feature-map-example/README.md +47 -0
- package/skills/create-verification-skill/references/feature-map-example/create-note.md +39 -0
- package/skills/create-verification-skill/references/feature-map-example/search.md +45 -0
- package/skills/deslop/SKILL.md +22 -0
- package/skills/figure-it-out/SKILL.md +52 -0
- package/skills/fix-ci/SKILL.md +29 -0
- package/skills/fix-merge-conflicts/SKILL.md +32 -0
- package/skills/get-pr-comments/SKILL.md +23 -0
- package/skills/how/SKILL.md +36 -0
- package/skills/how/references/explainer-prompt.md +55 -0
- package/skills/how/references/explorer-prompt.md +35 -0
- package/skills/in-your-own-words/SKILL.md +7 -0
- package/skills/interrogate/SKILL.md +31 -0
- package/skills/ketchup/SKILL.md +43 -0
- package/skills/ketchup-video/SKILL.md +29 -0
- package/skills/loop-on-ci/SKILL.md +50 -0
- package/skills/maintain-formal-verification-skill/SKILL.md +58 -0
- package/skills/maintain-verification-skill/SKILL.md +39 -0
- package/skills/make-bot-ui/SKILL.md +104 -0
- package/skills/make-pr-easy-to-review/SKILL.md +59 -0
- package/skills/new-branch-and-pr/SKILL.md +29 -0
- package/skills/no-comments/SKILL.md +24 -0
- package/skills/no-inline-imports/SKILL.md +12 -0
- package/skills/poteto-help/SKILL.md +161 -0
- package/skills/poteto-help/references/prompting.md +51 -0
- package/skills/poteto-help/references/recipes.md +51 -0
- package/skills/poteto-mode/SKILL.md +151 -0
- package/skills/poteto-mode/playbooks/authoring-a-skill.md +12 -0
- package/skills/poteto-mode/playbooks/autonomous-run.md +13 -0
- package/skills/poteto-mode/playbooks/autopilot-full.md +25 -0
- package/skills/poteto-mode/playbooks/autopilot-stack.md +8 -0
- package/skills/poteto-mode/playbooks/babysit.md +23 -0
- package/skills/poteto-mode/playbooks/bug-fix.md +15 -0
- package/skills/poteto-mode/playbooks/eval.md +25 -0
- package/skills/poteto-mode/playbooks/feature.md +21 -0
- package/skills/poteto-mode/playbooks/hillclimb.md +21 -0
- package/skills/poteto-mode/playbooks/investigation.md +14 -0
- package/skills/poteto-mode/playbooks/multi-phase-plan.md +155 -0
- package/skills/poteto-mode/playbooks/opening-a-pr.md +34 -0
- package/skills/poteto-mode/playbooks/orchestrate.md +25 -0
- package/skills/poteto-mode/playbooks/pause-safely.md +10 -0
- package/skills/poteto-mode/playbooks/perf-issue.md +25 -0
- package/skills/poteto-mode/playbooks/prototype.md +14 -0
- package/skills/poteto-mode/playbooks/refactoring.md +16 -0
- package/skills/poteto-mode/playbooks/runtime-forensics.md +11 -0
- package/skills/poteto-mode/playbooks/session-pickup.md +11 -0
- package/skills/poteto-mode/playbooks/shipping.md +12 -0
- package/skills/poteto-mode/playbooks/trace-forensics.md +14 -0
- package/skills/poteto-mode/playbooks/visual-parity.md +11 -0
- package/skills/poteto-mode/playbooks/worktree-cleanup.md +12 -0
- package/skills/poteto-mode/references/bugbot-triage.md +142 -0
- package/skills/poteto-mode/scripts/bootstrap.ts +62 -0
- package/skills/poteto-mode/scripts/bun.lock +67 -0
- package/skills/poteto-mode/scripts/check-plan.mjs +205 -0
- package/skills/poteto-mode/scripts/check-plan.test.ts +110 -0
- package/skills/poteto-mode/scripts/package.json +16 -0
- package/skills/poteto-mode/scripts/watch-pr/cli.test.ts +224 -0
- package/skills/poteto-mode/scripts/watch-pr/cli.ts +223 -0
- package/skills/poteto-mode/scripts/watch-pr/fakes.test-helper.ts +129 -0
- package/skills/poteto-mode/scripts/watch-pr/github.test.ts +498 -0
- package/skills/poteto-mode/scripts/watch-pr/github.ts +726 -0
- package/skills/poteto-mode/scripts/watch-pr/policy.test.ts +482 -0
- package/skills/poteto-mode/scripts/watch-pr/policy.ts +842 -0
- package/skills/poteto-mode/scripts/watch-pr/render.ts +169 -0
- package/skills/poteto-mode/scripts/watch-pr/tsconfig.json +13 -0
- package/skills/poteto-mode/scripts/watch-pr/types.compile.ts +93 -0
- package/skills/poteto-mode/scripts/watch-pr/types.ts +414 -0
- package/skills/poteto-mode/scripts/watch-pr/watch-pr +6 -0
- package/skills/poteto-mode/scripts/worktree-audit.sh +156 -0
- package/skills/pr-review-canvas/SKILL.md +176 -0
- package/skills/pr-review-canvas/renderer.js +170 -0
- package/skills/pr-review-canvas/styles.css +96 -0
- package/skills/pr-review-canvas/template.html +18 -0
- package/skills/principle-attack-the-premise/SKILL.md +21 -0
- package/skills/principle-boundary-discipline/SKILL.md +34 -0
- package/skills/principle-build-the-lever/SKILL.md +23 -0
- package/skills/principle-encode-lessons-in-structure/SKILL.md +11 -0
- package/skills/principle-exhaust-the-design-space/SKILL.md +9 -0
- package/skills/principle-experience-first/SKILL.md +19 -0
- package/skills/principle-explain-the-number/SKILL.md +18 -0
- package/skills/principle-fix-root-causes/SKILL.md +21 -0
- package/skills/principle-foundational-thinking/SKILL.md +21 -0
- package/skills/principle-guard-the-context-window/SKILL.md +12 -0
- package/skills/principle-laziness-protocol/SKILL.md +10 -0
- package/skills/principle-make-operations-idempotent/SKILL.md +22 -0
- package/skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md +14 -0
- package/skills/principle-minimize-reader-load/SKILL.md +18 -0
- package/skills/principle-model-the-domain/SKILL.md +24 -0
- package/skills/principle-never-block-on-the-human/SKILL.md +15 -0
- package/skills/principle-outcome-oriented-execution/SKILL.md +21 -0
- package/skills/principle-prove-it-works/SKILL.md +22 -0
- package/skills/principle-redesign-from-first-principles/SKILL.md +16 -0
- package/skills/principle-separate-before-serializing-shared-state/SKILL.md +16 -0
- package/skills/principle-sequence-verifiable-units/SKILL.md +17 -0
- package/skills/principle-subtract-before-you-add/SKILL.md +18 -0
- package/skills/principle-test-behavior-not-implementation/SKILL.md +20 -0
- package/skills/principle-type-system-discipline/SKILL.md +13 -0
- package/skills/recall/SKILL.md +35 -0
- package/skills/reflect/SKILL.md +69 -0
- package/skills/reflect/references/divergent-reviewer.md +38 -0
- package/skills/reflect/references/judgment-reviewer.md +37 -0
- package/skills/reflect/references/synthesizer.md +56 -0
- package/skills/reflect/references/tooling-reviewer.md +48 -0
- package/skills/review-and-ship/SKILL.md +41 -0
- package/skills/run-smoke-tests/SKILL.md +42 -0
- package/skills/setup-pstack/SKILL.md +74 -0
- package/skills/sharpen/SKILL.md +16 -0
- package/skills/show-me-your-work/SKILL.md +82 -0
- package/skills/show-me-your-work/references/decision-log-template.tsv +1 -0
- package/skills/show-me-your-work/scripts/log.sh +42 -0
- package/skills/statechart/SKILL.md +82 -0
- package/skills/statechart/references/render.md +93 -0
- package/skills/statechart/scripts/backends/cfg.ts +33 -0
- package/skills/statechart/scripts/backends/mermaid.ts +201 -0
- package/skills/statechart/scripts/backends/plain-text.ts +72 -0
- package/skills/statechart/scripts/backends/report.ts +177 -0
- package/skills/statechart/scripts/frontends/config.ts +276 -0
- package/skills/statechart/scripts/frontends/dot.ts +74 -0
- package/skills/statechart/scripts/frontends/marks.ts +93 -0
- package/skills/statechart/scripts/frontends/messages.ts +52 -0
- package/skills/statechart/scripts/frontends/spec.ts +114 -0
- package/skills/statechart/scripts/frontends/trace.ts +24 -0
- package/skills/statechart/scripts/frontends/value.ts +166 -0
- package/skills/statechart/scripts/frontends/verdict.ts +40 -0
- package/skills/statechart/scripts/frontends/view.ts +119 -0
- package/skills/statechart/scripts/ir.ts +547 -0
- package/skills/statechart/scripts/package.json +11 -0
- package/skills/statechart/scripts/passes/annotate.ts +128 -0
- package/skills/statechart/scripts/passes/label.ts +269 -0
- package/skills/statechart/scripts/passes/lift.ts +85 -0
- package/skills/statechart/scripts/passes/loop-check.ts +68 -0
- package/skills/statechart/scripts/passes/paths.ts +60 -0
- package/skills/statechart/scripts/passes/reach.ts +135 -0
- package/skills/statechart/scripts/passes/region-check.ts +97 -0
- package/skills/statechart/scripts/passes/regions.ts +295 -0
- package/skills/statechart/scripts/pipeline.ts +76 -0
- package/skills/statechart/scripts/run.ts +481 -0
- package/skills/statechart/scripts/statechart +29 -0
- package/skills/statechart/scripts/statechart.ts +164 -0
- package/skills/statechart/scripts/test/ConfigOracle.java +63 -0
- package/skills/statechart/scripts/test/chart.test.ts +1210 -0
- package/skills/statechart/scripts/test/charts/Braces.mmd +7 -0
- package/skills/statechart/scripts/test/charts/Escapes.mmd +11 -0
- package/skills/statechart/scripts/test/charts/Phases.mmd +29 -0
- package/skills/statechart/scripts/test/cli.test.ts +1314 -0
- package/skills/statechart/scripts/test/config-fuzz.test.ts +263 -0
- package/skills/statechart/scripts/test/corpus/Counter/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/Counter/Counter.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/Counter/Counter.tla +10 -0
- package/skills/statechart/scripts/test/corpus/Counter/chart.mmd +9 -0
- package/skills/statechart/scripts/test/corpus/Counter/graph.dot +16 -0
- package/skills/statechart/scripts/test/corpus/Counter/report.md +7 -0
- package/skills/statechart/scripts/test/corpus/Counter/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/Counter/verdict-1.out +49 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/ChartRun.out +60 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/CounterAction.cfg +4 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/CounterAction.tla +22 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/chart.mmd +26 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/graph.dot +19 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/report.md +20 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/verdict-1.out +56 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/verdict-2.out +82 -0
- package/skills/statechart/scripts/test/corpus/CounterAction/verdict-3.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/ChartRun.out +59 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/CounterDeadlock.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/CounterDeadlock.tla +11 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/chart.mmd +22 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/graph.dot +16 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/report.md +17 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-1.out +56 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-2.out +77 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/ChartRun.out +69 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/CounterFan.cfg +2 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/CounterFan.tla +11 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/chart.mmd +85 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/graph.dot +70 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/report.md +12 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/verdict-1.out +67 -0
- package/skills/statechart/scripts/test/corpus/CounterFan/verdict-2.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/ChartRun.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/ChartRun.out +85 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/CounterGuard.cfg +6 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/CounterGuard.tla +13 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/chart.mmd +5 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/graph.dot +10 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/report.md +31 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/verdict-1.out +64 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterGuard/verdict-2.out +77 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/ChartRun.out +55 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/CounterInitPast.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/CounterInitPast.tla +10 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/chart.mmd +12 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/graph.dot +6 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/report.md +12 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/verdict-1.out +33 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPast/verdict-2.out +54 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/ChartRun.out +54 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/CounterInitPastHolds.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/CounterInitPastHolds.tla +10 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/chart.mmd +1 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/graph.dot +6 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/report.md +7 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterInitPastHolds/verdict-1.out +46 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/ChartRun.out +59 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/CounterInstance.cfg +2 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/CounterInstance.tla +10 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/CounterSteps.tla +6 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/chart.mmd +17 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/graph.dot +15 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/report.md +14 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/sany.out +3 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterInstance/verdict-1.out +78 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/ChartRun.out +59 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/CounterJump.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/CounterJump.tla +19 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/chart.mmd +26 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/graph.dot +22 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/report.md +12 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/verdict-1.out +58 -0
- package/skills/statechart/scripts/test/corpus/CounterJump/verdict-2.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/CounterLoop.cfg +2 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/CounterLoop.tla +11 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/chart.mmd +17 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/graph.dot +15 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/report.md +14 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterLoop/verdict-1.out +76 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/ChartRun.out +59 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/CounterOrder.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/CounterOrder.tla +11 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/chart.mmd +19 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/graph.dot +10 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/report.md +15 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/verdict-1.out +56 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterOrder/verdict-2.out +67 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/ChartRun.out +62 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/CounterRules.cfg +6 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/CounterRules.tla +24 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/Moves.tla +5 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/chart.mmd +22 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/graph.dot +10 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/report.md +23 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/sany.out +3 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/verdict-1.out +58 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/verdict-2.out +66 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/verdict-3.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/verdict-3.out +74 -0
- package/skills/statechart/scripts/test/corpus/CounterRules/verdict-4.out +59 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/ChartRun.out +58 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/CounterStart.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/CounterStart.tla +15 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/chart.mmd +18 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/graph.dot +13 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/report.md +11 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/verdict-1.out +33 -0
- package/skills/statechart/scripts/test/corpus/CounterStart/verdict-2.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterStop/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterStop/CounterStop.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/CounterStop/CounterStop.tla +15 -0
- package/skills/statechart/scripts/test/corpus/CounterStop/chart.mmd +7 -0
- package/skills/statechart/scripts/test/corpus/CounterStop/graph.dot +13 -0
- package/skills/statechart/scripts/test/corpus/CounterStop/report.md +6 -0
- package/skills/statechart/scripts/test/corpus/CounterStop/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterStop/verdict-1.out +49 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/ChartRun.out +61 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/CounterTie.cfg +4 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/CounterTie.tla +14 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/chart.mmd +30 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/graph.dot +19 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/report.md +27 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/verdict-1.out +56 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/verdict-2.out +64 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/verdict-3.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/verdict-3.out +87 -0
- package/skills/statechart/scripts/test/corpus/CounterTie/verdict-4.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/ChartRun.out +60 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/CounterTieInGraph.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/CounterTieInGraph.tla +12 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/chart.mmd +23 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/graph.dot +19 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/report.md +11 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/verdict-1.out +56 -0
- package/skills/statechart/scripts/test/corpus/CounterTieInGraph/verdict-2.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterView/ChartRun.out +61 -0
- package/skills/statechart/scripts/test/corpus/CounterView/CounterView.cfg +4 -0
- package/skills/statechart/scripts/test/corpus/CounterView/CounterView.tla +14 -0
- package/skills/statechart/scripts/test/corpus/CounterView/chart.mmd +23 -0
- package/skills/statechart/scripts/test/corpus/CounterView/graph.dot +19 -0
- package/skills/statechart/scripts/test/corpus/CounterView/report.md +27 -0
- package/skills/statechart/scripts/test/corpus/CounterView/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/CounterView/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterView/verdict-1.out +56 -0
- package/skills/statechart/scripts/test/corpus/CounterView/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterView/verdict-2.out +64 -0
- package/skills/statechart/scripts/test/corpus/CounterView/verdict-3.exit +1 -0
- package/skills/statechart/scripts/test/corpus/CounterView/verdict-3.out +87 -0
- package/skills/statechart/scripts/test/corpus/CounterView/verdict-4.out +57 -0
- package/skills/statechart/scripts/test/corpus/CounterView/view.mjs +1 -0
- package/skills/statechart/scripts/test/corpus/DieHard/ChartRun.out +59 -0
- package/skills/statechart/scripts/test/corpus/DieHard/DieHard.cfg +4 -0
- package/skills/statechart/scripts/test/corpus/DieHard/DieHard.tla +38 -0
- package/skills/statechart/scripts/test/corpus/DieHard/chart.mmd +92 -0
- package/skills/statechart/scripts/test/corpus/DieHard/graph.dot +126 -0
- package/skills/statechart/scripts/test/corpus/DieHard/report.md +17 -0
- package/skills/statechart/scripts/test/corpus/DieHard/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/DieHard/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/DieHard/verdict-1.out +91 -0
- package/skills/statechart/scripts/test/corpus/DieHard/verdict-2.out +57 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/ChartRun.out +61 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/FirstRule.cfg +6 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/FirstRule.tla +11 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/chart.mmd +22 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/graph.dot +16 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/report.md +25 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/verdict-1.out +56 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/verdict-2.out +64 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/verdict-3.exit +1 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/verdict-3.out +64 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/verdict-4.exit +1 -0
- package/skills/statechart/scripts/test/corpus/FirstRule/verdict-4.out +77 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/HiddenClock.cfg +4 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/HiddenClock.tla +11 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/chart.mmd +13 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/graph.dot +12 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/report.md +11 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/HiddenClock/verdict-1.out +72 -0
- package/skills/statechart/scripts/test/corpus/Login/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/Login/Login.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/Login/Login.tla +62 -0
- package/skills/statechart/scripts/test/corpus/Login/chart.mmd +27 -0
- package/skills/statechart/scripts/test/corpus/Login/graph.dot +40 -0
- package/skills/statechart/scripts/test/corpus/Login/report.md +7 -0
- package/skills/statechart/scripts/test/corpus/Login/sany.out +1 -0
- package/skills/statechart/scripts/test/corpus/Login/verdict-1.out +47 -0
- package/skills/statechart/scripts/test/corpus/Login/view.mjs +1 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/LoginGuarded.cfg +2 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/LoginGuarded.tla +64 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/chart.mmd +28 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/graph.dot +37 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/report.md +8 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/sany.out +1 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/verdict-1.out +47 -0
- package/skills/statechart/scripts/test/corpus/LoginGuarded/view.mjs +1 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/ChartRun.out +60 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/LoginParallel.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/LoginParallel.tla +64 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/chart.mmd +44 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/graph.dot +58 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/report.md +17 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/sany.out +1 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/verdict-1.out +83 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/verdict-2.out +57 -0
- package/skills/statechart/scripts/test/corpus/LoginParallel/view.mjs +1 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/ChartRun.out +60 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/MediaPlayer.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/MediaPlayer.tla +103 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/chart.mmd +43 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/graph.dot +93 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/report.md +14 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/sany.out +1 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/verdict-1.out +59 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/verdict-2.out +72 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayer/view.mjs +3 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/MediaPlayerFixed.cfg +2 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/MediaPlayerFixed.tla +100 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/chart.mmd +31 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/graph.dot +85 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/report.md +9 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/sany.out +1 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/verdict-1.out +47 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerFixed/view.mjs +3 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/ChartRun.out +59 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/MediaPlayer.tla +103 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/MediaPlayerProps.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/MediaPlayerProps.tla +6 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/chart.mmd +42 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/graph.dot +93 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/report.md +19 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-1.out +61 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-2.out +59 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-3.out +61 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-4.exit +1 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-4.out +66 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-5.exit +1 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-5.out +58 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-6.out +49 -0
- package/skills/statechart/scripts/test/corpus/MediaPlayerProps/view.mjs +3 -0
- package/skills/statechart/scripts/test/corpus/PickWorker/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/PickWorker/PickWorker.cfg +6 -0
- package/skills/statechart/scripts/test/corpus/PickWorker/PickWorker.tla +11 -0
- package/skills/statechart/scripts/test/corpus/PickWorker/chart.mmd +5 -0
- package/skills/statechart/scripts/test/corpus/PickWorker/graph.dot +11 -0
- package/skills/statechart/scripts/test/corpus/PickWorker/report.md +7 -0
- package/skills/statechart/scripts/test/corpus/PickWorker/sany.out +5 -0
- package/skills/statechart/scripts/test/corpus/PickWorker/verdict-1.out +70 -0
- package/skills/statechart/scripts/test/corpus/Shadow/ChartRun.out +61 -0
- package/skills/statechart/scripts/test/corpus/Shadow/Shadow.cfg +4 -0
- package/skills/statechart/scripts/test/corpus/Shadow/Shadow.tla +11 -0
- package/skills/statechart/scripts/test/corpus/Shadow/ShadowLib.tla +6 -0
- package/skills/statechart/scripts/test/corpus/Shadow/ShadowSub.tla +3 -0
- package/skills/statechart/scripts/test/corpus/Shadow/chart.mmd +9 -0
- package/skills/statechart/scripts/test/corpus/Shadow/graph.dot +16 -0
- package/skills/statechart/scripts/test/corpus/Shadow/report.md +8 -0
- package/skills/statechart/scripts/test/corpus/Shadow/sany.out +4 -0
- package/skills/statechart/scripts/test/corpus/Shadow/verdict-1.out +65 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/ChartRun.out +59 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/SpacedNames.cfg +2 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/SpacedNames.tla +9 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/chart.mmd +23 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/graph.dot +17 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/report.md +15 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/sany.out +1 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/verdict-1.out +65 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/SpacedNames/verdict-2.out +75 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/ChartRun.out +69 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/TwoPhase.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/TwoPhase.tla +75 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/chart.mmd +60 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/graph.dot +297 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/report.md +20 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/sany.out +1 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/verdict-1.out +95 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/verdict-2.out +57 -0
- package/skills/statechart/scripts/test/corpus/TwoPhase/view.mjs +1 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/ChartRun.out +57 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/TwoPhaseFixed.cfg +3 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/TwoPhaseFixed.tla +75 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/chart.mmd +37 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/graph.dot +223 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/report.md +11 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/sany.out +1 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/verdict-1.out +47 -0
- package/skills/statechart/scripts/test/corpus/TwoPhaseFixed/view.mjs +1 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/ChartRun.exit +1 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/ChartRun.out +75 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/TypeGuard.cfg +5 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/TypeGuard.tla +11 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/chart.mmd +18 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/graph.dot +14 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/report.md +29 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/verdict-1.out +64 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/TypeGuard/verdict-2.out +75 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/ChartRun.out +58 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/UserNoDeadlock.cfg +2 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/UserNoDeadlock.tla +8 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/chart.mmd +22 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/graph.dot +16 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/report.md +15 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/sany.out +2 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-1.exit +1 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-1.out +56 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-2.exit +1 -0
- package/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-2.out +77 -0
- package/skills/statechart/scripts/test/corpus.test.ts +403 -0
- package/skills/statechart/scripts/test/differential.test.ts +565 -0
- package/skills/statechart/scripts/test/grid/Grid.cfg +2 -0
- package/skills/statechart/scripts/test/grid/Grid.tla +9 -0
- package/skills/statechart/scripts/test/grid/sany.out +2 -0
- package/skills/statechart/scripts/test/java.ts +63 -0
- package/skills/statechart/scripts/test/labels.ts +643 -0
- package/skills/statechart/scripts/test/messages.test.ts +212 -0
- package/skills/statechart/scripts/test/pipeline.test.ts +270 -0
- package/skills/statechart/scripts/test/plain-tlc.test.ts +255 -0
- package/skills/statechart/scripts/test/render.test.ts +81 -0
- package/skills/statechart/scripts/test/tlc-out.test.ts +90 -0
- package/skills/statechart/scripts/test/tlc.ts +158 -0
- package/skills/statechart/scripts/tsconfig.json +11 -0
- package/skills/statechart/scripts/worker.ts +35 -0
- package/skills/swarm/SKILL.md +41 -0
- package/skills/tdd/SKILL.md +42 -0
- package/skills/teach/SKILL.md +21 -0
- package/skills/technical-writing/SKILL.md +106 -0
- package/skills/thermo-nuclear-code-quality-review/SKILL.md +192 -0
- package/skills/typescript-best-practices/SKILL.md +32 -0
- package/skills/typescript-best-practices/references/patterns.md +328 -0
- package/skills/typescript-exhaustive-switch/SKILL.md +10 -0
- package/skills/unslop/SKILL.md +62 -0
- package/skills/verify-this/SKILL.md +74 -0
- package/skills/weekly-review/SKILL.md +32 -0
- package/skills/what-did-i-get-done/SKILL.md +31 -0
- package/skills/why/SKILL.md +98 -0
- package/skills/why/references/epistemics.md +71 -0
- package/skills/why/references/investigator-prompt.md +84 -0
- package/skills/why/references/source-playbook.md +17 -0
- package/skills/why/references/sources/code-archaeology.md +51 -0
- package/skills/why/references/sources/databricks.md +70 -0
- package/skills/why/references/sources/datadog.md +97 -0
- package/skills/why/references/sources/incident-postmortem.md +5 -0
- package/skills/why/references/sources/linear.md +48 -0
- package/skills/why/references/sources/notion.md +55 -0
- package/skills/why/references/sources/sentry.md +66 -0
- package/skills/why/references/sources/slack.md +17 -0
- package/skills/why/references/synthesizer-prompt.md +129 -0
- package/skills/workflow-from-chats/SKILL.md +50 -0
- package/src/aliases.ts +64 -0
- package/src/ask.ts +131 -0
- package/src/autocomplete.ts +21 -0
- package/src/child-env.ts +57 -0
- package/src/index.ts +138 -0
- package/src/loop.ts +238 -0
- package/src/mode.ts +180 -0
- package/src/modes.ts +8 -0
- package/src/path-skills.ts +104 -0
- package/src/paths.ts +90 -0
- package/src/pi-command.ts +12 -0
- package/src/plan.ts +226 -0
- package/src/readonly-shell.ts +107 -0
- package/src/rule.ts +56 -0
- package/src/sections.ts +136 -0
- package/src/subscriptions/cron.ts +75 -0
- package/src/subscriptions/durable-store.ts +531 -0
- package/src/subscriptions/durable-types.ts +69 -0
- package/src/subscriptions/ensure-supervisor.ts +67 -0
- package/src/subscriptions/github.ts +149 -0
- package/src/subscriptions/index.ts +575 -0
- package/src/subscriptions/supervisor-main.ts +134 -0
- package/src/subscriptions/supervisor.ts +325 -0
- package/src/subscriptions/webhook.ts +270 -0
- package/src/task/agents.ts +55 -0
- package/src/task/card.ts +61 -0
- package/src/task/format.ts +88 -0
- package/src/task/models.ts +147 -0
- package/src/task/progress.ts +112 -0
- package/src/task/records.ts +230 -0
- package/src/task/registry.ts +81 -0
- package/src/task/runner.ts +459 -0
- package/src/task/status.ts +170 -0
- package/src/task/stop.ts +100 -0
- package/src/task/tool.ts +560 -0
- package/src/task/worktree.ts +69 -0
- package/src/todo.ts +127 -0
- package/src/visualize.ts +244 -0
package/src/loop.ts
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from '@earendil-works/pi-coding-agent';
|
|
2
|
+
import { Type } from 'typebox';
|
|
3
|
+
import { isOneShot } from './modes.ts';
|
|
4
|
+
|
|
5
|
+
const DAY_MS = 86_400_000;
|
|
6
|
+
const UNIT_MS: Record<string, number> = { s: 1_000, m: 60_000, h: 3_600_000, d: DAY_MS };
|
|
7
|
+
const DURATION = /^(?:\d+[smhd])+$/;
|
|
8
|
+
const WORD_UNITS: Record<string, string> = { second: 's', seconds: 's', sec: 's', secs: 's', minute: 'm', minutes: 'm', min: 'm', mins: 'm', hour: 'h', hours: 'h', hr: 'h', hrs: 'h', day: 'd', days: 'd' };
|
|
9
|
+
// setTimeout fires at once for delays past 2^31-1 ms (about 24.8 days), which would turn a long loop into a runaway.
|
|
10
|
+
const MAX_DELAY_MS = 24 * DAY_MS;
|
|
11
|
+
const TOO_LONG = 'Loop intervals can be at most 24d.';
|
|
12
|
+
|
|
13
|
+
/** Milliseconds for a duration such as 30s, 5m, 1h30m, 10 minutes, or 1 hour 30 minutes; undefined when the text is not a duration. */
|
|
14
|
+
export function parseDuration(text: string): number | undefined {
|
|
15
|
+
const compact = text
|
|
16
|
+
.trim()
|
|
17
|
+
.toLowerCase()
|
|
18
|
+
.replace(/^every\s+/, '')
|
|
19
|
+
.replace(/(\d+)\s*(seconds?|secs?|minutes?|mins?|hours?|hrs?|days?)\b/g, (_match, count: string, word: string) => `${count}${WORD_UNITS[word] ?? ''}`)
|
|
20
|
+
.replace(/\s+/g, '');
|
|
21
|
+
if (!DURATION.test(compact)) return undefined;
|
|
22
|
+
const total = [...compact.matchAll(/(\d+)([smhd])/g)].reduce((sum, [, count, unit]) => sum + Number(count) * (UNIT_MS[unit ?? 's'] ?? 0), 0);
|
|
23
|
+
return total > 0 ? total : undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function delayOf(text: string): number {
|
|
27
|
+
const ms = parseDuration(text);
|
|
28
|
+
if (ms === undefined) throw new Error(`"${text}" is not a duration such as 30s, 10m, or 1h.`);
|
|
29
|
+
if (ms > MAX_DELAY_MS) throw new Error(TOO_LONG);
|
|
30
|
+
return ms;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type LoopCommand = { kind: 'status' } | { kind: 'stop' } | { kind: 'start'; prompt: string; intervalMs?: number } | { kind: 'error'; message: string };
|
|
34
|
+
|
|
35
|
+
/** The longest trailing phrase that parses as a duration, such as `5m`, `every 10 minutes`, or `1 hour 30 minutes`. */
|
|
36
|
+
function trailingInterval(text: string): { prompt: string; intervalMs: number } | undefined {
|
|
37
|
+
const tokens = text.split(/\s+/);
|
|
38
|
+
for (let take = Math.min(6, tokens.length); take >= 1; take -= 1) {
|
|
39
|
+
const intervalMs = parseDuration(tokens.slice(-take).join(' '));
|
|
40
|
+
if (intervalMs === undefined) continue;
|
|
41
|
+
const prompt = tokens
|
|
42
|
+
.slice(0, -take)
|
|
43
|
+
.join(' ')
|
|
44
|
+
.replace(/\s+every$/i, '')
|
|
45
|
+
.trim();
|
|
46
|
+
return { prompt, intervalMs };
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function parseLoopArgs(args: string): LoopCommand {
|
|
52
|
+
const trimmed = args.trim();
|
|
53
|
+
if (trimmed === '') return { kind: 'status' };
|
|
54
|
+
if (trimmed === 'stop' || trimmed === 'off') return { kind: 'stop' };
|
|
55
|
+
const [, first = '', rest = ''] = /^(\S+)\s*([\s\S]*)$/.exec(trimmed) ?? [];
|
|
56
|
+
const leadMs = parseDuration(first) ?? (first.toLowerCase() === 'every' ? parseDuration(rest.split(/\s+/)[0] ?? '') : undefined);
|
|
57
|
+
if (leadMs !== undefined) {
|
|
58
|
+
if (leadMs > MAX_DELAY_MS) return { kind: 'error', message: TOO_LONG };
|
|
59
|
+
const after = first.toLowerCase() === 'every' ? rest.split(/\s+/).slice(1).join(' ') : rest;
|
|
60
|
+
return after.trim() === '' ? { kind: 'error', message: '/loop needs a prompt: /loop [interval] <prompt>' } : { kind: 'start', prompt: after.trim(), intervalMs: leadMs };
|
|
61
|
+
}
|
|
62
|
+
// Cursor accepts the interval at either end, including `every 10 minutes`, so both ends are tried before treating it as a prompt.
|
|
63
|
+
const trailing = trailingInterval(trimmed);
|
|
64
|
+
if (trailing !== undefined) {
|
|
65
|
+
if (trailing.intervalMs > MAX_DELAY_MS) return { kind: 'error', message: TOO_LONG };
|
|
66
|
+
if (trailing.prompt === '') return { kind: 'error', message: '/loop needs a prompt: /loop [interval] <prompt>' };
|
|
67
|
+
return { kind: 'start', prompt: trailing.prompt, intervalMs: trailing.intervalMs };
|
|
68
|
+
}
|
|
69
|
+
return { kind: 'start', prompt: trimmed };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface Loop {
|
|
73
|
+
prompt: string;
|
|
74
|
+
intervalMs?: number;
|
|
75
|
+
iteration: number;
|
|
76
|
+
nextWakeMs?: number;
|
|
77
|
+
timer?: ReturnType<typeof setTimeout>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const formatMs = (ms: number) => (ms % 86_400_000 === 0 ? `${ms / 86_400_000}d` : ms % 3_600_000 === 0 ? `${ms / 3_600_000}h` : ms % 60_000 === 0 ? `${ms / 60_000}m` : `${Math.round(ms / 1_000)}s`);
|
|
81
|
+
|
|
82
|
+
/** Loop state rides in the system prompt, so the prompt itself stays verbatim and a template prompt keeps it too. */
|
|
83
|
+
function loopSection(loop: Loop): string {
|
|
84
|
+
if (loop.intervalMs !== undefined) {
|
|
85
|
+
return `A /loop is running: iteration ${loop.iteration}, every ${formatMs(loop.intervalMs)}. The user ends it with /loop stop; call the Loop tool with stop: true once the goal is met.`;
|
|
86
|
+
}
|
|
87
|
+
return `A /loop is running: iteration ${loop.iteration}, agent-paced. Call the Loop tool with wake_in (like 10m) to schedule the next run, or stop: true to end it. Without a wake_in call the loop ends after this turn.`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface LoopOptions {
|
|
91
|
+
/** True while this session waits on work that will wake the agent, such as background subagents. */
|
|
92
|
+
hasPendingWork: () => boolean;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function createLoopController(pi: ExtensionAPI, options: LoopOptions) {
|
|
96
|
+
let loop: Loop | undefined;
|
|
97
|
+
let lastCtx: ExtensionContext | undefined;
|
|
98
|
+
|
|
99
|
+
const notify = (ctx: ExtensionContext | undefined, message: string) => {
|
|
100
|
+
if (ctx?.hasUI) ctx.ui.notify(message, 'info');
|
|
101
|
+
};
|
|
102
|
+
const clear = () => {
|
|
103
|
+
if (loop?.timer !== undefined) clearTimeout(loop.timer);
|
|
104
|
+
loop = undefined;
|
|
105
|
+
};
|
|
106
|
+
const stop = (ctx: ExtensionContext | undefined, reason: string) => {
|
|
107
|
+
clear();
|
|
108
|
+
notify(ctx, `Loop stopped: ${reason}`);
|
|
109
|
+
};
|
|
110
|
+
const fire = (first = false) => {
|
|
111
|
+
if (loop === undefined) return;
|
|
112
|
+
// A scheduled tick that lands mid-run is skipped rather than queued, so one long run cannot leave a pile of stale ticks.
|
|
113
|
+
if (!first && lastCtx !== undefined && !lastCtx.isIdle()) {
|
|
114
|
+
if (loop.intervalMs !== undefined) loop = { ...loop, timer: setTimeout(fire, loop.intervalMs) };
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const { timer: _timer, nextWakeMs: _wake, ...rest } = loop;
|
|
118
|
+
loop = { ...rest, iteration: rest.iteration + 1 };
|
|
119
|
+
// Expansion lets a loop run a skill or template each time.
|
|
120
|
+
pi.sendUserMessage(loop.prompt, { expandPromptTemplates: true });
|
|
121
|
+
// A fixed loop is wall-clock from each fire, like the reference's sleep loop: a long run does not push the next tick out.
|
|
122
|
+
if (loop.intervalMs !== undefined) loop = { ...loop, timer: setTimeout(fire, loop.intervalMs) };
|
|
123
|
+
};
|
|
124
|
+
const settled = (ctx: ExtensionContext, aborted: boolean) => {
|
|
125
|
+
lastCtx = ctx;
|
|
126
|
+
if (loop === undefined) return;
|
|
127
|
+
if (aborted) return stop(ctx, 'the run was aborted.');
|
|
128
|
+
if (loop.timer !== undefined) return;
|
|
129
|
+
if (loop.intervalMs !== undefined) {
|
|
130
|
+
// An armed fixed loop has no timer yet; its first tick waits for this turn to end.
|
|
131
|
+
loop = { ...loop, timer: setTimeout(fire, loop.intervalMs) };
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const delay = loop.nextWakeMs;
|
|
135
|
+
if (delay !== undefined) loop = { ...loop, timer: setTimeout(fire, delay) };
|
|
136
|
+
else if (!options.hasPendingWork()) stop(ctx, 'the agent scheduled no next wake.');
|
|
137
|
+
};
|
|
138
|
+
const start = (ctx: ExtensionContext, prompt: string, intervalMs: number | undefined) => {
|
|
139
|
+
if (loop !== undefined) stop(ctx, 'replaced by a new /loop.');
|
|
140
|
+
lastCtx = ctx;
|
|
141
|
+
loop = { prompt, iteration: 0, ...(intervalMs === undefined ? {} : { intervalMs }) };
|
|
142
|
+
fire(true);
|
|
143
|
+
};
|
|
144
|
+
/** An agent arms a loop mid-turn, so its first run waits for this turn to settle and then for the first delay. */
|
|
145
|
+
const arm = (ctx: ExtensionContext, prompt: string, schedule: { intervalMs: number } | { firstWakeMs: number }) => {
|
|
146
|
+
if (loop !== undefined) stop(ctx, 'replaced by a new loop.');
|
|
147
|
+
loop = 'intervalMs' in schedule ? { prompt, iteration: 0, intervalMs: schedule.intervalMs } : { prompt, iteration: 0, nextWakeMs: schedule.firstWakeMs };
|
|
148
|
+
};
|
|
149
|
+
const status = () =>
|
|
150
|
+
loop === undefined
|
|
151
|
+
? 'No loop is running. Usage: /loop [interval] <prompt>, with the interval at either end; /loop stop ends one.'
|
|
152
|
+
: `Loop: "${loop.prompt}" (iteration ${loop.iteration}${loop.intervalMs === undefined ? ', agent-paced' : `, every ${formatMs(loop.intervalMs)}`})`;
|
|
153
|
+
const wake = (delayMs: number) => {
|
|
154
|
+
if (loop === undefined) throw new Error('No loop is running. Start one with prompt plus interval or wake_in, or ask the user to run /loop.');
|
|
155
|
+
if (loop.intervalMs !== undefined) throw new Error(`This loop runs every ${formatMs(loop.intervalMs)}; only the user can change its interval. Pass stop: true to end it.`);
|
|
156
|
+
// A wake already scheduled is replaced, so the new delay counts from the end of this turn.
|
|
157
|
+
if (loop.timer !== undefined) clearTimeout(loop.timer);
|
|
158
|
+
const { timer: _timer, ...rest } = loop;
|
|
159
|
+
loop = { ...rest, nextWakeMs: delayMs };
|
|
160
|
+
};
|
|
161
|
+
const section = () => (loop === undefined ? undefined : loopSection(loop));
|
|
162
|
+
return { notify, stop, settled, start, arm, status, wake, clear, section, active: () => loop !== undefined };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
type LoopController = ReturnType<typeof createLoopController>;
|
|
166
|
+
|
|
167
|
+
const ONE_SHOT = '/loop needs an interactive or RPC session; print and JSON runs exit when the agent settles.';
|
|
168
|
+
|
|
169
|
+
function handleLoopCommand(controller: LoopController, args: string, ctx: ExtensionCommandContext): void {
|
|
170
|
+
const command = parseLoopArgs(args);
|
|
171
|
+
if (command.kind === 'status') controller.notify(ctx, controller.status());
|
|
172
|
+
else if (command.kind === 'stop') controller.stop(ctx, 'stopped by /loop stop.');
|
|
173
|
+
else if (command.kind === 'error') controller.notify(ctx, command.message);
|
|
174
|
+
else if (isOneShot(ctx.mode)) process.stderr.write(`${ONE_SHOT}\n`);
|
|
175
|
+
else controller.start(ctx, command.prompt, command.intervalMs);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const LoopParams = Type.Object({
|
|
179
|
+
prompt: Type.Optional(Type.String({ description: 'Start (or replace) a loop that sends this prompt each run. It may be a skill or template command such as /poteto-mode <task>.' })),
|
|
180
|
+
interval: Type.Optional(Type.String({ description: 'With prompt: a fixed cadence such as 30m or 1h; the first run starts that long after this turn ends.' })),
|
|
181
|
+
wake_in: Type.Optional(Type.String({ description: 'With prompt: the first run of an agent-paced loop. Alone: the next run of the running agent-paced loop. A duration such as 10m, at most 24d.' })),
|
|
182
|
+
stop: Type.Optional(Type.Boolean({ description: 'End the loop once its goal is met.' })),
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
function loopToolText(controller: LoopController, params: { prompt?: string; interval?: string; wake_in?: string; stop?: boolean }, ctx: ExtensionContext): string {
|
|
186
|
+
if (isOneShot(ctx.mode)) throw new Error(`${ONE_SHOT} Do the work now instead of scheduling it.`);
|
|
187
|
+
if (params.stop === true) {
|
|
188
|
+
if (!controller.active()) throw new Error('No loop is running.');
|
|
189
|
+
controller.stop(ctx, 'the agent ended it.');
|
|
190
|
+
return 'Loop stopped.';
|
|
191
|
+
}
|
|
192
|
+
if (params.prompt !== undefined) {
|
|
193
|
+
if (params.interval !== undefined) {
|
|
194
|
+
const intervalMs = delayOf(params.interval);
|
|
195
|
+
controller.arm(ctx, params.prompt, { intervalMs });
|
|
196
|
+
return `Loop armed: "${params.prompt}" every ${formatMs(intervalMs)}; the first run starts ${formatMs(intervalMs)} after this turn ends.`;
|
|
197
|
+
}
|
|
198
|
+
if (params.wake_in === undefined) throw new Error('To start a loop, pass interval for a fixed cadence or wake_in for the first run of an agent-paced loop.');
|
|
199
|
+
const firstWakeMs = delayOf(params.wake_in);
|
|
200
|
+
controller.arm(ctx, params.prompt, { firstWakeMs });
|
|
201
|
+
return `Loop armed: "${params.prompt}", agent-paced; the first run starts ${formatMs(firstWakeMs)} after this turn ends.`;
|
|
202
|
+
}
|
|
203
|
+
if (params.interval !== undefined) throw new Error('interval applies only when starting a loop with prompt.');
|
|
204
|
+
if (params.wake_in === undefined) throw new Error('Pass prompt with interval or wake_in to start a loop, wake_in to schedule the next run, or stop: true.');
|
|
205
|
+
const delay = delayOf(params.wake_in);
|
|
206
|
+
controller.wake(delay);
|
|
207
|
+
return `Next loop run in ${formatMs(delay)}, after this turn ends.`;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function registerLoopTool(pi: ExtensionAPI, controller: LoopController): void {
|
|
211
|
+
pi.registerTool({
|
|
212
|
+
name: 'Loop',
|
|
213
|
+
label: 'Loop',
|
|
214
|
+
description: '/loop for you: start a loop that re-sends a prompt at a fixed interval or at wakes you pick, schedule the next wake of an agent-paced loop, or stop the loop once its goal is met. Use it when a playbook says to arm /loop.',
|
|
215
|
+
promptSnippet: 'Start a /loop, schedule its next wake, or stop it',
|
|
216
|
+
parameters: LoopParams,
|
|
217
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
218
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
219
|
+
return { content: [{ type: 'text', text: loopToolText(controller, params, ctx) }], details: undefined };
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** /loop: run a prompt at a fixed interval, or at wakes the agent picks, until stopped. */
|
|
225
|
+
export function registerLoop(pi: ExtensionAPI, options: LoopOptions): { section: () => string | undefined } {
|
|
226
|
+
const controller = createLoopController(pi, options);
|
|
227
|
+
pi.on('session_start', (_event, ctx) => {
|
|
228
|
+
if (isOneShot(ctx.mode)) pi.setActiveTools(pi.getActiveTools().filter((name) => name !== 'Loop'));
|
|
229
|
+
});
|
|
230
|
+
pi.on('agent_settled', (event, ctx) => controller.settled(ctx, event.aborted));
|
|
231
|
+
pi.on('session_shutdown', () => controller.clear());
|
|
232
|
+
pi.registerCommand('loop', {
|
|
233
|
+
description: 'Run a prompt repeatedly: /loop [interval] <prompt>, interval either end and like 30s, 5m, 1h, every 10 minutes (at most 24d); /loop stop',
|
|
234
|
+
handler: async (args, ctx) => handleLoopCommand(controller, args, ctx),
|
|
235
|
+
});
|
|
236
|
+
registerLoopTool(pi, controller);
|
|
237
|
+
return { section: controller.section };
|
|
238
|
+
}
|
package/src/mode.ts
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
|
|
4
|
+
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext, ThemeColor } from '@earendil-works/pi-coding-agent';
|
|
5
|
+
import { parseFrontmatter, stripFrontmatter } from '@earendil-works/pi-coding-agent';
|
|
6
|
+
|
|
7
|
+
export const MODE_ENTRY = 'pstack/mode';
|
|
8
|
+
const STATUS_KEY = 'pstack-mode';
|
|
9
|
+
|
|
10
|
+
/** The mode on the branch. `path` is the loaded skill's file; absent when no loaded skill has the name. */
|
|
11
|
+
export interface ActiveMode {
|
|
12
|
+
skill: string;
|
|
13
|
+
path?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type ModeCommand = { kind: 'status' } | { kind: 'off' } | { kind: 'set'; skill: string; task: string };
|
|
17
|
+
|
|
18
|
+
export function parseModeArgs(args: string): ModeCommand {
|
|
19
|
+
const trimmed = args.trim();
|
|
20
|
+
if (trimmed === '') return { kind: 'status' };
|
|
21
|
+
if (trimmed === 'off') return { kind: 'off' };
|
|
22
|
+
const match = /^\/?(\S+)(?:\s([\s\S]*))?$/.exec(trimmed);
|
|
23
|
+
return { kind: 'set', skill: match?.[1] ?? trimmed, task: (match?.[2] ?? '').trim() };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface BranchEntry {
|
|
27
|
+
type: string;
|
|
28
|
+
customType?: string;
|
|
29
|
+
data?: unknown;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const SKILL_NAME = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The last mode entry on the branch, as a skill name only: a session file can come from elsewhere, so a stored path
|
|
36
|
+
* is ignored and a value that is not a plausible skill name (it would reach the system prompt) counts as no mode.
|
|
37
|
+
*/
|
|
38
|
+
export function modeFromBranch(entries: readonly BranchEntry[]): ActiveMode | undefined {
|
|
39
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
40
|
+
const entry = entries[index];
|
|
41
|
+
if (entry?.type !== 'custom' || entry.customType !== MODE_ENTRY) continue;
|
|
42
|
+
const skill = (entry.data as { skill?: unknown } | null)?.skill;
|
|
43
|
+
return typeof skill === 'string' && SKILL_NAME.test(skill) ? { skill } : undefined;
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The mode text for a request. Cursor attaches the skill once, on the turn that enters the mode, then sends a reminder
|
|
50
|
+
* that names the skill path each turn. Pi rebuilds its prompt per request, so the body rides the first request after
|
|
51
|
+
* entry and a reminder follows. A mode whose body was never sent re-sends it, so a restart cannot leave a mode
|
|
52
|
+
* unread.
|
|
53
|
+
*/
|
|
54
|
+
export function modeSection(mode: ActiveMode, includeBody: boolean): string {
|
|
55
|
+
if (mode.path === undefined) return `Mode ${mode.skill} is on, but no loaded skill has that name. Tell the user to run /mode off or /mode <skill>.`;
|
|
56
|
+
if (!existsSync(mode.path)) return `Mode ${mode.skill} is on, but its skill file ${mode.path} no longer exists. Tell the user to run /mode off or /mode <skill>.`;
|
|
57
|
+
if (!includeBody)
|
|
58
|
+
return `Reminder: you are still in ${mode.skill} mode. Follow that mode's skill on this turn. Do not drop it because the request looks small or you already have context. Do not drift back to default agent behavior. If you cannot state the mode's hard rules, read ${JSON.stringify(mode.path)} before acting.`;
|
|
59
|
+
// The frontmatter, including `reminder`, stays out of the model's context in a mode (MODE-004).
|
|
60
|
+
const body = stripFrontmatter(readFileSync(mode.path, 'utf8')).trim();
|
|
61
|
+
return [
|
|
62
|
+
`The user has entered ${mode.skill} custom mode. Follow the skill instructions in ${JSON.stringify(mode.path)} until the user exits or switches modes. Do not drift back to default agent behavior.`,
|
|
63
|
+
`<skill name="${mode.skill}" location="${mode.path}">`,
|
|
64
|
+
`References are relative to ${dirname(mode.path)}.`,
|
|
65
|
+
'',
|
|
66
|
+
body,
|
|
67
|
+
'</skill>',
|
|
68
|
+
].join('\n');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// A mode's badge shows the skill's `icon` (default: lightning) and `color`. Icon names map to terminal glyphs and
|
|
72
|
+
// color names to the nearest theme color.
|
|
73
|
+
const BADGE_ICONS: Record<string, string> = {
|
|
74
|
+
crown: '♛',
|
|
75
|
+
lightning: '⚡',
|
|
76
|
+
code: '</>',
|
|
77
|
+
terminal: '>_',
|
|
78
|
+
bug: '✱',
|
|
79
|
+
'git-branch': '⎇',
|
|
80
|
+
'book-open': '❐',
|
|
81
|
+
beaker: '⚗',
|
|
82
|
+
shield: '⛨',
|
|
83
|
+
rocket: '➶',
|
|
84
|
+
};
|
|
85
|
+
const BADGE_COLORS: Record<string, ThemeColor> = { green: 'success', red: 'error', yellow: 'warning', orange: 'warning', cyan: 'accent', blue: 'accent', purple: 'accent', magenta: 'accent', brand: 'accent' };
|
|
86
|
+
|
|
87
|
+
/** A skill carries `icon` and `color` under `metadata`, or at the top level of its frontmatter. */
|
|
88
|
+
function skillMetadata(mode: ActiveMode): Record<string, unknown> {
|
|
89
|
+
if (mode.path === undefined || !existsSync(mode.path)) return {};
|
|
90
|
+
const { frontmatter } = parseFrontmatter(readFileSync(mode.path, 'utf8'));
|
|
91
|
+
const metadata = typeof frontmatter['metadata'] === 'object' && frontmatter['metadata'] !== null ? (frontmatter['metadata'] as Record<string, unknown>) : {};
|
|
92
|
+
return { icon: frontmatter['icon'], color: frontmatter['color'], ...metadata };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function modeBadge(mode: ActiveMode, metadata: Record<string, unknown> = skillMetadata(mode)): { text: string; color?: ThemeColor } {
|
|
96
|
+
const iconName = String(metadata['icon']);
|
|
97
|
+
const colorName = String(metadata['color']);
|
|
98
|
+
const icon = Object.hasOwn(BADGE_ICONS, iconName) ? BADGE_ICONS[iconName] : BADGE_ICONS['lightning'];
|
|
99
|
+
const color = Object.hasOwn(BADGE_COLORS, colorName) ? BADGE_COLORS[colorName] : undefined;
|
|
100
|
+
return { text: `${icon} mode: ${mode.skill}`, ...(color === undefined ? {} : { color }) };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function loadedSkills(pi: ExtensionAPI): Map<string, string> {
|
|
104
|
+
const skills = new Map<string, string>();
|
|
105
|
+
for (const command of pi.getCommands()) {
|
|
106
|
+
if (command.source === 'skill' && command.name.startsWith('skill:')) skills.set(command.name.slice('skill:'.length), command.sourceInfo.path);
|
|
107
|
+
}
|
|
108
|
+
return skills;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function registerMode(pi: ExtensionAPI): { section: () => string | undefined } {
|
|
112
|
+
let active: ActiveMode | undefined;
|
|
113
|
+
// The mode whose body the conversation already carries; cleared on entry, exit, and session change.
|
|
114
|
+
let bodySent: string | undefined;
|
|
115
|
+
const show = (ctx: ExtensionContext) => {
|
|
116
|
+
if (!ctx.hasUI) return;
|
|
117
|
+
const badge = active === undefined ? undefined : modeBadge(active);
|
|
118
|
+
ctx.ui.setStatus(STATUS_KEY, badge === undefined ? undefined : badge.color === undefined ? badge.text : ctx.ui.theme.fg(badge.color, badge.text));
|
|
119
|
+
};
|
|
120
|
+
// The skill is looked up by name among loaded skills; a stored path is never read, since it can be stale or crafted.
|
|
121
|
+
const restore = (ctx: ExtensionContext) => {
|
|
122
|
+
const stored = modeFromBranch(ctx.sessionManager.getBranch());
|
|
123
|
+
active = stored === undefined ? undefined : (tryResolve(stored.skill) ?? { skill: stored.skill });
|
|
124
|
+
bodySent = undefined;
|
|
125
|
+
show(ctx);
|
|
126
|
+
};
|
|
127
|
+
pi.on('session_start', (_event, ctx) => restore(ctx));
|
|
128
|
+
pi.on('session_tree', (_event, ctx) => restore(ctx));
|
|
129
|
+
|
|
130
|
+
const resolveSkill = (name: string): ActiveMode => {
|
|
131
|
+
const skills = loadedSkills(pi);
|
|
132
|
+
const path = skills.get(name);
|
|
133
|
+
if (path === undefined) throw new Error(`No skill named "${name}". Skills that can back a mode: ${[...skills.keys()].toSorted().join(', ')}.`);
|
|
134
|
+
return { skill: name, path };
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
function tryResolve(name: string): ActiveMode | undefined {
|
|
138
|
+
try {
|
|
139
|
+
return resolveSkill(name);
|
|
140
|
+
} catch (error) {
|
|
141
|
+
if (error instanceof Error && error.message.startsWith('No skill named')) return undefined;
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const handle = (args: string, ctx: ExtensionCommandContext) => {
|
|
147
|
+
const command = parseModeArgs(args);
|
|
148
|
+
if (command.kind === 'status') return ctx.ui.notify(active === undefined ? 'No mode is on.' : `Mode on: ${active.skill} (${active.path ?? 'no loaded skill has that name'}).`, 'info');
|
|
149
|
+
active = command.kind === 'off' ? undefined : resolveSkill(command.skill);
|
|
150
|
+
bodySent = undefined;
|
|
151
|
+
pi.appendEntry(MODE_ENTRY, active === undefined ? null : { skill: active.skill });
|
|
152
|
+
show(ctx);
|
|
153
|
+
ctx.ui.notify(active === undefined ? 'Mode off.' : `Mode on: ${active.skill}. /mode off exits.`, 'info');
|
|
154
|
+
if (command.kind === 'set' && command.task !== '') pi.sendUserMessage(command.task, { expandPromptTemplates: true, ...(ctx.isIdle() ? {} : { deliverAs: 'followUp' as const }) });
|
|
155
|
+
return undefined;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
pi.registerCommand('mode', {
|
|
159
|
+
description: 'Keep a skill on every turn: /mode <skill> [task], /mode off, /mode',
|
|
160
|
+
getArgumentCompletions: (prefix) => ['off', ...[...loadedSkills(pi).keys()].toSorted()].filter((name) => name.startsWith(prefix.trim())).map((name) => ({ value: name, label: name })),
|
|
161
|
+
handler: async (args, ctx) => {
|
|
162
|
+
try {
|
|
163
|
+
handle(args, ctx);
|
|
164
|
+
} catch (error) {
|
|
165
|
+
ctx.ui.notify((error as Error).message, 'error');
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
section: () => {
|
|
172
|
+
if (active === undefined) return undefined;
|
|
173
|
+
const includeBody = bodySent !== active.skill;
|
|
174
|
+
// Only a request that actually carried the body counts as sent, so a missing skill file cannot silence the body
|
|
175
|
+
// after the file comes back.
|
|
176
|
+
if (includeBody && active.path !== undefined && existsSync(active.path)) bodySent = active.skill;
|
|
177
|
+
return modeSection(active, includeBody);
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
package/src/modes.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ExtensionContext } from '@earendil-works/pi-coding-agent';
|
|
2
|
+
import { childIdentity } from './child-env.ts';
|
|
3
|
+
|
|
4
|
+
/** Print and JSON runs exit once the agent settles, and so does every subagent, an RPC child that its owner closes then. */
|
|
5
|
+
export const isOneShot = (mode: ExtensionContext['mode']): boolean => mode === 'print' || mode === 'json' || childIdentity.depth > 0;
|
|
6
|
+
|
|
7
|
+
/** Whether a user can answer a dialog. A subagent's owner dismisses every dialog, so a subagent has nobody to ask. */
|
|
8
|
+
export const canAsk = (ctx: Pick<ExtensionContext, 'hasUI'>): boolean => ctx.hasUI && childIdentity.depth === 0;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Cursor attaches a skill to the conversation when the agent reads a file matching its `paths`/`globs` frontmatter.
|
|
2
|
+
// Pi has no path-scoped skills, so this module tracks the files a session reads or edits and attaches the matching
|
|
3
|
+
// skill body once per session, in the same <skill> block shape Pi's own /skill:name expansion uses.
|
|
4
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
5
|
+
import { dirname, isAbsolute, matchesGlob, relative, sep } from 'node:path';
|
|
6
|
+
|
|
7
|
+
import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
8
|
+
import { parseFrontmatter } from '@earendil-works/pi-coding-agent';
|
|
9
|
+
|
|
10
|
+
/** A skill whose frontmatter scopes it to file patterns. */
|
|
11
|
+
export interface PathSkill {
|
|
12
|
+
name: string;
|
|
13
|
+
file: string;
|
|
14
|
+
globs: string[];
|
|
15
|
+
body: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const TOUCHED_TOOLS = new Set(['read', 'edit', 'write']);
|
|
19
|
+
const SECTION_LIMIT = 40_000;
|
|
20
|
+
|
|
21
|
+
function globsOf(value: unknown): string[] {
|
|
22
|
+
if (typeof value === 'string')
|
|
23
|
+
return value
|
|
24
|
+
.split(',')
|
|
25
|
+
.map((part) => part.trim())
|
|
26
|
+
.filter((part) => part !== '');
|
|
27
|
+
if (!Array.isArray(value)) return [];
|
|
28
|
+
return value.filter((part): part is string => typeof part === 'string' && part.trim() !== '').map((part) => part.trim());
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Every loaded skill that declares `paths` (Cursor's name for skill globs) or `globs`. */
|
|
32
|
+
export function loadPathSkills(commands: readonly { name: string; source: string; sourceInfo: { path: string } }[]): PathSkill[] {
|
|
33
|
+
const skills: PathSkill[] = [];
|
|
34
|
+
for (const command of commands) {
|
|
35
|
+
if (command.source !== 'skill' || !command.name.startsWith('skill:')) continue;
|
|
36
|
+
const file = command.sourceInfo.path;
|
|
37
|
+
if (!existsSync(file)) continue;
|
|
38
|
+
const { frontmatter, body } = parseFrontmatter(readFileSync(file, 'utf8'));
|
|
39
|
+
// `metadata` is the portable Agent Skills extension point; Cursor's own field is the top-level `paths`/`globs`.
|
|
40
|
+
const metadata = typeof frontmatter['metadata'] === 'object' && frontmatter['metadata'] !== null ? (frontmatter['metadata'] as Record<string, unknown>) : {};
|
|
41
|
+
const globs = [...new Set([...globsOf(frontmatter['paths']), ...globsOf(frontmatter['globs']), ...globsOf(metadata['paths']), ...globsOf(metadata['globs'])])];
|
|
42
|
+
if (globs.length === 0) continue;
|
|
43
|
+
skills.push({ name: command.name.slice('skill:'.length), file, globs, body: body.trim() });
|
|
44
|
+
}
|
|
45
|
+
return skills;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const slash = (path: string) => path.split(sep).join('/');
|
|
49
|
+
|
|
50
|
+
/** The skills whose patterns match a path the session read or edited. Paths outside the workspace are ignored. */
|
|
51
|
+
export function matchPathSkills(skills: readonly PathSkill[], paths: Iterable<string>, cwd: string): PathSkill[] {
|
|
52
|
+
const relativePaths = [...paths].map((path) => slash(isAbsolute(path) ? relative(cwd, path) : path)).filter((path) => path !== '' && path !== '..' && !path.startsWith('../'));
|
|
53
|
+
return skills.filter((skill) => relativePaths.some((path) => skill.globs.some((glob) => matchesGlob(path, glob))));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The attached bodies as <skill> blocks, in the shape Pi's /skill:name expansion builds. */
|
|
57
|
+
export function pathSkillsSection(skills: readonly PathSkill[]): string | undefined {
|
|
58
|
+
if (skills.length === 0) return undefined;
|
|
59
|
+
const blocks: string[] = [];
|
|
60
|
+
let size = 0;
|
|
61
|
+
for (const skill of skills) {
|
|
62
|
+
const block = [`<skill name="${skill.name}" location="${skill.file}">`, `References are relative to ${dirname(skill.file)}.`, '', skill.body, '</skill>'].join('\n');
|
|
63
|
+
if (size + block.length > SECTION_LIMIT) break;
|
|
64
|
+
size += block.length;
|
|
65
|
+
blocks.push(block);
|
|
66
|
+
}
|
|
67
|
+
return blocks.length === 0 ? undefined : blocks.join('\n\n');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface PathSkillsHandle {
|
|
71
|
+
/** The skills to attach to the next request, empty until a matching file has been read or edited. */
|
|
72
|
+
section: () => string | undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Tracks read and edit paths and attaches each matching skill once per session. */
|
|
76
|
+
export function createPathSkills(pi: ExtensionAPI): PathSkillsHandle {
|
|
77
|
+
let catalog: PathSkill[] | undefined;
|
|
78
|
+
let cwd = process.cwd();
|
|
79
|
+
let touched = new Set<string>();
|
|
80
|
+
const injected = new Set<string>();
|
|
81
|
+
|
|
82
|
+
pi.on('session_start', (_event, ctx) => {
|
|
83
|
+
catalog = undefined;
|
|
84
|
+
touched = new Set();
|
|
85
|
+
injected.clear();
|
|
86
|
+
cwd = ctx.cwd;
|
|
87
|
+
});
|
|
88
|
+
pi.on('tool_call', (event) => {
|
|
89
|
+
if (!TOUCHED_TOOLS.has(event.toolName)) return;
|
|
90
|
+
const path = (event.input as { path?: unknown }).path;
|
|
91
|
+
if (typeof path === 'string' && path !== '') touched.add(path);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
section: () => {
|
|
96
|
+
if (touched.size === 0) return undefined;
|
|
97
|
+
catalog ??= loadPathSkills(pi.getCommands());
|
|
98
|
+
const matches = matchPathSkills(catalog, touched, cwd).filter((skill) => !injected.has(skill.name));
|
|
99
|
+
if (matches.length === 0) return undefined;
|
|
100
|
+
for (const skill of matches) injected.add(skill.name);
|
|
101
|
+
return pathSkillsSection(matches);
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
package/src/paths.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { dirname, join, resolve } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
|
|
4
|
+
import { getAgentDir } from '@earendil-works/pi-coding-agent';
|
|
5
|
+
import { childIdentity } from './child-env.ts';
|
|
6
|
+
|
|
7
|
+
export const PACKAGE_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
8
|
+
export const SKILLS_DIR = join(PACKAGE_ROOT, 'skills');
|
|
9
|
+
export const AGENTS_DIR = join(PACKAGE_ROOT, 'agents');
|
|
10
|
+
|
|
11
|
+
/** Pi-owned state for this package. Follows PI_CODING_AGENT_DIR, so tests and users can relocate it. */
|
|
12
|
+
export function stateDir(): string {
|
|
13
|
+
return join(getAgentDir(), 'pstack');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** The model rule: pstack's per-role model choices, added to every request's system prompt. */
|
|
17
|
+
export function rulePath(): string {
|
|
18
|
+
return join(stateDir(), 'pstack-models.md');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Webhook routines' sender keys, one `<slug>/credentials.json` each. */
|
|
22
|
+
export function routinesDir(): string {
|
|
23
|
+
return join(stateDir(), 'routines');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Plan-mode artifacts, the way Cursor keeps a plan file under `~/.cursor/plans`. */
|
|
27
|
+
export function plansDir(): string {
|
|
28
|
+
return join(stateDir(), 'plans');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Desired-state registry and supervisor runtime for one workspace. */
|
|
32
|
+
export function durableDir(cwd: string): string {
|
|
33
|
+
return join(stateDir(), 'durable', workspaceSlug(cwd));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function durableRegistryPath(cwd: string): string {
|
|
37
|
+
return join(durableDir(cwd), 'subscriptions.json');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function durableRuntimeDir(cwd: string): string {
|
|
41
|
+
return join(durableDir(cwd), 'runtime');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Pi's rule for a session folder name, so per-workspace state lines up with `<agentDir>/sessions/<slug>`. The live
|
|
46
|
+
* `sessionManager.getSessionDir()` needs a session and names the current one, which is `<workspace>/subagents` in a
|
|
47
|
+
* subagent, so the rule stays here for a working directory (docs/native-gaps.md).
|
|
48
|
+
*/
|
|
49
|
+
export function workspaceSlug(cwd: string): string {
|
|
50
|
+
return `--${resolve(cwd)
|
|
51
|
+
.replace(/^[/\\]/, '')
|
|
52
|
+
.replace(/[/\\:]/g, '-')}--`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* State for one working directory, so transcripts and stores never cross workspaces (pstack's own rule). A subagent
|
|
57
|
+
* uses its main chat's, so an isolated worker in its own worktree shares the tree's Projects, records, and transcripts.
|
|
58
|
+
*/
|
|
59
|
+
export function workspaceStateDir(cwd: string, inherited: string | undefined = childIdentity.workspaceState): string {
|
|
60
|
+
return inherited ?? join(stateDir(), 'workspaces', workspaceSlug(cwd));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Subagent transcripts, records, and run locks for this workspace. */
|
|
64
|
+
export function subagentDir(cwd: string): string {
|
|
65
|
+
return join(workspaceStateDir(cwd), 'subagents');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Projects of this workspace: `<slug>/notes.md` is a project's tracker and `<slug>/store/` its store. */
|
|
69
|
+
export function projectsDir(cwd: string): string {
|
|
70
|
+
return join(workspaceStateDir(cwd), 'projects');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Files a session's tools produce for the user, such as visualize's SVG charts. */
|
|
74
|
+
export function artifactsDir(cwd: string, sessionId: string): string {
|
|
75
|
+
return join(workspaceStateDir(cwd), 'artifacts', sessionId);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function worktreesDir(cwd: string): string {
|
|
79
|
+
return join(workspaceStateDir(cwd), 'worktrees');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** The store of the main chat that started this subagent tree, which autopilot owners write their trails into. */
|
|
83
|
+
export function rootStoreDir(cwd: string, sessionId: string, inherited: string | undefined): string {
|
|
84
|
+
return inherited ?? storeDir(cwd, sessionId);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** "The current agent's store" that orchestrate's store layout writes into: one directory per session. */
|
|
88
|
+
export function storeDir(cwd: string, sessionId: string): string {
|
|
89
|
+
return join(workspaceStateDir(cwd), 'store', sessionId);
|
|
90
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { basename } from 'node:path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Argv prefix for spawning Pi: the running script when available so children match
|
|
6
|
+
* the parent's Pi version, else `pi` on PATH. Same rule as task/tool.ts historically.
|
|
7
|
+
*/
|
|
8
|
+
export function piCommand(): string[] {
|
|
9
|
+
const script = process.argv[1];
|
|
10
|
+
if (script !== undefined && !script.startsWith('/$bunfs/') && existsSync(script)) return [process.execPath, script];
|
|
11
|
+
return /^(node|bun)(\.exe)?$/.test(basename(process.execPath).toLowerCase()) ? ['pi'] : [process.execPath];
|
|
12
|
+
}
|