@herbertgao/pi-extensions 2026.9.6 → 2026.9.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.
Files changed (304) hide show
  1. package/README.md +3 -8
  2. package/THIRD_PARTY_NOTICES.md +0 -4
  3. package/node_modules/@narumitw/pi-btw/README.md +2 -0
  4. package/node_modules/@narumitw/pi-btw/dist/index.ts +284 -365
  5. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +3 -3
  6. package/node_modules/@narumitw/pi-btw/package.json +52 -53
  7. package/node_modules/@narumitw/pi-btw/src/bring-to-main.ts +494 -547
  8. package/node_modules/@narumitw/pi-btw/src/btw.ts +814 -856
  9. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +673 -674
  10. package/node_modules/@narumitw/pi-btw/src/keybindings.ts +228 -270
  11. package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +309 -318
  12. package/node_modules/@narumitw/pi-btw/src/menu.ts +416 -454
  13. package/node_modules/@narumitw/pi-btw/src/settings.ts +203 -219
  14. package/node_modules/@narumitw/pi-btw/src/side-thread.ts +173 -201
  15. package/node_modules/@narumitw/pi-btw/src/text.ts +21 -23
  16. package/node_modules/@narumitw/pi-btw/src/transcript-markdown.ts +65 -0
  17. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +611 -662
  18. package/node_modules/grok-mermaid/CHANGELOG.md +46 -0
  19. package/node_modules/grok-mermaid/LICENSE +205 -0
  20. package/node_modules/grok-mermaid/README.md +191 -0
  21. package/node_modules/grok-mermaid/dist/ansi.d.ts +16 -0
  22. package/node_modules/grok-mermaid/dist/ansi.d.ts.map +1 -0
  23. package/node_modules/grok-mermaid/dist/ansi.js +23 -0
  24. package/node_modules/grok-mermaid/dist/ansi.js.map +1 -0
  25. package/node_modules/grok-mermaid/dist/canvas.d.ts +87 -0
  26. package/node_modules/grok-mermaid/dist/canvas.d.ts.map +1 -0
  27. package/node_modules/grok-mermaid/dist/canvas.js +366 -0
  28. package/node_modules/grok-mermaid/dist/canvas.js.map +1 -0
  29. package/node_modules/grok-mermaid/dist/graph.d.ts +74 -0
  30. package/node_modules/grok-mermaid/dist/graph.d.ts.map +1 -0
  31. package/node_modules/grok-mermaid/dist/graph.js +91 -0
  32. package/node_modules/grok-mermaid/dist/graph.js.map +1 -0
  33. package/node_modules/grok-mermaid/dist/index.d.ts +32 -0
  34. package/node_modules/grok-mermaid/dist/index.d.ts.map +1 -0
  35. package/node_modules/grok-mermaid/dist/index.js +100 -0
  36. package/node_modules/grok-mermaid/dist/index.js.map +1 -0
  37. package/node_modules/grok-mermaid/dist/labels.d.ts +62 -0
  38. package/node_modules/grok-mermaid/dist/labels.d.ts.map +1 -0
  39. package/node_modules/grok-mermaid/dist/labels.js +324 -0
  40. package/node_modules/grok-mermaid/dist/labels.js.map +1 -0
  41. package/node_modules/grok-mermaid/dist/layout-seq.d.ts +12 -0
  42. package/node_modules/grok-mermaid/dist/layout-seq.d.ts.map +1 -0
  43. package/node_modules/grok-mermaid/dist/layout-seq.js +194 -0
  44. package/node_modules/grok-mermaid/dist/layout-seq.js.map +1 -0
  45. package/node_modules/grok-mermaid/dist/layout.d.ts +87 -0
  46. package/node_modules/grok-mermaid/dist/layout.d.ts.map +1 -0
  47. package/node_modules/grok-mermaid/dist/layout.js +881 -0
  48. package/node_modules/grok-mermaid/dist/layout.js.map +1 -0
  49. package/node_modules/grok-mermaid/dist/parse.d.ts +83 -0
  50. package/node_modules/grok-mermaid/dist/parse.d.ts.map +1 -0
  51. package/node_modules/grok-mermaid/dist/parse.js +1151 -0
  52. package/node_modules/grok-mermaid/dist/parse.js.map +1 -0
  53. package/node_modules/grok-mermaid/dist/source-box.d.ts +18 -0
  54. package/node_modules/grok-mermaid/dist/source-box.d.ts.map +1 -0
  55. package/node_modules/grok-mermaid/dist/source-box.js +78 -0
  56. package/node_modules/grok-mermaid/dist/source-box.js.map +1 -0
  57. package/node_modules/grok-mermaid/dist/types.d.ts +42 -0
  58. package/node_modules/grok-mermaid/dist/types.d.ts.map +1 -0
  59. package/node_modules/grok-mermaid/dist/types.js +1 -0
  60. package/node_modules/grok-mermaid/dist/types.js.map +1 -0
  61. package/node_modules/grok-mermaid/dist/width-data.d.ts +2 -0
  62. package/node_modules/grok-mermaid/dist/width-data.d.ts.map +1 -0
  63. package/node_modules/grok-mermaid/dist/width-data.js +994 -0
  64. package/node_modules/grok-mermaid/dist/width-data.js.map +1 -0
  65. package/node_modules/grok-mermaid/dist/width.d.ts +18 -0
  66. package/node_modules/grok-mermaid/dist/width.d.ts.map +1 -0
  67. package/node_modules/grok-mermaid/dist/width.js +76 -0
  68. package/node_modules/grok-mermaid/dist/width.js.map +1 -0
  69. package/node_modules/grok-mermaid/package.json +49 -0
  70. package/node_modules/grok-mermaid/src/ansi.ts +34 -0
  71. package/node_modules/grok-mermaid/src/canvas.ts +373 -0
  72. package/node_modules/grok-mermaid/src/graph.ts +142 -0
  73. package/node_modules/grok-mermaid/src/index.ts +104 -0
  74. package/node_modules/grok-mermaid/src/labels.ts +326 -0
  75. package/node_modules/grok-mermaid/src/layout-seq.ts +203 -0
  76. package/node_modules/grok-mermaid/src/layout.ts +1015 -0
  77. package/node_modules/grok-mermaid/src/parse.ts +1189 -0
  78. package/node_modules/grok-mermaid/src/source-box.ts +89 -0
  79. package/node_modules/grok-mermaid/src/types.ts +43 -0
  80. package/node_modules/grok-mermaid/src/width-data.ts +993 -0
  81. package/node_modules/grok-mermaid/src/width.ts +74 -0
  82. package/node_modules/pi-lens/CHANGELOG.md +239 -0
  83. package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +3 -0
  84. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +30 -4
  85. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +2 -0
  86. package/node_modules/pi-lens/dist/clients/bash-file-access.js +26 -0
  87. package/node_modules/pi-lens/dist/clients/biome-client.js +1 -1
  88. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +403 -35
  89. package/node_modules/pi-lens/dist/clients/bootstrap.js +6 -1
  90. package/node_modules/pi-lens/dist/clients/cascade-format.js +200 -4
  91. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +10 -2
  92. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +16 -1
  93. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +12 -1
  94. package/node_modules/pi-lens/dist/clients/dispatch/ast-grep-catalog.js +65 -0
  95. package/node_modules/pi-lens/dist/clients/dispatch/auxiliary-lsp.js +28 -0
  96. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +9 -2
  97. package/node_modules/pi-lens/dist/clients/dispatch/finding-policy.js +222 -0
  98. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +389 -13
  99. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +175 -25
  100. package/node_modules/pi-lens/dist/clients/dispatch/rule-ignores.js +62 -0
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +21 -41
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +6 -1
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +7 -7
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -12
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +2 -21
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +1 -1
  107. package/node_modules/pi-lens/dist/clients/dispatch/types.js +4 -1
  108. package/node_modules/pi-lens/dist/clients/disposition-publish.js +1 -0
  109. package/node_modules/pi-lens/dist/clients/effective-config.js +1 -1
  110. package/node_modules/pi-lens/dist/clients/file-kinds.js +26 -1
  111. package/node_modules/pi-lens/dist/clients/file-role.js +21 -21
  112. package/node_modules/pi-lens/dist/clients/file-utils.js +156 -10
  113. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +56 -9
  114. package/node_modules/pi-lens/dist/clients/format-service.js +39 -21
  115. package/node_modules/pi-lens/dist/clients/formatters.js +60 -13
  116. package/node_modules/pi-lens/dist/clients/generation-guard.js +2 -2
  117. package/node_modules/pi-lens/dist/clients/git-guard.js +11 -3
  118. package/node_modules/pi-lens/dist/clients/indent-retarget.js +78 -8
  119. package/node_modules/pi-lens/dist/clients/installer/index.js +333 -114
  120. package/node_modules/pi-lens/dist/clients/instance-reaper-state.js +7 -0
  121. package/node_modules/pi-lens/dist/clients/instance-reaper.js +20 -10
  122. package/node_modules/pi-lens/dist/clients/language-profile.js +23 -1
  123. package/node_modules/pi-lens/dist/clients/language-registry.js +5 -1
  124. package/node_modules/pi-lens/dist/clients/latency-logger.js +4 -1
  125. package/node_modules/pi-lens/dist/clients/lens-engine.js +12 -3
  126. package/node_modules/pi-lens/dist/clients/lens-events.js +2 -1
  127. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +79 -0
  128. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +2 -1
  129. package/node_modules/pi-lens/dist/clients/lsp/client.js +25 -21
  130. package/node_modules/pi-lens/dist/clients/lsp/config.js +2 -2
  131. package/node_modules/pi-lens/dist/clients/lsp/index.js +7 -0
  132. package/node_modules/pi-lens/dist/clients/lsp/launch.js +16 -4
  133. package/node_modules/pi-lens/dist/clients/lsp/server.js +19 -2
  134. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +2 -1
  135. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +5 -3
  136. package/node_modules/pi-lens/dist/clients/map-with-concurrency.js +12 -8
  137. package/node_modules/pi-lens/dist/clients/mcp/session.js +36 -4
  138. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +24 -7
  139. package/node_modules/pi-lens/dist/clients/observed-mutation.js +40 -2
  140. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +23 -3
  141. package/node_modules/pi-lens/dist/clients/opengrep-client.js +110 -15
  142. package/node_modules/pi-lens/dist/clients/path-utils.js +123 -3
  143. package/node_modules/pi-lens/dist/clients/performance-report.js +5 -1
  144. package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +1 -1
  145. package/node_modules/pi-lens/dist/clients/pipeline.js +74 -5
  146. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +37 -5
  147. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +145 -18
  148. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/dead-code.js +4 -1
  149. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +59 -3
  150. package/node_modules/pi-lens/dist/clients/project-lens-config.js +45 -2
  151. package/node_modules/pi-lens/dist/clients/read-guard.js +70 -11
  152. package/node_modules/pi-lens/dist/clients/resource-sampler.js +147 -9
  153. package/node_modules/pi-lens/dist/clients/ruff-client.js +1 -1
  154. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +33 -5
  155. package/node_modules/pi-lens/dist/clients/runtime-context.js +6 -2
  156. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +77 -7
  157. package/node_modules/pi-lens/dist/clients/runtime-session.js +21 -2
  158. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +43 -12
  159. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +330 -85
  160. package/node_modules/pi-lens/dist/clients/runtime-turn.js +147 -17
  161. package/node_modules/pi-lens/dist/clients/safe-spawn.js +258 -5
  162. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +6 -0
  163. package/node_modules/pi-lens/dist/clients/session-event-guard.js +50 -5
  164. package/node_modules/pi-lens/dist/clients/sg-runner.js +23 -11
  165. package/node_modules/pi-lens/dist/clients/sgconfig.js +79 -2
  166. package/node_modules/pi-lens/dist/clients/test-runner-client.js +6 -41
  167. package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +43 -0
  168. package/node_modules/pi-lens/dist/clients/tool-agreement.js +423 -0
  169. package/node_modules/pi-lens/dist/clients/tool-config.js +50 -0
  170. package/node_modules/pi-lens/dist/clients/tool-cwd.js +47 -76
  171. package/node_modules/pi-lens/dist/clients/tool-policy.js +163 -7
  172. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +120 -0
  173. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +127 -189
  174. package/node_modules/pi-lens/dist/clients/widget-state.js +98 -0
  175. package/node_modules/pi-lens/dist/clients/word-index.js +5 -2
  176. package/node_modules/pi-lens/dist/clients/write-ordering-guard.js +7 -0
  177. package/node_modules/pi-lens/dist/index.js +27416 -24153
  178. package/node_modules/pi-lens/dist/mcp/server.js +5 -2
  179. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +7 -1
  180. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +168 -53
  181. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +244 -72
  182. package/node_modules/pi-lens/docs/audit1.md +5 -5
  183. package/node_modules/pi-lens/docs/dependencies.md +11 -0
  184. package/node_modules/pi-lens/docs/dispositions.md +52 -0
  185. package/node_modules/pi-lens/docs/environment-variables.md +2 -2
  186. package/node_modules/pi-lens/docs/features.md +4 -4
  187. package/node_modules/pi-lens/docs/globalconfig.md +3 -1
  188. package/node_modules/pi-lens/docs/language-coverage.md +1 -0
  189. package/node_modules/pi-lens/docs/pi-lens-fixer.md +53 -94
  190. package/node_modules/pi-lens/docs/pi-lens-investigator.md +43 -38
  191. package/node_modules/pi-lens/docs/pi-lens-retro.md +97 -0
  192. package/node_modules/pi-lens/docs/pi-lens-reviewer.md +53 -66
  193. package/node_modules/pi-lens/docs/release-qa-baseline.md +22 -0
  194. package/node_modules/pi-lens/docs/settings.md +7 -4
  195. package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +1 -1
  196. package/node_modules/pi-lens/docs/usage.md +2 -0
  197. package/node_modules/pi-lens/package.json +1 -1
  198. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/sql-injection.yml +24 -12
  199. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +40 -0
  200. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +15 -0
  201. package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +7 -0
  202. package/package.json +6 -11
  203. package/node_modules/@luxusai/pi-hindsight/CHANGELOG.md +0 -376
  204. package/node_modules/@luxusai/pi-hindsight/README.md +0 -92
  205. package/node_modules/@luxusai/pi-hindsight/docs/adr/001-memory-lifecycle-and-scope.md +0 -56
  206. package/node_modules/@luxusai/pi-hindsight/docs/adr/002-explicit-routing-strategy-seam.md +0 -169
  207. package/node_modules/@luxusai/pi-hindsight/docs/adr/003-tui-memory-mode-vocabulary.md +0 -107
  208. package/node_modules/@luxusai/pi-hindsight/docs/adr/004-lifeos-dual-bank-design.md +0 -89
  209. package/node_modules/@luxusai/pi-hindsight/docs/adr/005-domain-banks-and-agent-first-surface.md +0 -189
  210. package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark.webp +0 -0
  211. package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark@2x.webp +0 -0
  212. package/node_modules/@luxusai/pi-hindsight/docs/coding-memory-evaluation.md +0 -54
  213. package/node_modules/@luxusai/pi-hindsight/docs/compatibility.md +0 -75
  214. package/node_modules/@luxusai/pi-hindsight/docs/hindsight-core-functions.md +0 -300
  215. package/node_modules/@luxusai/pi-hindsight/docs/mission-and-mental-model-quality.md +0 -158
  216. package/node_modules/@luxusai/pi-hindsight/docs/next-opt-out-design.md +0 -164
  217. package/node_modules/@luxusai/pi-hindsight/docs/risky-memory-modes.md +0 -139
  218. package/node_modules/@luxusai/pi-hindsight/docs/starter-mental-model-suggestions.md +0 -74
  219. package/node_modules/@luxusai/pi-hindsight/docs/surface-reference.md +0 -261
  220. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-operations.ts +0 -151
  221. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-selection.ts +0 -18
  222. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-settings-presenter.ts +0 -46
  223. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-templates.ts +0 -383
  224. package/node_modules/@luxusai/pi-hindsight/extensions/banks/banking.ts +0 -240
  225. package/node_modules/@luxusai/pi-hindsight/extensions/banks/knowledge-page-seed.ts +0 -176
  226. package/node_modules/@luxusai/pi-hindsight/extensions/banks/retain-strategies.ts +0 -178
  227. package/node_modules/@luxusai/pi-hindsight/extensions/client/client-retry.ts +0 -41
  228. package/node_modules/@luxusai/pi-hindsight/extensions/client/client.ts +0 -386
  229. package/node_modules/@luxusai/pi-hindsight/extensions/client/fetch-compat.ts +0 -39
  230. package/node_modules/@luxusai/pi-hindsight/extensions/client/timeout.ts +0 -34
  231. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-defaults.ts +0 -140
  232. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-model.ts +0 -61
  233. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-registry.ts +0 -925
  234. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-field-paths.ts +0 -247
  235. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-normalize.ts +0 -547
  236. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-writer.ts +0 -480
  237. package/node_modules/@luxusai/pi-hindsight/extensions/config/config.ts +0 -182
  238. package/node_modules/@luxusai/pi-hindsight/extensions/config/setup-gate.ts +0 -86
  239. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-execute.ts +0 -1010
  240. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-parse.ts +0 -175
  241. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-plan.ts +0 -425
  242. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-presentation.ts +0 -210
  243. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-sessions.ts +0 -817
  244. package/node_modules/@luxusai/pi-hindsight/extensions/index.ts +0 -25
  245. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/git-seed.ts +0 -319
  246. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-recall.ts +0 -196
  247. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-retain.ts +0 -189
  248. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-runtime.ts +0 -65
  249. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle.ts +0 -260
  250. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/mental-models.ts +0 -244
  251. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/observation-scopes.ts +0 -59
  252. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-cleanup.ts +0 -82
  253. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-visibility.ts +0 -45
  254. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall.ts +0 -331
  255. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-cursor.ts +0 -354
  256. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-job-builder.ts +0 -66
  257. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-receipts.ts +0 -132
  258. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain.ts +0 -228
  259. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-bank-template-operations.ts +0 -74
  260. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-config-operations.ts +0 -16
  261. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-control-operations.ts +0 -648
  262. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-diagnostics-operations.ts +0 -105
  263. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-identity.ts +0 -68
  264. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-service.ts +0 -71
  265. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-types.ts +0 -13
  266. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-recall-operations.ts +0 -162
  267. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-retain-operations.ts +0 -131
  268. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-scope.ts +0 -104
  269. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-session-operations.ts +0 -37
  270. package/node_modules/@luxusai/pi-hindsight/extensions/operations/operation-catalog.ts +0 -893
  271. package/node_modules/@luxusai/pi-hindsight/extensions/operations/reflect-presenter.ts +0 -35
  272. package/node_modules/@luxusai/pi-hindsight/extensions/operations/scope-migrate.ts +0 -177
  273. package/node_modules/@luxusai/pi-hindsight/extensions/operations/tools.ts +0 -7
  274. package/node_modules/@luxusai/pi-hindsight/extensions/queue/flush-presenter.ts +0 -21
  275. package/node_modules/@luxusai/pi-hindsight/extensions/queue/jsonl-queue-store.ts +0 -112
  276. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-delivery.ts +0 -111
  277. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-lock.ts +0 -214
  278. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-operations.ts +0 -70
  279. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue.ts +0 -392
  280. package/node_modules/@luxusai/pi-hindsight/extensions/tui/bank-template-presentation.ts +0 -45
  281. package/node_modules/@luxusai/pi-hindsight/extensions/tui/commands.ts +0 -9
  282. package/node_modules/@luxusai/pi-hindsight/extensions/tui/guided-setup.ts +0 -860
  283. package/node_modules/@luxusai/pi-hindsight/extensions/tui/prefill-input.ts +0 -105
  284. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-flow.ts +0 -189
  285. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-server-probe.ts +0 -299
  286. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-actions.ts +0 -201
  287. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-facts.ts +0 -47
  288. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-render.ts +0 -239
  289. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-types.ts +0 -50
  290. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui.ts +0 -259
  291. package/node_modules/@luxusai/pi-hindsight/extensions/tui/tool-presenters.ts +0 -77
  292. package/node_modules/@luxusai/pi-hindsight/extensions/types.ts +0 -534
  293. package/node_modules/@luxusai/pi-hindsight/extensions/utils/diagnostics.ts +0 -319
  294. package/node_modules/@luxusai/pi-hindsight/extensions/utils/messages.ts +0 -325
  295. package/node_modules/@luxusai/pi-hindsight/extensions/utils/sanitize.ts +0 -42
  296. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-memory-meta.ts +0 -244
  297. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-operations.ts +0 -56
  298. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session.ts +0 -50
  299. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-fields.ts +0 -167
  300. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-health.ts +0 -207
  301. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status.ts +0 -120
  302. package/node_modules/@luxusai/pi-hindsight/extensions/version.ts +0 -8
  303. package/node_modules/@luxusai/pi-hindsight/package.json +0 -118
  304. package/node_modules/@luxusai/pi-hindsight/skills/hindsight-memory-doctor/SKILL.md +0 -75
@@ -1,1010 +0,0 @@
1
- import type { HindsightLikeClient, ResolvedConfig, RetainJob, UpdateMode } from "../types.js";
2
- import type { ImportBranch, ParsedSession } from "./import-parse.js";
3
- import { baseTags } from "../banks/banking.js";
4
- import { buildDurableRetainJob } from "../lifecycle/retain.js";
5
- import { createHash } from "node:crypto";
6
- import { createMemoryIdentity } from "../operations/memory-identity.js";
7
- import {
8
- enqueueRetain,
9
- flushRetain,
10
- readQueuedRetains,
11
- removeQueuedRetains,
12
- } from "../queue/queue.js";
13
- import { expandObservationScopes } from "../lifecycle/observation-scopes.js";
14
- import { hashImportContent, type ImportManifestEntry } from "./import-plan.js";
15
- import { importDocumentId, stableSessionId } from "../utils/session.js";
16
- import { isInjectedHindsightMemory, projectMessage, projectMessages } from "../utils/messages.js";
17
- import { redactSecrets } from "../utils/sanitize.js";
18
-
19
- export interface ImportRetainIdentity {
20
- bankId: string;
21
- documentId: string;
22
- updateMode: UpdateMode;
23
- sourceFile: string;
24
- cwd: string;
25
- sessionId: string;
26
- leafId: string;
27
- includeBranches: "current-only" | "all-leaves";
28
- importMode?: "curated" | "raw" | "forensic" | undefined;
29
- toolResults?: "errors-only" | "summary" | "content" | undefined;
30
- importQualityProfile?: "compatible" | "strict" | undefined;
31
- projectionVersion?: string | undefined;
32
- importProfile?: string | undefined;
33
- chunkIndex?: number | undefined;
34
- messageRange?: { start: number; end: number } | undefined;
35
- contentHash: string;
36
- }
37
-
38
- const IMPORT_RETAIN_METADATA_KEYS = [
39
- "pi_session_file",
40
- "imported",
41
- "cwd",
42
- "session_id",
43
- "branch_leaf_id",
44
- "import_mode",
45
- "import_quality_profile",
46
- "projection_version",
47
- "import_profile",
48
- "chunk_index",
49
- "message_range_start",
50
- "message_range_end",
51
- "content_hash",
52
- "include_branches",
53
- "tool_results",
54
- ] as const;
55
-
56
- function identityMetadata(identity: ImportRetainIdentity): Record<string, string | undefined> {
57
- return {
58
- pi_session_file: identity.sourceFile,
59
- imported: "true",
60
- cwd: identity.cwd,
61
- session_id: identity.sessionId,
62
- branch_leaf_id: identity.leafId,
63
- import_mode: identity.importMode,
64
- import_quality_profile: identity.importQualityProfile,
65
- projection_version: identity.projectionVersion,
66
- import_profile: identity.importProfile,
67
- ...(identity.chunkIndex !== undefined ? { chunk_index: String(identity.chunkIndex) } : {}),
68
- ...(identity.messageRange
69
- ? {
70
- message_range_start: String(identity.messageRange.start),
71
- message_range_end: String(identity.messageRange.end),
72
- }
73
- : {}),
74
- content_hash: identity.contentHash,
75
- include_branches: identity.includeBranches,
76
- tool_results: identity.toolResults,
77
- };
78
- }
79
-
80
- function recordEqual(
81
- left: Record<string, string> | undefined,
82
- right: Record<string, string> | undefined,
83
- ): boolean {
84
- const leftEntries = Object.entries(left ?? {}).sort(([a], [b]) => a.localeCompare(b));
85
- const rightEntries = Object.entries(right ?? {}).sort(([a], [b]) => a.localeCompare(b));
86
- return JSON.stringify(leftEntries) === JSON.stringify(rightEntries);
87
- }
88
-
89
- function stableEqual(left: unknown, right: unknown): boolean {
90
- return JSON.stringify(left ?? null) === JSON.stringify(right ?? null);
91
- }
92
-
93
- export function isImportRetainJob(job: RetainJob): boolean {
94
- return (
95
- job.item.metadata?.source === "pi-hindsight" &&
96
- job.item.metadata.retainSource === "import" &&
97
- job.item.metadata.imported === "true"
98
- );
99
- }
100
-
101
- export function importRetainJobMatchesReference(job: RetainJob, reference: RetainJob): boolean {
102
- return (
103
- job.bankId === reference.bankId &&
104
- job.documentId === reference.documentId &&
105
- job.updateMode === reference.updateMode &&
106
- isImportRetainJob(job) &&
107
- isImportRetainJob(reference) &&
108
- job.item.content === reference.item.content &&
109
- job.item.context === reference.item.context &&
110
- recordEqual(job.item.metadata, reference.item.metadata) &&
111
- stableEqual(job.item.tags, reference.item.tags) &&
112
- stableEqual(job.item.observationScopes, reference.item.observationScopes)
113
- );
114
- }
115
-
116
- export function staleImportRetainJobForReference(job: RetainJob, reference: RetainJob): boolean {
117
- return (
118
- job.bankId === reference.bankId &&
119
- job.documentId === reference.documentId &&
120
- isImportRetainJob(job) &&
121
- !importRetainJobMatchesReference(job, reference)
122
- );
123
- }
124
-
125
- export function importRetainJobMatchesIdentity(
126
- job: RetainJob,
127
- identity: ImportRetainIdentity,
128
- ): boolean {
129
- if (
130
- job.bankId !== identity.bankId ||
131
- job.documentId !== identity.documentId ||
132
- job.updateMode !== identity.updateMode ||
133
- !isImportRetainJob(job)
134
- ) {
135
- return false;
136
- }
137
- const expected = identityMetadata(identity);
138
- const metadata = job.item.metadata ?? {};
139
- return IMPORT_RETAIN_METADATA_KEYS.every((key) => metadata[key] === expected[key]);
140
- }
141
-
142
- export interface ImportRetainDeliveryArgs {
143
- cwd: string;
144
- config: ResolvedConfig;
145
- client: HindsightLikeClient;
146
- bankId: string;
147
- content: string;
148
- context: string;
149
- documentId: string;
150
- updateMode: UpdateMode;
151
- tags: string[];
152
- metadata?: Record<string, string>;
153
- observationScopes?: string[][];
154
- }
155
-
156
- export interface ImportRetainDeliveryResult {
157
- queueJobId: string;
158
- enqueued: boolean;
159
- delivered: boolean;
160
- sent: number;
161
- remaining: number;
162
- deadLettered: number;
163
- }
164
-
165
- function stillQueued(jobs: RetainJob[], jobId: string): boolean {
166
- return jobs.some((job) => job.id === jobId);
167
- }
168
-
169
- export async function deliverImportRetain(
170
- args: ImportRetainDeliveryArgs,
171
- ): Promise<ImportRetainDeliveryResult> {
172
- const job = buildDurableRetainJob({
173
- cwd: args.cwd,
174
- config: args.config,
175
- bankId: args.bankId,
176
- content: args.content,
177
- context: args.context,
178
- documentId: args.documentId,
179
- updateMode: args.updateMode,
180
- tags: args.tags,
181
- source: "import",
182
- ...(args.metadata ? { metadata: args.metadata } : {}),
183
- ...(args.observationScopes?.length ? { observationScopes: args.observationScopes } : {}),
184
- });
185
- await removeQueuedRetains(args.cwd, args.config, (queued) =>
186
- staleImportRetainJobForReference(queued, job),
187
- );
188
- const existing = await readQueuedRetains(args.cwd, args.config);
189
- const existingJob = existing.find((queued) => importRetainJobMatchesReference(queued, job));
190
- if (!existingJob) await enqueueRetain(args.cwd, args.config, job);
191
- const result = await flushRetain(args.cwd, args.config, args.client, {
192
- stopOnFirstFailure: true,
193
- });
194
- const queued = await readQueuedRetains(args.cwd, args.config);
195
- const queueJobId = existingJob?.id ?? job.id;
196
- return {
197
- queueJobId,
198
- enqueued: true,
199
- delivered: !stillQueued(queued, queueJobId),
200
- sent: result.sent,
201
- remaining: result.remaining,
202
- deadLettered: result.deadLettered,
203
- };
204
- }
205
-
206
- export const STRICT_SUCCESSFUL_TOOL_RESULT_MAX_BYTES = 2 * 1024;
207
-
208
- export type ImportNoiseDropReason =
209
- | "successful-tool-output"
210
- | "tool-filter-excluded"
211
- | "tool-result-empty"
212
- | "recalled-memory"
213
- | "empty-projection"
214
- | "ui-noise"
215
- | "process-noise"
216
- | "oversized-output"
217
- | "repeated-output";
218
-
219
- export interface ImportToolNoisePolicy {
220
- qualityProfile: ResolvedConfig["import"]["qualityProfile"];
221
- dropSuccessful: boolean;
222
- summaryMaxChars: number;
223
- strictSuccessfulToolResultMaxBytes: number;
224
- }
225
-
226
- export interface StrictImportNoiseState {
227
- seenSuccessfulToolResults: Set<string>;
228
- }
229
-
230
- export function createStrictImportNoiseState(): StrictImportNoiseState {
231
- return { seenSuccessfulToolResults: new Set<string>() };
232
- }
233
-
234
- export function resolveImportToolNoisePolicy(config: ResolvedConfig): ImportToolNoisePolicy {
235
- return {
236
- qualityProfile: config.import.qualityProfile,
237
- dropSuccessful: config.import.toolResults === "errors-only",
238
- summaryMaxChars: config.import.toolResultSummaryMaxChars,
239
- strictSuccessfulToolResultMaxBytes: STRICT_SUCCESSFUL_TOOL_RESULT_MAX_BYTES,
240
- };
241
- }
242
-
243
- export function importToolAllowed(
244
- name: string,
245
- filter: { include?: string[]; exclude?: string[] },
246
- ): boolean {
247
- if (filter.include && !filter.include.includes(name)) return false;
248
- return !filter.exclude?.includes(name);
249
- }
250
-
251
- function textFromToolResultContent(content: unknown): string {
252
- if (typeof content === "string") return content;
253
- if (typeof content === "number" || typeof content === "boolean" || typeof content === "bigint")
254
- return String(content);
255
- if (!Array.isArray(content)) return JSON.stringify(content ?? "");
256
- return content
257
- .map((part) => {
258
- if (typeof part === "string") return part;
259
- if (typeof part === "number" || typeof part === "boolean" || typeof part === "bigint")
260
- return String(part);
261
- if (part && typeof part === "object") {
262
- const record = part as Record<string, unknown>;
263
- if (typeof record.text === "string") return record.text;
264
- if (typeof record.content === "string") return record.content;
265
- if (typeof record.output === "string") return record.output;
266
- }
267
- return JSON.stringify(part ?? "");
268
- })
269
- .filter(Boolean)
270
- .join("\n");
271
- }
272
-
273
- function normalizedName(value: unknown): string {
274
- return typeof value === "string" ? value.trim().toLowerCase() : "";
275
- }
276
-
277
- function matchesAny(value: string, patterns: RegExp[]): boolean {
278
- return patterns.some((pattern) => pattern.test(value));
279
- }
280
-
281
- const UI_NOISE_NAMES = new Set([
282
- "ui",
283
- "progress",
284
- "spinner",
285
- "toast",
286
- "notification",
287
- "render",
288
- "message_update",
289
- "extension_ui_request",
290
- ]);
291
-
292
- const PROCESS_NOISE_NAMES = new Set([
293
- "process",
294
- "process-status",
295
- "status",
296
- "watcher",
297
- "watch",
298
- "ci-status",
299
- "check-status",
300
- ]);
301
-
302
- const UI_NOISE_PATTERNS = [/\bspinner\b/i, /\btoast\b/i, /\bprogress ui\b/i, /\bmessage update\b/i];
303
- const PROCESS_NOISE_PATTERNS = [
304
- /\brefreshing checks status\b/i,
305
- /\bchecks? (still )?pending\b/i,
306
- /\bwatcher (pending|continues|running)\b/i,
307
- /\bwaiting for ci\b/i,
308
- /\bprocess status\b/i,
309
- ];
310
-
311
- function messageTypeNames(message: Record<string, unknown>): string[] {
312
- return [message.type, message.customType, message.event, message.kind]
313
- .map(normalizedName)
314
- .filter(Boolean);
315
- }
316
-
317
- export function summarizeToolResultContent(content: unknown, maxChars: number): string {
318
- const text = typeof content === "string" ? content : JSON.stringify(content ?? "");
319
- return text.length > maxChars ? `${text.slice(0, maxChars)}…` : text;
320
- }
321
-
322
- function successfulToolResultFingerprint(name: string, contentText: string): string {
323
- return createHash("sha256")
324
- .update(name)
325
- .update("\0")
326
- .update(contentText.trim().replace(/\s+/g, " "))
327
- .digest("hex");
328
- }
329
-
330
- export function strictSuccessfulToolResultDropReason(
331
- message: Record<string, unknown>,
332
- policy: ImportToolNoisePolicy,
333
- state: StrictImportNoiseState,
334
- ): ImportNoiseDropReason | undefined {
335
- if (policy.qualityProfile !== "strict") return undefined;
336
- if (message.role !== "toolResult" || message.isError === true) return undefined;
337
-
338
- const toolName = normalizedName(message.name ?? message.toolName ?? message.tool);
339
- const typeNames = messageTypeNames(message);
340
- const contentText = textFromToolResultContent(message.content);
341
- const contentBytes = Buffer.byteLength(contentText, "utf8");
342
- const combined = `${toolName}\n${typeNames.join("\n")}\n${contentText}`;
343
-
344
- if (UI_NOISE_NAMES.has(toolName) || typeNames.some((type) => UI_NOISE_NAMES.has(type)))
345
- return "ui-noise";
346
- if (
347
- PROCESS_NOISE_NAMES.has(toolName) ||
348
- typeNames.some((type) => PROCESS_NOISE_NAMES.has(type)) ||
349
- matchesAny(combined, PROCESS_NOISE_PATTERNS)
350
- ) {
351
- return "process-noise";
352
- }
353
- if (matchesAny(combined, UI_NOISE_PATTERNS)) return "ui-noise";
354
- if (!contentText.trim()) return "tool-result-empty";
355
- if (contentBytes > policy.strictSuccessfulToolResultMaxBytes) return "oversized-output";
356
-
357
- const fingerprint = successfulToolResultFingerprint(toolName, contentText);
358
- if (state.seenSuccessfulToolResults.has(fingerprint)) return "repeated-output";
359
- state.seenSuccessfulToolResults.add(fingerprint);
360
- return undefined;
361
- }
362
-
363
- export type CuratedImportKeepReason =
364
- | "user-text"
365
- | "assistant-text"
366
- | "tool-error-kept"
367
- | "message-kept";
368
-
369
- export type CuratedImportDropReason = ImportNoiseDropReason;
370
-
371
- export type CuratedImportReason = CuratedImportKeepReason | CuratedImportDropReason;
372
-
373
- export interface CuratedImportClassification {
374
- original: Record<string, unknown>;
375
- stableMessage: Record<string, unknown>;
376
- projectedMessages: Record<string, unknown>[];
377
- decision: "keep" | "drop";
378
- reasons: CuratedImportReason[];
379
- rawBytes: number;
380
- projectedBytes: number;
381
- toolName?: string;
382
- toolResultDropped?: boolean;
383
- toolErrorKept?: boolean;
384
- }
385
-
386
- export interface CuratedImportProjection {
387
- messages: Record<string, unknown>[];
388
- rawBytes: number;
389
- projectedBytes: number;
390
- droppedToolResultCount: number;
391
- droppedToolResultBytes: number;
392
- droppedTools: Array<{ name: string; count: number; bytes: number }>;
393
- topDroppedTools: Array<{ name: string; count: number; bytes: number }>;
394
- keptToolErrorCount: number;
395
- keptToolErrorBytes: number;
396
- estimatedChunkCount: number;
397
- classificationReasonCounts: Partial<Record<CuratedImportReason, number>>;
398
- classifications: CuratedImportClassification[];
399
- }
400
-
401
- export function importByteLength(value: unknown): number {
402
- return Buffer.byteLength(JSON.stringify(value), "utf8");
403
- }
404
-
405
- export function importToolName(message: Record<string, unknown>): string {
406
- const name = message.name ?? message.toolName ?? message.tool;
407
- return typeof name === "string" && name.trim() ? name : "unknown";
408
- }
409
-
410
- export function stableProjectionMessage(message: Record<string, unknown>): Record<string, unknown> {
411
- const timestamp = message.timestamp;
412
- const parsedTimestamp = typeof timestamp === "string" ? Date.parse(timestamp) : undefined;
413
- return {
414
- ...message,
415
- timestamp:
416
- typeof timestamp === "number"
417
- ? timestamp
418
- : typeof parsedTimestamp === "number" && Number.isFinite(parsedTimestamp)
419
- ? parsedTimestamp
420
- : 0,
421
- };
422
- }
423
-
424
- function mergeImportProvenance(
425
- original: Record<string, unknown>,
426
- projectedMessages: Record<string, unknown>[],
427
- ): Record<string, unknown>[] {
428
- return projectedMessages.map((message) => ({
429
- ...(original.id !== undefined ? { id: original.id } : {}),
430
- ...(original.parentId !== undefined ? { parentId: original.parentId } : {}),
431
- ...message,
432
- }));
433
- }
434
-
435
- function keepReason(message: Record<string, unknown>): CuratedImportKeepReason {
436
- if (message.role === "user") return "user-text";
437
- if (message.role === "assistant") return "assistant-text";
438
- if (message.role === "toolResult" && message.isError === true) return "tool-error-kept";
439
- return "message-kept";
440
- }
441
-
442
- function dropReasons(
443
- message: Record<string, unknown>,
444
- projectedMessages: Record<string, unknown>[],
445
- config: ResolvedConfig,
446
- strictDropReason?: ImportNoiseDropReason,
447
- ): CuratedImportDropReason[] {
448
- if (isInjectedHindsightMemory(message)) return ["recalled-memory"];
449
- if (strictDropReason) return [strictDropReason];
450
- if (!projectedMessages.length && message.role === "toolResult" && message.isError !== true) {
451
- if (!importToolAllowed(importToolName(message), config.retain.toolFilter.toolResult))
452
- return ["tool-filter-excluded"];
453
- return ["successful-tool-output"];
454
- }
455
- return ["empty-projection"];
456
- }
457
-
458
- interface CuratedImportProjectionDecision {
459
- projectedMessages: Record<string, unknown>[];
460
- strictDropReason?: ImportNoiseDropReason;
461
- }
462
-
463
- function projectCuratedImportMessage(
464
- stableMessage: Record<string, unknown>,
465
- config: ResolvedConfig,
466
- strictState: StrictImportNoiseState,
467
- ): CuratedImportProjectionDecision {
468
- if (stableMessage.role !== "toolResult" || stableMessage.isError === true) {
469
- return { projectedMessages: projectMessages([stableMessage as never], config) };
470
- }
471
- const policy = resolveImportToolNoisePolicy(config);
472
- if (!importToolAllowed(importToolName(stableMessage), config.retain.toolFilter.toolResult)) {
473
- return { projectedMessages: [] };
474
- }
475
- const strictDropReason = strictSuccessfulToolResultDropReason(stableMessage, policy, strictState);
476
- if (strictDropReason || policy.dropSuccessful)
477
- return { projectedMessages: [], ...(strictDropReason ? { strictDropReason } : {}) };
478
- const projected = projectMessage(stableMessage as never, {
479
- ...config,
480
- retain: {
481
- ...config.retain,
482
- content: {
483
- ...config.retain.content,
484
- toolResult: config.import.toolResults === "content" ? ["content"] : ["summary"],
485
- },
486
- },
487
- });
488
- return {
489
- projectedMessages: [
490
- config.import.toolResults === "summary"
491
- ? {
492
- ...projected,
493
- content: summarizeToolResultContent(stableMessage.content, policy.summaryMaxChars),
494
- }
495
- : projected,
496
- ],
497
- };
498
- }
499
-
500
- export function classifyCuratedImportMessage(
501
- message: Record<string, unknown>,
502
- config: ResolvedConfig,
503
- strictState: StrictImportNoiseState = createStrictImportNoiseState(),
504
- ): CuratedImportClassification {
505
- const stableMessage = stableProjectionMessage(message);
506
- const projectionDecision = projectCuratedImportMessage(stableMessage, config, strictState);
507
- const projectedMessages = mergeImportProvenance(
508
- stableMessage,
509
- projectionDecision.projectedMessages,
510
- );
511
- const decision = projectedMessages.length ? "keep" : "drop";
512
- const reasons =
513
- decision === "keep"
514
- ? [keepReason(stableMessage)]
515
- : dropReasons(stableMessage, projectedMessages, config, projectionDecision.strictDropReason);
516
- const rawBytes = importByteLength(stableMessage);
517
- const projectedBytes = importByteLength(projectedMessages);
518
- return {
519
- original: message,
520
- stableMessage,
521
- projectedMessages,
522
- decision,
523
- reasons,
524
- rawBytes,
525
- projectedBytes,
526
- ...(stableMessage.role === "toolResult" ? { toolName: importToolName(stableMessage) } : {}),
527
- ...(stableMessage.role === "toolResult" && decision === "drop"
528
- ? { toolResultDropped: true }
529
- : {}),
530
- ...(stableMessage.role === "toolResult" && stableMessage.isError === true && decision === "keep"
531
- ? { toolErrorKept: true }
532
- : {}),
533
- };
534
- }
535
-
536
- function incrementReasonCounts(
537
- counts: Partial<Record<CuratedImportReason, number>>,
538
- reasons: CuratedImportReason[],
539
- ): void {
540
- for (const reason of reasons) counts[reason] = (counts[reason] ?? 0) + 1;
541
- }
542
-
543
- export function buildCuratedImportProjection(
544
- messages: Array<{ data: Record<string, unknown> }>,
545
- config: ResolvedConfig,
546
- ): CuratedImportProjection {
547
- const droppedTools = new Map<string, { count: number; bytes: number }>();
548
- const classificationReasonCounts: Partial<Record<CuratedImportReason, number>> = {};
549
- const strictState = createStrictImportNoiseState();
550
- const classifications = messages.map((message) =>
551
- classifyCuratedImportMessage(message.data, config, strictState),
552
- );
553
- const projected = classifications.flatMap((classification) => {
554
- incrementReasonCounts(classificationReasonCounts, classification.reasons);
555
- if (classification.toolResultDropped) {
556
- const name = classification.toolName ?? "unknown";
557
- const current = droppedTools.get(name) ?? { count: 0, bytes: 0 };
558
- droppedTools.set(name, {
559
- count: current.count + 1,
560
- bytes: current.bytes + classification.rawBytes,
561
- });
562
- }
563
- return classification.projectedMessages;
564
- });
565
- const keptToolErrors = classifications.filter((classification) => classification.toolErrorKept);
566
- return {
567
- messages: projected,
568
- rawBytes: classifications.reduce((total, classification) => total + classification.rawBytes, 0),
569
- projectedBytes: importByteLength(projected),
570
- droppedToolResultCount: [...droppedTools.values()].reduce(
571
- (total, tool) => total + tool.count,
572
- 0,
573
- ),
574
- droppedToolResultBytes: [...droppedTools.values()].reduce(
575
- (total, tool) => total + tool.bytes,
576
- 0,
577
- ),
578
- keptToolErrorCount: keptToolErrors.length,
579
- keptToolErrorBytes: keptToolErrors.reduce(
580
- (total, classification) => total + classification.rawBytes,
581
- 0,
582
- ),
583
- estimatedChunkCount: Math.max(1, Math.ceil(importByteLength(projected) / 8_000)),
584
- droppedTools: [...droppedTools]
585
- .map(([name, value]) => ({ name, ...value }))
586
- .sort(
587
- (left, right) =>
588
- right.bytes - left.bytes ||
589
- right.count - left.count ||
590
- left.name.localeCompare(right.name),
591
- ),
592
- topDroppedTools: [...droppedTools]
593
- .map(([name, value]) => ({ name, ...value }))
594
- .sort(
595
- (left, right) =>
596
- right.bytes - left.bytes ||
597
- right.count - left.count ||
598
- left.name.localeCompare(right.name),
599
- )
600
- .slice(0, 5),
601
- classificationReasonCounts,
602
- classifications,
603
- };
604
- }
605
-
606
- export interface ImportRetainArgs {
607
- sessionFile: string;
608
- bankId: string;
609
- client: HindsightLikeClient;
610
- config: ResolvedConfig;
611
- parsed: ParsedSession;
612
- cwd: string;
613
- sessionId: string;
614
- leaves: string[];
615
- branch: ImportBranch;
616
- }
617
-
618
- export interface ImportDocumentPreview {
619
- documentId: string;
620
- leafId: string;
621
- messageCount: number;
622
- rawMessageCount?: number;
623
- projectedMessageCount?: number;
624
- rawBytes?: number;
625
- projectedBytes?: number;
626
- droppedToolResultCount?: number;
627
- droppedToolResultBytes?: number;
628
- droppedTools?: Array<{ name: string; count: number; bytes: number }>;
629
- topDroppedTools?: Array<{ name: string; count: number; bytes: number }>;
630
- keptToolErrorCount?: number;
631
- keptToolErrorBytes?: number;
632
- classificationReasonCounts?: Record<string, number>;
633
- estimatedDocumentCount?: number;
634
- estimatedChunkCount?: number;
635
- importMode?: ResolvedConfig["import"]["mode"];
636
- importQualityProfile?: ResolvedConfig["import"]["qualityProfile"];
637
- projectionVersion?: string;
638
- importProfile?: string;
639
- chunkIndex?: number;
640
- messageRange?: { start: number; end: number };
641
- contentHash: string;
642
- contentBytes: number;
643
- tags: string[];
644
- updateMode: "append" | "replace";
645
- bankId: string;
646
- wouldWrite: boolean;
647
- status: "pending" | "queued" | "completed" | "failed" | "skipped";
648
- skipReason?: "already-imported" | "empty-curated-projection";
649
- error?: string;
650
- }
651
-
652
- export interface ImportRetainResult {
653
- document: ImportDocumentPreview;
654
- manifestEntry: ImportManifestEntry;
655
- }
656
-
657
- export class ImportRetainQueuedError extends Error {
658
- readonly code = "IMPORT_RETAIN_QUEUED";
659
-
660
- constructor(message: string) {
661
- super(message);
662
- this.name = "ImportRetainQueuedError";
663
- }
664
- }
665
-
666
- export function isImportRetainQueuedError(error: unknown): error is ImportRetainQueuedError {
667
- return error instanceof ImportRetainQueuedError;
668
- }
669
-
670
- interface ImportBranchBuildResult extends ImportRetainResult {
671
- content: string;
672
- context: string;
673
- observationScopes: string[][];
674
- }
675
-
676
- function resolvedParentSessionId(parsed: ParsedSession, cwd: string): string | undefined {
677
- return (
678
- parsed.parentSessionId ??
679
- (parsed.parentSessionFile ? stableSessionId(parsed.parentSessionFile, cwd) : undefined)
680
- );
681
- }
682
-
683
- const CURATED_PROJECTION_VERSION = "curated-turns-v1";
684
-
685
- interface ImportChunk {
686
- index: number;
687
- messages: Array<{ message: ImportBranch["messages"][number]; originalIndex: number }>;
688
- start: number;
689
- end: number;
690
- }
691
-
692
- function chunkCuratedMessages(
693
- messages: ImportBranch["messages"],
694
- config: ResolvedConfig,
695
- ): ImportChunk[] {
696
- const indexed = messages.map((message, originalIndex) => ({ message, originalIndex }));
697
- const turns: ImportChunk[] = [];
698
- let current: ImportChunk["messages"] = [];
699
- for (const entry of indexed) {
700
- if (entry.message.data.role === "user" && current.length) {
701
- turns.push({
702
- index: turns.length,
703
- messages: current,
704
- start: current[0]!.originalIndex,
705
- end: current.at(-1)!.originalIndex,
706
- });
707
- current = [];
708
- }
709
- current.push(entry);
710
- }
711
- if (current.length)
712
- turns.push({
713
- index: turns.length,
714
- messages: current,
715
- start: current[0]!.originalIndex,
716
- end: current.at(-1)!.originalIndex,
717
- });
718
- const chunks: ImportChunk[] = [];
719
- let chunk: ImportChunk["messages"] = [];
720
- let turnCount = 0;
721
- const flush = () => {
722
- if (!chunk.length) return;
723
- chunks.push({
724
- index: chunks.length,
725
- messages: chunk,
726
- start: chunk[0]!.originalIndex,
727
- end: chunk.at(-1)!.originalIndex,
728
- });
729
- chunk = [];
730
- turnCount = 0;
731
- };
732
- for (const turn of turns) {
733
- const nextMessages = [...chunk, ...turn.messages];
734
- const wouldOverflowTurns = turnCount >= config.import.turnsPerDocument;
735
- const wouldOverflowBytes =
736
- chunk.length > 0 &&
737
- importByteLength(nextMessages.map((entry) => entry.message.data)) >
738
- config.import.maxDocumentBytes;
739
- if (wouldOverflowTurns || wouldOverflowBytes) flush();
740
- chunk.push(...turn.messages);
741
- turnCount += 1;
742
- }
743
- flush();
744
- return chunks.length ? chunks : [{ index: 0, messages: [], start: 0, end: 0 }];
745
- }
746
-
747
- function curatedImportProfile(config: ResolvedConfig): string {
748
- return `turns-${config.import.turnsPerDocument}-bytes-${config.import.maxDocumentBytes}`;
749
- }
750
-
751
- function shouldSurfaceImportQualityProfile(config: ResolvedConfig): boolean {
752
- return config.import.mode === "curated" && config.import.qualityProfile !== "compatible";
753
- }
754
-
755
- function importChunkDocumentId(args: {
756
- sessionId: string;
757
- leafId: string;
758
- mode: ResolvedConfig["import"]["mode"];
759
- profile?: string;
760
- chunk?: ImportChunk;
761
- }): string {
762
- if (args.mode !== "curated" || !args.chunk || !args.profile)
763
- return importDocumentId(args.sessionId, args.leafId);
764
- return `${importDocumentId(args.sessionId, args.leafId)}:${args.profile}:${CURATED_PROJECTION_VERSION}:chunk-${args.chunk.index}-${args.chunk.start}-${args.chunk.end}`;
765
- }
766
-
767
- function buildImportBranch(args: Omit<ImportRetainArgs, "client">): ImportBranchBuildResult[] {
768
- const leafId = args.branch.leafId;
769
- const parentSessionId = resolvedParentSessionId(args.parsed, args.cwd);
770
- const mode = args.config.import.mode;
771
- const branchMessages =
772
- mode === "forensic"
773
- ? args.branch.messages
774
- : args.branch.messages.filter((message) => !isInjectedHindsightMemory(message.data));
775
- const chunks =
776
- mode === "curated"
777
- ? chunkCuratedMessages(branchMessages, args.config)
778
- : [
779
- {
780
- index: 0,
781
- messages: branchMessages.map((message, originalIndex) => ({ message, originalIndex })),
782
- start: 0,
783
- end: Math.max(0, branchMessages.length - 1),
784
- },
785
- ];
786
- const updateMode = args.config.import.replaceExistingImportedDocs ? "replace" : "append";
787
- const identity = createMemoryIdentity(args.cwd, args.config, args.sessionFile);
788
- const observationScopes = args.config.observations.enabled
789
- ? expandObservationScopes(args.config.observations.scopes, {
790
- ...identity,
791
- sessionId: args.sessionId,
792
- projectBankId: args.bankId,
793
- })
794
- : [];
795
-
796
- return chunks.map((chunk) => {
797
- const chunkMessages = chunk.messages.map((entry) => entry.message);
798
- const projection =
799
- mode === "curated"
800
- ? buildCuratedImportProjection(chunkMessages, args.config)
801
- : {
802
- messages: chunkMessages.map((message) => stableProjectionMessage(message.data)),
803
- rawBytes: chunkMessages.reduce(
804
- (total, message) => total + importByteLength(message.data),
805
- 0,
806
- ),
807
- projectedBytes: importByteLength(chunkMessages.map((message) => message.data)),
808
- droppedToolResultCount: 0,
809
- droppedToolResultBytes: 0,
810
- droppedTools: [],
811
- topDroppedTools: [],
812
- keptToolErrorCount: chunkMessages.filter(
813
- (message) => message.data.role === "toolResult" && message.data.isError === true,
814
- ).length,
815
- keptToolErrorBytes: chunkMessages
816
- .filter(
817
- (message) => message.data.role === "toolResult" && message.data.isError === true,
818
- )
819
- .reduce((total, message) => total + importByteLength(message.data), 0),
820
- estimatedChunkCount: Math.max(
821
- 1,
822
- Math.ceil(importByteLength(chunkMessages.map((message) => message.data)) / 8_000),
823
- ),
824
- };
825
- const importProfile = mode === "curated" ? curatedImportProfile(args.config) : undefined;
826
- const documentId = importChunkDocumentId({
827
- sessionId: args.sessionId,
828
- leafId,
829
- mode,
830
- ...(importProfile ? { profile: importProfile } : {}),
831
- chunk,
832
- });
833
- const projectionVersion = mode === "curated" ? CURATED_PROJECTION_VERSION : undefined;
834
- const messageRange = { start: chunk.start, end: chunk.end };
835
- const contentRaw = JSON.stringify(
836
- {
837
- source: "pi-session-import",
838
- sessionFile: args.sessionFile,
839
- cwd: args.cwd,
840
- sessionId: args.sessionId,
841
- ...(parentSessionId ? { parentSessionId } : {}),
842
- ...(args.parsed.parentSessionFile
843
- ? { parentSessionFile: args.parsed.parentSessionFile }
844
- : {}),
845
- branchLeafId: leafId,
846
- projection:
847
- mode === "curated"
848
- ? projectionVersion
849
- : mode === "forensic"
850
- ? "forensic-raw-v1"
851
- : "raw-v1",
852
- ...(shouldSurfaceImportQualityProfile(args.config)
853
- ? { importQualityProfile: args.config.import.qualityProfile }
854
- : {}),
855
- ...(mode === "curated" ? { chunkIndex: chunk.index, messageRange } : {}),
856
- projectedMessageCount: projection.messages.length,
857
- messages:
858
- mode === "curated" ? projection.messages : chunkMessages.map((message) => message.data),
859
- },
860
- null,
861
- 2,
862
- );
863
- const content = args.config.retain.redactSecrets ? redactSecrets(contentRaw) : contentRaw;
864
- const contentHash = hashImportContent(content);
865
- const tags = [
866
- ...baseTags(args.cwd, args.sessionId, leafId, args.config),
867
- "import:historical",
868
- "imported:true",
869
- `document:${documentId}`,
870
- ];
871
- if (parentSessionId) tags.push(`parent:${parentSessionId}`);
872
- if (args.leaves.length > 1) tags.push("forked:true");
873
- const document: ImportDocumentPreview = {
874
- documentId,
875
- leafId,
876
- messageCount: chunkMessages.length,
877
- rawMessageCount: chunkMessages.length,
878
- projectedMessageCount: projection.messages.length,
879
- rawBytes: projection.rawBytes,
880
- projectedBytes: projection.projectedBytes,
881
- droppedToolResultCount: projection.droppedToolResultCount,
882
- droppedToolResultBytes: projection.droppedToolResultBytes,
883
- ...("droppedTools" in projection ? { droppedTools: projection.droppedTools } : {}),
884
- topDroppedTools: projection.topDroppedTools,
885
- keptToolErrorCount: projection.keptToolErrorCount,
886
- keptToolErrorBytes: projection.keptToolErrorBytes,
887
- ...("classificationReasonCounts" in projection
888
- ? { classificationReasonCounts: projection.classificationReasonCounts }
889
- : {}),
890
- estimatedDocumentCount: chunks.length,
891
- estimatedChunkCount: projection.estimatedChunkCount,
892
- importMode: mode,
893
- ...(shouldSurfaceImportQualityProfile(args.config)
894
- ? { importQualityProfile: args.config.import.qualityProfile }
895
- : {}),
896
- ...(projectionVersion ? { projectionVersion } : {}),
897
- ...(importProfile ? { importProfile } : {}),
898
- ...(mode === "curated" ? { chunkIndex: chunk.index, messageRange } : {}),
899
- contentHash,
900
- contentBytes: Buffer.byteLength(content, "utf8"),
901
- tags,
902
- updateMode,
903
- bankId: args.bankId,
904
- wouldWrite: !(mode === "curated" && projection.messages.length === 0),
905
- status:
906
- mode === "curated" && projection.messages.length === 0
907
- ? ("skipped" as const)
908
- : ("pending" as const),
909
- ...(mode === "curated" && projection.messages.length === 0
910
- ? { skipReason: "empty-curated-projection" as const }
911
- : {}),
912
- };
913
- const manifestEntry: ImportManifestEntry = {
914
- documentId,
915
- bankId: args.bankId,
916
- sourceFile: args.sessionFile,
917
- importedAt: new Date().toISOString(),
918
- contentHash,
919
- messageCount: chunkMessages.length,
920
- leafId,
921
- sessionId: args.sessionId,
922
- cwd: args.cwd,
923
- includeBranches: args.config.import.includeBranches,
924
- importMode: mode,
925
- toolResults: args.config.import.toolResults,
926
- ...(shouldSurfaceImportQualityProfile(args.config)
927
- ? { importQualityProfile: args.config.import.qualityProfile }
928
- : {}),
929
- ...(projectionVersion ? { projectionVersion } : {}),
930
- ...(importProfile ? { importProfile } : {}),
931
- ...(mode === "curated" ? { chunkIndex: chunk.index, messageRange } : {}),
932
- updateMode,
933
- };
934
- return {
935
- document,
936
- manifestEntry,
937
- content,
938
- context: `Historical Pi session import from ${args.sessionFile}, branch ${leafId}, chunk ${chunk.index}`,
939
- observationScopes,
940
- };
941
- });
942
- }
943
-
944
- export function previewImportBranch(args: Omit<ImportRetainArgs, "client">): ImportRetainResult[] {
945
- return buildImportBranch(args).map((built) => ({
946
- document: { ...built.document, wouldWrite: false },
947
- manifestEntry: built.manifestEntry,
948
- }));
949
- }
950
-
951
- export async function retainImportBranch(
952
- args: ImportRetainArgs & { documentId: string },
953
- ): Promise<ImportRetainResult> {
954
- const built = buildImportBranch(args).find(
955
- (candidate) => candidate.document.documentId === args.documentId,
956
- );
957
- if (!built)
958
- throw new Error(`Import document ${args.documentId} no longer exists in import plan.`);
959
- const parentSessionId = resolvedParentSessionId(args.parsed, args.cwd);
960
- const retainResult = await deliverImportRetain({
961
- cwd: args.cwd,
962
- config: args.config,
963
- client: args.client,
964
- bankId: args.bankId,
965
- content: built.content,
966
- context: built.context,
967
- documentId: built.document.documentId,
968
- updateMode: built.document.updateMode,
969
- tags: built.document.tags,
970
- metadata: {
971
- pi_session_file: args.sessionFile,
972
- imported: "true",
973
- cwd: args.cwd,
974
- session_id: args.sessionId,
975
- ...(parentSessionId ? { parent_session_id: parentSessionId } : {}),
976
- ...(args.parsed.parentSessionFile
977
- ? { parent_session_file: args.parsed.parentSessionFile }
978
- : {}),
979
- branch_leaf_id: built.document.leafId,
980
- import_mode: args.config.import.mode,
981
- ...(shouldSurfaceImportQualityProfile(args.config)
982
- ? { import_quality_profile: args.config.import.qualityProfile }
983
- : {}),
984
- ...(built.document.projectionVersion
985
- ? { projection_version: built.document.projectionVersion }
986
- : {}),
987
- ...(built.document.importProfile ? { import_profile: built.document.importProfile } : {}),
988
- ...(built.document.chunkIndex !== undefined
989
- ? { chunk_index: String(built.document.chunkIndex) }
990
- : {}),
991
- ...(built.document.messageRange
992
- ? {
993
- message_range_start: String(built.document.messageRange.start),
994
- message_range_end: String(built.document.messageRange.end),
995
- }
996
- : {}),
997
- content_hash: built.document.contentHash,
998
- include_branches: args.config.import.includeBranches,
999
- tool_results: args.config.import.toolResults,
1000
- ...(args.parsed.sessionTimestamp ? { session_timestamp: args.parsed.sessionTimestamp } : {}),
1001
- },
1002
- ...(built.observationScopes.length ? { observationScopes: built.observationScopes } : {}),
1003
- });
1004
- if (!retainResult.delivered) {
1005
- throw new ImportRetainQueuedError(
1006
- `Hindsight import retain queued as ${retainResult.queueJobId}; ${retainResult.remaining} retain job${retainResult.remaining === 1 ? "" : "s"} pending`,
1007
- );
1008
- }
1009
- return { document: built.document, manifestEntry: built.manifestEntry };
1010
- }