@herbertgao/pi-extensions 2026.8.6 → 2026.8.8
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/README.md +8 -6
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +19 -7
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +30 -9
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +320 -22
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +79 -17
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +27 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +66 -17
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +41 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +75 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +7 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +64 -1
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
- package/node_modules/@herbertgao/pi-subagents/README.md +30 -22
- package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +5 -5
- package/node_modules/@herbertgao/pi-subagents/package.json +7 -7
- package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +7 -1
- package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +48 -19
- package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +17 -13
- package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +26 -2
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +219 -40
- package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +101 -3
- package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +18 -4
- package/node_modules/@herbertgao/pi-subagents/src/settings.ts +99 -0
- package/node_modules/@herbertgao/pi-subagents/src/types.ts +22 -3
- package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +51 -3
- package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +20 -2
- package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +21 -6
- package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
- package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +20 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +5 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +174 -100
- package/node_modules/@juicesharp/rpiv-ask-user-question/config.ts +25 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/configuration.md +13 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +5 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +10 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +10 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/tool-schema.md +11 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +5 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/zh.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +3 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +10 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +140 -97
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +63 -28
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/selectors/projections.ts +22 -15
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state-reducer.ts +11 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/tool/response-envelope.ts +11 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/tool/types.ts +11 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/multi-select-view.ts +31 -17
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/preview/preview-block-renderer.ts +15 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/wrapping-select.ts +15 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +86 -38
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +76 -9
- package/node_modules/@narumitw/pi-btw/README.md +120 -111
- package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
- package/node_modules/@narumitw/pi-btw/package.json +10 -6
- package/node_modules/@narumitw/pi-btw/src/btw.ts +36 -40
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
- package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
- package/node_modules/@narumitw/pi-btw/src/menu.ts +45 -2
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +44 -1856
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
- package/node_modules/@pi-plugins/fast-mode/package.json +4 -6
- package/node_modules/pi-lens/CHANGELOG.md +999 -0
- package/node_modules/pi-lens/README.md +117 -3
- package/node_modules/pi-lens/config/ruff/core.toml +42 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +126 -13
- package/node_modules/pi-lens/dist/clients/agent-nudge.js +67 -11
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
- package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +381 -13
- package/node_modules/pi-lens/dist/clients/biome-client.js +61 -30
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
- package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +129 -0
- package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +206 -0
- package/node_modules/pi-lens/dist/clients/cache-observability.js +353 -76
- package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
- package/node_modules/pi-lens/dist/clients/cascade-format.js +20 -1
- package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
- package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
- package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +123 -31
- package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
- package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +84 -14
- package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +155 -0
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +25 -3
- package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +8 -2
- package/node_modules/pi-lens/dist/clients/deps/typebox.js +8 -3
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +147 -33
- package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +52 -2
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +256 -88
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +9 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +9 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +8 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +60 -53
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +25 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +20 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +44 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +17 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +32 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +47 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +14 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +127 -28
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +12 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +275 -13
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +21 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +734 -64
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +188 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +9 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +21 -10
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
- package/node_modules/pi-lens/dist/clients/extension-log.js +22 -1
- package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +316 -0
- package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
- package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
- package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
- package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
- package/node_modules/pi-lens/dist/clients/git-guard.js +31 -0
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +109 -9
- package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
- package/node_modules/pi-lens/dist/clients/host-ports.js +8 -0
- package/node_modules/pi-lens/dist/clients/installer/index.js +1114 -100
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
- package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +87 -8
- package/node_modules/pi-lens/dist/clients/knip-client.js +310 -10
- package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +9 -2
- package/node_modules/pi-lens/dist/clients/latency-logger.js +440 -11
- package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +128 -8
- package/node_modules/pi-lens/dist/clients/lsp/client.js +1660 -164
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +83 -1
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
- package/node_modules/pi-lens/dist/clients/lsp/index.js +2423 -151
- package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
- package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
- package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
- package/node_modules/pi-lens/dist/clients/lsp/server.js +277 -16
- package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
- package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +79 -3
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +43 -0
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
- package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
- package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
- package/node_modules/pi-lens/dist/clients/mcp/session.js +10 -2
- package/node_modules/pi-lens/dist/clients/module-report.js +22 -1
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +114 -23
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
- package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
- package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
- package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
- package/node_modules/pi-lens/dist/clients/pipeline.js +154 -33
- package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +84 -14
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +50 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +23 -9
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
- package/node_modules/pi-lens/dist/clients/project-report.js +62 -27
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
- package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
- package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +8 -3
- package/node_modules/pi-lens/dist/clients/read-guard.js +253 -10
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
- package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +194 -31
- package/node_modules/pi-lens/dist/clients/review-graph/query.js +52 -4
- package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +21 -0
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +6 -3
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +96 -7
- package/node_modules/pi-lens/dist/clients/runtime-context.js +8 -1
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +352 -45
- package/node_modules/pi-lens/dist/clients/runtime-session.js +373 -9
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +212 -79
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +620 -67
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
- package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
- package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +157 -24
- package/node_modules/pi-lens/dist/clients/session-event-guard.js +184 -0
- package/node_modules/pi-lens/dist/clients/sg-runner.js +116 -22
- package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
- package/node_modules/pi-lens/dist/clients/source-filter.js +6 -2
- package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
- package/node_modules/pi-lens/dist/clients/startup-scan.js +5 -2
- package/node_modules/pi-lens/dist/clients/startup-timing.js +19 -1
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +151 -16
- package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
- package/node_modules/pi-lens/dist/clients/tool-policy.js +125 -20
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +1 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
- package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
- package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
- package/node_modules/pi-lens/dist/index.js +61407 -48577
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +476 -57
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +132 -43
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
- package/node_modules/pi-lens/docs/agent-guide.md +6 -1
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +515 -506
- package/node_modules/pi-lens/docs/dispositions.md +21 -0
- package/node_modules/pi-lens/docs/features.md +19 -5
- package/node_modules/pi-lens/docs/globalconfig.md +3 -0
- package/node_modules/pi-lens/docs/language-coverage.md +71 -5
- package/node_modules/pi-lens/docs/mcp.md +2 -2
- package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
- package/node_modules/pi-lens/docs/settings.md +19 -1
- package/node_modules/pi-lens/docs/usage.md +1 -0
- package/node_modules/pi-lens/package.json +27 -10
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-js-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/ts-void-zero-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-object-param-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +15 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-compile-call-test.yml +29 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-dupe-class-members-test.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +2 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +2 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-parameters-test.yml +12 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +57 -12
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-dupe-class-members.yml +52 -8
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +22 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +23 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +33 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +34 -8
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +6 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +53 -1
- package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
- package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
- package/node_modules/pi-lens/scripts/install-selftest.mjs +99 -11
- package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +75 -0
- package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +285 -0
- package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +233 -0
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +2 -0
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +80 -3
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +41 -0
- package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +36 -0
- package/node_modules/pi-mcp-adapter/README.md +47 -5
- package/node_modules/pi-mcp-adapter/cli.js +163 -1
- package/node_modules/pi-mcp-adapter/commands.ts +128 -22
- package/node_modules/pi-mcp-adapter/config.ts +25 -7
- package/node_modules/pi-mcp-adapter/direct-tools.ts +5 -4
- package/node_modules/pi-mcp-adapter/index.ts +219 -32
- package/node_modules/pi-mcp-adapter/init.ts +36 -4
- package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
- package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
- package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
- package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
- package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +32 -21
- package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
- package/node_modules/pi-mcp-adapter/package.json +3 -1
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +31 -37
- package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
- package/node_modules/pi-mcp-adapter/server-manager.ts +140 -2
- package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
- package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
- package/node_modules/pi-mcp-adapter/types.ts +2 -0
- package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
- package/node_modules/pi-mcp-adapter/utils.ts +70 -0
- package/node_modules/pi-web-access/CHANGELOG.md +37 -0
- package/node_modules/pi-web-access/README.md +32 -13
- package/node_modules/pi-web-access/anysearch.ts +4 -2
- package/node_modules/pi-web-access/brave.ts +16 -4
- package/node_modules/pi-web-access/chrome-cookies.ts +86 -15
- package/node_modules/pi-web-access/curator-page.ts +6 -3
- package/node_modules/pi-web-access/curator-server.ts +4 -1
- package/node_modules/pi-web-access/data-uri-sanitize.ts +406 -0
- package/node_modules/pi-web-access/exa.ts +18 -7
- package/node_modules/pi-web-access/extract.ts +40 -5
- package/node_modules/pi-web-access/firecrawl.ts +18 -2
- package/node_modules/pi-web-access/gemini-search.ts +16 -4
- package/node_modules/pi-web-access/github-extract.ts +65 -36
- package/node_modules/pi-web-access/index.ts +60 -61
- package/node_modules/pi-web-access/openai-search.ts +17 -6
- package/node_modules/pi-web-access/package.json +1 -1
- package/node_modules/pi-web-access/page-query.ts +4 -2
- package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
- package/node_modules/pi-web-access/parallel.ts +2 -2
- package/node_modules/pi-web-access/pdf-extract.ts +18 -5
- package/node_modules/pi-web-access/query-rewrite.ts +51 -0
- package/node_modules/pi-web-access/serper.ts +211 -0
- package/node_modules/pi-web-access/ssrf-protection.ts +12 -2
- package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
- package/node_modules/pi-web-access/summary-review.ts +44 -22
- package/node_modules/pi-web-access/tavily.ts +16 -4
- package/node_modules/pi-web-access/utils.ts +87 -0
- package/node_modules/pi-web-access/valyu.ts +199 -0
- package/package.json +14 -14
|
@@ -5,23 +5,32 @@ import type { SubmitPickerProps } from "../../view/components/submit-picker.js";
|
|
|
5
5
|
import type { TabBarProps } from "../../view/components/tab-bar.js";
|
|
6
6
|
import type { DialogProps } from "../../view/dialog-builder.js";
|
|
7
7
|
import { displayLabel } from "../i18n-bridge.js";
|
|
8
|
-
import type { GlobalSelector, PerTabSelector } from "./contract.js";
|
|
8
|
+
import type { GlobalSelector, PerTabBindingContext, PerTabSelector } from "./contract.js";
|
|
9
9
|
import { selectConfirmedIndicator } from "./derivations.js";
|
|
10
10
|
|
|
11
|
+
function emptyMultiSelectProps(ctx: PerTabBindingContext): MultiSelectViewProps {
|
|
12
|
+
return {
|
|
13
|
+
rows: [],
|
|
14
|
+
other: {
|
|
15
|
+
active: false,
|
|
16
|
+
inputMode: false,
|
|
17
|
+
inputBuffer: ctx.inputBuffer,
|
|
18
|
+
inputCursorOffset: ctx.inputCursorOffset,
|
|
19
|
+
},
|
|
20
|
+
nextActive: false,
|
|
21
|
+
nextLabel: displayLabel("next"),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function nextLabelFor(ctx: PerTabBindingContext): string {
|
|
26
|
+
const isLastQuestion = ctx.i === ctx.questions.length - 1;
|
|
27
|
+
return isLastQuestion ? MULTI_SUBMIT_LABEL : displayLabel("next");
|
|
28
|
+
}
|
|
29
|
+
|
|
11
30
|
export const selectMultiSelectProps: PerTabSelector<MultiSelectViewProps> = (state, ctx) => {
|
|
12
31
|
const question = ctx.questions[ctx.i];
|
|
13
32
|
if (!question) {
|
|
14
|
-
return
|
|
15
|
-
rows: [],
|
|
16
|
-
other: {
|
|
17
|
-
active: false,
|
|
18
|
-
inputMode: false,
|
|
19
|
-
inputBuffer: ctx.inputBuffer,
|
|
20
|
-
inputCursorOffset: ctx.inputCursorOffset,
|
|
21
|
-
},
|
|
22
|
-
nextActive: false,
|
|
23
|
-
nextLabel: displayLabel("next"),
|
|
24
|
-
};
|
|
33
|
+
return emptyMultiSelectProps(ctx);
|
|
25
34
|
}
|
|
26
35
|
const focused = ctx.activeView === "options";
|
|
27
36
|
const rows: { checked: boolean; active: boolean }[] = [];
|
|
@@ -33,8 +42,6 @@ export const selectMultiSelectProps: PerTabSelector<MultiSelectViewProps> = (sta
|
|
|
33
42
|
}
|
|
34
43
|
const otherActive = focused && state.optionIndex === question.options.length;
|
|
35
44
|
const nextActive = focused && state.optionIndex === question.options.length + 1;
|
|
36
|
-
const isLastQuestion = ctx.i === ctx.questions.length - 1;
|
|
37
|
-
const nextLabel = isLastQuestion ? MULTI_SUBMIT_LABEL : displayLabel("next");
|
|
38
45
|
return {
|
|
39
46
|
rows,
|
|
40
47
|
other: {
|
|
@@ -44,7 +51,7 @@ export const selectMultiSelectProps: PerTabSelector<MultiSelectViewProps> = (sta
|
|
|
44
51
|
inputCursorOffset: ctx.inputCursorOffset,
|
|
45
52
|
},
|
|
46
53
|
nextActive,
|
|
47
|
-
nextLabel,
|
|
54
|
+
nextLabel: nextLabelFor(ctx),
|
|
48
55
|
};
|
|
49
56
|
};
|
|
50
57
|
|
|
@@ -139,7 +139,17 @@ function switchTabResult(state: QuestionnaireState, nextTab: number, ctx: ApplyC
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
function doneFor(state: QuestionnaireState, ctx: ApplyContext, cancelled: boolean): ApplyResult {
|
|
142
|
-
|
|
142
|
+
// Global note lift: the Submit-tab note lives at the `questions.length` pseudo-index
|
|
143
|
+
// in `notesByTab` — question tabs only occupy 0..questions.length-1, so this can never
|
|
144
|
+
// cross-contaminate a per-question note. Attached regardless of `cancelled` (the
|
|
145
|
+
// reducer is truth; the envelope owns decline presentation), with cancel/submit/confirm
|
|
146
|
+
// sharing this single lift. Conditional spread keeps note-free results byte-identical.
|
|
147
|
+
const globalNote = state.notesByTab.get(ctx.questions.length);
|
|
148
|
+
const result: QuestionnaireResult = {
|
|
149
|
+
answers: orderedAnswers(state, ctx.questions),
|
|
150
|
+
cancelled,
|
|
151
|
+
...(globalNote && globalNote.length > 0 ? { globalNote } : {}),
|
|
152
|
+
};
|
|
143
153
|
return { state, effects: [{ kind: "done", result }] };
|
|
144
154
|
}
|
|
145
155
|
|
|
@@ -25,12 +25,20 @@ export interface QuestionnaireState {
|
|
|
25
25
|
/** Canonical mirror of the in-flight notes editor; runtime mirrors after `forward_notes_keystroke`. */
|
|
26
26
|
notesDraft: string;
|
|
27
27
|
/**
|
|
28
|
-
* Collapsed mode: the questionnaire
|
|
29
|
-
*
|
|
30
|
-
* while true, every keystroke except cancel is swallowed (see
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
28
|
+
* Collapsed mode: the questionnaire gets out of the way so the agent transcript behind
|
|
29
|
+
* the bottom-anchored overlay becomes readable. Toggled by the configured collapse key
|
|
30
|
+
* from any state; while true, every keystroke except cancel is swallowed (see
|
|
31
|
+
* `routeKey`). Two renderings, chosen by host capability:
|
|
32
|
+
*
|
|
33
|
+
* - Hosts with an `OverlayHandle` AND a raw `onTerminalInput` listener (real pi-tui):
|
|
34
|
+
* the `set_overlay_hidden` effect fully hides the overlay; the raw listener registered
|
|
35
|
+
* in `execute()` reopens it, because pi-tui routes no input to a hidden overlay.
|
|
36
|
+
* - Hosts without the raw listener (or without a handle): the overlay stays visible and
|
|
37
|
+
* shrinks to a single hint row. The row keeps focus and input routing, so the same key
|
|
38
|
+
* expands it and Esc cancels, and the expand key never falls through to an underlying
|
|
39
|
+
* overlay (e.g. `/btw`). The session gates `set_overlay_hidden` on the listener's
|
|
40
|
+
* existence (`canReopenWhileHidden`) so a handle-bearing host without raw input can
|
|
41
|
+
* never hide the overlay into a state nothing can reopen.
|
|
34
42
|
*/
|
|
35
43
|
collapsed: boolean;
|
|
36
44
|
}
|
|
@@ -9,12 +9,18 @@ export const ENVELOPE_SUFFIX = "You can now continue with the user's answers in
|
|
|
9
9
|
* Map a `QuestionnaireResult` (or null/cancelled) to the LLM-facing tool envelope.
|
|
10
10
|
* Pure of `(result, params)`; cancelled and "no segments" both fall to `DECLINE_MESSAGE`
|
|
11
11
|
* so the model sees a single canonical "didn't answer" signal regardless of why.
|
|
12
|
+
* "No segments" means no answers AND no global note — the `global note:` segment is
|
|
13
|
+
* pushed before the zero-segments check, so a note-bearing submit with zero answers
|
|
14
|
+
* still yields the answered envelope.
|
|
12
15
|
*/
|
|
13
16
|
export function buildQuestionnaireResponse(result: QuestionnaireResult | null | undefined, params: QuestionParams) {
|
|
14
17
|
if (!result || result.cancelled) {
|
|
18
|
+
// Decline text stays canonical even when a global note rides the cancelled result;
|
|
19
|
+
// the note survives in `details` (like partial `answers`) for replay consumers.
|
|
15
20
|
return buildToolResult(DECLINE_MESSAGE, {
|
|
16
21
|
answers: result?.answers ?? [],
|
|
17
22
|
cancelled: true,
|
|
23
|
+
...(result?.globalNote && result.globalNote.length > 0 ? { globalNote: result.globalNote } : {}),
|
|
18
24
|
});
|
|
19
25
|
}
|
|
20
26
|
const segments: string[] = [];
|
|
@@ -22,6 +28,11 @@ export function buildQuestionnaireResponse(result: QuestionnaireResult | null |
|
|
|
22
28
|
const a = result.answers.find((x) => x.questionIndex === i);
|
|
23
29
|
if (a) segments.push(buildAnswerSegment(a));
|
|
24
30
|
}
|
|
31
|
+
// Global note rides after the per-question segments: raw multiline echo (no
|
|
32
|
+
// reformatting), trailing period mirroring `buildAnswerSegment`'s shape.
|
|
33
|
+
if (result.globalNote && result.globalNote.length > 0) {
|
|
34
|
+
segments.push(`global note: ${result.globalNote}.`);
|
|
35
|
+
}
|
|
25
36
|
if (segments.length === 0) {
|
|
26
37
|
return buildToolResult(DECLINE_MESSAGE, { answers: result.answers, cancelled: true });
|
|
27
38
|
}
|
|
@@ -135,6 +135,17 @@ export type QuestionnaireError =
|
|
|
135
135
|
export interface QuestionnaireResult {
|
|
136
136
|
answers: QuestionAnswer[];
|
|
137
137
|
cancelled: boolean;
|
|
138
|
+
/**
|
|
139
|
+
* Global note authored on the Submit tab: `n` opens the shared notes editor there,
|
|
140
|
+
* and the committed text lives at the `notesByTab[questions.length]` pseudo-index
|
|
141
|
+
* (a slot no question tab can occupy) until `doneFor` lifts it onto the result —
|
|
142
|
+
* attached on both submit and cancel, like per-question `answers[].notes`.
|
|
143
|
+
* Conditional-spread contract, mirroring `QuestionAnswer.notes`: the key appears
|
|
144
|
+
* only via conditional spread of a non-empty string — never assigned `undefined`,
|
|
145
|
+
* never kept for an empty/whitespace-only draft — so note-free results stay
|
|
146
|
+
* byte-identical (`!("globalNote" in result)` holds).
|
|
147
|
+
*/
|
|
148
|
+
globalNote?: string;
|
|
138
149
|
error?: QuestionnaireError;
|
|
139
150
|
}
|
|
140
151
|
|
package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/multi-select-view.ts
CHANGED
|
@@ -50,6 +50,12 @@ interface MultiSelectLayout {
|
|
|
50
50
|
focusedRange: [number, number];
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/** Mutable row accumulator threaded through the append helpers during a layout miss. */
|
|
54
|
+
interface MultiSelectBuild {
|
|
55
|
+
lines: string[];
|
|
56
|
+
focusedRange: [number, number];
|
|
57
|
+
}
|
|
58
|
+
|
|
53
59
|
export class MultiSelectView implements StatefulView<MultiSelectViewProps> {
|
|
54
60
|
private props: MultiSelectViewProps;
|
|
55
61
|
private cachedLayout: { width: number; value: MultiSelectLayout } | undefined;
|
|
@@ -92,47 +98,55 @@ export class MultiSelectView implements StatefulView<MultiSelectViewProps> {
|
|
|
92
98
|
private layout(width: number): MultiSelectLayout {
|
|
93
99
|
if (this.cachedLayout?.width === width) return this.cachedLayout.value;
|
|
94
100
|
|
|
95
|
-
const lines:
|
|
96
|
-
let focusedRange: [number, number] = [0, 0];
|
|
101
|
+
const build: MultiSelectBuild = { lines: [], focusedRange: [0, 0] };
|
|
97
102
|
const contentWidth = Math.max(1, width - this.prefixVisibleWidth());
|
|
98
103
|
const numberWidth = String(Math.max(1, this.question.options.length + 1)).length;
|
|
104
|
+
|
|
105
|
+
this.appendOptionRows(build, width, contentWidth, numberWidth);
|
|
106
|
+
|
|
107
|
+
const otherStart = build.lines.length;
|
|
108
|
+
build.lines.push(...this.renderOtherRow(contentWidth, numberWidth));
|
|
109
|
+
if (this.props.other.active) build.focusedRange = [otherStart, build.lines.length];
|
|
110
|
+
|
|
111
|
+
this.appendNextRow(build, width);
|
|
112
|
+
|
|
113
|
+
const value = { lines: build.lines, focusedRange: build.focusedRange };
|
|
114
|
+
this.cachedLayout = { width, value };
|
|
115
|
+
return value;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private appendOptionRows(build: MultiSelectBuild, width: number, contentWidth: number, numberWidth: number): void {
|
|
99
119
|
for (let i = 0; i < this.question.options.length; i++) {
|
|
100
120
|
const opt = this.question.options[i];
|
|
101
121
|
const row = this.props.rows[i];
|
|
102
122
|
if (!opt || !row) continue;
|
|
103
|
-
const start = lines.length;
|
|
123
|
+
const start = build.lines.length;
|
|
104
124
|
const pointer = row.active ? this.theme.fg("accent", ACTIVE_POINTER) : INACTIVE_POINTER;
|
|
105
125
|
// Checked and active rows share the accent hue, matching the dialog's selection rhythm.
|
|
106
126
|
const box = row.checked ? this.theme.fg("accent", CHECKED) : this.theme.fg("muted", UNCHECKED);
|
|
107
127
|
const label = truncateToWidth(opt.label, contentWidth, "…");
|
|
108
128
|
const styledLabel = row.active ? this.theme.fg("accent", this.theme.bold(label)) : label;
|
|
109
129
|
const number = String(i + 1).padStart(numberWidth, " ");
|
|
110
|
-
lines.push(
|
|
130
|
+
build.lines.push(
|
|
111
131
|
truncateToWidth(`${pointer}${number}${NUMBER_SEPARATOR}${box}${BOX_LABEL_GAP}${styledLabel}`, width, ""),
|
|
112
132
|
);
|
|
113
133
|
if (opt.description) {
|
|
114
134
|
for (const segment of wrapTextWithAnsi(opt.description, contentWidth)) {
|
|
115
|
-
lines.push(CONTINUATION_INDENT + this.theme.fg("muted", segment));
|
|
135
|
+
build.lines.push(CONTINUATION_INDENT + this.theme.fg("muted", segment));
|
|
116
136
|
}
|
|
117
137
|
}
|
|
118
|
-
if (row.active) focusedRange = [start, lines.length];
|
|
138
|
+
if (row.active) build.focusedRange = [start, build.lines.length];
|
|
119
139
|
}
|
|
140
|
+
}
|
|
120
141
|
|
|
121
|
-
|
|
122
|
-
lines.
|
|
123
|
-
if (this.props.other.active) focusedRange = [otherStart, lines.length];
|
|
124
|
-
|
|
125
|
-
const nextStart = lines.length;
|
|
142
|
+
private appendNextRow(build: MultiSelectBuild, width: number): void {
|
|
143
|
+
const nextStart = build.lines.length;
|
|
126
144
|
const nextPointer = this.props.nextActive ? this.theme.fg("accent", ACTIVE_POINTER) : INACTIVE_POINTER;
|
|
127
145
|
const nextLabel = this.props.nextActive
|
|
128
146
|
? this.theme.fg("accent", this.theme.bold(this.props.nextLabel))
|
|
129
147
|
: this.props.nextLabel;
|
|
130
|
-
lines.push(truncateToWidth(`${nextPointer}${nextLabel}`, width, ""));
|
|
131
|
-
if (this.props.nextActive) focusedRange = [nextStart, lines.length];
|
|
132
|
-
|
|
133
|
-
const value = { lines, focusedRange };
|
|
134
|
-
this.cachedLayout = { width, value };
|
|
135
|
-
return value;
|
|
148
|
+
build.lines.push(truncateToWidth(`${nextPointer}${nextLabel}`, width, ""));
|
|
149
|
+
if (this.props.nextActive) build.focusedRange = [nextStart, build.lines.length];
|
|
136
150
|
}
|
|
137
151
|
|
|
138
152
|
private renderOtherRow(contentWidth: number, numberWidth: number): string[] {
|
|
@@ -23,6 +23,17 @@ import type { PreviewLayoutMode } from "./preview-layout-decider.js";
|
|
|
23
23
|
*/
|
|
24
24
|
export const NOTES_AFFORDANCE_TEXT = "Notes: press n to add notes";
|
|
25
25
|
|
|
26
|
+
/** Content row budget for a layout mode: preview cap minus border + affordance overhead. */
|
|
27
|
+
function contentBudgetFor(mode: PreviewLayoutMode): number {
|
|
28
|
+
const cap = mode === "side-by-side" ? MAX_PREVIEW_HEIGHT_SIDE_BY_SIDE : MAX_PREVIEW_HEIGHT_STACKED;
|
|
29
|
+
return Math.max(1, cap - BORDER_VERTICAL_OVERHEAD - NOTES_AFFORDANCE_OVERHEAD);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Inner (padding-aware) content width for a total block width. */
|
|
33
|
+
function innerWidthFor(width: number): number {
|
|
34
|
+
return Math.max(1, width - BORDER_HORIZONTAL_OVERHEAD - 2 * BORDER_INNER_PADDING_HORIZONTAL);
|
|
35
|
+
}
|
|
36
|
+
|
|
26
37
|
export interface PreviewBlockRendererConfig {
|
|
27
38
|
question: QuestionData;
|
|
28
39
|
theme: Theme;
|
|
@@ -66,9 +77,8 @@ export class PreviewBlockRenderer {
|
|
|
66
77
|
* — the affordance overhead is constant, not gated by `focused`/`notesVisible`.
|
|
67
78
|
*/
|
|
68
79
|
blockHeight(width: number, optionIndex: number, mode: PreviewLayoutMode): number {
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
const innerWidth = Math.max(1, width - BORDER_HORIZONTAL_OVERHEAD - 2 * BORDER_INNER_PADDING_HORIZONTAL);
|
|
80
|
+
const contentBudget = contentBudgetFor(mode);
|
|
81
|
+
const innerWidth = innerWidthFor(width);
|
|
72
82
|
const rawRows = this.cache.bodyFor(optionIndex, innerWidth).length;
|
|
73
83
|
const contentRows = Math.min(rawRows, contentBudget);
|
|
74
84
|
return BORDER_VERTICAL_OVERHEAD + contentRows + NOTES_AFFORDANCE_OVERHEAD;
|
|
@@ -87,9 +97,8 @@ export class PreviewBlockRenderer {
|
|
|
87
97
|
focused: boolean,
|
|
88
98
|
notesVisible: boolean,
|
|
89
99
|
): string[] {
|
|
90
|
-
const
|
|
91
|
-
const
|
|
92
|
-
const maxInnerWidth = Math.max(1, width - BORDER_HORIZONTAL_OVERHEAD - 2 * BORDER_INNER_PADDING_HORIZONTAL);
|
|
100
|
+
const contentBudget = contentBudgetFor(mode);
|
|
101
|
+
const maxInnerWidth = innerWidthFor(width);
|
|
93
102
|
|
|
94
103
|
const raw = this.cache.bodyFor(optionIndex, maxInnerWidth);
|
|
95
104
|
const truncated = raw.length > contentBudget;
|
|
@@ -216,6 +216,20 @@ export class WrappingSelect implements Component {
|
|
|
216
216
|
return this.renderInlineInputRow(rowPrefix, continuationPrefix, contentWidth);
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
+
const { label, isConfirmed } = this.deriveConfirmedState(item, index);
|
|
220
|
+
const applySelectedStyle = isActive || isConfirmed;
|
|
221
|
+
|
|
222
|
+
return [
|
|
223
|
+
...this.renderLabelBlock(label, rowPrefix, continuationPrefix, contentWidth, applySelectedStyle),
|
|
224
|
+
...this.renderDescriptionBlock(item.description, continuationPrefix, contentWidth),
|
|
225
|
+
];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Derive the confirmed-rendering facts for one row: the final label (custom draft
|
|
230
|
+
* or confirmed-override aware) and whether the ✔ mark applies.
|
|
231
|
+
*/
|
|
232
|
+
private deriveConfirmedState(item: WrappingSelectItem, index: number): { label: string; isConfirmed: boolean } {
|
|
219
233
|
// Keep an in-flight custom draft visible even while the cursor browses another row.
|
|
220
234
|
// If it differs from a previously confirmed custom answer, omit the confirmation
|
|
221
235
|
// mark so the pending draft is not presented as committed.
|
|
@@ -230,12 +244,7 @@ export class WrappingSelect implements Component {
|
|
|
230
244
|
const label = isConfirmed
|
|
231
245
|
? `${this.confirmedLabelOverride ?? baseLabel}${WrappingSelect.CONFIRMED_MARK}`
|
|
232
246
|
: baseLabel;
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
return [
|
|
236
|
-
...this.renderLabelBlock(label, rowPrefix, continuationPrefix, contentWidth, applySelectedStyle),
|
|
237
|
-
...this.renderDescriptionBlock(item.description, continuationPrefix, contentWidth),
|
|
238
|
-
];
|
|
247
|
+
return { label, isConfirmed };
|
|
239
248
|
}
|
|
240
249
|
|
|
241
250
|
private buildRowPrefix(index: number, isActive: boolean, numberWidth: number): string {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DynamicBorder, type Theme } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { type Component, Container, type Editor, Spacer } from "@earendil-works/pi-tui";
|
|
3
|
+
import { DEFAULT_COLLAPSE_KEY, formatKeySpecForDisplay } from "../config.js";
|
|
3
4
|
import type { QuestionnaireState } from "../state/state.js";
|
|
4
5
|
import type { QuestionData } from "../tool/types.js";
|
|
5
6
|
import type { PreviewPaneProps } from "./components/preview/preview-pane.js";
|
|
@@ -16,8 +17,21 @@ export const HINT_PART_TOGGLE = "Space to toggle";
|
|
|
16
17
|
export const HINT_PART_NOTES = "n to add notes";
|
|
17
18
|
export const HINT_PART_TAB = "Tab to switch questions";
|
|
18
19
|
export const HINT_PART_CANCEL = "Esc to cancel";
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Collapse/expand hint copy is templated on `KEY_PLACEHOLDER` because the
|
|
22
|
+
* shortcut is configurable (`collapseKey`) and `rpiv-i18n`'s `tr` has no
|
|
23
|
+
* interpolation — locale entries carry the same `{key}` placeholder and call
|
|
24
|
+
* sites `.replace()` it with `formatKeySpecForDisplay(collapseKey)` after
|
|
25
|
+
* lookup, so per-locale word order is preserved.
|
|
26
|
+
*/
|
|
27
|
+
export const KEY_PLACEHOLDER = "{key}";
|
|
28
|
+
export const HINT_PART_COLLAPSE_TEMPLATE = `${KEY_PLACEHOLDER} to collapse`;
|
|
29
|
+
export const HINT_PART_EXPAND_TEMPLATE = `${KEY_PLACEHOLDER} to expand`;
|
|
30
|
+
/** Default-key (`Ctrl+]`) rendering of the collapse template, for tests and default-config assertions. */
|
|
31
|
+
export const HINT_PART_COLLAPSE = HINT_PART_COLLAPSE_TEMPLATE.replace(
|
|
32
|
+
KEY_PLACEHOLDER,
|
|
33
|
+
formatKeySpecForDisplay(DEFAULT_COLLAPSE_KEY),
|
|
34
|
+
);
|
|
21
35
|
/**
|
|
22
36
|
* `HINT_SINGLE` / `HINT_MULTI` are the resting core hint for NON-multiSelect
|
|
23
37
|
* question tabs only: `buildHintText` drops `NOTES` while the notes editor is
|
|
@@ -33,8 +47,12 @@ export const HINT_SINGLE = [HINT_PART_ENTER, HINT_PART_NAV, HINT_PART_NOTES, HIN
|
|
|
33
47
|
export const HINT_MULTI = [HINT_PART_ENTER, HINT_PART_NAV, HINT_PART_NOTES, HINT_PART_TAB, HINT_PART_CANCEL].join(
|
|
34
48
|
" · ",
|
|
35
49
|
);
|
|
36
|
-
/**
|
|
37
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Template for the single-line footer shown by `QuestionnaireSession` when
|
|
52
|
+
* `state.collapsed === true`. Bypasses `buildHintText`; the session replaces
|
|
53
|
+
* `KEY_PLACEHOLDER` with the configured key's display form.
|
|
54
|
+
*/
|
|
55
|
+
export const COLLAPSED_HINT_TEMPLATE = [HINT_PART_EXPAND_TEMPLATE, HINT_PART_CANCEL].join(" · ");
|
|
38
56
|
export const REVIEW_HEADING = "Review your answers";
|
|
39
57
|
export const READY_PROMPT = "Ready to submit your answers?";
|
|
40
58
|
export const INCOMPLETE_WARNING_PREFIX = "⚠ Answer remaining questions before submitting:";
|
|
@@ -43,6 +61,47 @@ const OVERFLOW_UP = "↑";
|
|
|
43
61
|
const OVERFLOW_DOWN = "↓";
|
|
44
62
|
const OVERFLOW_BOTH = "↕";
|
|
45
63
|
|
|
64
|
+
/** No-overflow path: append the residual spacer rows after the footer. */
|
|
65
|
+
function renderFitsTerminal(natural: string[], spacerRows: number): string[] {
|
|
66
|
+
return spacerRows > 0 ? [...natural, ...Array<string>(spacerRows).fill("")] : natural;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Terminal too small for any middle content — show just chrome, hard-clamped to termRows. */
|
|
70
|
+
function renderChromeOnly(natural: string[], topFixed: number, bottomFixed: number, termRows: number): string[] {
|
|
71
|
+
const chromeOnly = [...natural.slice(0, topFixed), ...natural.slice(natural.length - bottomFixed)];
|
|
72
|
+
return chromeOnly.length > termRows ? chromeOnly.slice(0, termRows) : chromeOnly;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Scroll window start, centered on the focused option; top-anchored when there is no interactive focus. */
|
|
76
|
+
function computeScrollStart(
|
|
77
|
+
bodyRange: [number, number] | undefined,
|
|
78
|
+
headingCount: number,
|
|
79
|
+
availableMiddle: number,
|
|
80
|
+
middleRows: number,
|
|
81
|
+
): number {
|
|
82
|
+
if (!bodyRange) return 0;
|
|
83
|
+
const focusedRowInMiddle = headingCount + bodyRange[0];
|
|
84
|
+
const focusedHeight = bodyRange[1] - bodyRange[0];
|
|
85
|
+
// Center the focused item vertically in the available middle space.
|
|
86
|
+
const idealStart = focusedRowInMiddle - Math.floor(Math.max(0, availableMiddle - focusedHeight) / 2);
|
|
87
|
+
return Math.max(0, Math.min(idealStart, middleRows - availableMiddle));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Mark the scroll window edges with overflow arrows; combined ↕ on a single-row middle. */
|
|
91
|
+
function decorateOverflow(scrollableMiddle: string[], hasUp: boolean, hasDown: boolean, theme: Theme): void {
|
|
92
|
+
if (hasUp && hasDown && scrollableMiddle.length === 1) {
|
|
93
|
+
// Single-row middle: combined ↕ avoids the prior collision where ↓ overwrote ↑.
|
|
94
|
+
scrollableMiddle[0] = theme.fg("dim", OVERFLOW_BOTH);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (hasUp && scrollableMiddle.length > 0) {
|
|
98
|
+
scrollableMiddle[0] = theme.fg("dim", OVERFLOW_UP);
|
|
99
|
+
}
|
|
100
|
+
if (hasDown && scrollableMiddle.length > 0) {
|
|
101
|
+
scrollableMiddle[scrollableMiddle.length - 1] = theme.fg("dim", OVERFLOW_DOWN);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
46
105
|
export type DialogState = QuestionnaireState;
|
|
47
106
|
|
|
48
107
|
/** Per-tick projection of dialog state. Written by the adapter; read by the strategy thunk. */
|
|
@@ -67,6 +126,13 @@ export interface DialogConfig {
|
|
|
67
126
|
getCurrentBodyHeight: (width: number) => number;
|
|
68
127
|
/** Terminal height getter. Mirrors `getTerminalWidth` — reads `tui.terminal.rows` at render time. */
|
|
69
128
|
getTerminalRows: () => number;
|
|
129
|
+
/**
|
|
130
|
+
* Resolved collapse/expand key spec (`resolveCollapseKey` output: `"ctrl+]"`,
|
|
131
|
+
* `"alt+o"`, or `"off"`). Construction-time config, NOT canonical state —
|
|
132
|
+
* `QuestionnaireRuntime.collapseKey` must never reach view setProps consumers.
|
|
133
|
+
* The footer hint interpolates it, and drops the collapse part when `"off"`.
|
|
134
|
+
*/
|
|
135
|
+
collapseKey: string;
|
|
70
136
|
}
|
|
71
137
|
|
|
72
138
|
/**
|
|
@@ -95,12 +161,14 @@ export class DialogView implements StatefulView<DialogProps> {
|
|
|
95
161
|
notesInput: config.notesInput,
|
|
96
162
|
isMulti: config.isMulti,
|
|
97
163
|
getCurrentBodyHeight: config.getCurrentBodyHeight,
|
|
164
|
+
collapseKey: config.collapseKey,
|
|
98
165
|
});
|
|
99
166
|
this.submitStrategy = config.isMulti
|
|
100
167
|
? new SubmitTabStrategy({
|
|
101
168
|
theme: config.theme,
|
|
102
169
|
questions: config.questions,
|
|
103
170
|
submitPicker: config.submitPicker,
|
|
171
|
+
notesInput: config.notesInput,
|
|
104
172
|
})
|
|
105
173
|
: undefined;
|
|
106
174
|
this.maxFooterRowCount = Math.max(this.questionStrategy.footerRowCount, this.submitStrategy?.footerRowCount ?? 0);
|
|
@@ -147,48 +215,28 @@ export class DialogView implements StatefulView<DialogProps> {
|
|
|
147
215
|
const termRows = this.config.getTerminalRows();
|
|
148
216
|
|
|
149
217
|
if (natural.length + spacerRows <= termRows) {
|
|
150
|
-
|
|
151
|
-
return spacerRows > 0 ? [...natural, ...Array<string>(spacerRows).fill("")] : natural;
|
|
218
|
+
return renderFitsTerminal(natural, spacerRows);
|
|
152
219
|
}
|
|
153
220
|
|
|
154
221
|
// OVERFLOW — apply 3-region partition with scroll-to-focus.
|
|
155
222
|
const availableMiddle = Math.max(0, termRows - topFixed - bottomFixed);
|
|
156
223
|
if (availableMiddle === 0) {
|
|
157
|
-
|
|
158
|
-
const chromeOnly = [...natural.slice(0, topFixed), ...natural.slice(natural.length - bottomFixed)];
|
|
159
|
-
return chromeOnly.length > termRows ? chromeOnly.slice(0, termRows) : chromeOnly;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const bodyRange = strategy.focusedItemRowRange(width, state);
|
|
163
|
-
|
|
164
|
-
// Compute scroll window centered on the focused option.
|
|
165
|
-
let scrollStart: number;
|
|
166
|
-
if (bodyRange) {
|
|
167
|
-
const focusedRowInMiddle = headingCount + bodyRange[0];
|
|
168
|
-
const focusedHeight = bodyRange[1] - bodyRange[0];
|
|
169
|
-
// Center the focused item vertically in the available middle space.
|
|
170
|
-
const idealStart = focusedRowInMiddle - Math.floor(Math.max(0, availableMiddle - focusedHeight) / 2);
|
|
171
|
-
scrollStart = Math.max(0, Math.min(idealStart, middleRows - availableMiddle));
|
|
172
|
-
} else {
|
|
173
|
-
// No interactive focus (submit tab) — top-anchor the middle.
|
|
174
|
-
scrollStart = 0;
|
|
224
|
+
return renderChromeOnly(natural, topFixed, bottomFixed, termRows);
|
|
175
225
|
}
|
|
176
226
|
|
|
227
|
+
const scrollStart = computeScrollStart(
|
|
228
|
+
strategy.focusedItemRowRange(width, state),
|
|
229
|
+
headingCount,
|
|
230
|
+
availableMiddle,
|
|
231
|
+
middleRows,
|
|
232
|
+
);
|
|
177
233
|
const scrollableMiddle = natural.slice(topFixed + scrollStart, topFixed + scrollStart + availableMiddle);
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
} else {
|
|
185
|
-
if (hasUp && scrollableMiddle.length > 0) {
|
|
186
|
-
scrollableMiddle[0] = this.config.theme.fg("dim", OVERFLOW_UP);
|
|
187
|
-
}
|
|
188
|
-
if (hasDown && scrollableMiddle.length > 0) {
|
|
189
|
-
scrollableMiddle[scrollableMiddle.length - 1] = this.config.theme.fg("dim", OVERFLOW_DOWN);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
234
|
+
decorateOverflow(
|
|
235
|
+
scrollableMiddle,
|
|
236
|
+
scrollStart > 0,
|
|
237
|
+
scrollStart + availableMiddle < middleRows,
|
|
238
|
+
this.config.theme,
|
|
239
|
+
);
|
|
192
240
|
|
|
193
241
|
const result = [
|
|
194
242
|
...natural.slice(0, topFixed),
|