@herbertgao/pi-extensions 2026.9.1 → 2026.9.3

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.
Files changed (341) hide show
  1. package/README.md +3 -2
  2. package/THIRD_PARTY_NOTICES.md +24 -0
  3. package/node_modules/@herbertgao/sol-pi/LICENSE +19 -0
  4. package/node_modules/@herbertgao/sol-pi/README.md +159 -0
  5. package/node_modules/@herbertgao/sol-pi/SECURITY.md +26 -0
  6. package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +19 -0
  7. package/node_modules/@herbertgao/sol-pi/agents-install.md +150 -0
  8. package/node_modules/@herbertgao/sol-pi/assets/sol-pi-hero.png +0 -0
  9. package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +69 -0
  10. package/node_modules/@herbertgao/sol-pi/docs/configuration.md +75 -0
  11. package/node_modules/@herbertgao/sol-pi/package.json +76 -0
  12. package/node_modules/@herbertgao/sol-pi/scripts/check-pi-compat.mjs +32 -0
  13. package/node_modules/@herbertgao/sol-pi/scripts/check-sol-pi-config.mjs +120 -0
  14. package/node_modules/@herbertgao/sol-pi/sol-pi.example.json +10 -0
  15. package/node_modules/@herbertgao/sol-pi/src/sol-pi/config.ts +135 -0
  16. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/file-queue.ts +74 -0
  17. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/index.ts +185 -0
  18. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/then-run.ts +128 -0
  19. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/archive.ts +53 -0
  20. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/candidate.ts +101 -0
  21. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/config.ts +71 -0
  22. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/index.ts +220 -0
  23. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/journal.ts +25 -0
  24. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/provider.ts +164 -0
  25. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/receipt.ts +177 -0
  26. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/index.ts +227 -0
  27. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/ledger.ts +20 -0
  28. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/observation.ts +252 -0
  29. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/economics.ts +237 -0
  30. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts +455 -0
  31. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/index.ts +49 -0
  32. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/plan.ts +79 -0
  33. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/state.ts +208 -0
  34. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/tools.ts +100 -0
  35. package/node_modules/@herbertgao/sol-pi/src/sol-pi/index.ts +42 -0
  36. package/node_modules/@herbertgao/sol-pi/src/sol-pi/runtime-paths.ts +17 -0
  37. package/node_modules/@herbertgao/sol-pi/src/sol-pi/tui.ts +71 -0
  38. package/node_modules/@narumitw/pi-btw/README.md +57 -141
  39. package/node_modules/@narumitw/pi-btw/dist/index.ts +478 -43
  40. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +4 -4
  41. package/node_modules/@narumitw/pi-btw/docs/workflows.md +74 -0
  42. package/node_modules/@narumitw/pi-btw/package.json +2 -1
  43. package/node_modules/@narumitw/pi-btw/src/btw.ts +28 -3
  44. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +32 -2
  45. package/node_modules/@narumitw/pi-btw/src/keybindings.ts +330 -0
  46. package/node_modules/@narumitw/pi-btw/src/menu.ts +136 -19
  47. package/node_modules/@narumitw/pi-btw/src/settings.ts +32 -0
  48. package/node_modules/@narumitw/pi-btw/src/side-thread.ts +57 -5
  49. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +52 -30
  50. package/node_modules/pi-lens/CHANGELOG.md +260 -0
  51. package/node_modules/pi-lens/README.md +13 -8
  52. package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +3 -1
  53. package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +0 -7
  54. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +1 -1
  55. package/node_modules/pi-lens/dist/clients/analysed-root.js +1 -0
  56. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +1 -1
  57. package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +1 -8
  58. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +2 -0
  59. package/node_modules/pi-lens/dist/clients/bash-file-access.js +133 -1
  60. package/node_modules/pi-lens/dist/clients/biome-client.js +13 -2
  61. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +0 -6
  62. package/node_modules/pi-lens/dist/clients/bootstrap.js +4 -4
  63. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +1 -1
  64. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +2 -5
  65. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +1 -9
  66. package/node_modules/pi-lens/dist/clients/cache-observability.js +122 -6
  67. package/node_modules/pi-lens/dist/clients/cargo-manifest.js +2 -2
  68. package/node_modules/pi-lens/dist/clients/cascade-logger.js +0 -7
  69. package/node_modules/pi-lens/dist/clients/child-unref.js +1 -19
  70. package/node_modules/pi-lens/dist/clients/complexity-client.js +5 -0
  71. package/node_modules/pi-lens/dist/clients/config-core/index.js +11 -8
  72. package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +1 -1
  73. package/node_modules/pi-lens/dist/clients/config-core/provenance.js +2 -9
  74. package/node_modules/pi-lens/dist/clients/config-core/records.js +1 -1
  75. package/node_modules/pi-lens/dist/clients/config-core/schema.js +3 -5
  76. package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +3 -1
  77. package/node_modules/pi-lens/dist/clients/config-resolve.js +10 -7
  78. package/node_modules/pi-lens/dist/clients/config-schema.js +56 -2
  79. package/node_modules/pi-lens/dist/clients/config-warn.js +2 -2
  80. package/node_modules/pi-lens/dist/clients/dead-code-client.js +8 -1
  81. package/node_modules/pi-lens/dist/clients/dead-code-logger.js +0 -4
  82. package/node_modules/pi-lens/dist/clients/dependency-checker.js +5 -1
  83. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +1 -1
  84. package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +1 -1
  85. package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +0 -4
  86. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +38 -41
  87. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +1 -1
  88. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +5 -1
  89. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +18 -1
  90. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +0 -6
  91. package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +1 -1
  92. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +0 -3
  93. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-complexity.js +2 -2
  94. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-fan-out.js +1 -1
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +2 -1
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +3 -1
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +2 -3
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +7 -2
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +2 -1
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +2 -1
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +2 -1
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +2 -1
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +2 -1
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +2 -1
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +2 -1
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +2 -1
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +2 -1
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +2 -1
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +2 -1
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +3 -1
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +3 -2
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +2 -1
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +2 -1
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +2 -1
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +19 -1
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +3 -2
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +2 -1
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +3 -1
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +2 -1
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +2 -1
  122. package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +2 -1
  123. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +15 -11
  124. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +2 -1
  125. package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +2 -1
  126. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +3 -3
  127. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +12 -11
  128. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +3 -2
  129. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -1
  130. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +5 -3
  131. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
  132. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +3 -2
  133. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +3 -2
  134. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +2 -1
  135. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
  136. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +2 -1
  137. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +2 -1
  138. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +2 -1
  139. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +5 -0
  140. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +2 -2
  141. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +1 -64
  142. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +8 -2
  143. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils.js +0 -21
  144. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +2 -1
  145. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +2 -20
  146. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +5 -3
  147. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +2 -1
  148. package/node_modules/pi-lens/dist/clients/dispatch/utils/format-utils.js +2 -2
  149. package/node_modules/pi-lens/dist/clients/disposition-logger.js +0 -7
  150. package/node_modules/pi-lens/dist/clients/effective-config.js +12 -2
  151. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +2 -2
  152. package/node_modules/pi-lens/dist/clients/extension-log.js +2 -0
  153. package/node_modules/pi-lens/dist/clients/file-kinds.js +1 -38
  154. package/node_modules/pi-lens/dist/clients/file-role.js +18 -1
  155. package/node_modules/pi-lens/dist/clients/file-time.js +1 -1
  156. package/node_modules/pi-lens/dist/clients/file-utils.js +5 -1
  157. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +4 -0
  158. package/node_modules/pi-lens/dist/clients/format-service.js +0 -1
  159. package/node_modules/pi-lens/dist/clients/formatters.js +66 -93
  160. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +3 -4
  161. package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -0
  162. package/node_modules/pi-lens/dist/clients/git-guard.js +5 -0
  163. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +42 -6
  164. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +48 -7
  165. package/node_modules/pi-lens/dist/clients/grammar-source.js +3 -3
  166. package/node_modules/pi-lens/dist/clients/installer/index.js +416 -61
  167. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +84 -18
  168. package/node_modules/pi-lens/dist/clients/instance-reaper.js +6 -6
  169. package/node_modules/pi-lens/dist/clients/jscpd-client.js +9 -1
  170. package/node_modules/pi-lens/dist/clients/knip-client.js +9 -2
  171. package/node_modules/pi-lens/dist/clients/language-profile.js +12 -11
  172. package/node_modules/pi-lens/dist/clients/language-registry.js +5 -1
  173. package/node_modules/pi-lens/dist/clients/latency-logger.js +7 -7
  174. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -1
  175. package/node_modules/pi-lens/dist/clients/lens-config.js +23 -0
  176. package/node_modules/pi-lens/dist/clients/lens-engine.js +3 -4
  177. package/node_modules/pi-lens/dist/clients/lens-events.js +1 -1
  178. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +18 -0
  179. package/node_modules/pi-lens/dist/clients/lens-map.js +1 -1
  180. package/node_modules/pi-lens/dist/clients/log-cleanup.js +0 -36
  181. package/node_modules/pi-lens/dist/clients/lsp/client.js +4 -3
  182. package/node_modules/pi-lens/dist/clients/lsp/config.js +37 -7
  183. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +24 -1
  184. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +79 -1
  185. package/node_modules/pi-lens/dist/clients/lsp/edits.js +3 -3
  186. package/node_modules/pi-lens/dist/clients/lsp/index.js +491 -64
  187. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +1 -1
  188. package/node_modules/pi-lens/dist/clients/lsp/language.js +0 -8
  189. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
  190. package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +0 -2
  191. package/node_modules/pi-lens/dist/clients/lsp/server.js +62 -15
  192. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +0 -1
  193. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +5 -5
  194. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +6 -0
  195. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +2 -1
  196. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +37 -4
  197. package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +1 -1
  198. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +3 -0
  199. package/node_modules/pi-lens/dist/clients/mcp/session.js +2 -0
  200. package/node_modules/pi-lens/dist/clients/metrics-history.js +28 -107
  201. package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +1 -1
  202. package/node_modules/pi-lens/dist/clients/module-report.js +1 -1
  203. package/node_modules/pi-lens/dist/clients/mutating-tool.js +3 -3
  204. package/node_modules/pi-lens/dist/clients/mutation-attribution.js +3 -3
  205. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +0 -4
  206. package/node_modules/pi-lens/dist/clients/observed-mutation.js +9 -9
  207. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +2 -6
  208. package/node_modules/pi-lens/dist/clients/opengrep-client.js +2 -0
  209. package/node_modules/pi-lens/dist/clients/opengrep-config.js +1 -1
  210. package/node_modules/pi-lens/dist/clients/package-manager.js +2 -1
  211. package/node_modules/pi-lens/dist/clients/path-utils.js +23 -2
  212. package/node_modules/pi-lens/dist/clients/performance-report.js +2 -2
  213. package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +9 -4
  214. package/node_modules/pi-lens/dist/clients/pipeline.js +5 -4
  215. package/node_modules/pi-lens/dist/clients/project-changes.js +1 -1
  216. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +1 -1
  217. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +38 -10
  218. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +10 -9
  219. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/jscpd.js +1 -1
  220. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +1 -1
  221. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +1 -1
  222. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +1 -1
  223. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +1 -1
  224. package/node_modules/pi-lens/dist/clients/project-lens-config.js +49 -1
  225. package/node_modules/pi-lens/dist/clients/project-scan-policy.js +3 -51
  226. package/node_modules/pi-lens/dist/clients/python-provenance.js +1 -1
  227. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +3 -1
  228. package/node_modules/pi-lens/dist/clients/read-guard.js +5 -2
  229. package/node_modules/pi-lens/dist/clients/recent-touches.js +2 -2
  230. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +3 -5
  231. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +1 -1
  232. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +2 -0
  233. package/node_modules/pi-lens/dist/clients/ruff-client.js +18 -9
  234. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +10 -1
  235. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +5 -0
  236. package/node_modules/pi-lens/dist/clients/runtime-session.js +58 -14
  237. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +11 -1
  238. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +4 -1
  239. package/node_modules/pi-lens/dist/clients/runtime-turn.js +48 -1
  240. package/node_modules/pi-lens/dist/clients/sanitize.js +0 -11
  241. package/node_modules/pi-lens/dist/clients/scan-utils.js +1 -56
  242. package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -2
  243. package/node_modules/pi-lens/dist/clients/session-event-guard.js +69 -1
  244. package/node_modules/pi-lens/dist/clients/session-summary.js +0 -24
  245. package/node_modules/pi-lens/dist/clients/sg-runner.js +2 -1
  246. package/node_modules/pi-lens/dist/clients/sgconfig.js +1 -5
  247. package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +1 -1
  248. package/node_modules/pi-lens/dist/clients/situational-tool-telemetry.js +108 -0
  249. package/node_modules/pi-lens/dist/clients/smells-rollup.js +2 -2
  250. package/node_modules/pi-lens/dist/clients/startup-scan.js +2 -10
  251. package/node_modules/pi-lens/dist/clients/test-runner-client.js +291 -76
  252. package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +77 -72
  253. package/node_modules/pi-lens/dist/clients/tool-config.js +199 -0
  254. package/node_modules/pi-lens/dist/clients/tool-cwd.js +299 -0
  255. package/node_modules/pi-lens/dist/clients/tool-policy.js +1 -1
  256. package/node_modules/pi-lens/dist/clients/tool-probe.js +53 -0
  257. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +42 -0
  258. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +1 -52
  259. package/node_modules/pi-lens/dist/clients/trivy-client.js +9 -1
  260. package/node_modules/pi-lens/dist/clients/tui-fit.js +0 -4
  261. package/node_modules/pi-lens/dist/clients/turn-context.js +52 -0
  262. package/node_modules/pi-lens/dist/clients/user-notify.js +0 -4
  263. package/node_modules/pi-lens/dist/clients/widget-state.js +4 -3
  264. package/node_modules/pi-lens/dist/clients/word-index-logger.js +0 -7
  265. package/node_modules/pi-lens/dist/clients/word-index-store.js +3 -7
  266. package/node_modules/pi-lens/dist/clients/word-index.js +9 -16
  267. package/node_modules/pi-lens/dist/clients/zizmor-config.js +1 -1
  268. package/node_modules/pi-lens/dist/index.js +19969 -17481
  269. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -2
  270. package/node_modules/pi-lens/dist/mcp/build-staleness.js +1 -1
  271. package/node_modules/pi-lens/dist/mcp/server.js +135 -159
  272. package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +1 -1
  273. package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +1 -1
  274. package/node_modules/pi-lens/dist/tools/activate-tools.js +10 -7
  275. package/node_modules/pi-lens/dist/tools/ast-grep-outline.js +2 -13
  276. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +8 -13
  277. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +83 -39
  278. package/node_modules/pi-lens/dist/tools/effective-config.js +4 -3
  279. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +1 -10
  280. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +354 -86
  281. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +54 -112
  282. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +20 -44
  283. package/node_modules/pi-lens/dist/tools/lsp-structured-output.js +3 -3
  284. package/node_modules/pi-lens/dist/tools/module-report.js +5 -9
  285. package/node_modules/pi-lens/dist/tools/project-report.js +9 -17
  286. package/node_modules/pi-lens/dist/tools/render-compact.js +281 -2
  287. package/node_modules/pi-lens/dist/tools/symbol-search.js +3 -4
  288. package/node_modules/pi-lens/docs/agent-guide.md +3 -4
  289. package/node_modules/pi-lens/docs/agent-tools.md +46 -22
  290. package/node_modules/pi-lens/docs/configuration.md +9 -0
  291. package/node_modules/pi-lens/docs/environment-variables.md +0 -5
  292. package/node_modules/pi-lens/docs/features.md +5 -5
  293. package/node_modules/pi-lens/docs/globalconfig.md +31 -1
  294. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +9 -1
  295. package/node_modules/pi-lens/docs/mcp.md +13 -1
  296. package/node_modules/pi-lens/docs/pi-lens-fixer.md +71 -0
  297. package/node_modules/pi-lens/docs/pi-lens-investigator.md +15 -0
  298. package/node_modules/pi-lens/docs/pi-lens-monitor.md +88 -0
  299. package/node_modules/pi-lens/docs/pi-lens-reviewer.md +41 -0
  300. package/node_modules/pi-lens/docs/pi-lens-subagent.md +21 -2
  301. package/node_modules/pi-lens/docs/public-api-stability.md +1 -0
  302. package/node_modules/pi-lens/docs/real-harness.md +46 -0
  303. package/node_modules/pi-lens/docs/release-qa-baseline.md +17 -5
  304. package/node_modules/pi-lens/docs/servercapabilities.md +2 -3
  305. package/node_modules/pi-lens/docs/settings.md +37 -2
  306. package/node_modules/pi-lens/docs/tools_improvement2.md +4 -4
  307. package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +1 -1
  308. package/node_modules/pi-lens/docs/usage.md +13 -3
  309. package/node_modules/pi-lens/docs/word-index.md +1 -1
  310. package/node_modules/pi-lens/package.json +15 -15
  311. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/sql-injection.yml +7 -3
  312. package/node_modules/pi-lens/rules/typos/_typos.toml +4 -2
  313. package/node_modules/pi-lens/scripts/lib/skills-predicate.mjs +1 -1
  314. package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +1 -1
  315. package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +4 -2
  316. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +8 -6
  317. package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +19 -9
  318. package/node_modules/pi-web-access/CHANGELOG.md +29 -0
  319. package/node_modules/pi-web-access/README.md +33 -22
  320. package/node_modules/pi-web-access/abortable.ts +17 -0
  321. package/node_modules/pi-web-access/crawl4ai.ts +204 -0
  322. package/node_modules/pi-web-access/credential-source.ts +1 -0
  323. package/node_modules/pi-web-access/curator-page.ts +20 -2
  324. package/node_modules/pi-web-access/curator-run.ts +44 -0
  325. package/node_modules/pi-web-access/curator-server.ts +3 -1
  326. package/node_modules/pi-web-access/duckduckgo.ts +1 -1
  327. package/node_modules/pi-web-access/extract.ts +57 -12
  328. package/node_modules/pi-web-access/fetch-params.ts +1 -1
  329. package/node_modules/pi-web-access/gemini-search.ts +9 -5
  330. package/node_modules/pi-web-access/index.ts +25 -18
  331. package/node_modules/pi-web-access/openai-search.ts +35 -13
  332. package/node_modules/pi-web-access/package.json +2 -2
  333. package/node_modules/pi-web-access/page-query.ts +5 -2
  334. package/node_modules/pi-web-access/query-rewrite.ts +5 -2
  335. package/node_modules/pi-web-access/serpapi.ts +220 -0
  336. package/node_modules/pi-web-access/ssrf-protection.ts +5 -1
  337. package/node_modules/pi-web-access/storage.ts +10 -0
  338. package/node_modules/pi-web-access/summary-review.ts +34 -21
  339. package/node_modules/pi-web-access/utils.ts +6 -4
  340. package/package.json +7 -4
  341. package/node_modules/pi-lens/dist/tools/ast-dump.js +0 -103
@@ -0,0 +1,455 @@
1
+ /*
2
+ * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+ import type { AgentMessage, AgentToolResult } from "@earendil-works/pi-agent-core";
6
+ import {
7
+ buildSessionContext,
8
+ estimateTokens,
9
+ findCutPoint,
10
+ sessionEntryToContextMessages,
11
+ type ExtensionContext,
12
+ type ExtensionFactory,
13
+ type SessionEntry,
14
+ } from "@earendil-works/pi-coding-agent";
15
+ import { formatSavingsCount, showSolPiSavings } from "../../tui.ts";
16
+ import {
17
+ DEFAULT_COMPACTION_ECONOMICS,
18
+ decideCompaction,
19
+ type CompactionDecision,
20
+ } from "./economics.ts";
21
+ import { analyzePlanTransition, formatPlanSnapshot, parsePlanSteps } from "./plan.ts";
22
+ import {
23
+ appendOnlineState,
24
+ initialOnlineState,
25
+ recordBoundary,
26
+ recordCompaction,
27
+ recordCorrection,
28
+ recordProviderRequest,
29
+ restoreOnlineState,
30
+ type OnlineState,
31
+ type ProgressSummary,
32
+ } from "./state.ts";
33
+ import { registerOnlineTools, type PlanUpdateInput } from "./tools.ts";
34
+
35
+ export const DEFAULT_KEEP_RECENT_TOKENS = 20_000;
36
+ export const DEFAULT_NATIVE_SUMMARY_TOKEN_ESTIMATE = 1_000;
37
+ export const BOUNDARY_COMPACTION_INSTRUCTIONS =
38
+ "Preserve completed work, verification results, important decisions, and remaining work.";
39
+ export const POST_COMPACTION_PLAN_REMINDER =
40
+ "Online context compaction finished. The parent task is still active. " +
41
+ "Before continuing work, call update_plan with a fresh plan for the remaining work.";
42
+
43
+ export type OnlineContextCompactOptions = {
44
+ readonly cacheWriteReadRatio?: number | null;
45
+ readonly keepRecentTokens?: number;
46
+ };
47
+
48
+ type PendingBoundary = { readonly toolCallId: string };
49
+ type SelectedCompaction = { readonly decision: CompactionDecision };
50
+ type CacheDebt = { readonly debtTokens: number; readonly repaymentTokens: number };
51
+ type PendingContinuation = { readonly promise: Promise<void>; readonly resolve: () => void };
52
+
53
+ const SUBAGENTS_MANAGER_KEY = Symbol.for("pi-subagents:manager");
54
+
55
+ export function hasRunningSubagents(): boolean {
56
+ try {
57
+ const manager = (globalThis as Record<PropertyKey, unknown>)[SUBAGENTS_MANAGER_KEY];
58
+ if (!manager || typeof manager !== "object") return false;
59
+ const hasRunning = (manager as { hasRunning?: unknown }).hasRunning;
60
+ return typeof hasRunning === "function" && hasRunning.call(manager) === true;
61
+ } catch {
62
+ return true;
63
+ }
64
+ }
65
+
66
+ export function resolveKeepRecentTokens(value: number | undefined): number {
67
+ const resolved = value ?? DEFAULT_KEEP_RECENT_TOKENS;
68
+ if (!Number.isSafeInteger(resolved) || resolved < 1) {
69
+ throw new Error("Online Context Compact keepRecentTokens must be a positive safe integer");
70
+ }
71
+ return resolved;
72
+ }
73
+
74
+ function resolveCacheWriteReadRatio(value: number | null | undefined): number | null {
75
+ if (value === undefined || value === null) return null;
76
+ if (!Number.isFinite(value) || value < 0) {
77
+ throw new Error("Online Context Compact cacheWriteReadRatio must be finite and non-negative");
78
+ }
79
+ return value;
80
+ }
81
+
82
+ function tokenEstimate(text: string): number {
83
+ return Math.ceil(Buffer.byteLength(text) / 4);
84
+ }
85
+
86
+ function result(text: string, details: Readonly<Record<string, unknown>>): AgentToolResult<Readonly<Record<string, unknown>>> {
87
+ return { content: [{ type: "text", text }], details };
88
+ }
89
+
90
+ function progressSummary(input: PlanUpdateInput, completedStepId: string): ProgressSummary | undefined {
91
+ const step = input.steps.find((item) => item.id === completedStepId);
92
+ if (!step || !input.progress) return;
93
+ return {
94
+ stepId: step.id,
95
+ goal: step.goal,
96
+ filesChanged: [...input.progress.files_changed],
97
+ verification: [...input.progress.verification],
98
+ decisions: [...input.progress.decisions],
99
+ nextWork: input.steps.filter((item) => item.status !== "completed").map((item) => item.goal),
100
+ };
101
+ }
102
+
103
+ function compactionMessageCount(entries: readonly SessionEntry[], startIndex: number, endIndex: number): number {
104
+ let count = 0;
105
+ for (let index = startIndex; index < endIndex; index++) {
106
+ const entry = entries[index];
107
+ if (entry && entry.type !== "compaction" && sessionEntryToContextMessages(entry).length > 0) count++;
108
+ }
109
+ return count;
110
+ }
111
+
112
+ function branchAfterAbort(entries: readonly SessionEntry[]): SessionEntry[] {
113
+ const last = entries.at(-1);
114
+ const markerProvider = ["sol", "pi"].join("-");
115
+ return [
116
+ ...entries,
117
+ {
118
+ type: "message",
119
+ id: "sol-pi-online-context-compact-abort-marker",
120
+ parentId: last?.id ?? null,
121
+ timestamp: new Date(0).toISOString(),
122
+ message: {
123
+ role: "assistant",
124
+ content: [],
125
+ api: markerProvider,
126
+ provider: markerProvider,
127
+ model: "aborted",
128
+ usage: {
129
+ input: 0,
130
+ output: 0,
131
+ cacheRead: 0,
132
+ cacheWrite: 0,
133
+ totalTokens: 0,
134
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
135
+ },
136
+ stopReason: "aborted",
137
+ timestamp: 0,
138
+ },
139
+ } as SessionEntry,
140
+ ];
141
+ }
142
+
143
+ function nativeCompactionFeasible(entries: readonly SessionEntry[], keepRecentTokens: number): boolean {
144
+ const path = branchAfterAbort(entries);
145
+ let startIndex = 0;
146
+ for (let index = path.length - 1; index >= 0; index--) {
147
+ const entry = path[index];
148
+ if (entry?.type !== "compaction") continue;
149
+ const keptIndex = path.findIndex((item) => item.id === entry.firstKeptEntryId);
150
+ startIndex = keptIndex >= 0 ? keptIndex : index + 1;
151
+ break;
152
+ }
153
+
154
+ const cut = findCutPoint(path, startIndex, path.length, keepRecentTokens);
155
+ const historyEnd = cut.isSplitTurn ? cut.turnStartIndex : cut.firstKeptEntryIndex;
156
+ const historyMessages = historyEnd > startIndex ? compactionMessageCount(path, startIndex, historyEnd) : 0;
157
+ const prefixMessages =
158
+ cut.isSplitTurn && cut.turnStartIndex >= 0
159
+ ? compactionMessageCount(path, cut.turnStartIndex, cut.firstKeptEntryIndex)
160
+ : 0;
161
+ return historyMessages > 0 || prefixMessages > 0;
162
+ }
163
+
164
+ function validPositiveInteger(value: unknown): value is number {
165
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
166
+ }
167
+
168
+ function releaseParentContinuation(continuation: PendingContinuation | undefined): void {
169
+ if (continuation) setTimeout(continuation.resolve, 0);
170
+ }
171
+
172
+ export function createOnlineContextCompactExtension(options: OnlineContextCompactOptions = {}): ExtensionFactory {
173
+ const keepRecentTokens = resolveKeepRecentTokens(options.keepRecentTokens);
174
+ const cacheWriteReadRatio = resolveCacheWriteReadRatio(options.cacheWriteReadRatio);
175
+
176
+ return (pi) => {
177
+ let state: OnlineState = initialOnlineState();
178
+ let restored = false;
179
+ let observedMessages: readonly AgentMessage[] = [];
180
+ let pendingBoundary: PendingBoundary | undefined;
181
+ let selected: SelectedCompaction | undefined;
182
+ let activeDebt: CacheDebt | undefined;
183
+ let nextContinuation: PendingContinuation | undefined;
184
+ let compactionInFlight = false;
185
+
186
+ const releaseContinuation = (): void => {
187
+ const continuation = nextContinuation;
188
+ nextContinuation = undefined;
189
+ continuation?.resolve();
190
+ };
191
+ const restore = (context: ExtensionContext): void => {
192
+ releaseContinuation();
193
+ state = restoreOnlineState(context.sessionManager.getBranch());
194
+ restored = true;
195
+ observedMessages = buildSessionContext(
196
+ context.sessionManager.getEntries(),
197
+ context.sessionManager.getLeafId(),
198
+ ).messages;
199
+ pendingBoundary = undefined;
200
+ selected = undefined;
201
+ activeDebt = undefined;
202
+ compactionInFlight = false;
203
+ };
204
+ const ensureRestored = (context: ExtensionContext): void => {
205
+ if (!restored) restore(context);
206
+ };
207
+ const save = (): void => appendOnlineState(pi, state);
208
+ const contextTokens = (context: ExtensionContext): number => {
209
+ const visible = observedMessages.reduce((total, message) => total + estimateTokens(message), 0);
210
+ const estimated = visible + tokenEstimate(context.getSystemPrompt());
211
+ const reported = context.getContextUsage()?.tokens;
212
+ return validPositiveInteger(reported) ? Math.max(reported, estimated) : estimated;
213
+ };
214
+
215
+ registerOnlineTools(pi, {
216
+ updatePlan: async (input) => {
217
+ ensureRestored(input.context);
218
+ if (input.signal?.aborted) throw new Error("Plan update was aborted");
219
+ const steps = parsePlanSteps(input.steps);
220
+ if (!steps || steps.length === 0) throw new Error("Plan must contain at least one valid step");
221
+
222
+ const transition = analyzePlanTransition(state.plan, steps);
223
+ const completedIds = transition.completedSteps.map((step) => step.id);
224
+ if (completedIds.length > 0) {
225
+ state = recordBoundary(state, steps, progressSummary(input, completedIds[0] ?? ""));
226
+ if (!pendingBoundary) pendingBoundary = { toolCallId: input.toolCallId };
227
+ } else if (JSON.stringify(state.plan) !== JSON.stringify(steps)) {
228
+ state = { ...state, plan: [...steps] };
229
+ }
230
+ save();
231
+
232
+ return result(
233
+ [formatPlanSnapshot(steps), ...transition.advice].join("\n"),
234
+ {
235
+ boundary: completedIds.length > 0,
236
+ completed_step_ids: completedIds,
237
+ progress_recorded: completedIds.length > 0 && input.progress !== undefined,
238
+ task_status: "active",
239
+ plan: steps,
240
+ },
241
+ );
242
+ },
243
+ });
244
+
245
+ pi.on("session_start", (_event, context) => restore(context));
246
+ pi.on("session_before_tree", () => (compactionInFlight ? { cancel: true } : undefined));
247
+ pi.on("session_tree", (_event, context) => restore(context));
248
+
249
+ pi.on("context", (event, context) => {
250
+ ensureRestored(context);
251
+ observedMessages = [...event.messages];
252
+ });
253
+
254
+ pi.on("before_provider_request", (_event, context) => {
255
+ ensureRestored(context);
256
+ state = recordProviderRequest(state, contextTokens(context));
257
+ save();
258
+ });
259
+
260
+ pi.on("input", (event, context) => {
261
+ if (event.streamingBehavior !== "steer" && !event.text.startsWith("CORRECTION:")) {
262
+ return { action: "continue" as const };
263
+ }
264
+ ensureRestored(context);
265
+ pendingBoundary = undefined;
266
+ selected = undefined;
267
+ activeDebt = undefined;
268
+ state = recordCorrection(state);
269
+ save();
270
+ return { action: "continue" as const };
271
+ });
272
+
273
+ pi.on("turn_end", (event, context) => {
274
+ const boundary = pendingBoundary;
275
+ pendingBoundary = undefined;
276
+ if (!boundary || selected || hasRunningSubagents()) return;
277
+ const toolResult = event.toolResults.find((item) => item.toolCallId === boundary.toolCallId);
278
+ if (
279
+ event.message.role !== "assistant" ||
280
+ event.message.stopReason === "error" ||
281
+ event.message.stopReason === "aborted" ||
282
+ context.signal?.aborted ||
283
+ !toolResult ||
284
+ toolResult.isError
285
+ ) {
286
+ return;
287
+ }
288
+
289
+ const usage = context.getContextUsage();
290
+ const writeTokens = contextTokens(context);
291
+ const fixedTokens = tokenEstimate(context.getSystemPrompt());
292
+ const archiveTokens = Math.max(0, writeTokens - fixedTokens - keepRecentTokens);
293
+ const contextWindowTokens = validPositiveInteger(usage?.contextWindow)
294
+ ? usage.contextWindow
295
+ : validPositiveInteger(context.model?.contextWindow)
296
+ ? context.model.contextWindow
297
+ : null;
298
+ const averageContextTokenIncrement =
299
+ state.positiveContextDeltaCount === 0
300
+ ? null
301
+ : state.positiveContextDeltaTotal / state.positiveContextDeltaCount;
302
+ const priced = decideCompaction({
303
+ writeTokens,
304
+ archiveTokens,
305
+ memoTokens: DEFAULT_NATIVE_SUMMARY_TOKEN_ESTIMATE,
306
+ contextTokens: writeTokens,
307
+ completedBoundaryRequestCounts: state.completedBoundaryRequestCounts,
308
+ remainingBoundaries: state.plan.filter((step) => step.status !== "completed").length,
309
+ averageContextTokenIncrement,
310
+ contextWindowTokens,
311
+ priorCompactionCount: state.nativeCompactionCount,
312
+ carriedDebtTokens: state.cacheDebtTokens,
313
+ cacheDebtRepaymentTokens: state.cacheDebtRepaymentTokens,
314
+ cacheWriteReadRatio,
315
+ economics: DEFAULT_COMPACTION_ECONOMICS,
316
+ });
317
+ const decision: CompactionDecision =
318
+ priced.compact && !nativeCompactionFeasible(context.sessionManager.getBranch(), keepRecentTokens)
319
+ ? { ...priced, compact: false, reason: "native_not_compactable" }
320
+ : priced;
321
+ if (!decision.compact) return;
322
+
323
+ selected = { decision };
324
+ context.abort();
325
+ });
326
+
327
+ pi.on("agent_settled", async (_event, context) => {
328
+ // sendMessage() starts a turn without returning its promise. Capture the
329
+ // child settlement so print/JSON mode cannot dispose while it is running.
330
+ const parentContinuation = nextContinuation;
331
+ nextContinuation = undefined;
332
+ const pending = selected;
333
+ selected = undefined;
334
+ if (!context.isIdle()) {
335
+ selected = pending;
336
+ nextContinuation = parentContinuation;
337
+ return;
338
+ }
339
+ if (!pending || hasRunningSubagents()) {
340
+ releaseParentContinuation(parentContinuation);
341
+ return;
342
+ }
343
+
344
+ activeDebt = {
345
+ debtTokens: pending.decision.writeTokens * (pending.decision.incrementalCacheCostRatio ?? 0),
346
+ repaymentTokens: Math.max(0, pending.decision.archiveTokens - pending.decision.memoTokens),
347
+ };
348
+ let compacted = false;
349
+ let compactionError: Error | undefined;
350
+ try {
351
+ compactionInFlight = true;
352
+ await new Promise<void>((resolve) => {
353
+ let finished = false;
354
+ const finish = (): void => {
355
+ if (finished) return;
356
+ finished = true;
357
+ resolve();
358
+ };
359
+ context.compact({
360
+ customInstructions: BOUNDARY_COMPACTION_INSTRUCTIONS,
361
+ onComplete: (compaction) => {
362
+ try {
363
+ compacted = true;
364
+ const removed = Math.max(
365
+ 0,
366
+ pending.decision.archiveTokens - tokenEstimate(compaction.summary),
367
+ );
368
+ if (removed > 0) {
369
+ showSolPiSavings(
370
+ context,
371
+ "Online Context Compact",
372
+ formatSavingsCount(removed, "context tokens removed"),
373
+ );
374
+ }
375
+ } finally {
376
+ finish();
377
+ }
378
+ },
379
+ onError: (error) => {
380
+ compactionError = error;
381
+ finish();
382
+ },
383
+ });
384
+ });
385
+ compactionInFlight = false;
386
+ if (
387
+ compactionError &&
388
+ compactionError.name !== "AbortError" &&
389
+ compactionError.message !== "Compaction cancelled"
390
+ ) {
391
+ throw compactionError;
392
+ }
393
+
394
+ if (compacted) {
395
+ let resolveContinuation!: () => void;
396
+ const continuation: PendingContinuation = {
397
+ promise: new Promise<void>((resolve) => {
398
+ resolveContinuation = resolve;
399
+ }),
400
+ resolve: () => resolveContinuation(),
401
+ };
402
+ nextContinuation = continuation;
403
+ try {
404
+ pi.sendMessage(
405
+ {
406
+ customType: "sol-pi-online-context-compact",
407
+ content: POST_COMPACTION_PLAN_REMINDER,
408
+ display: false,
409
+ },
410
+ { triggerTurn: true },
411
+ );
412
+ } catch (error) {
413
+ if (nextContinuation === continuation) nextContinuation = undefined;
414
+ continuation.resolve();
415
+ throw error;
416
+ }
417
+ if (context.isIdle() && nextContinuation === continuation) {
418
+ nextContinuation = undefined;
419
+ continuation.resolve();
420
+ throw new Error("Online context compact continuation did not start");
421
+ }
422
+ await continuation.promise;
423
+ }
424
+ } finally {
425
+ compactionInFlight = false;
426
+ activeDebt = undefined;
427
+ releaseParentContinuation(parentContinuation);
428
+ }
429
+ });
430
+
431
+ pi.on("session_compact", (event, context) => {
432
+ ensureRestored(context);
433
+ state = recordCompaction(
434
+ state,
435
+ event.fromExtension || !activeDebt ? { debtTokens: 0, repaymentTokens: 0 } : activeDebt,
436
+ );
437
+ save();
438
+ pendingBoundary = undefined;
439
+ selected = undefined;
440
+ activeDebt = undefined;
441
+ observedMessages = buildSessionContext(
442
+ context.sessionManager.getEntries(),
443
+ context.sessionManager.getLeafId(),
444
+ ).messages;
445
+ });
446
+
447
+ pi.on("session_shutdown", () => {
448
+ releaseContinuation();
449
+ pendingBoundary = undefined;
450
+ selected = undefined;
451
+ activeDebt = undefined;
452
+ compactionInFlight = false;
453
+ });
454
+ };
455
+ }
@@ -0,0 +1,49 @@
1
+ /*
2
+ * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
6
+ import { DEFAULT_CACHE_WRITE_READ_RATIO } from "../../config.ts";
7
+ import { createOnlineContextCompactExtension } from "./extension.ts";
8
+
9
+ export {
10
+ DEFAULT_COMPACTION_ECONOMICS,
11
+ decideCompaction,
12
+ estimateRemainingRequests,
13
+ type CompactionDecision,
14
+ type CompactionEconomics,
15
+ type CompactionReason,
16
+ } from "./economics.ts";
17
+ export {
18
+ BOUNDARY_COMPACTION_INSTRUCTIONS,
19
+ createOnlineContextCompactExtension,
20
+ DEFAULT_KEEP_RECENT_TOKENS,
21
+ DEFAULT_NATIVE_SUMMARY_TOKEN_ESTIMATE,
22
+ POST_COMPACTION_PLAN_REMINDER,
23
+ type OnlineContextCompactOptions,
24
+ resolveKeepRecentTokens,
25
+ } from "./extension.ts";
26
+ export {
27
+ analyzePlanTransition,
28
+ formatPlanSnapshot,
29
+ parsePlanSteps,
30
+ type PlanStatus,
31
+ type PlanStep,
32
+ } from "./plan.ts";
33
+ export {
34
+ initialOnlineState,
35
+ ONLINE_STATE_ENTRY,
36
+ restoreOnlineState,
37
+ type OnlineState,
38
+ type ProgressSummary,
39
+ } from "./state.ts";
40
+ export type { PlanProgress, PlanUpdateInput } from "./tools.ts";
41
+
42
+ export function registerOnlineContextCompact(
43
+ pi: ExtensionAPI,
44
+ cacheWriteReadRatio = DEFAULT_CACHE_WRITE_READ_RATIO,
45
+ ): void {
46
+ createOnlineContextCompactExtension({ cacheWriteReadRatio })(pi);
47
+ }
48
+
49
+ export default registerOnlineContextCompact;
@@ -0,0 +1,79 @@
1
+ /*
2
+ * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ export const PLAN_STATUSES = ["pending", "in_progress", "completed"] as const;
7
+
8
+ export type PlanStatus = (typeof PLAN_STATUSES)[number];
9
+
10
+ export type PlanStep = {
11
+ readonly id: string;
12
+ readonly goal: string;
13
+ readonly status: PlanStatus;
14
+ };
15
+
16
+ export type PlanTransition = {
17
+ readonly completedSteps: readonly PlanStep[];
18
+ readonly advice: readonly string[];
19
+ };
20
+
21
+ const MAX_PLAN_STEPS = 128;
22
+ const MAX_PLAN_STRING_BYTES = 16_384;
23
+
24
+ function isRecord(value: unknown): value is Readonly<Record<string, unknown>> {
25
+ return typeof value === "object" && value !== null && !Array.isArray(value);
26
+ }
27
+
28
+ function isBoundedString(value: unknown): value is string {
29
+ return typeof value === "string" && value.length > 0 && Buffer.byteLength(value) <= MAX_PLAN_STRING_BYTES;
30
+ }
31
+
32
+ function isPlanStatus(value: unknown): value is PlanStatus {
33
+ return PLAN_STATUSES.some((status) => status === value);
34
+ }
35
+
36
+ export function parsePlanSteps(value: unknown): readonly PlanStep[] | undefined {
37
+ if (!Array.isArray(value) || value.length > MAX_PLAN_STEPS) return;
38
+ const steps: PlanStep[] = [];
39
+ for (const item of value) {
40
+ if (
41
+ !isRecord(item) ||
42
+ Object.keys(item).length !== 3 ||
43
+ !isBoundedString(item.id) ||
44
+ !isBoundedString(item.goal) ||
45
+ !isPlanStatus(item.status)
46
+ ) {
47
+ return;
48
+ }
49
+ steps.push({ id: item.id, goal: item.goal, status: item.status });
50
+ }
51
+ if (new Set(steps.map((step) => step.id)).size !== steps.length) return;
52
+ return steps;
53
+ }
54
+
55
+ export function analyzePlanTransition(previous: readonly PlanStep[], next: readonly PlanStep[]): PlanTransition {
56
+ const previousById = new Map(previous.map((step) => [step.id, step]));
57
+ const completedSteps: PlanStep[] = [];
58
+ const advice: string[] = [];
59
+
60
+ for (const step of next) {
61
+ const prior = previousById.get(step.id);
62
+ if ((!prior || prior.status !== "completed") && step.status === "completed") completedSteps.push(step);
63
+ if (prior && prior.goal !== step.goal) {
64
+ advice.push(`Plan step ${JSON.stringify(step.id)} changed goal; reuse an id only for the same goal.`);
65
+ }
66
+ }
67
+
68
+ const inProgress = next.filter((step) => step.status === "in_progress").length;
69
+ if (inProgress > 1) advice.push("Keep at most one plan step in_progress.");
70
+ if (inProgress === 0 && next.some((step) => step.status === "pending")) {
71
+ advice.push("Mark one pending plan step in_progress before starting it.");
72
+ }
73
+
74
+ return { completedSteps, advice };
75
+ }
76
+
77
+ export function formatPlanSnapshot(steps: readonly PlanStep[]): string {
78
+ return `<sol-pi-plan task_status="active">${JSON.stringify({ steps })}</sol-pi-plan>`;
79
+ }