monorepo_root = true [monorepo] config_roots = ["extensions/*"] [tools] node = "latest" go = "latest" biome = "latest" "aqua:mikefarah/yq" = "latest" "aqua:rvben/rumdl" = "latest" "aqua:tamasfe/taplo" = "latest" # README demo recordings: asciicast → GIF. "github:asciinema/agg" = "latest" "go:golang.org/x/perf/cmd/benchstat" = "latest" [tasks.default] description = "List tasks" run = "mise tasks ls" [tasks.install] description = "Install Node dependencies" run = "npm ci" sources = ["package.json", "package-lock.json"] outputs = ["node_modules/vitest/package.json"] [tasks.lock] description = "Regenerate package lock; optional package names refresh selected dependencies" usage = ''' arg "[packages]" var=#true ''' run = ''' {% if usage.packages %}npm update --package-lock-only{% for package in usage.packages %} "{{ package }}"{% endfor %}{% else %}npm install --package-lock-only{% endif %} ''' [tasks.codegen] description = "Write configured generated extension files" run = "node scripts/codegen.ts" [tasks.demo] description = "Record README demos from extensions//demo/scene.json into assets/demo.{cast,gif}; --assert-only runs the scenes without writing" depends = ["install"] usage = ''' arg "[args]" var=#true help="Extension names, or --assert-only; default every extension with a scene" ''' run = 'node scripts/demo/runner.ts{% if usage.args %}{% for arg in usage.args %} "{{ arg }}"{% endfor %}{% endif %}' [tasks.demo-check] description = "Run README demo scenes against the built packages without writing recordings; a failing scene means the demo is stale. Pass extension names to limit the run" depends = ["build-all"] usage = ''' arg "[extensions]" var=#true help="Extension names; default every extension with a scene" ''' run = 'node scripts/demo/runner.ts --assert-only{% if usage.extensions %}{% for arg in usage.extensions %} "{{ arg }}"{% endfor %}{% endif %}' [tasks.banners] description = "Write every extension's README banner from its name, pi-ext.logo, and assets/nugu.json" usage = ''' arg "[args]" var=#true help="Extension directory names, or --check; default all" ''' run = 'node scripts/readme/banners.ts{% if usage.args %}{% for arg in usage.args %} "{{ arg }}"{% endfor %}{% endif %}' [tasks.readme-config] description = "Write generated extension README configuration references" depends = ["install"] usage = ''' arg "[extensions]" var=#true help="Extension names; default all" ''' run = 'node scripts/readme/check.ts --write{% if usage.extensions %}{% for extension in usage.extensions %} "{{ extension }}"{% endfor %}{% endif %}' [tasks.check-readmes] description = "Verify extension README structure and generated configuration references" depends = ["install"] usage = ''' arg "[extensions]" var=#true help="Extension names; default all" ''' run = 'node scripts/readme/check.ts{% if usage.extensions %}{% for extension in usage.extensions %} "{{ extension }}"{% endfor %}{% endif %}' [tasks.readme-test] description = "Run focused README automation tests" depends = ["install"] run = [ "biome check scripts/readme", { task = "//:test", args = ["scripts/readme"] }, ] [tasks.fmt] description = "Format repo" depends = ["install"] run = [ "npm run fmt", "rumdl fmt .", "taplo format", ] [tasks.format-files] description = "Format selected repository TypeScript files without touching unrelated work" depends = ["install"] usage = ''' arg "" var=#true ''' run = '''biome check --write{% for file in usage.files %} "{{ file }}"{% endfor %}''' [tasks.lint] description = "Verify formatting and lint" depends = ["install"] run = [ "npm run lint", "taplo format --check", "node scripts/check_frontmatter.ts", "node scripts/check_skills.ts", ] [tasks.test] description = "Run tests" tools."aqua:nushell/nushell" = "latest" depends = ["install"] usage = ''' arg "[args]" var=#true ''' run = [ '''npm run test --{% for arg in usage.args %} "{{ arg }}"{% endfor %}''', { task = "//:modernize-test" }, ] [tasks.modernize-test] description = "Test modernize installation discovery and audit evidence" run = "node --test .pi/skills/modernize/scripts/audit.test.mjs" [tasks.mutate] description = "Author-driven Stryker mutation testing (vitest runner, per-extension incremental cache). Never in hooks or CI. Usage: mutate " depends = ["install"] usage = ''' arg "" arg "" help="Path under extensions// to mutate (file or glob)" ''' run = ''' npx stryker run --mutate "extensions/{{ usage.extension }}/{{ usage.target }}" --incrementalFile ".stryker-tmp/incremental-{{ usage.extension }}.json" ''' [tasks.bump] description = "Deliberately update npm deps within their ranges and bump mise tool versions, then re-lock. Pass --dry-run to preview." depends = ["install"] run = ''' node scripts/bump.ts{% if usage.args %}{% for arg in usage.args %} "{{ arg }}"{% endfor %}{% endif %} ''' usage = ''' arg "[args]" var=#true ''' [tasks.fuzz] description = "Author-driven hostile-input fuzz campaign over a parser (seeded; minimized findings become replay regression tests). Never in hooks or CI. Usage: fuzz ; FUZZ_RUNS overrides the run count." depends = ["install"] usage = ''' arg "" arg "" help="Fuzz target at extensions//__fuzz__/.fuzz.ts" ''' run = ''' node "extensions/{{ usage.extension }}/__fuzz__/{{ usage.target }}.fuzz.ts" ''' [tasks.mutate-all] description = "Full Stryker mutation report across all extensions (author-driven; slow; never in CI)." depends = ["install"] run = "npx stryker run --incrementalFile .stryker-tmp/incremental-all.json" [tasks.snapshot-update] description = "Explicitly update committed snapshots (normal `test` runs never rewrite them). Pass test paths to narrow." depends = ["install"] usage = ''' arg "[args]" var=#true ''' run = ''' npm run test -- -u{% for arg in usage.args %} "{{ arg }}"{% endfor %} ''' [tasks.coverage] description = "Non-gating V8 coverage (chosen over Istanbul: 37s vs 44s on the suite, lower transform overhead, ast-aware line/branch/function) over the deterministic test projects, all owned production files. Pass an extension to scope the report." depends = ["install"] usage = ''' arg "[extension]" help="Extension slug to scope coverage to" ''' run = ''' npm run test -- --project unit --project contract --project isolated-serial --project native{% if usage.extension %} "extensions/{{ usage.extension }}/"{% endif %} --coverage.enabled=true --coverage.all=true{% if usage.extension %} "--coverage.include=extensions/{{ usage.extension }}/**/*.ts"{% endif %} ''' [tasks.knip] description = "Report unused files, dependencies, and exports (author-driven; not a gate)" depends = ["install"] # Shared extensions/* entry globs cannot match in every extension, so the # resulting "no matches" hints are structural noise rather than config drift. run = "npx knip --no-config-hints" [tasks.context-startup] description = "Compare stock, configured, and no-Pi-text headless context (three live requests)" usage = ''' arg "[cwd]" help="Project directory to measure" ''' run = ''' node scripts/context-startup.ts{% if usage.cwd %} "{{ usage.cwd }}"{% endif %} ''' [tasks.context-startup-sources] description = "Estimate APPEND_SYSTEM and skill tokens by source (no measurement prompt)" run = "node scripts/context-startup-session.ts --sources" [tasks.context-startup-skill-descriptions] description = "Rank pi/agent skill descriptions by size and show the largest five" run = "node scripts/context-startup-session.ts --skill-descriptions" [tasks.context-extensions] description = "Inspect runtime extensions and measure leave-one-out input tokens (N+2 live requests)" usage = ''' arg "[cwd]" help="Project directory to measure" ''' run = ''' node scripts/context-extensions.ts{% if usage.cwd %} "{{ usage.cwd }}"{% endif %} ''' [tasks.context-guidance-check] description = "Read-only live activation check for tool-owned mockup guidance" depends = ["install"] env.PI_OFFLINE = "1" run = ''' pi --print --mode json --no-session --no-extensions --extension extensions/mockup/index.ts --no-context-files --tools read,mockup "Plan an interactive 80-column terminal task-list mockup with keyboard selection. Planning only: do not create or edit files, execute commands, call mockup, or open a browser. Load the applicable authoring guidance using read only, then explain the document boundary and target-platform constraints." | node --input-type=module -e " import { createInterface } from 'node:readline'; import { basename, dirname } from 'node:path'; const missing = new Set(['mockup-html']); const calls = new Map(); let completed = false; for await (const line of createInterface({ input: process.stdin })) { const event = JSON.parse(line); if (event.type === 'tool_execution_start') { if (event.toolName !== 'read') throw new Error('Unexpected tool: ' + event.toolName); console.log('read ' + event.args.path); if (basename(event.args.path) === 'SKILL.md') calls.set(event.toolCallId, basename(dirname(event.args.path))); } if (event.type === 'tool_execution_end' && !event.isError) missing.delete(calls.get(event.toolCallId)); if (event.type === 'message_end' && event.message.role === 'assistant' && event.message.stopReason === 'stop') { completed = true; console.log(event.message.content.filter(part => part.type === 'text').map(part => part.text).join('\n')); } } if (missing.size || !completed) throw new Error('Incomplete guidance check: ' + [...missing].join(', ')); console.log('PASS: mockup guidance read; only read tools used; turn completed.'); " ''' [tasks.context-startup-test] description = "Check the startup context measurement script" depends = ["install"] run = [ "biome check scripts/context-startup.ts scripts/context-startup-session.ts scripts/context-startup.test.ts scripts/context-extensions.ts scripts/context-extensions.test.ts", "rumdl check scripts/context-startup.md", "taplo format --check mise.toml", { task = "//:test", args = [ "scripts/context-startup.test.ts", "scripts/context-extensions.test.ts", ] }, ] [tasks.context-startup-fmt] description = "Format context measurement files only" depends = ["install"] run = [ "biome check --write scripts/context-startup.ts scripts/context-startup-session.ts scripts/context-startup.test.ts scripts/context-extensions.ts scripts/context-extensions.test.ts", "rumdl fmt scripts/context-startup.md", "taplo format mise.toml", ] [tasks.bench] description = "Run all extension benchmarks sequentially" depends = ["install"] run = "mise run --jobs 1 //extensions/...:bench" [tasks.modernize-bench] description = "Benchmark modernize audit" tools.hyperfine = "latest" usage = ''' arg "[args]" var=#true ''' run = ''' node .pi/skills/modernize/scripts/audit.bench.mjs{% for arg in usage.args %} "{{ arg }}"{% endfor %} ''' [tasks.extension-startup-bench] description = "Benchmark configured extension startup to RPC readiness" depends = ["install"] run = "node scripts/extension-startup.bench.ts" [tasks.debug-bench] description = "Benchmark the generated debug writer at startup and per record" depends = ["install"] usage = ''' arg "[template]" help="Template copy to measure, defaults to the current template" ''' run = 'node scripts/codegen/pi-ext-debug.bench.ts{% if usage.template %} "{{ usage.template }}"{% endif %}' [tasks.extension-startup-benchstat] description = "Compare extension startup benchmark results" depends = ["install"] usage = ''' arg "" arg "" ''' run = 'benchstat "{{ usage.baseline }}" "{{ usage.candidate }}"' [tasks.e2e] description = "Run local E2E in disposable OS temp (PI_EXT_E2E_FILTER= for one suite; real S3: //extensions/bak:e2e-s3)" depends = ["install"] run = "node scripts/e2e.ts //extensions/chrome-cdp:e2e //extensions/klaus:e2e //extensions/mockup:e2e //extensions/strata:e2e //extensions/the-system:e2e" [tasks.e2e-extension] description = "Run one extension acceptance suite with isolated browser provisioning in OS temp" depends = ["install"] usage = ''' arg "" ''' run = 'node scripts/e2e.ts "//extensions/{{ usage.extension }}:e2e"' [tasks.build-ext] description = "Build selected extension packages into dist/ (--release for the release variant)" depends = ["install"] usage = ''' arg "" var=#true flag "--release" help="Minified release variant without sourcemaps" ''' run = ''' node --no-warnings scripts/build/cli.ts{% if usage.release %} --release{% endif %}{% for extension in usage.extensions %} "{{ extension }}"{% endfor %} ''' [tasks.build-all] description = "Build every extension package into dist/ (--release for the release variant)" depends = ["install"] usage = ''' flag "--release" help="Minified release variant without sourcemaps" ''' run = ''' node --no-warnings scripts/build/cli.ts --all{% if usage.release %} --release{% endif %} ''' [tasks.settings-entries] description = "Print the explicit dist/ package list for ~/.pi/agent/settings.json packages" run = "node --no-warnings scripts/build/settings-entries.ts" [tasks.verify-packages] description = "Build release packages and verify relocated collection against minimum Pi or PI_EXT_MATRIX_PI" depends = ["install"] env = { PI_EXT_VERIFY_PACKAGES = "1" } run = [ "node --no-warnings scripts/build/cli.ts --all --release", "npm run test -- --project packages", ] [tasks.build] description = "Typecheck and statically validate extensions" depends = ["install"] usage = ''' arg "[extensions]" var=#true ''' run = [ "npm run typecheck", '''node scripts/extensions.ts check{% for extension in usage.extensions %} "{{ extension }}"{% endfor %}''', ] [tasks.check] description = "Typecheck and run static extension checks" depends = ["install"] run = [ "npm run typecheck", "node scripts/check_skills.ts", "node scripts/test_extensions_static_check.ts", "node scripts/extensions.ts check", "node scripts/compatibility.ts", "node scripts/readme/banners.ts --check", { task = "//:check-readmes" }, ] [tasks.release-all] description = "Build and validate all release packages and exact archives" depends = ["install"] run = "node --no-warnings scripts/build/release.ts" [tasks.ci] description = "Release gate" run = [ { tasks = ["check", "lint"] }, { task = "test" }, { task = "e2e" }, { task = "demo-check" }, { task = "release-all" }, { task = "verify-packages" }, ] [tasks.list] description = "List extensions" usage = ''' arg "[extensions]" var=#true ''' run = ''' node scripts/extensions.ts list{% for extension in usage.extensions %} "{{ extension }}"{% endfor %} ''' [tasks.changelog] description = "Generate changelog" usage = ''' arg "" var=#true ''' run = ''' node scripts/extensions.ts changelog{% for extension in usage.extensions %} "{{ extension }}"{% endfor %} ''' [tasks.readme] description = "Generate/update READMEs" usage = ''' arg "[extensions]" var=#true flag "--model " ''' run = ''' node scripts/extensions.ts readme --write{% if usage.model %} --model "{{ usage.model }}"{% endif %}{% for extension in usage.extensions %} "{{ extension }}"{% endfor %} ''' [tasks.release-snapshot] description = "Snapshot explicitly selected eligible release packages" depends = ["install"] usage = ''' arg "" var=#true ''' run = ''' npm run release:snapshot --{% for extension in usage.extensions %} "{{ extension }}"{% endfor %} ''' [tasks.release-plan] description = "Validate explicitly selected release eligibility" usage = ''' arg "" var=#true ''' run = ''' npm run release:snapshot --{% for extension in usage.extensions %} "{{ extension }}"{% endfor %} ''' [tasks.release-prepare] description = "Create verified snapshots for explicitly selected extensions after their README demos still pass" usage = ''' arg "" var=#true ''' run = [ '''node scripts/demo/runner.ts --assert-only{% for extension in usage.extensions %} "{{ extension }}"{% endfor %}''', '''npm run release:snapshot --{% for extension in usage.extensions %} "{{ extension }}"{% endfor %}''', ] [tasks.clean] description = "Remove generated caches and scratch artifacts" run = ''' find . -path ./.git -prune -o -path ./.jj -prune -o -type d -name node_modules -prune -exec rm -rf {} + ''' [tasks.publish] description = "Create local Git delivery from selected verified snapshots; --push is required for remote delivery" depends = ["install"] usage = ''' arg "" var=#true flag "--push" help="Push temporary distribution repositories to declared remotes" ''' run = ''' npm run release:publish --{% if usage.push %} --push{% endif %}{% for extension in usage.extensions %} "{{ extension }}"{% endfor %} ''' [tasks.pre-commit] description = "Pre-commit hook: changed-scope check + lint (repository-wide when shared files are staged)" run = "node scripts/scope.ts" [tasks.pre-push] description = "Pre-push hook: check + lint" run = [{ tasks = ["check", "lint"] }]