pi-usereq 0.4.0
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/.g.conf +20 -0
- package/.github/workflows/release-npm.yml +131 -0
- package/.gitignore +270 -0
- package/CHANGELOG.md +221 -0
- package/LICENSE +674 -0
- package/README.md +260 -0
- package/TODO.md +20 -0
- package/docs/pi.dev/agent-document-manifest.json +6399 -0
- package/docs/pi.dev/coding-agent-docs/compaction.md +394 -0
- package/docs/pi.dev/coding-agent-docs/custom-provider.md +596 -0
- package/docs/pi.dev/coding-agent-docs/development.md +71 -0
- package/docs/pi.dev/coding-agent-docs/extensions.md +2262 -0
- package/docs/pi.dev/coding-agent-docs/images/doom-extension.png +0 -0
- package/docs/pi.dev/coding-agent-docs/images/exy.png +0 -0
- package/docs/pi.dev/coding-agent-docs/images/interactive-mode.png +0 -0
- package/docs/pi.dev/coding-agent-docs/images/tree-view.png +0 -0
- package/docs/pi.dev/coding-agent-docs/json.md +82 -0
- package/docs/pi.dev/coding-agent-docs/keybindings.md +175 -0
- package/docs/pi.dev/coding-agent-docs/models.md +392 -0
- package/docs/pi.dev/coding-agent-docs/packages.md +218 -0
- package/docs/pi.dev/coding-agent-docs/prompt-templates.md +67 -0
- package/docs/pi.dev/coding-agent-docs/providers.md +195 -0
- package/docs/pi.dev/coding-agent-docs/rpc.md +1377 -0
- package/docs/pi.dev/coding-agent-docs/sdk.md +1124 -0
- package/docs/pi.dev/coding-agent-docs/session.md +412 -0
- package/docs/pi.dev/coding-agent-docs/settings.md +247 -0
- package/docs/pi.dev/coding-agent-docs/shell-aliases.md +13 -0
- package/docs/pi.dev/coding-agent-docs/skills.md +232 -0
- package/docs/pi.dev/coding-agent-docs/terminal-setup.md +106 -0
- package/docs/pi.dev/coding-agent-docs/termux.md +127 -0
- package/docs/pi.dev/coding-agent-docs/themes.md +295 -0
- package/docs/pi.dev/coding-agent-docs/tmux.md +61 -0
- package/docs/pi.dev/coding-agent-docs/tree.md +231 -0
- package/docs/pi.dev/coding-agent-docs/tui.md +887 -0
- package/docs/pi.dev/coding-agent-docs/windows.md +17 -0
- package/docs/pi.dev/mom-docs/artifacts-server.md +475 -0
- package/docs/pi.dev/mom-docs/events.md +307 -0
- package/docs/pi.dev/mom-docs/new.md +970 -0
- package/docs/pi.dev/mom-docs/sandbox.md +153 -0
- package/docs/pi.dev/mom-docs/slack-bot-minimal-guide.md +399 -0
- package/docs/pi.dev/mom-docs/v86.md +319 -0
- package/docs/pi.dev/pods-docs/gml-4.5.md +189 -0
- package/docs/pi.dev/pods-docs/gpt-oss.md +233 -0
- package/docs/pi.dev/pods-docs/implementation-plan.md +183 -0
- package/docs/pi.dev/pods-docs/kimi-k2.md +197 -0
- package/docs/pi.dev/pods-docs/models.md +116 -0
- package/docs/pi.dev/pods-docs/plan.md +166 -0
- package/docs/pi.dev/pods-docs/qwen3-coder.md +132 -0
- package/images/flowchart-bw.png +0 -0
- package/images/flowchart-bw.svg +102 -0
- package/images/flowchart.md +100 -0
- package/images/flowchart.png +0 -0
- package/images/flowchart.svg +3 -0
- package/package.json +46 -0
- package/req/docs/REFERENCES.md +4554 -0
- package/req/docs/REQUIREMENTS.md +475 -0
- package/req/docs/WORKFLOW.md +1059 -0
- package/scripts/debug-extension.ts +497 -0
- package/scripts/lib/extension-debug-harness.ts +450 -0
- package/scripts/lib/recording-extension-api.ts +786 -0
- package/scripts/lib/sdk-smoke.ts +503 -0
- package/scripts/pi-usereq-debug.sh +330 -0
- package/scripts/tool-args-to-params.ts +208 -0
- package/src/cli.ts +349 -0
- package/src/core/agent-tool-json.ts +621 -0
- package/src/core/compress-files.ts +72 -0
- package/src/core/compress-payload.ts +648 -0
- package/src/core/compress.ts +464 -0
- package/src/core/config.ts +272 -0
- package/src/core/doxygen-parser.ts +318 -0
- package/src/core/errors.ts +31 -0
- package/src/core/extension-status.ts +660 -0
- package/src/core/find-constructs.ts +319 -0
- package/src/core/find-payload.ts +915 -0
- package/src/core/generate-markdown.ts +120 -0
- package/src/core/path-context.ts +196 -0
- package/src/core/pi-notify.ts +430 -0
- package/src/core/pi-usereq-tools.ts +140 -0
- package/src/core/prompts.ts +184 -0
- package/src/core/reference-payload.ts +818 -0
- package/src/core/resources.ts +63 -0
- package/src/core/runtime-project-paths.ts +99 -0
- package/src/core/settings-menu.ts +233 -0
- package/src/core/source-analyzer.ts +1721 -0
- package/src/core/static-check.ts +674 -0
- package/src/core/token-counter.ts +729 -0
- package/src/core/tool-runner.ts +717 -0
- package/src/core/utils.ts +185 -0
- package/src/index.ts +2209 -0
- package/src/resources/guidelines/Google_C++_Style_Guide.md +3711 -0
- package/src/resources/guidelines/Google_Python_Style_Guide.md +3709 -0
- package/src/resources/prompts/analyze.md +130 -0
- package/src/resources/prompts/change.md +227 -0
- package/src/resources/prompts/check.md +139 -0
- package/src/resources/prompts/cover.md +219 -0
- package/src/resources/prompts/create.md +104 -0
- package/src/resources/prompts/fix.md +221 -0
- package/src/resources/prompts/flowchart.md +220 -0
- package/src/resources/prompts/implement.md +163 -0
- package/src/resources/prompts/new.md +226 -0
- package/src/resources/prompts/readme.md +182 -0
- package/src/resources/prompts/recreate.md +213 -0
- package/src/resources/prompts/refactor.md +213 -0
- package/src/resources/prompts/references.md +100 -0
- package/src/resources/prompts/renumber.md +119 -0
- package/src/resources/prompts/workflow.md +202 -0
- package/src/resources/prompts/write.md +99 -0
- package/src/resources/sounds/Machine-alert-beep-sound-effect.mp3 +0 -0
- package/src/resources/sounds/Soft-high-tech-notification-sound-effect.mp3 +0 -0
- package/src/resources/templates/Document_Source_Code_in_Doxygen_Style.md +130 -0
- package/src/resources/templates/HDT_Test_Authoring_Guide.md +318 -0
- package/src/resources/templates/Requirements_Template.md +78 -0
- package/tests/attended-results-scenarios.ts +758 -0
- package/tests/attended-results.test.ts +39 -0
- package/tests/cli-command-option-parity.test.ts +815 -0
- package/tests/debug-extension-harness.test.ts +463 -0
- package/tests/extension-registration.test.ts +2006 -0
- package/tests/fixtures/fixture_c.c +361 -0
- package/tests/fixtures/fixture_cpp.cpp +407 -0
- package/tests/fixtures/fixture_csharp.cs +411 -0
- package/tests/fixtures/fixture_elixir.ex +409 -0
- package/tests/fixtures/fixture_go.go +341 -0
- package/tests/fixtures/fixture_haskell.hs +250 -0
- package/tests/fixtures/fixture_java.java +430 -0
- package/tests/fixtures/fixture_javascript.js +383 -0
- package/tests/fixtures/fixture_kotlin.kt +451 -0
- package/tests/fixtures/fixture_lua.lua +276 -0
- package/tests/fixtures/fixture_perl.pl +310 -0
- package/tests/fixtures/fixture_php.php +433 -0
- package/tests/fixtures/fixture_python.py +502 -0
- package/tests/fixtures/fixture_ruby.rb +345 -0
- package/tests/fixtures/fixture_rust.rs +380 -0
- package/tests/fixtures/fixture_scala.scala +398 -0
- package/tests/fixtures/fixture_shell.sh +276 -0
- package/tests/fixtures/fixture_swift.swift +397 -0
- package/tests/fixtures/fixture_typescript.ts +434 -0
- package/tests/fixtures/fixture_zig.zig +295 -0
- package/tests/fixtures_attended_results/project/compress-line-numbers.json +5 -0
- package/tests/fixtures_attended_results/project/compress.json +5 -0
- package/tests/fixtures_attended_results/project/enable-static-check-invalid-command.json +5 -0
- package/tests/fixtures_attended_results/project/enable-static-check-valid.json +5 -0
- package/tests/fixtures_attended_results/project/files-static-check.json +5 -0
- package/tests/fixtures_attended_results/project/find-line-numbers.json +5 -0
- package/tests/fixtures_attended_results/project/find.json +5 -0
- package/tests/fixtures_attended_results/project/get-base-path.json +5 -0
- package/tests/fixtures_attended_results/project/git-check-clean.json +5 -0
- package/tests/fixtures_attended_results/project/git-check-dirty.json +5 -0
- package/tests/fixtures_attended_results/project/git-path.json +5 -0
- package/tests/fixtures_attended_results/project/git-wt-create-invalid.json +5 -0
- package/tests/fixtures_attended_results/project/git-wt-create-valid.json +5 -0
- package/tests/fixtures_attended_results/project/git-wt-delete-nonexistent.json +5 -0
- package/tests/fixtures_attended_results/project/git-wt-delete-valid.json +5 -0
- package/tests/fixtures_attended_results/project/git-wt-name.json +5 -0
- package/tests/fixtures_attended_results/project/references.json +5 -0
- package/tests/fixtures_attended_results/project/static-check.json +5 -0
- package/tests/fixtures_attended_results/project/tokens.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_zig.zig.json +5 -0
- package/tests/helpers.ts +204 -0
- package/tests/oracle-project.test.ts +63 -0
- package/tests/oracle-standalone.test.ts +48 -0
- package/tests/prompt-rendering.test.ts +66 -0
- package/tests/release-workflow.test.ts +133 -0
|
@@ -0,0 +1,660 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
* @brief Tracks pi-usereq extension status state and renders status-bar telemetry.
|
|
4
|
+
* @details Centralizes hook interception, context-usage snapshots, run timing,
|
|
5
|
+
* and deterministic status-bar formatting for the pi-usereq extension. Runtime
|
|
6
|
+
* is O(1) per event plus O(s) in configured source-path count during status
|
|
7
|
+
* rendering. Side effects are limited to in-memory state mutation and interval
|
|
8
|
+
* scheduling through exported controller helpers.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type {
|
|
12
|
+
AgentEndEvent,
|
|
13
|
+
ContextUsage,
|
|
14
|
+
ExtensionContext,
|
|
15
|
+
ThemeColor,
|
|
16
|
+
} from "@mariozechner/pi-coding-agent";
|
|
17
|
+
import type { UseReqConfig } from "./config.js";
|
|
18
|
+
import { formatPiNotifyBeepStatus } from "./pi-notify.js";
|
|
19
|
+
import { formatAbsoluteGitPath, formatBasePathRelativeToGitPath, resolveRuntimeGitPath } from "./runtime-project-paths.js";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @brief Enumerates the CLI-supported theme tokens consumed by status rendering.
|
|
23
|
+
* @details Restricts the status formatter to documented pi theme tokens so the
|
|
24
|
+
* status bar remains compatible with the active CLI theme schema. Compile-time
|
|
25
|
+
* only and introduces no runtime cost.
|
|
26
|
+
*/
|
|
27
|
+
type StatusForegroundColor = Extract<
|
|
28
|
+
ThemeColor,
|
|
29
|
+
"accent" | "warning" | "dim" | "error"
|
|
30
|
+
>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @brief Describes the raw theme capabilities required for status rendering.
|
|
34
|
+
* @details Accepts the `ctx.ui.theme` foreground renderer plus optional helpers
|
|
35
|
+
* that can convert a foreground color into a background-styled fragment for the
|
|
36
|
+
* context-usage bar. Compile-time only and introduces no runtime cost.
|
|
37
|
+
*/
|
|
38
|
+
interface RawStatusTheme {
|
|
39
|
+
fg: (color: StatusForegroundColor, text: string) => string;
|
|
40
|
+
bgFromFg?: (color: StatusForegroundColor, text: string) => string;
|
|
41
|
+
getFgAnsi?: (color: StatusForegroundColor) => string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @brief Describes the normalized theme adapter used by status formatters.
|
|
46
|
+
* @details Exposes deterministic label, value, foreground, background, and
|
|
47
|
+
* context-cell renderers so status text generation stays independent from the
|
|
48
|
+
* raw theme API. Compile-time only and introduces no runtime cost.
|
|
49
|
+
*/
|
|
50
|
+
interface StatusThemeAdapter {
|
|
51
|
+
label: (fieldName: string) => string;
|
|
52
|
+
value: (text: string) => string;
|
|
53
|
+
colorize: (color: StatusForegroundColor, text: string) => string;
|
|
54
|
+
backgroundize: (color: StatusForegroundColor, text: string) => string;
|
|
55
|
+
separator: string;
|
|
56
|
+
filledContextCell: string;
|
|
57
|
+
emptyContextCell: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @brief Describes one fixed-width context-bar overlay.
|
|
62
|
+
* @details Stores the literal text plus foreground and background color roles
|
|
63
|
+
* used when the context bar must render threshold-specific labels instead of
|
|
64
|
+
* block glyphs. Compile-time only and introduces no runtime cost.
|
|
65
|
+
*/
|
|
66
|
+
interface ContextUsageOverlaySpec {
|
|
67
|
+
backgroundColor: StatusForegroundColor;
|
|
68
|
+
foregroundColor: StatusForegroundColor;
|
|
69
|
+
text: "CLEAR" | "FULL!";
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @brief Lists every pi lifecycle hook intercepted by pi-usereq status logic.
|
|
74
|
+
* @details Preserves the canonical user-requested registration order so the
|
|
75
|
+
* extension can install wrappers for all supported resource, session, agent,
|
|
76
|
+
* model, tool, bash, and input hooks. Access complexity is O(1).
|
|
77
|
+
*/
|
|
78
|
+
export const PI_USEREQ_STATUS_HOOK_NAMES = [
|
|
79
|
+
"resources_discover",
|
|
80
|
+
"session_start",
|
|
81
|
+
"session_before_switch",
|
|
82
|
+
"session_before_fork",
|
|
83
|
+
"session_before_compact",
|
|
84
|
+
"session_compact",
|
|
85
|
+
"session_shutdown",
|
|
86
|
+
"session_before_tree",
|
|
87
|
+
"session_tree",
|
|
88
|
+
"context",
|
|
89
|
+
"before_provider_request",
|
|
90
|
+
"before_agent_start",
|
|
91
|
+
"agent_start",
|
|
92
|
+
"agent_end",
|
|
93
|
+
"turn_start",
|
|
94
|
+
"turn_end",
|
|
95
|
+
"message_start",
|
|
96
|
+
"message_update",
|
|
97
|
+
"message_end",
|
|
98
|
+
"tool_execution_start",
|
|
99
|
+
"tool_execution_update",
|
|
100
|
+
"tool_execution_end",
|
|
101
|
+
"model_select",
|
|
102
|
+
"tool_call",
|
|
103
|
+
"tool_result",
|
|
104
|
+
"user_bash",
|
|
105
|
+
"input",
|
|
106
|
+
] as const;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @brief Represents one hook name handled by the pi-usereq status controller.
|
|
110
|
+
* @details Narrows hook registration and event-update calls to the canonical
|
|
111
|
+
* intercepted-hook set. Compile-time only and introduces no runtime cost.
|
|
112
|
+
*/
|
|
113
|
+
export type PiUsereqStatusHookName = (typeof PI_USEREQ_STATUS_HOOK_NAMES)[number];
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @brief Stores the mutable runtime facts displayed by the status bar.
|
|
117
|
+
* @details Persists the latest context-usage snapshot, the active run start
|
|
118
|
+
* timestamp, and the most recent normally completed run duration. Runtime state
|
|
119
|
+
* is mutated in-place by controller helpers. Compile-time only and introduces
|
|
120
|
+
* no runtime cost.
|
|
121
|
+
*/
|
|
122
|
+
export interface PiUsereqStatusState {
|
|
123
|
+
contextUsage: ContextUsage | undefined;
|
|
124
|
+
runStartTimeMs: number | undefined;
|
|
125
|
+
lastRunDurationMs: number | undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @brief Stores the controller state required for event-driven status updates.
|
|
130
|
+
* @details Keeps the mutable status snapshot, the current configuration, the
|
|
131
|
+
* latest extension context used for rendering, the active-tools provider, and
|
|
132
|
+
* the interval handle used for live elapsed-time refreshes. Compile-time only
|
|
133
|
+
* and introduces no runtime cost.
|
|
134
|
+
*/
|
|
135
|
+
export interface PiUsereqStatusController {
|
|
136
|
+
readonly getActiveTools: () => readonly string[];
|
|
137
|
+
config: UseReqConfig | undefined;
|
|
138
|
+
latestContext: ExtensionContext | undefined;
|
|
139
|
+
state: PiUsereqStatusState;
|
|
140
|
+
tickHandle: ReturnType<typeof setInterval> | undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @brief Converts a foreground ANSI sequence into the equivalent background ANSI.
|
|
145
|
+
* @details Supports the standard `38;` foreground prefix emitted by pi themes.
|
|
146
|
+
* Returns `undefined` when the input cannot be transformed deterministically.
|
|
147
|
+
* Runtime is O(n) in ANSI sequence length. No external state is mutated.
|
|
148
|
+
* @param[in] foregroundAnsi {string} Foreground ANSI sequence.
|
|
149
|
+
* @return {string | undefined} Background ANSI sequence when derivable.
|
|
150
|
+
*/
|
|
151
|
+
function convertForegroundAnsiToBackgroundAnsi(
|
|
152
|
+
foregroundAnsi: string,
|
|
153
|
+
): string | undefined {
|
|
154
|
+
if (!foregroundAnsi.includes("\u001b[")) {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
const backgroundAnsi = foregroundAnsi.replace("[38;", "[48;");
|
|
158
|
+
return backgroundAnsi === foregroundAnsi ? undefined : backgroundAnsi;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* @brief Applies a foreground-derived background style to one text fragment.
|
|
163
|
+
* @details Prefers a theme-provided `bgFromFg` encoder for deterministic test
|
|
164
|
+
* rendering and falls back to ANSI conversion when the runtime theme exposes
|
|
165
|
+
* `getFgAnsi`. Runtime is O(n) in fragment length. No external state is
|
|
166
|
+
* mutated.
|
|
167
|
+
* @param[in] theme {RawStatusTheme} Raw theme adapter.
|
|
168
|
+
* @param[in] color {StatusForegroundColor} Foreground color reused as background.
|
|
169
|
+
* @param[in] text {string} Already-colored foreground fragment.
|
|
170
|
+
* @return {string} Background-decorated text fragment.
|
|
171
|
+
*/
|
|
172
|
+
function applyForegroundAsBackground(
|
|
173
|
+
theme: RawStatusTheme,
|
|
174
|
+
color: StatusForegroundColor,
|
|
175
|
+
text: string,
|
|
176
|
+
): string {
|
|
177
|
+
if (typeof theme.bgFromFg === "function") {
|
|
178
|
+
return theme.bgFromFg(color, text);
|
|
179
|
+
}
|
|
180
|
+
if (typeof theme.getFgAnsi === "function") {
|
|
181
|
+
const backgroundAnsi = convertForegroundAnsiToBackgroundAnsi(
|
|
182
|
+
theme.getFgAnsi(color),
|
|
183
|
+
);
|
|
184
|
+
if (backgroundAnsi) {
|
|
185
|
+
return `${backgroundAnsi}${text}\u001b[39m\u001b[49m`;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return text;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* @brief Builds the normalized theme adapter used by pi-usereq status formatters.
|
|
193
|
+
* @details Precomputes label, value, foreground, background, separator, and
|
|
194
|
+
* context-cell renderers so status formatting remains stable across real TUI
|
|
195
|
+
* themes and deterministic test doubles. Runtime is O(1). No external state
|
|
196
|
+
* is mutated.
|
|
197
|
+
* @param[in] theme {RawStatusTheme} Raw theme implementation from `ctx.ui.theme`.
|
|
198
|
+
* @return {StatusThemeAdapter} Normalized status-theme adapter.
|
|
199
|
+
*/
|
|
200
|
+
function createStatusThemeAdapter(theme: RawStatusTheme): StatusThemeAdapter {
|
|
201
|
+
const colorize = (color: StatusForegroundColor, text: string): string =>
|
|
202
|
+
theme.fg(color, text);
|
|
203
|
+
const backgroundize = (color: StatusForegroundColor, text: string): string =>
|
|
204
|
+
applyForegroundAsBackground(theme, color, text);
|
|
205
|
+
return {
|
|
206
|
+
label: (fieldName: string): string => colorize("accent", `${fieldName}:`),
|
|
207
|
+
value: (text: string): string => colorize("warning", text),
|
|
208
|
+
colorize,
|
|
209
|
+
backgroundize,
|
|
210
|
+
separator: colorize("dim", " • "),
|
|
211
|
+
filledContextCell: backgroundize(
|
|
212
|
+
"accent",
|
|
213
|
+
colorize("warning", "▓"),
|
|
214
|
+
),
|
|
215
|
+
emptyContextCell: backgroundize(
|
|
216
|
+
"accent",
|
|
217
|
+
colorize("dim", "▓"),
|
|
218
|
+
),
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* @brief Normalizes one raw context-usage snapshot.
|
|
224
|
+
* @details Preserves the runtime token and context-window counts, derives a
|
|
225
|
+
* percentage when the runtime omits it, and clamps percentages into `[0, 100]`.
|
|
226
|
+
* Runtime is O(1). No external state is mutated.
|
|
227
|
+
* @param[in] contextUsage {ContextUsage | undefined} Raw runtime snapshot.
|
|
228
|
+
* @return {ContextUsage | undefined} Normalized snapshot.
|
|
229
|
+
*/
|
|
230
|
+
function normalizeContextUsage(
|
|
231
|
+
contextUsage: ContextUsage | undefined,
|
|
232
|
+
): ContextUsage | undefined {
|
|
233
|
+
if (!contextUsage) {
|
|
234
|
+
return undefined;
|
|
235
|
+
}
|
|
236
|
+
const derivedPercent = contextUsage.percent ?? (
|
|
237
|
+
contextUsage.tokens === null || contextUsage.contextWindow <= 0
|
|
238
|
+
? null
|
|
239
|
+
: (contextUsage.tokens / contextUsage.contextWindow) * 100
|
|
240
|
+
);
|
|
241
|
+
return {
|
|
242
|
+
...contextUsage,
|
|
243
|
+
percent: derivedPercent === null
|
|
244
|
+
? null
|
|
245
|
+
: Math.max(0, Math.min(100, derivedPercent)),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* @brief Refreshes the stored context-usage snapshot from the active extension context.
|
|
251
|
+
* @details Calls `ctx.getContextUsage()` on every intercepted event so the
|
|
252
|
+
* controller retains the newest context-usage facts available from the pi
|
|
253
|
+
* runtime. Runtime is O(1). Side effect: mutates `state.contextUsage`.
|
|
254
|
+
* @param[in,out] state {PiUsereqStatusState} Mutable status state.
|
|
255
|
+
* @param[in] ctx {ExtensionContext} Active extension context.
|
|
256
|
+
* @return {void} No return value.
|
|
257
|
+
* @satisfies REQ-118, REQ-119
|
|
258
|
+
*/
|
|
259
|
+
function refreshContextUsage(
|
|
260
|
+
state: PiUsereqStatusState,
|
|
261
|
+
ctx: ExtensionContext,
|
|
262
|
+
): void {
|
|
263
|
+
state.contextUsage = normalizeContextUsage(ctx.getContextUsage());
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* @brief Counts the filled cells rendered by the 5-cell context bar.
|
|
268
|
+
* @details Uses ceiling semantics for positive percentages so any non-zero
|
|
269
|
+
* usage occupies at least one cell and zero usage occupies none. Runtime is
|
|
270
|
+
* O(1). No external state is mutated.
|
|
271
|
+
* @param[in] contextUsage {ContextUsage | undefined} Normalized context snapshot.
|
|
272
|
+
* @return {number} Filled-cell count in the inclusive range `[0, 5]`.
|
|
273
|
+
* @satisfies REQ-122
|
|
274
|
+
*/
|
|
275
|
+
function countFilledContextCells(
|
|
276
|
+
contextUsage: ContextUsage | undefined,
|
|
277
|
+
): number {
|
|
278
|
+
const percent = contextUsage?.percent;
|
|
279
|
+
if (percent === null || percent === undefined || percent <= 0) {
|
|
280
|
+
return 0;
|
|
281
|
+
}
|
|
282
|
+
return Math.min(5, Math.ceil((percent * 5) / 100));
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* @brief Resolves the threshold-specific context-bar overlay when required.
|
|
287
|
+
* @details Returns the empty-state `CLEAR` overlay when normalized context
|
|
288
|
+
* usage is unavailable or non-positive and returns the high-water `FULL!`
|
|
289
|
+
* overlay with the active theme `error` token when usage exceeds 90 percent.
|
|
290
|
+
* Runtime is O(1). No external state is mutated.
|
|
291
|
+
* @param[in] contextUsage {ContextUsage | undefined} Normalized context snapshot.
|
|
292
|
+
* @return {ContextUsageOverlaySpec | undefined} Overlay spec when a replacement label is required.
|
|
293
|
+
* @satisfies REQ-127, REQ-128
|
|
294
|
+
*/
|
|
295
|
+
function resolveContextUsageOverlay(
|
|
296
|
+
contextUsage: ContextUsage | undefined,
|
|
297
|
+
): ContextUsageOverlaySpec | undefined {
|
|
298
|
+
const percent = contextUsage?.percent;
|
|
299
|
+
if (percent === undefined || percent === null || percent <= 0) {
|
|
300
|
+
return {
|
|
301
|
+
backgroundColor: "accent",
|
|
302
|
+
foregroundColor: "warning",
|
|
303
|
+
text: "CLEAR",
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
if (percent > 90) {
|
|
307
|
+
return {
|
|
308
|
+
backgroundColor: "warning",
|
|
309
|
+
foregroundColor: "error",
|
|
310
|
+
text: "FULL!",
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
return undefined;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* @brief Formats one threshold-specific context-bar overlay.
|
|
318
|
+
* @details Renders the fixed-width overlay text with the requested foreground
|
|
319
|
+
* color and reuses the selected bar color as the background so the bar width
|
|
320
|
+
* and state-specific backdrop remain preserved. Runtime is O(n) in overlay
|
|
321
|
+
* width. No external state is mutated.
|
|
322
|
+
* @param[in] theme {StatusThemeAdapter} Normalized status theme.
|
|
323
|
+
* @param[in] overlay {ContextUsageOverlaySpec} Overlay specification.
|
|
324
|
+
* @return {string} Rendered overlay text.
|
|
325
|
+
* @satisfies REQ-127, REQ-128
|
|
326
|
+
*/
|
|
327
|
+
function formatContextUsageOverlay(
|
|
328
|
+
theme: StatusThemeAdapter,
|
|
329
|
+
overlay: ContextUsageOverlaySpec,
|
|
330
|
+
): string {
|
|
331
|
+
return theme.backgroundize(
|
|
332
|
+
overlay.backgroundColor,
|
|
333
|
+
theme.colorize(overlay.foregroundColor, overlay.text),
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* @brief Formats one 5-cell context-usage bar.
|
|
339
|
+
* @details Renders threshold-specific overlays for empty and high-water states;
|
|
340
|
+
* otherwise renders filled cells with the theme `warning` token on an
|
|
341
|
+
* accent-derived background and unfilled cells in `dim` on the same background
|
|
342
|
+
* to preserve constant bar width. Runtime is O(1). No external state is
|
|
343
|
+
* mutated.
|
|
344
|
+
* @param[in] theme {StatusThemeAdapter} Normalized status theme.
|
|
345
|
+
* @param[in] contextUsage {ContextUsage | undefined} Normalized context snapshot.
|
|
346
|
+
* @return {string} Rendered 5-cell bar or overlay.
|
|
347
|
+
* @satisfies REQ-121, REQ-122, REQ-126, REQ-127, REQ-128
|
|
348
|
+
*/
|
|
349
|
+
function formatContextUsageBar(
|
|
350
|
+
theme: StatusThemeAdapter,
|
|
351
|
+
contextUsage: ContextUsage | undefined,
|
|
352
|
+
): string {
|
|
353
|
+
const overlay = resolveContextUsageOverlay(contextUsage);
|
|
354
|
+
if (overlay) {
|
|
355
|
+
return formatContextUsageOverlay(theme, overlay);
|
|
356
|
+
}
|
|
357
|
+
const filledCells = countFilledContextCells(contextUsage);
|
|
358
|
+
return Array.from({ length: 5 }, (_value, index) =>
|
|
359
|
+
index < filledCells ? theme.filledContextCell : theme.emptyContextCell,
|
|
360
|
+
).join("");
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* @brief Formats one elapsed-duration value as `M:SS`.
|
|
365
|
+
* @details Floors the input to whole seconds, keeps minutes unbounded above 59,
|
|
366
|
+
* and zero-pads seconds to two digits. Runtime is O(1). No external state is
|
|
367
|
+
* mutated.
|
|
368
|
+
* @param[in] durationMs {number} Duration in milliseconds.
|
|
369
|
+
* @return {string} Duration rendered as `M:SS`.
|
|
370
|
+
* @satisfies REQ-125
|
|
371
|
+
*/
|
|
372
|
+
function formatStatusDuration(durationMs: number): string {
|
|
373
|
+
const totalSeconds = Math.max(0, Math.floor(durationMs / 1000));
|
|
374
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
375
|
+
const seconds = totalSeconds % 60;
|
|
376
|
+
return `${minutes}:${String(seconds).padStart(2, "0")}`;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* @brief Formats one standard status-bar field.
|
|
381
|
+
* @details Renders the field label in accent color and the value in warning
|
|
382
|
+
* color. Runtime is O(n) in combined text length. No external state is mutated.
|
|
383
|
+
* @param[in] theme {StatusThemeAdapter} Normalized status theme.
|
|
384
|
+
* @param[in] fieldName {string} Field label emitted before the colon.
|
|
385
|
+
* @param[in] value {string} Unstyled field value.
|
|
386
|
+
* @return {string} Rendered status-field fragment.
|
|
387
|
+
*/
|
|
388
|
+
function formatStatusField(
|
|
389
|
+
theme: StatusThemeAdapter,
|
|
390
|
+
fieldName: string,
|
|
391
|
+
value: string,
|
|
392
|
+
): string {
|
|
393
|
+
return `${theme.label(fieldName)}${theme.value(value)}`;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* @brief Formats one pre-rendered status-bar field value.
|
|
398
|
+
* @details Preserves the accent-colored field label while allowing callers to
|
|
399
|
+
* provide a custom styled value such as the context-usage bar. Runtime is O(n)
|
|
400
|
+
* in combined text length. No external state is mutated.
|
|
401
|
+
* @param[in] theme {StatusThemeAdapter} Normalized status theme.
|
|
402
|
+
* @param[in] fieldName {string} Field label emitted before the colon.
|
|
403
|
+
* @param[in] renderedValue {string} Pre-rendered field value.
|
|
404
|
+
* @return {string} Rendered status-field fragment.
|
|
405
|
+
*/
|
|
406
|
+
function formatRenderedStatusField(
|
|
407
|
+
theme: StatusThemeAdapter,
|
|
408
|
+
fieldName: string,
|
|
409
|
+
renderedValue: string,
|
|
410
|
+
): string {
|
|
411
|
+
return `${theme.label(fieldName)}${renderedValue}`;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* @brief Detects whether an agent run ended through abort semantics.
|
|
416
|
+
* @details Treats any assistant message whose `stopReason` equals `aborted` as
|
|
417
|
+
* an escape-triggered termination that must not overwrite the `last` timer.
|
|
418
|
+
* Runtime is O(n) in message count. No external state is mutated.
|
|
419
|
+
* @param[in] messages {AgentEndEvent["messages"]} Messages emitted by `agent_end`.
|
|
420
|
+
* @return {boolean} `true` when the run ended in aborted state.
|
|
421
|
+
* @satisfies REQ-125
|
|
422
|
+
*/
|
|
423
|
+
function didAgentEndAbort(messages: AgentEndEvent["messages"]): boolean {
|
|
424
|
+
return messages.some((message) =>
|
|
425
|
+
typeof message === "object"
|
|
426
|
+
&& message !== null
|
|
427
|
+
&& (message as { role?: unknown }).role === "assistant"
|
|
428
|
+
&& (message as { stopReason?: unknown }).stopReason === "aborted",
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* @brief Builds the full single-line pi-usereq status-bar payload.
|
|
434
|
+
* @details Renders git, base, docs, tests, src, tools, context, elapsed, last, beep, and sound fields in the canonical order with dim bullet separators and threshold-specific context-bar overlays. Runtime is O(s) in configured source-path count plus runtime git probing. No external state is mutated.
|
|
435
|
+
* @param[in] cwd {string} Runtime working directory used for git/base path derivation.
|
|
436
|
+
* @param[in] config {UseReqConfig} Effective project configuration.
|
|
437
|
+
* @param[in] activeTools {readonly string[]} Active runtime tool names.
|
|
438
|
+
* @param[in] theme {StatusThemeAdapter} Normalized status theme.
|
|
439
|
+
* @param[in] state {PiUsereqStatusState} Mutable status state snapshot.
|
|
440
|
+
* @param[in] nowMs {number} Current wall-clock time in milliseconds.
|
|
441
|
+
* @return {string} Single-line status-bar text.
|
|
442
|
+
* @satisfies REQ-109, REQ-112, REQ-120, REQ-121, REQ-123, REQ-124, REQ-125, REQ-126, REQ-127, REQ-128, REQ-135, REQ-136, REQ-147, REQ-148, REQ-156
|
|
443
|
+
*/
|
|
444
|
+
function buildPiUsereqStatusText(
|
|
445
|
+
cwd: string,
|
|
446
|
+
config: UseReqConfig,
|
|
447
|
+
activeTools: readonly string[],
|
|
448
|
+
theme: StatusThemeAdapter,
|
|
449
|
+
state: PiUsereqStatusState,
|
|
450
|
+
nowMs: number,
|
|
451
|
+
): string {
|
|
452
|
+
const gitPath = resolveRuntimeGitPath(cwd);
|
|
453
|
+
const gitText = formatAbsoluteGitPath(gitPath);
|
|
454
|
+
const baseText = formatBasePathRelativeToGitPath(cwd, gitPath);
|
|
455
|
+
const sourcePaths = config["src-dir"].join(",");
|
|
456
|
+
const elapsedText = state.runStartTimeMs === undefined
|
|
457
|
+
? "idle"
|
|
458
|
+
: formatStatusDuration(nowMs - state.runStartTimeMs);
|
|
459
|
+
const lastText = state.lastRunDurationMs === undefined
|
|
460
|
+
? "N/A"
|
|
461
|
+
: formatStatusDuration(state.lastRunDurationMs);
|
|
462
|
+
const beepText = formatPiNotifyBeepStatus(config);
|
|
463
|
+
const soundText = config["notify-sound"];
|
|
464
|
+
return [
|
|
465
|
+
formatStatusField(theme, "git", gitText),
|
|
466
|
+
formatStatusField(theme, "base", baseText),
|
|
467
|
+
formatStatusField(theme, "docs", config["docs-dir"]),
|
|
468
|
+
formatStatusField(theme, "tests", config["tests-dir"]),
|
|
469
|
+
formatStatusField(theme, "src", sourcePaths),
|
|
470
|
+
formatStatusField(theme, "tools", String(activeTools.length)),
|
|
471
|
+
formatRenderedStatusField(
|
|
472
|
+
theme,
|
|
473
|
+
"context",
|
|
474
|
+
formatContextUsageBar(theme, state.contextUsage),
|
|
475
|
+
),
|
|
476
|
+
formatStatusField(theme, "elapsed", elapsedText),
|
|
477
|
+
formatStatusField(theme, "last", lastText),
|
|
478
|
+
formatStatusField(theme, "beep", beepText),
|
|
479
|
+
formatStatusField(theme, "sound", soundText),
|
|
480
|
+
].join(theme.separator);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* @brief Stops the live elapsed-time ticker when it is active.
|
|
485
|
+
* @details Clears the interval handle and resets the stored timer reference so
|
|
486
|
+
* subsequent runs can reinitialize live status refreshes deterministically.
|
|
487
|
+
* Runtime is O(1). Side effect: mutates `controller.tickHandle`.
|
|
488
|
+
* @param[in,out] controller {PiUsereqStatusController} Mutable status controller.
|
|
489
|
+
* @return {void} No return value.
|
|
490
|
+
*/
|
|
491
|
+
function stopStatusTicker(controller: PiUsereqStatusController): void {
|
|
492
|
+
if (controller.tickHandle !== undefined) {
|
|
493
|
+
clearInterval(controller.tickHandle);
|
|
494
|
+
controller.tickHandle = undefined;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* @brief Synchronizes the live elapsed-time ticker with the current run state.
|
|
500
|
+
* @details Starts a 1-second render ticker while a run is active and stops the
|
|
501
|
+
* ticker when the run returns to idle. Runtime is O(1). Side effects include
|
|
502
|
+
* interval creation, interval disposal, and footer-status mutation on timer
|
|
503
|
+
* ticks.
|
|
504
|
+
* @param[in,out] controller {PiUsereqStatusController} Mutable status controller.
|
|
505
|
+
* @return {void} No return value.
|
|
506
|
+
* @satisfies REQ-123
|
|
507
|
+
*/
|
|
508
|
+
function syncPiUsereqStatusTicker(
|
|
509
|
+
controller: PiUsereqStatusController,
|
|
510
|
+
): void {
|
|
511
|
+
if (controller.state.runStartTimeMs === undefined) {
|
|
512
|
+
stopStatusTicker(controller);
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
if (controller.tickHandle !== undefined) {
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
controller.tickHandle = setInterval(() => {
|
|
519
|
+
if (!controller.latestContext || !controller.config) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
renderPiUsereqStatus(controller, controller.latestContext);
|
|
523
|
+
}, 1000);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* @brief Creates an empty pi-usereq status controller.
|
|
528
|
+
* @details Initializes the mutable status snapshot, stores the active-tools
|
|
529
|
+
* provider used by render-time tool counting, and starts with no config, no
|
|
530
|
+
* context, and no live ticker. Runtime is O(1). No external state is mutated.
|
|
531
|
+
* @param[in] getActiveTools {() => readonly string[]} Provider for active tools.
|
|
532
|
+
* @return {PiUsereqStatusController} New status controller.
|
|
533
|
+
* @satisfies DES-010
|
|
534
|
+
*/
|
|
535
|
+
export function createPiUsereqStatusController(
|
|
536
|
+
getActiveTools: () => readonly string[],
|
|
537
|
+
): PiUsereqStatusController {
|
|
538
|
+
return {
|
|
539
|
+
getActiveTools,
|
|
540
|
+
config: undefined,
|
|
541
|
+
latestContext: undefined,
|
|
542
|
+
state: {
|
|
543
|
+
contextUsage: undefined,
|
|
544
|
+
runStartTimeMs: undefined,
|
|
545
|
+
lastRunDurationMs: undefined,
|
|
546
|
+
},
|
|
547
|
+
tickHandle: undefined,
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* @brief Stores the effective project configuration used by status rendering.
|
|
553
|
+
* @details Replaces the controller's cached configuration so later status
|
|
554
|
+
* renders reuse the latest docs, tests, source-path, and pi-notify values
|
|
555
|
+
* without reading from disk on every event. Runtime is O(1). Side effect:
|
|
556
|
+
* mutates `controller.config`.
|
|
557
|
+
* @param[in,out] controller {PiUsereqStatusController} Mutable status controller.
|
|
558
|
+
* @param[in] config {UseReqConfig} Effective project configuration.
|
|
559
|
+
* @return {void} No return value.
|
|
560
|
+
*/
|
|
561
|
+
export function setPiUsereqStatusConfig(
|
|
562
|
+
controller: PiUsereqStatusController,
|
|
563
|
+
config: UseReqConfig,
|
|
564
|
+
): void {
|
|
565
|
+
controller.config = config;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* @brief Renders the current pi-usereq status bar into the active UI context.
|
|
570
|
+
* @details Updates the controller's latest context pointer and writes the
|
|
571
|
+
* single-line status text only when configuration is available, including any
|
|
572
|
+
* threshold-specific context-bar overlays. Runtime is O(s) in configured
|
|
573
|
+
* source-path count. Side effect: mutates `ctx.ui` status.
|
|
574
|
+
* @param[in,out] controller {PiUsereqStatusController} Mutable status controller.
|
|
575
|
+
* @param[in] ctx {ExtensionContext} Active extension context.
|
|
576
|
+
* @return {void} No return value.
|
|
577
|
+
* @satisfies REQ-120, REQ-121, REQ-123, REQ-124, REQ-125, REQ-126, REQ-127, REQ-128, REQ-135, REQ-136
|
|
578
|
+
*/
|
|
579
|
+
export function renderPiUsereqStatus(
|
|
580
|
+
controller: PiUsereqStatusController,
|
|
581
|
+
ctx: ExtensionContext,
|
|
582
|
+
): void {
|
|
583
|
+
controller.latestContext = ctx;
|
|
584
|
+
if (!controller.config) {
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
const theme = createStatusThemeAdapter(ctx.ui.theme as RawStatusTheme);
|
|
588
|
+
ctx.ui.setStatus(
|
|
589
|
+
"pi-usereq",
|
|
590
|
+
buildPiUsereqStatusText(
|
|
591
|
+
ctx.cwd,
|
|
592
|
+
controller.config,
|
|
593
|
+
controller.getActiveTools(),
|
|
594
|
+
theme,
|
|
595
|
+
controller.state,
|
|
596
|
+
Date.now(),
|
|
597
|
+
),
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* @brief Updates mutable status state for one intercepted lifecycle hook.
|
|
603
|
+
* @details Refreshes stored context usage on every hook, starts run timing on
|
|
604
|
+
* `agent_start`, captures non-aborted run duration on `agent_end`, clears live
|
|
605
|
+
* timing on shutdown, synchronizes the live ticker, and re-renders the status
|
|
606
|
+
* bar when configuration is available. Runtime is O(n) in `agent_end` message
|
|
607
|
+
* count and otherwise O(1). Side effects include in-memory state mutation,
|
|
608
|
+
* interval scheduling, and footer-status updates.
|
|
609
|
+
* @param[in,out] controller {PiUsereqStatusController} Mutable status controller.
|
|
610
|
+
* @param[in] hookName {PiUsereqStatusHookName} Intercepted hook name.
|
|
611
|
+
* @param[in] event {unknown} Hook payload forwarded from the wrapper.
|
|
612
|
+
* @param[in] ctx {ExtensionContext} Active extension context.
|
|
613
|
+
* @return {void} No return value.
|
|
614
|
+
* @satisfies REQ-117, REQ-118, REQ-119, REQ-123, REQ-124, REQ-125
|
|
615
|
+
*/
|
|
616
|
+
export function updateExtensionStatus(
|
|
617
|
+
controller: PiUsereqStatusController,
|
|
618
|
+
hookName: PiUsereqStatusHookName,
|
|
619
|
+
event: unknown,
|
|
620
|
+
ctx: ExtensionContext,
|
|
621
|
+
): void {
|
|
622
|
+
controller.latestContext = ctx;
|
|
623
|
+
refreshContextUsage(controller.state, ctx);
|
|
624
|
+
const nowMs = Date.now();
|
|
625
|
+
|
|
626
|
+
if (hookName === "agent_start") {
|
|
627
|
+
controller.state.runStartTimeMs = nowMs;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
if (hookName === "agent_end" && controller.state.runStartTimeMs !== undefined) {
|
|
631
|
+
const durationMs = nowMs - controller.state.runStartTimeMs;
|
|
632
|
+
if (!didAgentEndAbort((event as AgentEndEvent).messages ?? [])) {
|
|
633
|
+
controller.state.lastRunDurationMs = durationMs;
|
|
634
|
+
}
|
|
635
|
+
controller.state.runStartTimeMs = undefined;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
if (hookName === "session_shutdown") {
|
|
639
|
+
controller.state.runStartTimeMs = undefined;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
syncPiUsereqStatusTicker(controller);
|
|
643
|
+
renderPiUsereqStatus(controller, ctx);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* @brief Disposes the pi-usereq status controller.
|
|
648
|
+
* @details Stops the live ticker, clears the cached context pointer, and leaves
|
|
649
|
+
* the last captured status snapshot available for inspection until the
|
|
650
|
+
* controller object itself is discarded. Runtime is O(1). Side effects are
|
|
651
|
+
* limited to interval disposal and in-memory state mutation.
|
|
652
|
+
* @param[in,out] controller {PiUsereqStatusController} Mutable status controller.
|
|
653
|
+
* @return {void} No return value.
|
|
654
|
+
*/
|
|
655
|
+
export function disposePiUsereqStatusController(
|
|
656
|
+
controller: PiUsereqStatusController,
|
|
657
|
+
): void {
|
|
658
|
+
stopStatusTicker(controller);
|
|
659
|
+
controller.latestContext = undefined;
|
|
660
|
+
}
|