@herbertgao/pi-extensions 2026.9.5 → 2026.9.7

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 (276) hide show
  1. package/README.md +5 -22
  2. package/THIRD_PARTY_NOTICES.md +0 -4
  3. package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +1 -1
  4. package/node_modules/@herbertgao/sol-pi/package.json +1 -1
  5. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/index.ts +0 -5
  6. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/state.ts +3 -1
  7. package/node_modules/@narumitw/pi-btw/README.md +2 -0
  8. package/node_modules/@narumitw/pi-btw/dist/index.ts +284 -365
  9. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +3 -3
  10. package/node_modules/@narumitw/pi-btw/package.json +52 -53
  11. package/node_modules/@narumitw/pi-btw/src/bring-to-main.ts +494 -547
  12. package/node_modules/@narumitw/pi-btw/src/btw.ts +814 -856
  13. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +673 -674
  14. package/node_modules/@narumitw/pi-btw/src/keybindings.ts +228 -270
  15. package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +309 -318
  16. package/node_modules/@narumitw/pi-btw/src/menu.ts +416 -454
  17. package/node_modules/@narumitw/pi-btw/src/settings.ts +203 -219
  18. package/node_modules/@narumitw/pi-btw/src/side-thread.ts +173 -201
  19. package/node_modules/@narumitw/pi-btw/src/text.ts +21 -23
  20. package/node_modules/@narumitw/pi-btw/src/transcript-markdown.ts +65 -0
  21. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +611 -662
  22. package/node_modules/pi-lens/CHANGELOG.md +239 -0
  23. package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +3 -0
  24. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +30 -4
  25. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +2 -0
  26. package/node_modules/pi-lens/dist/clients/bash-file-access.js +26 -0
  27. package/node_modules/pi-lens/dist/clients/biome-client.js +1 -1
  28. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +403 -35
  29. package/node_modules/pi-lens/dist/clients/bootstrap.js +6 -1
  30. package/node_modules/pi-lens/dist/clients/cascade-format.js +200 -4
  31. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +10 -2
  32. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +16 -1
  33. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +12 -1
  34. package/node_modules/pi-lens/dist/clients/dispatch/ast-grep-catalog.js +65 -0
  35. package/node_modules/pi-lens/dist/clients/dispatch/auxiliary-lsp.js +28 -0
  36. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +9 -2
  37. package/node_modules/pi-lens/dist/clients/dispatch/finding-policy.js +222 -0
  38. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +389 -13
  39. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +175 -25
  40. package/node_modules/pi-lens/dist/clients/dispatch/rule-ignores.js +62 -0
  41. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +21 -41
  42. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +6 -1
  43. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +7 -7
  44. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -12
  45. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +2 -21
  46. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +1 -1
  47. package/node_modules/pi-lens/dist/clients/dispatch/types.js +4 -1
  48. package/node_modules/pi-lens/dist/clients/disposition-publish.js +1 -0
  49. package/node_modules/pi-lens/dist/clients/effective-config.js +1 -1
  50. package/node_modules/pi-lens/dist/clients/file-kinds.js +26 -1
  51. package/node_modules/pi-lens/dist/clients/file-role.js +21 -21
  52. package/node_modules/pi-lens/dist/clients/file-utils.js +156 -10
  53. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +56 -9
  54. package/node_modules/pi-lens/dist/clients/format-service.js +39 -21
  55. package/node_modules/pi-lens/dist/clients/formatters.js +60 -13
  56. package/node_modules/pi-lens/dist/clients/generation-guard.js +2 -2
  57. package/node_modules/pi-lens/dist/clients/git-guard.js +11 -3
  58. package/node_modules/pi-lens/dist/clients/indent-retarget.js +78 -8
  59. package/node_modules/pi-lens/dist/clients/installer/index.js +333 -114
  60. package/node_modules/pi-lens/dist/clients/instance-reaper-state.js +7 -0
  61. package/node_modules/pi-lens/dist/clients/instance-reaper.js +20 -10
  62. package/node_modules/pi-lens/dist/clients/language-profile.js +23 -1
  63. package/node_modules/pi-lens/dist/clients/language-registry.js +5 -1
  64. package/node_modules/pi-lens/dist/clients/latency-logger.js +4 -1
  65. package/node_modules/pi-lens/dist/clients/lens-engine.js +12 -3
  66. package/node_modules/pi-lens/dist/clients/lens-events.js +2 -1
  67. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +79 -0
  68. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +2 -1
  69. package/node_modules/pi-lens/dist/clients/lsp/client.js +25 -21
  70. package/node_modules/pi-lens/dist/clients/lsp/config.js +2 -2
  71. package/node_modules/pi-lens/dist/clients/lsp/index.js +7 -0
  72. package/node_modules/pi-lens/dist/clients/lsp/launch.js +16 -4
  73. package/node_modules/pi-lens/dist/clients/lsp/server.js +19 -2
  74. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +2 -1
  75. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +5 -3
  76. package/node_modules/pi-lens/dist/clients/map-with-concurrency.js +12 -8
  77. package/node_modules/pi-lens/dist/clients/mcp/session.js +36 -4
  78. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +24 -7
  79. package/node_modules/pi-lens/dist/clients/observed-mutation.js +40 -2
  80. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +23 -3
  81. package/node_modules/pi-lens/dist/clients/opengrep-client.js +110 -15
  82. package/node_modules/pi-lens/dist/clients/path-utils.js +123 -3
  83. package/node_modules/pi-lens/dist/clients/performance-report.js +5 -1
  84. package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +1 -1
  85. package/node_modules/pi-lens/dist/clients/pipeline.js +74 -5
  86. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +37 -5
  87. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +145 -18
  88. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/dead-code.js +4 -1
  89. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +59 -3
  90. package/node_modules/pi-lens/dist/clients/project-lens-config.js +45 -2
  91. package/node_modules/pi-lens/dist/clients/read-guard.js +70 -11
  92. package/node_modules/pi-lens/dist/clients/resource-sampler.js +147 -9
  93. package/node_modules/pi-lens/dist/clients/ruff-client.js +1 -1
  94. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +33 -5
  95. package/node_modules/pi-lens/dist/clients/runtime-context.js +6 -2
  96. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +77 -7
  97. package/node_modules/pi-lens/dist/clients/runtime-session.js +21 -2
  98. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +43 -12
  99. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +330 -85
  100. package/node_modules/pi-lens/dist/clients/runtime-turn.js +147 -17
  101. package/node_modules/pi-lens/dist/clients/safe-spawn.js +258 -5
  102. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +6 -0
  103. package/node_modules/pi-lens/dist/clients/session-event-guard.js +50 -5
  104. package/node_modules/pi-lens/dist/clients/sg-runner.js +23 -11
  105. package/node_modules/pi-lens/dist/clients/sgconfig.js +79 -2
  106. package/node_modules/pi-lens/dist/clients/test-runner-client.js +6 -41
  107. package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +43 -0
  108. package/node_modules/pi-lens/dist/clients/tool-agreement.js +423 -0
  109. package/node_modules/pi-lens/dist/clients/tool-config.js +50 -0
  110. package/node_modules/pi-lens/dist/clients/tool-cwd.js +47 -76
  111. package/node_modules/pi-lens/dist/clients/tool-policy.js +163 -7
  112. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +120 -0
  113. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +127 -189
  114. package/node_modules/pi-lens/dist/clients/widget-state.js +98 -0
  115. package/node_modules/pi-lens/dist/clients/word-index.js +5 -2
  116. package/node_modules/pi-lens/dist/clients/write-ordering-guard.js +7 -0
  117. package/node_modules/pi-lens/dist/index.js +27416 -24153
  118. package/node_modules/pi-lens/dist/mcp/server.js +5 -2
  119. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +7 -1
  120. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +168 -53
  121. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +244 -72
  122. package/node_modules/pi-lens/docs/audit1.md +5 -5
  123. package/node_modules/pi-lens/docs/dependencies.md +11 -0
  124. package/node_modules/pi-lens/docs/dispositions.md +52 -0
  125. package/node_modules/pi-lens/docs/environment-variables.md +2 -2
  126. package/node_modules/pi-lens/docs/features.md +4 -4
  127. package/node_modules/pi-lens/docs/globalconfig.md +3 -1
  128. package/node_modules/pi-lens/docs/language-coverage.md +1 -0
  129. package/node_modules/pi-lens/docs/pi-lens-fixer.md +53 -94
  130. package/node_modules/pi-lens/docs/pi-lens-investigator.md +43 -38
  131. package/node_modules/pi-lens/docs/pi-lens-retro.md +97 -0
  132. package/node_modules/pi-lens/docs/pi-lens-reviewer.md +53 -66
  133. package/node_modules/pi-lens/docs/release-qa-baseline.md +22 -0
  134. package/node_modules/pi-lens/docs/settings.md +7 -4
  135. package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +1 -1
  136. package/node_modules/pi-lens/docs/usage.md +2 -0
  137. package/node_modules/pi-lens/package.json +1 -1
  138. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/sql-injection.yml +24 -12
  139. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +40 -0
  140. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +15 -0
  141. package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +7 -0
  142. package/package.json +6 -17
  143. package/examples/pi-footer.json +0 -275
  144. package/node_modules/@czottmann/pi-automode/CHANGELOG.md +0 -70
  145. package/node_modules/@czottmann/pi-automode/LICENSE.md +0 -21
  146. package/node_modules/@czottmann/pi-automode/README.md +0 -215
  147. package/node_modules/@czottmann/pi-automode/docs/GLOSSARY.md +0 -39
  148. package/node_modules/@czottmann/pi-automode/docs/adr/ADR-001-permission-precedence-and-trust-boundaries.md +0 -46
  149. package/node_modules/@czottmann/pi-automode/docs/adr/ADR-002-global-config-in-extension-data-directory.md +0 -60
  150. package/node_modules/@czottmann/pi-automode/docs/adr/INDEX.md +0 -6
  151. package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +0 -428
  152. package/node_modules/@czottmann/pi-automode/docs/configuration.md +0 -171
  153. package/node_modules/@czottmann/pi-automode/docs/defaults.md +0 -178
  154. package/node_modules/@czottmann/pi-automode/docs/diagnostics.md +0 -90
  155. package/node_modules/@czottmann/pi-automode/docs/observability-logging.md +0 -160
  156. package/node_modules/@czottmann/pi-automode/examples/automode.local.json +0 -44
  157. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/bash.ts +0 -692
  158. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +0 -852
  159. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +0 -904
  160. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +0 -228
  161. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +0 -954
  162. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/hard-deny.ts +0 -429
  163. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/log.ts +0 -173
  164. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/model-selector.ts +0 -113
  165. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/model.ts +0 -13
  166. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/paths.ts +0 -297
  167. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/permissions.ts +0 -623
  168. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/state.ts +0 -102
  169. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/transcript.ts +0 -236
  170. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/types.ts +0 -205
  171. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/utils.ts +0 -54
  172. package/node_modules/@czottmann/pi-automode/extensions/auto-mode.ts +0 -26
  173. package/node_modules/@czottmann/pi-automode/package.json +0 -61
  174. package/node_modules/@czottmann/pi-automode/skills/automode-diagnostics/SKILL.md +0 -63
  175. package/node_modules/@luxusai/pi-hindsight/CHANGELOG.md +0 -376
  176. package/node_modules/@luxusai/pi-hindsight/README.md +0 -92
  177. package/node_modules/@luxusai/pi-hindsight/docs/adr/001-memory-lifecycle-and-scope.md +0 -56
  178. package/node_modules/@luxusai/pi-hindsight/docs/adr/002-explicit-routing-strategy-seam.md +0 -169
  179. package/node_modules/@luxusai/pi-hindsight/docs/adr/003-tui-memory-mode-vocabulary.md +0 -107
  180. package/node_modules/@luxusai/pi-hindsight/docs/adr/004-lifeos-dual-bank-design.md +0 -89
  181. package/node_modules/@luxusai/pi-hindsight/docs/adr/005-domain-banks-and-agent-first-surface.md +0 -189
  182. package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark.webp +0 -0
  183. package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark@2x.webp +0 -0
  184. package/node_modules/@luxusai/pi-hindsight/docs/coding-memory-evaluation.md +0 -54
  185. package/node_modules/@luxusai/pi-hindsight/docs/compatibility.md +0 -75
  186. package/node_modules/@luxusai/pi-hindsight/docs/hindsight-core-functions.md +0 -300
  187. package/node_modules/@luxusai/pi-hindsight/docs/mission-and-mental-model-quality.md +0 -158
  188. package/node_modules/@luxusai/pi-hindsight/docs/next-opt-out-design.md +0 -164
  189. package/node_modules/@luxusai/pi-hindsight/docs/risky-memory-modes.md +0 -139
  190. package/node_modules/@luxusai/pi-hindsight/docs/starter-mental-model-suggestions.md +0 -74
  191. package/node_modules/@luxusai/pi-hindsight/docs/surface-reference.md +0 -261
  192. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-operations.ts +0 -151
  193. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-selection.ts +0 -18
  194. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-settings-presenter.ts +0 -46
  195. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-templates.ts +0 -383
  196. package/node_modules/@luxusai/pi-hindsight/extensions/banks/banking.ts +0 -240
  197. package/node_modules/@luxusai/pi-hindsight/extensions/banks/knowledge-page-seed.ts +0 -176
  198. package/node_modules/@luxusai/pi-hindsight/extensions/banks/retain-strategies.ts +0 -178
  199. package/node_modules/@luxusai/pi-hindsight/extensions/client/client-retry.ts +0 -41
  200. package/node_modules/@luxusai/pi-hindsight/extensions/client/client.ts +0 -386
  201. package/node_modules/@luxusai/pi-hindsight/extensions/client/fetch-compat.ts +0 -39
  202. package/node_modules/@luxusai/pi-hindsight/extensions/client/timeout.ts +0 -34
  203. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-defaults.ts +0 -140
  204. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-model.ts +0 -61
  205. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-registry.ts +0 -925
  206. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-field-paths.ts +0 -247
  207. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-normalize.ts +0 -547
  208. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-writer.ts +0 -480
  209. package/node_modules/@luxusai/pi-hindsight/extensions/config/config.ts +0 -182
  210. package/node_modules/@luxusai/pi-hindsight/extensions/config/setup-gate.ts +0 -86
  211. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-execute.ts +0 -1010
  212. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-parse.ts +0 -175
  213. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-plan.ts +0 -425
  214. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-presentation.ts +0 -210
  215. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-sessions.ts +0 -817
  216. package/node_modules/@luxusai/pi-hindsight/extensions/index.ts +0 -25
  217. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/git-seed.ts +0 -319
  218. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-recall.ts +0 -196
  219. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-retain.ts +0 -189
  220. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-runtime.ts +0 -65
  221. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle.ts +0 -260
  222. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/mental-models.ts +0 -244
  223. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/observation-scopes.ts +0 -59
  224. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-cleanup.ts +0 -82
  225. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-visibility.ts +0 -45
  226. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall.ts +0 -331
  227. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-cursor.ts +0 -354
  228. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-job-builder.ts +0 -66
  229. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-receipts.ts +0 -132
  230. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain.ts +0 -228
  231. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-bank-template-operations.ts +0 -74
  232. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-config-operations.ts +0 -16
  233. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-control-operations.ts +0 -648
  234. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-diagnostics-operations.ts +0 -105
  235. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-identity.ts +0 -68
  236. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-service.ts +0 -71
  237. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-types.ts +0 -13
  238. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-recall-operations.ts +0 -162
  239. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-retain-operations.ts +0 -131
  240. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-scope.ts +0 -104
  241. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-session-operations.ts +0 -37
  242. package/node_modules/@luxusai/pi-hindsight/extensions/operations/operation-catalog.ts +0 -893
  243. package/node_modules/@luxusai/pi-hindsight/extensions/operations/reflect-presenter.ts +0 -35
  244. package/node_modules/@luxusai/pi-hindsight/extensions/operations/scope-migrate.ts +0 -177
  245. package/node_modules/@luxusai/pi-hindsight/extensions/operations/tools.ts +0 -7
  246. package/node_modules/@luxusai/pi-hindsight/extensions/queue/flush-presenter.ts +0 -21
  247. package/node_modules/@luxusai/pi-hindsight/extensions/queue/jsonl-queue-store.ts +0 -112
  248. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-delivery.ts +0 -111
  249. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-lock.ts +0 -214
  250. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-operations.ts +0 -70
  251. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue.ts +0 -392
  252. package/node_modules/@luxusai/pi-hindsight/extensions/tui/bank-template-presentation.ts +0 -45
  253. package/node_modules/@luxusai/pi-hindsight/extensions/tui/commands.ts +0 -9
  254. package/node_modules/@luxusai/pi-hindsight/extensions/tui/guided-setup.ts +0 -860
  255. package/node_modules/@luxusai/pi-hindsight/extensions/tui/prefill-input.ts +0 -105
  256. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-flow.ts +0 -189
  257. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-server-probe.ts +0 -299
  258. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-actions.ts +0 -201
  259. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-facts.ts +0 -47
  260. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-render.ts +0 -239
  261. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-types.ts +0 -50
  262. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui.ts +0 -259
  263. package/node_modules/@luxusai/pi-hindsight/extensions/tui/tool-presenters.ts +0 -77
  264. package/node_modules/@luxusai/pi-hindsight/extensions/types.ts +0 -534
  265. package/node_modules/@luxusai/pi-hindsight/extensions/utils/diagnostics.ts +0 -319
  266. package/node_modules/@luxusai/pi-hindsight/extensions/utils/messages.ts +0 -325
  267. package/node_modules/@luxusai/pi-hindsight/extensions/utils/sanitize.ts +0 -42
  268. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-memory-meta.ts +0 -244
  269. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-operations.ts +0 -56
  270. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session.ts +0 -50
  271. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-fields.ts +0 -167
  272. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-health.ts +0 -207
  273. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status.ts +0 -120
  274. package/node_modules/@luxusai/pi-hindsight/extensions/version.ts +0 -8
  275. package/node_modules/@luxusai/pi-hindsight/package.json +0 -118
  276. package/node_modules/@luxusai/pi-hindsight/skills/hindsight-memory-doctor/SKILL.md +0 -75
@@ -1,429 +0,0 @@
1
- import { statSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import { resolve } from "node:path";
4
- import {
5
- analyzeBash,
6
- type BashAnalysis,
7
- type BashCommandAnalysis,
8
- type EffectiveCommand,
9
- } from "./bash.ts";
10
- import { HOME } from "./constants.ts";
11
- import {
12
- isProfileOrAuthorizedKeysPath,
13
- isSafetyControlPath,
14
- resolveInputPath,
15
- resolvePathForPolicy,
16
- shellPathTokenToPath,
17
- } from "./paths.ts";
18
-
19
- function isRecursiveRmArg(arg: string): boolean {
20
- return (
21
- (arg.length > 2 && arg.startsWith("--") && "--recursive".startsWith(arg)) ||
22
- /^-[A-Za-z]*r[A-Za-z]*f?[A-Za-z]*$/i.test(arg) ||
23
- /^-[A-Za-z]*f[A-Za-z]*r[A-Za-z]*$/i.test(arg)
24
- );
25
- }
26
-
27
- export type RmInvocation = {
28
- recursive: boolean;
29
- operands: Array<{ value: string; text: string; tildeExpansion: boolean }>;
30
- };
31
-
32
- export function parseRmInvocation(command: EffectiveCommand): RmInvocation {
33
- let recursive = false;
34
- let optionsEnded = false;
35
- const operands: RmInvocation["operands"] = [];
36
-
37
- for (const [index, value] of command.args.entries()) {
38
- const text = command.argTexts[index] ?? value;
39
- const tildeExpansion = command.argTildeExpansions[index] ?? false;
40
- if (!optionsEnded && value === "--") {
41
- optionsEnded = true;
42
- continue;
43
- }
44
- if (!optionsEnded && value !== "-" && value.startsWith("-")) {
45
- if (isRecursiveRmArg(value)) recursive = true;
46
- continue;
47
- }
48
- operands.push({ value, text, tildeExpansion });
49
- }
50
-
51
- return { recursive, operands };
52
- }
53
-
54
- function isUnresolvedUserHomeToken(
55
- shellText: string,
56
- tildeExpansion: boolean,
57
- ): boolean {
58
- return tildeExpansion && shellText !== "~" && !shellText.startsWith("~/");
59
- }
60
-
61
- function isSameExistingPath(left: string, right: string): boolean {
62
- try {
63
- const leftStat = statSync(left);
64
- const rightStat = statSync(right);
65
- return leftStat.dev === rightStat.dev && leftStat.ino === rightStat.ino;
66
- } catch {
67
- return false;
68
- }
69
- }
70
-
71
- function matchesPathRoot(path: string, root: string): boolean {
72
- if (path === root || path.startsWith(`${root}/`)) return true;
73
- const lowerPath = path.toLowerCase();
74
- const lowerRoot = root.toLowerCase();
75
- if (lowerPath !== lowerRoot && !lowerPath.startsWith(`${lowerRoot}/`)) {
76
- return false;
77
- }
78
- return isSameExistingPath(path.slice(0, root.length), root);
79
- }
80
-
81
- /**
82
- * Top-level directories whose deletion or wholesale modification is a
83
- * system-wide event. Shared between candidate validation and path
84
- * classification; do not inline copies.
85
- */
86
- const SYSTEM_ROOTS: ReadonlyArray<string> = [
87
- "/bin",
88
- "/boot",
89
- "/dev",
90
- "/etc",
91
- "/home",
92
- "/lib",
93
- "/lib64",
94
- "/Library",
95
- "/private",
96
- "/proc",
97
- "/root",
98
- "/run",
99
- "/sbin",
100
- "/sys",
101
- "/System",
102
- "/usr",
103
- "/var",
104
- ];
105
-
106
- /**
107
- * Normalize a proposed temp-root value into a comparable absolute path.
108
- * Returns undefined for values that cannot denote a subdirectory: the
109
- * empty string, `/`, and slash-only artifacts.
110
- */
111
- function normalizeRootCandidate(value: string): string | undefined {
112
- const stripped = value.replace(/\/+$/, "");
113
- // An empty stripped value must not fall through to `resolve()`, which
114
- // would silently turn `/` into the process working directory.
115
- if (!stripped) return undefined;
116
- const normalized = resolve(stripped);
117
- if (normalized === "/") return undefined;
118
- return normalized;
119
- }
120
-
121
- /**
122
- * True when a candidate temp root would weaken the deterministic deny tiers:
123
- * it aliases (exact, case-folded, or dev/inode) `HOME`, `/`, or any system
124
- * root, or it is a proper ancestor of the canonical home directory.
125
- *
126
- * Dev/inode identity covers symlinked spellings of existing directories;
127
- * string comparison alone handles candidates that do not exist yet. See
128
- * issue #31: without these guards, `TMPDIR=/` reduced every absolute path
129
- * below an empty-string prefix match, and `TMPDIR=/private` made
130
- * `/private/etc/**` disposable.
131
- */
132
- function conflictsWithProtectedRoots(candidate: string, home: string): boolean {
133
- if (candidate === "/") return true;
134
- for (const protectedRoot of ["/", home, ...SYSTEM_ROOTS]) {
135
- const canonical = resolve(protectedRoot);
136
- if (
137
- candidate === canonical ||
138
- candidate.toLowerCase() === canonical.toLowerCase()
139
- ) {
140
- return true;
141
- }
142
- if (isSameExistingPath(candidate, canonical)) return true;
143
- }
144
- const homeCanonical = resolvePathForPolicy(home) ?? resolve(home);
145
- return homeCanonical.toLowerCase().startsWith(`${candidate.toLowerCase()}/`);
146
- }
147
-
148
- let cachedTempRoots: ReadonlyArray<string> | undefined;
149
- let cachedTmpdirValue: string | undefined;
150
-
151
- /**
152
- * Validated launcher-declared temp-dir roots whose subtrees are treated as
153
- * disposable by `isRootHomeOrSystemPath`: the platform tmpdir, plus `/tmp` on
154
- * macOS where it exists independently of `os.tmpdir()`. Each root appears in
155
- * canonical and resolved spelling because callers pass symlink-resolved
156
- * policy paths (`/tmp` → `/private/tmp` on macOS) and unresolved fallbacks
157
- * alike. Values from `os.tmpdir()` are not trusted blindly; see
158
- * `conflictsWithProtectedRoots`. The roots themselves are never exempt:
159
- * deleting one is a system-wide delete.
160
- *
161
- * The memoization keys on the effective `os.tmpdir()` return value so tests
162
- * can mutate `TMPDIR`, `TMP`, or `TEMP` between calls.
163
- */
164
- export function tempRootCandidates(): ReadonlyArray<string> {
165
- const currentTmpdir = tmpdir();
166
- if (cachedTempRoots && cachedTmpdirValue === currentTmpdir) {
167
- return cachedTempRoots;
168
- }
169
- cachedTmpdirValue = currentTmpdir;
170
- cachedTempRoots = (() => {
171
- const roots = new Set<string>();
172
- const consider = (value: string) => {
173
- const candidate = normalizeRootCandidate(value);
174
- if (!candidate || conflictsWithProtectedRoots(candidate, HOME)) return;
175
- roots.add(candidate);
176
- const resolved = resolvePathForPolicy(candidate);
177
- if (resolved) roots.add(resolved);
178
- };
179
- consider(currentTmpdir);
180
- if (process.platform === "darwin") consider("/tmp");
181
- return [...roots];
182
- })();
183
- return cachedTempRoots;
184
- }
185
-
186
- /**
187
- * True for `/`, the user's home root, or a top-level system root such as
188
- * `/etc`, `/usr`, or `/var`. Excludes the home *subtree* and the subtrees of
189
- * platform temp directories (`os.tmpdir()` and `/tmp` on macOS).
190
- *
191
- * On some distros (e.g. Fedora Silverblue) HOME lives under `/var`, which is
192
- * in `systemRoots`. Without the subtree exemption, `path.startsWith("/var/")`
193
- * would treat every path under HOME as a system root and hard-deny routine
194
- * `rm -rf ~/...`. HOME itself is still matched below, so `rm -rf ~` stays
195
- * blocked. `home` is a parameter so this can be unit-tested with a synthetic
196
- * `/var/home/...` value.
197
- *
198
- * The temp exemption mirrors the home one and covers cleanup of directories
199
- * created with `mktemp`, `os.tmpdir()`, or plain `/tmp` paths. On macOS these
200
- * resolve into `/private/tmp` or `/private/var/folders`, which used to match
201
- * the `/private` system root and hard-deny every temp cleanup. Deleting a
202
- * temp root itself still returns true; `tempRoots` is injectable for tests.
203
- *
204
- * Protection order matters (issue #31): exact `/`, the exact home root, and
205
- * system roots win over every exemption. Injected `tempRoots` values are
206
- * validated per call so hostile or malformed candidates cannot weaken the
207
- * deterministic tiers.
208
- */
209
- export function isRootHomeOrSystemPath(
210
- path: string,
211
- home: string,
212
- tempRoots: ReadonlyArray<string> = tempRootCandidates(),
213
- ): boolean {
214
- if (path === "/") return true;
215
- if (path === home || isSameExistingPath(path, home)) return true;
216
- if (matchesPathRoot(path, home) && path.length > home.length) return false;
217
- for (const root of tempRoots) {
218
- const candidate = normalizeRootCandidate(root);
219
- if (!candidate || conflictsWithProtectedRoots(candidate, home)) continue;
220
- if (!matchesPathRoot(path, candidate)) continue;
221
- // Subtree: disposable. Exact match: the temp root stays protected.
222
- return path.length > candidate.length ? false : true;
223
- }
224
- return (
225
- matchesPathRoot(path, home) ||
226
- SYSTEM_ROOTS.some((root) => matchesPathRoot(path, root))
227
- );
228
- }
229
-
230
- function segmentHardDeny(
231
- segment: BashCommandAnalysis,
232
- cwd: string,
233
- ): string | undefined {
234
- for (const target of segment.redirectTargets) {
235
- const path = shellPathTokenToPath(target, cwd);
236
- if (!path) continue;
237
- const profileReason = isProfileOrAuthorizedKeysPath(path);
238
- if (profileReason) return profileReason;
239
- if (isSafetyControlPath(path, cwd)) {
240
- return "auto-mode or permission safety-control modification is hard-denied";
241
- }
242
- }
243
-
244
- for (const word of segment.words) {
245
- if (
246
- /^(NODE_TLS_REJECT_UNAUTHORIZED=0|GIT_SSL_NO_VERIFY=(1|true))$/i.test(
247
- word,
248
- )
249
- ) {
250
- return "TLS verification weakening is hard-denied";
251
- }
252
- }
253
-
254
- const command = segment.effectiveCommand;
255
- const name = command.name;
256
- if (!name) return undefined;
257
- const args = command.args;
258
- const lowerArgs = args.map((arg) => arg.toLowerCase());
259
-
260
- if (
261
- ["curl", "wget"].includes(name) &&
262
- lowerArgs.some((arg) =>
263
- ["--insecure", "-k", "--no-check-certificate"].includes(arg)
264
- )
265
- ) {
266
- return "certificate verification weakening is hard-denied";
267
- }
268
- if (
269
- ["npm", "yarn", "pnpm"].includes(name) &&
270
- lowerArgs[0] === "config" &&
271
- lowerArgs[1] === "set" &&
272
- ["strict-ssl", "cafile"].includes(lowerArgs[2] ?? "") &&
273
- ["false", "null"].includes(lowerArgs[3] ?? "")
274
- ) {
275
- return "package-manager TLS weakening is hard-denied";
276
- }
277
- if (
278
- name === "git" &&
279
- lowerArgs[0] === "config" &&
280
- lowerArgs.some(
281
- (arg) => arg === "sslverify" || arg.endsWith(".sslverify"),
282
- ) &&
283
- lowerArgs.includes("false")
284
- ) {
285
- return "git TLS verification weakening is hard-denied";
286
- }
287
- if (name === "crontab" && !lowerArgs.includes("-l")) {
288
- return "persistence or system service mutation is hard-denied";
289
- }
290
- if (
291
- name === "launchctl" &&
292
- ["load", "bootstrap", "enable"].includes(lowerArgs[0] ?? "")
293
- ) {
294
- return "persistence or system service mutation is hard-denied";
295
- }
296
- if (
297
- name === "systemctl" &&
298
- ["enable", "disable"].includes(lowerArgs[0] ?? "")
299
- ) {
300
- return "persistence or system service mutation is hard-denied";
301
- }
302
- if (name === "security" && lowerArgs[0] === "add-trusted-cert") {
303
- return "platform security weakening is hard-denied";
304
- }
305
- if (name === "spctl" && lowerArgs.includes("--master-disable")) {
306
- return "platform security weakening is hard-denied";
307
- }
308
- if (name === "csrutil" && lowerArgs[0] === "disable") {
309
- return "platform security weakening is hard-denied";
310
- }
311
-
312
- if (name === "rm") {
313
- const rm = parseRmInvocation(command);
314
- if (rm.recursive) {
315
- for (const { value: arg, text: shellText, tildeExpansion } of rm.operands) {
316
- if (isUnresolvedUserHomeToken(shellText, tildeExpansion)) {
317
- return "irreversible deletion of a user-home expansion is hard-denied";
318
- }
319
- const path = shellPathTokenToPath(arg, cwd, shellText);
320
- const policyPath = path ? (resolvePathForPolicy(path) ?? path) : undefined;
321
- const policyHome = resolvePathForPolicy(HOME) ?? HOME;
322
- if (policyPath && isRootHomeOrSystemPath(policyPath, policyHome)) {
323
- return "irreversible deletion of home/root/system paths is hard-denied";
324
- }
325
- }
326
- }
327
- }
328
-
329
- if (name === "find" && lowerArgs.includes("-delete")) {
330
- const root = shellPathTokenToPath(args[0] ?? "", cwd);
331
- const policyRoot = root ? (resolvePathForPolicy(root) ?? root) : undefined;
332
- const policyHome = resolvePathForPolicy(HOME) ?? HOME;
333
- if (
334
- policyRoot &&
335
- isRootHomeOrSystemPath(policyRoot, policyHome) &&
336
- policyRoot !== policyHome
337
- ) {
338
- return "system-wide delete is hard-denied";
339
- }
340
- }
341
-
342
- if (["chmod", "chown"].includes(name)) {
343
- for (const arg of args.filter((arg) => !arg.startsWith("-"))) {
344
- const path = shellPathTokenToPath(arg, cwd);
345
- if (
346
- path &&
347
- (path.startsWith("/etc/") ||
348
- path.startsWith("/usr/") ||
349
- path.startsWith("/bin/") ||
350
- path.startsWith("/sbin/") ||
351
- path.startsWith("/System/") ||
352
- path.startsWith(resolve(HOME, ".ssh")))
353
- ) {
354
- return "system or SSH permission mutation is hard-denied";
355
- }
356
- }
357
- }
358
-
359
- if (
360
- [
361
- "tee",
362
- "mv",
363
- "cp",
364
- "rm",
365
- "unlink",
366
- "truncate",
367
- "python",
368
- "python3",
369
- "node",
370
- "perl",
371
- "ruby",
372
- "sd",
373
- "sed",
374
- ].includes(name) &&
375
- /\.pi\/automode|\.pi\/extensions|pi-automode|auto-mode\.json/i.test(
376
- segment.raw,
377
- )
378
- ) {
379
- return "auto-mode or permission safety-control modification is hard-denied";
380
- }
381
-
382
- return undefined;
383
- }
384
-
385
- /**
386
- * Deterministic deny checks for actions too risky to delegate to the classifier.
387
- *
388
- * Bash checks use the shared unbash AST analysis. The hook passes one analysis
389
- * through every enforcement stage so nested commands are not reparsed.
390
- */
391
- export function deterministicHardDeny(
392
- toolName: string,
393
- input: Record<string, unknown>,
394
- cwd: string,
395
- bashAnalysis?: BashAnalysis,
396
- ): string | undefined {
397
- if (toolName === "write" || toolName === "edit") {
398
- const path = resolveInputPath(cwd, input.path);
399
- if (!path) return undefined;
400
- const policyPath = resolvePathForPolicy(path) ?? path;
401
- const policyCwd = resolvePathForPolicy(cwd) ?? cwd;
402
- const profileReason = isProfileOrAuthorizedKeysPath(policyPath);
403
- if (profileReason) return profileReason;
404
- if (isSafetyControlPath(policyPath, policyCwd)) {
405
- return "auto-mode or permission safety-control modification is hard-denied";
406
- }
407
- }
408
-
409
- if (toolName !== "bash") return undefined;
410
- const command = typeof input.command === "string" ? input.command : "";
411
- const analysis = bashAnalysis ?? analyzeBash(command);
412
- if (analysis.errors.length > 0) {
413
- return `Bash input could not be parsed safely: ${analysis.errors[0]?.message ?? "unknown parser error"}`;
414
- }
415
- for (const target of analysis.redirectTargets) {
416
- const path = shellPathTokenToPath(target, cwd);
417
- if (!path) continue;
418
- const profileReason = isProfileOrAuthorizedKeysPath(path);
419
- if (profileReason) return profileReason;
420
- if (isSafetyControlPath(path, cwd)) {
421
- return "auto-mode or permission safety-control modification is hard-denied";
422
- }
423
- }
424
- for (const segment of analysis.commands) {
425
- const reason = segmentHardDeny(segment, cwd);
426
- if (reason) return reason;
427
- }
428
- return undefined;
429
- }
@@ -1,173 +0,0 @@
1
- import { createHash, randomBytes } from "node:crypto";
2
- import { appendFileSync, mkdirSync } from "node:fs";
3
- import { homedir } from "node:os";
4
- import { basename, dirname, extname, isAbsolute, join, resolve } from "node:path";
5
- import type {
6
- ClassifierIo,
7
- ClassifierIoAttempt,
8
- ClassifierReasoningLog,
9
- ClassificationDecision,
10
- DecisionKind,
11
- } from "./types.ts";
12
-
13
- /** A final allow/block decision for a tool call. */
14
- export type DecisionLogEntry = {
15
- type: "decision";
16
- ts: string;
17
- decisionId: string;
18
- sessionId?: string;
19
- cwd: string;
20
- tool: string;
21
- summary: string;
22
- kind: DecisionKind;
23
- outcome: "allow" | "block";
24
- reason: string;
25
- classifierModel?: string;
26
- reasoning: ClassifierReasoningLog;
27
- };
28
-
29
- /** The classifier prompt, raw responses, and parsed decision for one action. */
30
- export type ClassifierLogEntry = {
31
- type: "classifier";
32
- ts: string;
33
- decisionId: string;
34
- model: string;
35
- reasoning: ClassifierIo["reasoning"];
36
- prompt: ClassifierIo["prompt"];
37
- attempts: ClassifierIoAttempt[];
38
- durationMs: number;
39
- parsed: ClassificationDecision;
40
- };
41
-
42
- /** A ccusage-compatible record for one classifier model response. */
43
- export type ClassifierUsageLogEntry = {
44
- type: "message";
45
- timestamp: string;
46
- message: {
47
- role: "assistant";
48
- model: string;
49
- usage: NonNullable<ClassifierIoAttempt["response"]>["usage"];
50
- };
51
- };
52
-
53
- export type LogEntry =
54
- | DecisionLogEntry
55
- | ClassifierLogEntry
56
- | ClassifierUsageLogEntry;
57
-
58
- export type Logger = {
59
- enabled: boolean;
60
- classifierIo: boolean;
61
- append(entry: LogEntry): void;
62
- };
63
-
64
- export type LoggerOptions = {
65
- enabled: boolean;
66
- classifierIo: boolean;
67
- sessionFile?: string;
68
- sessionDir: string;
69
- /** Effective cwd for an in-memory session. */
70
- sessionCwd?: string;
71
- sessionId: string;
72
- /** Test/embedder override. Runtime uses ~/.pi/agent/extensions/pi-automode/logs. */
73
- logRoot?: string;
74
- /** Test clock used for the UTC date partition. */
75
- now?: Date;
76
- };
77
-
78
- export const DEFAULT_AUTOMODE_LOG_ROOT = join(
79
- homedir(),
80
- ".pi/agent/extensions/pi-automode/logs",
81
- );
82
-
83
- const VALID_SESSION_ID =
84
- /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
85
-
86
- function safeLogSessionId(sessionId: string): string {
87
- if (VALID_SESSION_ID.test(sessionId)) return sessionId;
88
- const digest = createHash("sha256")
89
- .update(sessionId)
90
- .digest("hex")
91
- .slice(0, 16);
92
- return `invalid-${digest}`;
93
- }
94
-
95
- /** Short id linking a classifier entry to its decision entry in the same file. */
96
- export function newDecisionId(): string {
97
- return randomBytes(4).toString("hex");
98
- }
99
-
100
- /**
101
- * Derive the log file path from the current session: the session file's
102
- * directory with `-pi-automode` inserted before the extension. Falls back to
103
- * an absolute session directory when one is available. In-memory sessions use
104
- * an application-owned, project- and date-partitioned directory instead of a
105
- * relative path resolved against the launching process cwd.
106
- */
107
- export function resolveLogPath(
108
- sessionFile: string | undefined,
109
- sessionDir: string,
110
- sessionId: string,
111
- sessionCwd = process.cwd(),
112
- logRoot = DEFAULT_AUTOMODE_LOG_ROOT,
113
- now = new Date(),
114
- ): string {
115
- if (sessionFile) {
116
- const ext = extname(sessionFile);
117
- const stem = ext ? basename(sessionFile, ext) : basename(sessionFile);
118
- return join(dirname(sessionFile), `${stem}-pi-automode${ext}`);
119
- }
120
-
121
- const logFile = `${safeLogSessionId(sessionId)}-pi-automode.jsonl`;
122
- if (isAbsolute(sessionDir)) {
123
- return join(sessionDir, logFile);
124
- }
125
-
126
- const resolvedCwd = resolve(sessionCwd);
127
- const projectDir = `--${
128
- resolvedCwd.replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")
129
- }--`;
130
- const dateDir = now.toISOString().slice(0, 10);
131
- const resolvedLogRoot = isAbsolute(logRoot)
132
- ? logRoot
133
- : DEFAULT_AUTOMODE_LOG_ROOT;
134
- return join(
135
- resolvedLogRoot,
136
- projectDir,
137
- dateDir,
138
- logFile,
139
- );
140
- }
141
-
142
- /** Append one JSON object as a line. Failures are swallowed: logging must
143
- * never change a safety decision. */
144
- function appendJsonl(path: string, entry: unknown): void {
145
- try {
146
- mkdirSync(dirname(path), { recursive: true });
147
- appendFileSync(path, `${JSON.stringify(entry)}\n`, "utf8");
148
- } catch {
149
- // Fail open.
150
- }
151
- }
152
-
153
- /** Build a logger bound to one session's log path. No-ops when disabled. */
154
- export function createLogger(opts: LoggerOptions): Logger {
155
- const { enabled, classifierIo } = opts;
156
- const path = resolveLogPath(
157
- opts.sessionFile,
158
- opts.sessionDir,
159
- opts.sessionId,
160
- opts.sessionCwd,
161
- opts.logRoot,
162
- opts.now,
163
- );
164
- return {
165
- enabled,
166
- classifierIo,
167
- append(entry) {
168
- if (!enabled) return;
169
- if (entry.type === "classifier" && !classifierIo) return;
170
- appendJsonl(path, entry);
171
- },
172
- };
173
- }