@bastani/atomic 0.9.9-alpha.1 → 0.9.9-alpha.2

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 (534) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/builtin/cursor/CHANGELOG.md +6 -0
  3. package/dist/builtin/cursor/package.json +3 -3
  4. package/dist/builtin/intercom/CHANGELOG.md +7 -0
  5. package/dist/builtin/intercom/package.json +3 -3
  6. package/dist/builtin/mcp/CHANGELOG.md +7 -0
  7. package/dist/builtin/mcp/package.json +4 -4
  8. package/dist/builtin/subagents/CHANGELOG.md +7 -0
  9. package/dist/builtin/subagents/package.json +5 -5
  10. package/dist/builtin/web-access/CHANGELOG.md +7 -0
  11. package/dist/builtin/web-access/package.json +3 -3
  12. package/dist/builtin/web-access/web-search-tool.ts +1 -2
  13. package/dist/builtin/workflows/CHANGELOG.md +7 -0
  14. package/dist/builtin/workflows/package.json +3 -3
  15. package/dist/builtin/workflows/src/shared/serializable.ts +1 -1
  16. package/dist/bun/cli.d.ts.map +1 -1
  17. package/dist/bun/internal-intercom-broker.d.ts.map +1 -1
  18. package/dist/bun/register-bedrock.d.ts.map +1 -1
  19. package/dist/bun/restore-sandbox-env.d.ts.map +1 -1
  20. package/dist/bun/split-loader.d.ts.map +1 -1
  21. package/dist/cli/args.d.ts.map +1 -1
  22. package/dist/cli/config-selector.d.ts.map +1 -1
  23. package/dist/cli/file-processor.d.ts.map +1 -1
  24. package/dist/cli/initial-message.d.ts.map +1 -1
  25. package/dist/cli/list-models.d.ts.map +1 -1
  26. package/dist/cli/project-trust.d.ts.map +1 -1
  27. package/dist/cli/session-picker.d.ts.map +1 -1
  28. package/dist/cli/startup-ui.d.ts.map +1 -1
  29. package/dist/cli.d.ts.map +1 -1
  30. package/dist/config-self-update.d.ts.map +1 -1
  31. package/dist/config.d.ts.map +1 -1
  32. package/dist/core/agent-session-accessors.d.ts.map +1 -1
  33. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
  34. package/dist/core/agent-session-bash.d.ts.map +1 -1
  35. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  36. package/dist/core/agent-session-events.d.ts.map +1 -1
  37. package/dist/core/agent-session-export.d.ts.map +1 -1
  38. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  39. package/dist/core/agent-session-message-queue.d.ts.map +1 -1
  40. package/dist/core/agent-session-methods.d.ts.map +1 -1
  41. package/dist/core/agent-session-models.d.ts.map +1 -1
  42. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  43. package/dist/core/agent-session-retry.d.ts.map +1 -1
  44. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  45. package/dist/core/agent-session-services.d.ts.map +1 -1
  46. package/dist/core/agent-session-skill-block.d.ts.map +1 -1
  47. package/dist/core/agent-session-state.d.ts.map +1 -1
  48. package/dist/core/agent-session-tool-hooks.d.ts.map +1 -1
  49. package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
  50. package/dist/core/agent-session-tree.d.ts.map +1 -1
  51. package/dist/core/agent-session-types.d.ts.map +1 -1
  52. package/dist/core/agent-session.d.ts.map +1 -1
  53. package/dist/core/anthropic-thinking-guard.d.ts.map +1 -1
  54. package/dist/core/async/format.d.ts.map +1 -1
  55. package/dist/core/async/job-manager.d.ts.map +1 -1
  56. package/dist/core/async/session-manager.d.ts.map +1 -1
  57. package/dist/core/async/types.d.ts.map +1 -1
  58. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  59. package/dist/core/auth-guidance.d.ts.map +1 -1
  60. package/dist/core/auth-storage-backends.d.ts.map +1 -1
  61. package/dist/core/auth-storage.d.ts +4 -0
  62. package/dist/core/auth-storage.d.ts.map +1 -1
  63. package/dist/core/bash-executor.d.ts.map +1 -1
  64. package/dist/core/builtin-packages.d.ts.map +1 -1
  65. package/dist/core/codex-fast-mode.d.ts.map +1 -1
  66. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  67. package/dist/core/compaction/compaction-boundary.d.ts.map +1 -1
  68. package/dist/core/compaction/compaction-parameters.d.ts.map +1 -1
  69. package/dist/core/compaction/compaction-runner.d.ts.map +1 -1
  70. package/dist/core/compaction/compaction-types.d.ts.map +1 -1
  71. package/dist/core/compaction/compaction.d.ts.map +1 -1
  72. package/dist/core/compaction/deleted-ranges.d.ts.map +1 -1
  73. package/dist/core/compaction/index.d.ts.map +1 -1
  74. package/dist/core/compaction/range-planner.d.ts.map +1 -1
  75. package/dist/core/compaction/transcript-serialization.d.ts.map +1 -1
  76. package/dist/core/compaction/utils.d.ts.map +1 -1
  77. package/dist/core/context-window.d.ts.map +1 -1
  78. package/dist/core/copilot-anthropic-sse-repair.d.ts.map +1 -1
  79. package/dist/core/copilot-errors.d.ts.map +1 -1
  80. package/dist/core/copilot-gemini-payload-sanitizer.d.ts.map +1 -1
  81. package/dist/core/copilot-gemini-reasoning.d.ts.map +1 -1
  82. package/dist/core/copilot-gemini-tool-arguments.d.ts.map +1 -1
  83. package/dist/core/copilot-hosts.d.ts.map +1 -1
  84. package/dist/core/copilot-model-catalog.d.ts.map +1 -1
  85. package/dist/core/copilot-model-static-fallbacks.d.ts.map +1 -1
  86. package/dist/core/copilot-model-synthesis.d.ts.map +1 -1
  87. package/dist/core/defaults.d.ts.map +1 -1
  88. package/dist/core/diagnostics.d.ts.map +1 -1
  89. package/dist/core/event-bus.d.ts.map +1 -1
  90. package/dist/core/exec.d.ts.map +1 -1
  91. package/dist/core/experimental.d.ts.map +1 -1
  92. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  93. package/dist/core/export-html/index.d.ts.map +1 -1
  94. package/dist/core/export-html/template-script.d.ts.map +1 -1
  95. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  96. package/dist/core/extensions/agent-events.d.ts.map +1 -1
  97. package/dist/core/extensions/api-types.d.ts.map +1 -1
  98. package/dist/core/extensions/command-types.d.ts.map +1 -1
  99. package/dist/core/extensions/context-types.d.ts.map +1 -1
  100. package/dist/core/extensions/event-results.d.ts.map +1 -1
  101. package/dist/core/extensions/event-types.d.ts.map +1 -1
  102. package/dist/core/extensions/index.d.ts.map +1 -1
  103. package/dist/core/extensions/loader-api.d.ts.map +1 -1
  104. package/dist/core/extensions/loader-core.d.ts.map +1 -1
  105. package/dist/core/extensions/loader-discovery.d.ts.map +1 -1
  106. package/dist/core/extensions/loader-resources.d.ts.map +1 -1
  107. package/dist/core/extensions/loader-runtime.d.ts.map +1 -1
  108. package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
  109. package/dist/core/extensions/loader.d.ts.map +1 -1
  110. package/dist/core/extensions/message-types.d.ts.map +1 -1
  111. package/dist/core/extensions/provider-types.d.ts.map +1 -1
  112. package/dist/core/extensions/reactive-widget.d.ts.map +1 -1
  113. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  114. package/dist/core/extensions/runner-events.d.ts.map +1 -1
  115. package/dist/core/extensions/runner-handlers.d.ts.map +1 -1
  116. package/dist/core/extensions/runner-project-trust.d.ts.map +1 -1
  117. package/dist/core/extensions/runner-registries.d.ts.map +1 -1
  118. package/dist/core/extensions/runner-shortcuts.d.ts.map +1 -1
  119. package/dist/core/extensions/runner-ui.d.ts.map +1 -1
  120. package/dist/core/extensions/runner.d.ts.map +1 -1
  121. package/dist/core/extensions/runtime-types.d.ts.map +1 -1
  122. package/dist/core/extensions/session-events.d.ts.map +1 -1
  123. package/dist/core/extensions/tool-events.d.ts.map +1 -1
  124. package/dist/core/extensions/tool-types.d.ts.map +1 -1
  125. package/dist/core/extensions/types.d.ts.map +1 -1
  126. package/dist/core/extensions/ui-types.d.ts.map +1 -1
  127. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  128. package/dist/core/flattened-tool-arguments.d.ts.map +1 -1
  129. package/dist/core/footer-data-provider.d.ts.map +1 -1
  130. package/dist/core/http-dispatcher.d.ts.map +1 -1
  131. package/dist/core/index.d.ts.map +1 -1
  132. package/dist/core/keybindings.d.ts.map +1 -1
  133. package/dist/core/messages.d.ts.map +1 -1
  134. package/dist/core/model-registry-auth.d.ts.map +1 -1
  135. package/dist/core/model-registry-builtins.d.ts.map +1 -1
  136. package/dist/core/model-registry-builtins.js.map +1 -1
  137. package/dist/core/model-registry-custom-loader.d.ts.map +1 -1
  138. package/dist/core/model-registry-custom-loader.js.map +1 -1
  139. package/dist/core/model-registry-dynamic.d.ts.map +1 -1
  140. package/dist/core/model-registry-loader.d.ts.map +1 -1
  141. package/dist/core/model-registry-schemas.d.ts +65 -13
  142. package/dist/core/model-registry-schemas.d.ts.map +1 -1
  143. package/dist/core/model-registry-schemas.js +5 -1
  144. package/dist/core/model-registry-schemas.js.map +1 -1
  145. package/dist/core/model-registry-types.d.ts.map +1 -1
  146. package/dist/core/model-registry.d.ts.map +1 -1
  147. package/dist/core/model-resolver-cli.d.ts.map +1 -1
  148. package/dist/core/model-resolver-defaults.d.ts.map +1 -1
  149. package/dist/core/model-resolver-initial.d.ts.map +1 -1
  150. package/dist/core/model-resolver-patterns.d.ts.map +1 -1
  151. package/dist/core/model-resolver-scope.d.ts.map +1 -1
  152. package/dist/core/model-resolver-types.d.ts.map +1 -1
  153. package/dist/core/model-resolver.d.ts.map +1 -1
  154. package/dist/core/openai-responses-payload-sanitizer.d.ts.map +1 -1
  155. package/dist/core/output-guard.d.ts.map +1 -1
  156. package/dist/core/package-manager-auto-resources.d.ts.map +1 -1
  157. package/dist/core/package-manager-command.d.ts.map +1 -1
  158. package/dist/core/package-manager-constants.d.ts.map +1 -1
  159. package/dist/core/package-manager-env.d.ts.map +1 -1
  160. package/dist/core/package-manager-git.d.ts.map +1 -1
  161. package/dist/core/package-manager-manifest.d.ts.map +1 -1
  162. package/dist/core/package-manager-npm.d.ts.map +1 -1
  163. package/dist/core/package-manager-operations.d.ts.map +1 -1
  164. package/dist/core/package-manager-paths.d.ts.map +1 -1
  165. package/dist/core/package-manager-progress.d.ts.map +1 -1
  166. package/dist/core/package-manager-resolver.d.ts.map +1 -1
  167. package/dist/core/package-manager-resource-accumulator.d.ts.map +1 -1
  168. package/dist/core/package-manager-resource-collector.d.ts.map +1 -1
  169. package/dist/core/package-manager-resource-files.d.ts.map +1 -1
  170. package/dist/core/package-manager-resource-patterns.d.ts.map +1 -1
  171. package/dist/core/package-manager-settings.d.ts.map +1 -1
  172. package/dist/core/package-manager-source.d.ts.map +1 -1
  173. package/dist/core/package-manager-types.d.ts.map +1 -1
  174. package/dist/core/package-manager.d.ts.map +1 -1
  175. package/dist/core/project-trust.d.ts.map +1 -1
  176. package/dist/core/prompt-templates-async.d.ts.map +1 -1
  177. package/dist/core/prompt-templates.d.ts.map +1 -1
  178. package/dist/core/provider-attribution.d.ts.map +1 -1
  179. package/dist/core/provider-context-usage.d.ts.map +1 -1
  180. package/dist/core/provider-display-names.d.ts.map +1 -1
  181. package/dist/core/resolve-config-value.d.ts.map +1 -1
  182. package/dist/core/resource-loader-assets.d.ts.map +1 -1
  183. package/dist/core/resource-loader-context-files.d.ts.map +1 -1
  184. package/dist/core/resource-loader-core.d.ts.map +1 -1
  185. package/dist/core/resource-loader-discovery.d.ts.map +1 -1
  186. package/dist/core/resource-loader-extensions.d.ts.map +1 -1
  187. package/dist/core/resource-loader-helpers.d.ts.map +1 -1
  188. package/dist/core/resource-loader-internals.d.ts.map +1 -1
  189. package/dist/core/resource-loader-package-resources.d.ts.map +1 -1
  190. package/dist/core/resource-loader-paths.d.ts.map +1 -1
  191. package/dist/core/resource-loader-reload.d.ts.map +1 -1
  192. package/dist/core/resource-loader-source-info.d.ts.map +1 -1
  193. package/dist/core/resource-loader-types.d.ts.map +1 -1
  194. package/dist/core/resource-loader.d.ts.map +1 -1
  195. package/dist/core/sdk-exports.d.ts.map +1 -1
  196. package/dist/core/sdk-types.d.ts.map +1 -1
  197. package/dist/core/sdk.d.ts.map +1 -1
  198. package/dist/core/session-cwd.d.ts.map +1 -1
  199. package/dist/core/session-entry-normalization.d.ts.map +1 -1
  200. package/dist/core/session-manager-archive.d.ts.map +1 -1
  201. package/dist/core/session-manager-classification.d.ts.map +1 -1
  202. package/dist/core/session-manager-core.d.ts.map +1 -1
  203. package/dist/core/session-manager-entries.d.ts.map +1 -1
  204. package/dist/core/session-manager-history.d.ts.map +1 -1
  205. package/dist/core/session-manager-list.d.ts.map +1 -1
  206. package/dist/core/session-manager-migrations.d.ts.map +1 -1
  207. package/dist/core/session-manager-paths.d.ts.map +1 -1
  208. package/dist/core/session-manager-storage.d.ts.map +1 -1
  209. package/dist/core/session-manager-types.d.ts.map +1 -1
  210. package/dist/core/session-manager-validation.d.ts.map +1 -1
  211. package/dist/core/session-manager.d.ts.map +1 -1
  212. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  213. package/dist/core/settings-manager-core.d.ts.map +1 -1
  214. package/dist/core/settings-manager-internals.d.ts.map +1 -1
  215. package/dist/core/settings-manager-resource-accessors.d.ts.map +1 -1
  216. package/dist/core/settings-manager-ui-accessors.d.ts.map +1 -1
  217. package/dist/core/settings-manager.d.ts.map +1 -1
  218. package/dist/core/settings-merge.d.ts.map +1 -1
  219. package/dist/core/settings-storage.d.ts.map +1 -1
  220. package/dist/core/settings-types.d.ts.map +1 -1
  221. package/dist/core/skills-async.d.ts.map +1 -1
  222. package/dist/core/skills.d.ts.map +1 -1
  223. package/dist/core/slash-commands.d.ts.map +1 -1
  224. package/dist/core/source-info.d.ts.map +1 -1
  225. package/dist/core/system-prompt.d.ts.map +1 -1
  226. package/dist/core/telemetry.d.ts.map +1 -1
  227. package/dist/core/thinking-blocks.d.ts.map +1 -1
  228. package/dist/core/timings.d.ts.map +1 -1
  229. package/dist/core/tools/artifact-protocol.d.ts.map +1 -1
  230. package/dist/core/tools/artifacts.d.ts.map +1 -1
  231. package/dist/core/tools/ask-user-question/ask-user-question.d.ts.map +1 -1
  232. package/dist/core/tools/ask-user-question/config.d.ts.map +1 -1
  233. package/dist/core/tools/ask-user-question/index.d.ts.map +1 -1
  234. package/dist/core/tools/ask-user-question/state/build-questionnaire.d.ts.map +1 -1
  235. package/dist/core/tools/ask-user-question/state/inline-input.d.ts.map +1 -1
  236. package/dist/core/tools/ask-user-question/state/key-router.d.ts.map +1 -1
  237. package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts.map +1 -1
  238. package/dist/core/tools/ask-user-question/state/row-intent.d.ts.map +1 -1
  239. package/dist/core/tools/ask-user-question/state/selectors/contract.d.ts.map +1 -1
  240. package/dist/core/tools/ask-user-question/state/selectors/derivations.d.ts.map +1 -1
  241. package/dist/core/tools/ask-user-question/state/selectors/focus.d.ts.map +1 -1
  242. package/dist/core/tools/ask-user-question/state/selectors/projections.d.ts.map +1 -1
  243. package/dist/core/tools/ask-user-question/state/state-reducer.d.ts.map +1 -1
  244. package/dist/core/tools/ask-user-question/state/state.d.ts.map +1 -1
  245. package/dist/core/tools/ask-user-question/tool/format-answer.d.ts.map +1 -1
  246. package/dist/core/tools/ask-user-question/tool/response-envelope.d.ts.map +1 -1
  247. package/dist/core/tools/ask-user-question/tool/types.d.ts.map +1 -1
  248. package/dist/core/tools/ask-user-question/tool/validate-questionnaire.d.ts.map +1 -1
  249. package/dist/core/tools/ask-user-question/view/body-residual-spacer.d.ts.map +1 -1
  250. package/dist/core/tools/ask-user-question/view/component-binding.d.ts.map +1 -1
  251. package/dist/core/tools/ask-user-question/view/components/chat-row-view.d.ts.map +1 -1
  252. package/dist/core/tools/ask-user-question/view/components/multi-select-view.d.ts.map +1 -1
  253. package/dist/core/tools/ask-user-question/view/components/option-list-view.d.ts.map +1 -1
  254. package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.d.ts.map +1 -1
  255. package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.d.ts.map +1 -1
  256. package/dist/core/tools/ask-user-question/view/components/preview/preview-box-renderer.d.ts.map +1 -1
  257. package/dist/core/tools/ask-user-question/view/components/preview/preview-layout-decider.d.ts.map +1 -1
  258. package/dist/core/tools/ask-user-question/view/components/preview/preview-pane.d.ts.map +1 -1
  259. package/dist/core/tools/ask-user-question/view/components/submit-picker.d.ts.map +1 -1
  260. package/dist/core/tools/ask-user-question/view/components/tab-bar.d.ts.map +1 -1
  261. package/dist/core/tools/ask-user-question/view/components/wrapping-select.d.ts.map +1 -1
  262. package/dist/core/tools/ask-user-question/view/dialog-builder.d.ts.map +1 -1
  263. package/dist/core/tools/ask-user-question/view/props-adapter.d.ts.map +1 -1
  264. package/dist/core/tools/ask-user-question/view/stateful-view.d.ts.map +1 -1
  265. package/dist/core/tools/ask-user-question/view/tab-components.d.ts.map +1 -1
  266. package/dist/core/tools/ask-user-question/view/tab-content-strategy.d.ts.map +1 -1
  267. package/dist/core/tools/bash-async-execution.d.ts.map +1 -1
  268. package/dist/core/tools/bash-async-jobs.d.ts.map +1 -1
  269. package/dist/core/tools/bash-async-output.d.ts.map +1 -1
  270. package/dist/core/tools/bash-interceptor.d.ts.map +1 -1
  271. package/dist/core/tools/bash-leading-cd.d.ts.map +1 -1
  272. package/dist/core/tools/bash-pty-native.d.ts.map +1 -1
  273. package/dist/core/tools/bash.d.ts.map +1 -1
  274. package/dist/core/tools/block-resolver.d.ts.map +1 -1
  275. package/dist/core/tools/conflict-registry.d.ts.map +1 -1
  276. package/dist/core/tools/directory-tree.d.ts.map +1 -1
  277. package/dist/core/tools/edit-diff-preserve.d.ts.map +1 -1
  278. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  279. package/dist/core/tools/edit.d.ts.map +1 -1
  280. package/dist/core/tools/fetch-url.d.ts.map +1 -1
  281. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  282. package/dist/core/tools/find.d.ts.map +1 -1
  283. package/dist/core/tools/glob-path-utils.d.ts.map +1 -1
  284. package/dist/core/tools/grep.d.ts.map +1 -1
  285. package/dist/core/tools/hashline-engine/apply.d.ts.map +1 -1
  286. package/dist/core/tools/hashline-engine/block.d.ts.map +1 -1
  287. package/dist/core/tools/hashline-engine/diff-preview.d.ts.map +1 -1
  288. package/dist/core/tools/hashline-engine/format.d.ts.map +1 -1
  289. package/dist/core/tools/hashline-engine/fs.d.ts.map +1 -1
  290. package/dist/core/tools/hashline-engine/index.d.ts.map +1 -1
  291. package/dist/core/tools/hashline-engine/input.d.ts.map +1 -1
  292. package/dist/core/tools/hashline-engine/messages.d.ts.map +1 -1
  293. package/dist/core/tools/hashline-engine/mismatch.d.ts.map +1 -1
  294. package/dist/core/tools/hashline-engine/normalize.d.ts.map +1 -1
  295. package/dist/core/tools/hashline-engine/parser.d.ts.map +1 -1
  296. package/dist/core/tools/hashline-engine/patcher.d.ts.map +1 -1
  297. package/dist/core/tools/hashline-engine/prefixes.d.ts.map +1 -1
  298. package/dist/core/tools/hashline-engine/recovery.d.ts.map +1 -1
  299. package/dist/core/tools/hashline-engine/snapshots.d.ts.map +1 -1
  300. package/dist/core/tools/hashline-engine/stream.d.ts.map +1 -1
  301. package/dist/core/tools/hashline-engine/tokenizer.d.ts.map +1 -1
  302. package/dist/core/tools/hashline-engine/types.d.ts.map +1 -1
  303. package/dist/core/tools/hashline.d.ts.map +1 -1
  304. package/dist/core/tools/index.d.ts.map +1 -1
  305. package/dist/core/tools/ls.d.ts.map +1 -1
  306. package/dist/core/tools/notebook.d.ts.map +1 -1
  307. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  308. package/dist/core/tools/oversized-tool-result.d.ts.map +1 -1
  309. package/dist/core/tools/path-utils.d.ts.map +1 -1
  310. package/dist/core/tools/read-document-extract.d.ts.map +1 -1
  311. package/dist/core/tools/read-selectors.d.ts.map +1 -1
  312. package/dist/core/tools/read-url.d.ts.map +1 -1
  313. package/dist/core/tools/read.d.ts.map +1 -1
  314. package/dist/core/tools/render-utils.d.ts.map +1 -1
  315. package/dist/core/tools/resource-selectors.d.ts.map +1 -1
  316. package/dist/core/tools/search-details.d.ts.map +1 -1
  317. package/dist/core/tools/search-line-ranges.d.ts.map +1 -1
  318. package/dist/core/tools/search-native.d.ts.map +1 -1
  319. package/dist/core/tools/search.d.ts.map +1 -1
  320. package/dist/core/tools/structured-output.d.ts.map +1 -1
  321. package/dist/core/tools/todos-execute.d.ts.map +1 -1
  322. package/dist/core/tools/todos-locks.d.ts.map +1 -1
  323. package/dist/core/tools/todos-model.d.ts.map +1 -1
  324. package/dist/core/tools/todos-mutations.d.ts.map +1 -1
  325. package/dist/core/tools/todos-paths.d.ts.map +1 -1
  326. package/dist/core/tools/todos-render.d.ts.map +1 -1
  327. package/dist/core/tools/todos-storage.d.ts.map +1 -1
  328. package/dist/core/tools/todos-types.d.ts.map +1 -1
  329. package/dist/core/tools/todos-types.js +1 -1
  330. package/dist/core/tools/todos-types.js.map +1 -1
  331. package/dist/core/tools/todos.d.ts.map +1 -1
  332. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  333. package/dist/core/tools/tool-definition-wrapper.js +6 -2
  334. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  335. package/dist/core/tools/tool-limits.d.ts.map +1 -1
  336. package/dist/core/tools/truncate.d.ts.map +1 -1
  337. package/dist/core/tools/url-ip-guards.d.ts.map +1 -1
  338. package/dist/core/tools/write.d.ts.map +1 -1
  339. package/dist/core/trust-manager.d.ts.map +1 -1
  340. package/dist/core/typebox-compat.d.ts +12 -0
  341. package/dist/core/typebox-compat.d.ts.map +1 -0
  342. package/dist/core/typebox-compat.js +10 -0
  343. package/dist/core/typebox-compat.js.map +1 -0
  344. package/dist/index-extensions.d.ts.map +1 -1
  345. package/dist/index.d.ts +1 -0
  346. package/dist/index.d.ts.map +1 -1
  347. package/dist/index.js +1 -0
  348. package/dist/index.js.map +1 -1
  349. package/dist/main-app-mode.d.ts.map +1 -1
  350. package/dist/main-deferred-startup.d.ts.map +1 -1
  351. package/dist/main-early-input.d.ts.map +1 -1
  352. package/dist/main-session-options.d.ts.map +1 -1
  353. package/dist/main-session.d.ts.map +1 -1
  354. package/dist/main-stdio.d.ts.map +1 -1
  355. package/dist/main.d.ts.map +1 -1
  356. package/dist/migrations-config-values.d.ts.map +1 -1
  357. package/dist/migrations.d.ts.map +1 -1
  358. package/dist/modes/index.d.ts.map +1 -1
  359. package/dist/modes/interactive/chat-input-actions.d.ts.map +1 -1
  360. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  361. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  362. package/dist/modes/interactive/components/atomic-banner.d.ts.map +1 -1
  363. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  364. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  365. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  366. package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
  367. package/dist/modes/interactive/components/chat-session-host-actions.d.ts.map +1 -1
  368. package/dist/modes/interactive/components/chat-session-host-editor.d.ts.map +1 -1
  369. package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -1
  370. package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -1
  371. package/dist/modes/interactive/components/chat-session-host-runtime.d.ts.map +1 -1
  372. package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
  373. package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.d.ts.map +1 -1
  374. package/dist/modes/interactive/components/chat-session-host-types.d.ts.map +1 -1
  375. package/dist/modes/interactive/components/chat-session-host-utils.d.ts.map +1 -1
  376. package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
  377. package/dist/modes/interactive/components/chat-transcript.d.ts.map +1 -1
  378. package/dist/modes/interactive/components/compaction-boundary-message.d.ts.map +1 -1
  379. package/dist/modes/interactive/components/config-selector-list.d.ts.map +1 -1
  380. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  381. package/dist/modes/interactive/components/context-window-selector.d.ts.map +1 -1
  382. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  383. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  384. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  385. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  386. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  387. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  388. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -1
  389. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  390. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  391. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  392. package/dist/modes/interactive/components/fast-mode-selector.d.ts.map +1 -1
  393. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  394. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  395. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  396. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  397. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  398. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  399. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  400. package/dist/modes/interactive/components/session-selector-delete.d.ts.map +1 -1
  401. package/dist/modes/interactive/components/session-selector-header.d.ts.map +1 -1
  402. package/dist/modes/interactive/components/session-selector-list.d.ts.map +1 -1
  403. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  404. package/dist/modes/interactive/components/session-selector-tree.d.ts.map +1 -1
  405. package/dist/modes/interactive/components/session-selector-types.d.ts.map +1 -1
  406. package/dist/modes/interactive/components/session-selector-utils.d.ts.map +1 -1
  407. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  408. package/dist/modes/interactive/components/settings-selector-handlers.d.ts.map +1 -1
  409. package/dist/modes/interactive/components/settings-selector-items.d.ts.map +1 -1
  410. package/dist/modes/interactive/components/settings-selector-options.d.ts.map +1 -1
  411. package/dist/modes/interactive/components/settings-selector-submenus.d.ts.map +1 -1
  412. package/dist/modes/interactive/components/settings-selector-types.d.ts.map +1 -1
  413. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  414. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  415. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  416. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  417. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  418. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  419. package/dist/modes/interactive/components/tree-selector-component.d.ts.map +1 -1
  420. package/dist/modes/interactive/components/tree-selector-content.d.ts.map +1 -1
  421. package/dist/modes/interactive/components/tree-selector-help.d.ts.map +1 -1
  422. package/dist/modes/interactive/components/tree-selector-label-input.d.ts.map +1 -1
  423. package/dist/modes/interactive/components/tree-selector-list.d.ts.map +1 -1
  424. package/dist/modes/interactive/components/tree-selector-model.d.ts.map +1 -1
  425. package/dist/modes/interactive/components/tree-selector-types.d.ts.map +1 -1
  426. package/dist/modes/interactive/components/tree-selector-viewport.d.ts.map +1 -1
  427. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  428. package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -1
  429. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  430. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  431. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  432. package/dist/modes/interactive/components/working-status.d.ts.map +1 -1
  433. package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -1
  434. package/dist/modes/interactive/interactive-auth-login.d.ts.map +1 -1
  435. package/dist/modes/interactive/interactive-auth-routing.d.ts.map +1 -1
  436. package/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
  437. package/dist/modes/interactive/interactive-bash-compact.d.ts.map +1 -1
  438. package/dist/modes/interactive/interactive-child-ordering.d.ts.map +1 -1
  439. package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
  440. package/dist/modes/interactive/interactive-editor-actions.d.ts.map +1 -1
  441. package/dist/modes/interactive/interactive-extension-context.d.ts.map +1 -1
  442. package/dist/modes/interactive/interactive-extension-custom-ui.d.ts.map +1 -1
  443. package/dist/modes/interactive/interactive-extension-dialogs.d.ts.map +1 -1
  444. package/dist/modes/interactive/interactive-extension-runtime.d.ts.map +1 -1
  445. package/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
  446. package/dist/modes/interactive/interactive-hotkeys-debug.d.ts.map +1 -1
  447. package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
  448. package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
  449. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  450. package/dist/modes/interactive/interactive-mode-helpers.d.ts.map +1 -1
  451. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  452. package/dist/modes/interactive/interactive-mode-types.d.ts.map +1 -1
  453. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  454. package/dist/modes/interactive/interactive-model-routing.d.ts.map +1 -1
  455. package/dist/modes/interactive/interactive-onboarding.d.ts.map +1 -1
  456. package/dist/modes/interactive/interactive-process-lifecycle.d.ts.map +1 -1
  457. package/dist/modes/interactive/interactive-queueing.d.ts.map +1 -1
  458. package/dist/modes/interactive/interactive-render-chat.d.ts.map +1 -1
  459. package/dist/modes/interactive/interactive-resource-disclosure.d.ts.map +1 -1
  460. package/dist/modes/interactive/interactive-resource-paths.d.ts.map +1 -1
  461. package/dist/modes/interactive/interactive-resource-rendering.d.ts.map +1 -1
  462. package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
  463. package/dist/modes/interactive/interactive-session-routing.d.ts.map +1 -1
  464. package/dist/modes/interactive/interactive-session-runtime.d.ts.map +1 -1
  465. package/dist/modes/interactive/interactive-slash-commands.d.ts.map +1 -1
  466. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
  467. package/dist/modes/interactive/model-search.d.ts.map +1 -1
  468. package/dist/modes/interactive/theme/color-utils.d.ts.map +1 -1
  469. package/dist/modes/interactive/theme/export-colors.d.ts.map +1 -1
  470. package/dist/modes/interactive/theme/global-theme.d.ts.map +1 -1
  471. package/dist/modes/interactive/theme/terminal-detection.d.ts.map +1 -1
  472. package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -1
  473. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  474. package/dist/modes/interactive/theme/theme-loading.d.ts.map +1 -1
  475. package/dist/modes/interactive/theme/theme-parse.d.ts.map +1 -1
  476. package/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  477. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  478. package/dist/modes/interactive/theme/tui-theme.d.ts.map +1 -1
  479. package/dist/modes/interactive/whimsical-messages.d.ts.map +1 -1
  480. package/dist/modes/print-mode.d.ts.map +1 -1
  481. package/dist/modes/rpc/jsonl.d.ts.map +1 -1
  482. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  483. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  484. package/dist/modes/rpc/rpc-extension-ui.d.ts.map +1 -1
  485. package/dist/modes/rpc/rpc-input.d.ts.map +1 -1
  486. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  487. package/dist/modes/rpc/rpc-responses.d.ts.map +1 -1
  488. package/dist/modes/rpc/rpc-session-binding.d.ts.map +1 -1
  489. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  490. package/dist/package-manager-cli-parser.d.ts.map +1 -1
  491. package/dist/package-manager-cli.d.ts.map +1 -1
  492. package/dist/rpc-entry.d.ts.map +1 -1
  493. package/dist/utils/ansi.d.ts.map +1 -1
  494. package/dist/utils/changelog.d.ts.map +1 -1
  495. package/dist/utils/child-process.d.ts.map +1 -1
  496. package/dist/utils/clipboard-image.d.ts.map +1 -1
  497. package/dist/utils/clipboard-native.d.ts.map +1 -1
  498. package/dist/utils/clipboard.d.ts.map +1 -1
  499. package/dist/utils/deprecation.d.ts.map +1 -1
  500. package/dist/utils/event-loop.d.ts.map +1 -1
  501. package/dist/utils/exif-orientation.d.ts.map +1 -1
  502. package/dist/utils/frontmatter.d.ts.map +1 -1
  503. package/dist/utils/fs-watch.d.ts.map +1 -1
  504. package/dist/utils/git-env.d.ts.map +1 -1
  505. package/dist/utils/git.d.ts.map +1 -1
  506. package/dist/utils/html.d.ts.map +1 -1
  507. package/dist/utils/image-convert.d.ts.map +1 -1
  508. package/dist/utils/image-process.d.ts.map +1 -1
  509. package/dist/utils/image-resize-core.d.ts.map +1 -1
  510. package/dist/utils/image-resize-worker.d.ts.map +1 -1
  511. package/dist/utils/image-resize.d.ts.map +1 -1
  512. package/dist/utils/json.d.ts.map +1 -1
  513. package/dist/utils/markit.d.ts.map +1 -1
  514. package/dist/utils/mime.d.ts.map +1 -1
  515. package/dist/utils/module-require.d.ts.map +1 -1
  516. package/dist/utils/open-browser.d.ts.map +1 -1
  517. package/dist/utils/paths.d.ts.map +1 -1
  518. package/dist/utils/photon.d.ts.map +1 -1
  519. package/dist/utils/pi-user-agent.d.ts.map +1 -1
  520. package/dist/utils/shell.d.ts.map +1 -1
  521. package/dist/utils/sleep.d.ts.map +1 -1
  522. package/dist/utils/split-launcher.d.ts.map +1 -1
  523. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  524. package/dist/utils/tools-manager.d.ts.map +1 -1
  525. package/dist/utils/version-check.d.ts.map +1 -1
  526. package/dist/utils/windows-self-update.d.ts.map +1 -1
  527. package/docs/custom-provider.md +7 -1
  528. package/docs/extensions.md +6 -4
  529. package/examples/extensions/README.md +3 -1
  530. package/examples/extensions/subagent/schemas.ts +1 -1
  531. package/examples/extensions/tic-tac-toe.ts +1 -2
  532. package/examples/extensions/todo.ts +1 -2
  533. package/npm-shrinkwrap.json +214 -98
  534. package/package.json +12 -12
@@ -1 +1 @@
1
- {"version":3,"file":"chat-session-host-actions.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-actions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAYpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAOzE,wBAAsB,oBAAoB,CACxC,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAYzD;AAED,wBAAsB,iBAAiB,CAAC,WAAW,SAAS,uBAAuB,EACjF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,IAAI,GAAE,MAAM,GAAG,UAAmB,EAClC,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,CA4Ef;AAED,wBAAsB,0BAA0B,CAC9C,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAYzD;AAED,wBAAsB,oBAAoB,CAAC,WAAW,SAAS,uBAAuB,EACpF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,wBAAsB,+BAA+B,CACnD,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBzD;AAED,wBAAgB,6BAA6B,CAC3C,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GAAG,OAAO,CAkBnD","sourcesContent":["import type { BashExecutionMessage } from \"../../../core/messages.ts\";\nimport { combineQueuedMessagesForEditor } from \"../chat-input-actions.ts\";\nimport type { ChatMessageEntry } from \"./chat-message-renderer.ts\";\nimport type { ChatTranscriptEntryLike } from \"./chat-transcript.ts\";\nimport { setChatSessionEditorText } from \"./chat-session-host-editor.ts\";\nimport {\n decrementOptimisticUserSignature,\n incrementOptimisticUserSignature,\n isChatSessionBashRunning,\n isChatSessionStreaming,\n notifyChatSessionStatus,\n notifyChatSessionWarning,\n requiredChatSessionCommand,\n syncChatSessionAnimationTick,\n} from \"./chat-session-host-runtime.ts\";\nimport type { ChatSessionHostState } from \"./chat-session-host-state.ts\";\nimport {\n errorMessage,\n parseBashInput,\n userMessageSignature,\n} from \"./chat-session-host-utils.ts\";\n\nexport async function interruptChatSession<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): Promise<void> {\n try {\n restoreQueuedMessagesToEditor(state);\n state.sdkBusy = false;\n state.workingMessage = undefined;\n await state.commands.interrupt?.();\n } catch (err) {\n state.statusMessage = errorMessage(err);\n } finally {\n syncChatSessionAnimationTick(state);\n state.requestRender?.();\n }\n}\n\nexport async function submitChatSession<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n mode: \"auto\" | \"followUp\" = \"auto\",\n submittedText?: string,\n): Promise<void> {\n const text = (submittedText ?? state.inputBuffer).trim();\n if (!text) return;\n if (text.startsWith(\"/\") && state.commands.handleSlashCommand) {\n const handled = await state.commands.handleSlashCommand(text);\n if (handled) {\n setChatSessionEditorText(state, \"\");\n state.requestRender?.();\n return;\n }\n }\n if (state.compacting) {\n setChatSessionEditorText(state, \"\");\n state.compactionQueuedMessages = [...state.compactionQueuedMessages, text];\n notifyChatSessionStatus(state, \"Queued message until compaction completes\");\n return;\n }\n const bash = parseBashInput(text);\n if (bash?.command) {\n if (isChatSessionBashRunning(state)) {\n notifyChatSessionWarning(state, \"A bash command is already running. esc cancel first.\");\n setChatSessionEditorText(state, text);\n return;\n }\n setChatSessionEditorText(state, \"\");\n await runChatSessionBashCommand(state, bash.command, bash.excludeFromContext);\n return;\n }\n setChatSessionEditorText(state, \"\");\n const isPaused = state.isPaused?.() === true;\n const isStreaming = isChatSessionStreaming(state);\n const shouldAppendOptimisticUser = mode === \"auto\" && !isStreaming;\n const optimisticSignature = shouldAppendOptimisticUser\n ? userMessageSignature(text)\n : undefined;\n if (optimisticSignature !== undefined) {\n state.liveChat.appendUserText(text);\n state.bodyViewport.scrollToBottom();\n incrementOptimisticUserSignature(state, optimisticSignature);\n }\n state.requestRender?.();\n try {\n if (isPaused) {\n state.sdkBusy = true;\n state.statusMessage = \"resuming…\";\n syncChatSessionAnimationTick(state);\n state.requestRender?.();\n await requiredChatSessionCommand(state, \"resume\")(text);\n state.sdkBusy = false;\n state.statusMessage = \"\";\n syncChatSessionAnimationTick(state);\n return;\n }\n if (mode === \"followUp\" && isStreaming) {\n await queueChatSessionFollowUp(state, text);\n return;\n }\n if (isStreaming) {\n await queueChatSessionSteer(state, text);\n } else {\n state.sdkBusy = true;\n syncChatSessionAnimationTick(state);\n await state.commands.ensureAttached?.();\n await requiredChatSessionCommand(state, \"prompt\")(text);\n state.sdkBusy = false;\n syncChatSessionAnimationTick(state);\n }\n } catch (err) {\n if (optimisticSignature !== undefined) {\n decrementOptimisticUserSignature(state, optimisticSignature);\n }\n state.sdkBusy = false;\n state.statusMessage = errorMessage(err);\n syncChatSessionAnimationTick(state);\n state.requestRender?.();\n }\n}\n\nexport async function abortChatSessionCompaction<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): Promise<void> {\n try {\n await state.commands.abortCompaction?.();\n state.compacting = false;\n state.sdkBusy = false;\n notifyChatSessionStatus(state, \"Compaction cancelled\");\n } catch (err) {\n notifyChatSessionWarning(state, errorMessage(err));\n } finally {\n syncChatSessionAnimationTick(state);\n state.requestRender?.();\n }\n}\n\nexport async function abortChatSessionBash<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): Promise<void> {\n try {\n await state.commands.abortBash?.();\n state.localBashRunning = false;\n notifyChatSessionStatus(state, \"Bash command cancelled\");\n } catch (err) {\n notifyChatSessionWarning(state, errorMessage(err));\n } finally {\n state.requestRender?.();\n }\n}\n\nexport async function flushChatSessionCompactionQueue<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): Promise<void> {\n const queued = [...state.compactionQueuedMessages];\n state.compactionQueuedMessages = [];\n if (queued.length === 0) return;\n let nextIndex = 0;\n try {\n const first = queued[0];\n if (first !== undefined) {\n await requiredChatSessionCommand(state, \"prompt\")(first);\n nextIndex = 1;\n }\n for (; nextIndex < queued.length; nextIndex++) {\n await queueChatSessionFollowUp(state, queued[nextIndex]!);\n }\n } catch (err) {\n state.compactionQueuedMessages = [\n ...queued.slice(nextIndex),\n ...state.compactionQueuedMessages,\n ];\n notifyChatSessionWarning(state, errorMessage(err));\n state.requestRender?.();\n }\n}\n\nexport function restoreQueuedMessagesToEditor<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): boolean {\n const queuedMessages = [\n ...state.pendingSteeringMessages,\n ...state.pendingFollowUpMessages,\n ...state.compactionQueuedMessages,\n ];\n if (queuedMessages.length === 0) {\n notifyChatSessionStatus(state, \"No queued messages to restore\");\n return false;\n }\n const restoredText = combineQueuedMessagesForEditor(queuedMessages, state.inputBuffer);\n state.pendingSteeringMessages = [];\n state.pendingFollowUpMessages = [];\n state.compactionQueuedMessages = [];\n setChatSessionEditorText(state, restoredText);\n state.getAgentSession?.()?.clearQueue();\n state.requestRender?.();\n return true;\n}\n\nasync function runChatSessionBashCommand<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n command: string,\n excludeFromContext: boolean,\n): Promise<void> {\n const runBash = state.commands.runBash;\n if (!runBash) {\n notifyChatSessionWarning(state, \"no bash command configured for this chat session\");\n return;\n }\n const bashMessage: BashExecutionMessage = {\n role: \"bashExecution\",\n command,\n output: \"\",\n exitCode: undefined,\n cancelled: false,\n truncated: false,\n timestamp: Date.now(),\n ...(excludeFromContext ? { excludeFromContext: true } : {}),\n };\n const bashEntry: ChatMessageEntry = {\n role: \"tool\",\n kind: \"bashExecution\",\n message: bashMessage,\n isPartial: true,\n };\n state.transcript.push(bashEntry);\n state.localBashRunning = true;\n state.bodyViewport.scrollToBottom();\n state.requestRender?.();\n try {\n const result = await runBash({\n command,\n excludeFromContext,\n onChunk: (chunk) => {\n bashMessage.output += chunk;\n state.requestRender?.();\n },\n });\n bashMessage.output = result.output;\n bashMessage.exitCode = result.exitCode;\n bashMessage.cancelled = result.cancelled;\n bashMessage.truncated = result.truncated;\n if (result.fullOutputPath !== undefined) {\n bashMessage.fullOutputPath = result.fullOutputPath;\n }\n } catch (err) {\n bashMessage.output = errorMessage(err);\n bashMessage.exitCode = undefined;\n bashMessage.cancelled = false;\n bashMessage.truncated = false;\n } finally {\n bashEntry.isPartial = false;\n state.localBashRunning = false;\n state.requestRender?.();\n }\n}\n\nasync function queueChatSessionSteer<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n text: string,\n): Promise<void> {\n const agentSession = state.getAgentSession?.();\n if (agentSession?.isStreaming) {\n await agentSession.prompt(text, { streamingBehavior: \"steer\" });\n return;\n }\n await requiredChatSessionCommand(state, \"steer\")(text);\n}\n\nasync function queueChatSessionFollowUp<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n text: string,\n): Promise<void> {\n const agentSession = state.getAgentSession?.();\n if (agentSession?.isStreaming) {\n await agentSession.prompt(text, { streamingBehavior: \"followUp\" });\n return;\n }\n await requiredChatSessionCommand(state, \"followUp\")(text);\n}\n"]}
1
+ {"version":3,"file":"chat-session-host-actions.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-actions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAYpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAOzE,wBAAsB,oBAAoB,CACxC,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAYzD;AAED,wBAAsB,iBAAiB,CAAC,WAAW,SAAS,uBAAuB,EACjF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,IAAI,GAAE,MAAM,GAAG,UAAmB,EAClC,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,CA4Ef;AAED,wBAAsB,0BAA0B,CAC9C,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAYzD;AAED,wBAAsB,oBAAoB,CAAC,WAAW,SAAS,uBAAuB,EACpF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,wBAAsB,+BAA+B,CACnD,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBzD;AAED,wBAAgB,6BAA6B,CAC3C,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GAAG,OAAO,CAkBnD"}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-session-host-editor.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-editor.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,WAAW,EAEhB,KAAK,GAAG,EACT,MAAM,wBAAwB,CAAC;AAMhC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AASxE,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,aAAa,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpF,6BAA6B,EAAE,MAAM,OAAO,CAAC;IAC7C,eAAe,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,wBAAgB,uBAAuB,CACrC,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,GAAG,EAAE,GAAG,GAAG,SAAS,EACpB,WAAW,EAAE,OAAO,EACpB,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC,eAAe,CAAC,EAChE,SAAS,EAAE,0BAA0B,GACpC,eAAe,GAAG,SAAS,CAoE7B;AAED,wBAAgB,sBAAsB,CACpC,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,0BAA0B,GACpC,OAAO,CA8CT;AAED,wBAAgB,wBAAwB,CACtC,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAI9D;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,eAAe,EACvB,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,IAAI,CAKN;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,eAAe,EACvB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GACpC,IAAI,CAKN;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAGhF","sourcesContent":["import {\n type EditorComponent,\n type EditorTheme,\n type Focusable,\n type TUI,\n} from \"@earendil-works/pi-tui\";\nimport {\n openExternalEditorForText,\n pasteClipboardImageToEditor,\n} from \"../chat-input-actions.ts\";\nimport { CustomEditor } from \"./custom-editor.ts\";\nimport type { ChatTranscriptEntryLike } from \"./chat-transcript.ts\";\nimport type { ChatSessionHostState } from \"./chat-session-host-state.ts\";\nimport type { ChatSessionHostOpts } from \"./chat-session-host-types.ts\";\nimport {\n isChatSessionBashRunning,\n isChatSessionStreaming,\n notifyChatSessionStatus,\n notifyChatSessionWarning,\n} from \"./chat-session-host-runtime.ts\";\nimport { matchesKey } from \"./chat-session-host-utils.ts\";\n\nexport interface ChatSessionEditorCallbacks {\n submit: (mode: \"auto\" | \"followUp\", submittedText?: string) => void | Promise<void>;\n restoreQueuedMessagesToEditor: () => boolean;\n abortCompaction: () => void | Promise<void>;\n interrupt: () => void | Promise<void>;\n abortBash: () => void | Promise<void>;\n}\n\nexport function createChatSessionEditor<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n tui: TUI | undefined,\n keybindings: unknown,\n editorTheme: EditorTheme,\n editorFactory: ChatSessionHostOpts<TExtraEntry>[\"editorFactory\"],\n callbacks: ChatSessionEditorCallbacks,\n): EditorComponent | undefined {\n if (!tui || !keybindings) return undefined;\n const editor = createInheritedEditor(tui, editorTheme, keybindings, editorFactory) ??\n new CustomEditor(\n tui,\n editorTheme,\n keybindings as ConstructorParameters<typeof CustomEditor>[2],\n { paddingX: 0, autocompleteMaxVisible: 5 },\n );\n editor.onChange = (text) => {\n state.inputBuffer = text;\n state.isBashMode = text.trimStart().startsWith(\"!\");\n };\n editor.onSubmit = (text) => {\n void callbacks.submit(\"auto\", text);\n };\n const actionEditor = editor as EditorComponent & {\n onAction?: (action: string, handler: () => void) => void;\n onEscape?: () => void;\n onPasteImage?: () => void;\n };\n actionEditor.onAction?.(\"app.message.followUp\", () => {\n void callbacks.submit(\"followUp\");\n });\n actionEditor.onAction?.(\"app.message.dequeue\", () => {\n callbacks.restoreQueuedMessagesToEditor();\n });\n actionEditor.onAction?.(\"app.editor.external\", () => {\n openChatSessionExternalEditor(state);\n });\n if (state.actions) {\n for (const [action, handler] of Object.entries(state.actions)) {\n actionEditor.onAction?.(action, () => {\n void handler();\n });\n }\n }\n const previousPasteImage = actionEditor.onPasteImage;\n actionEditor.onPasteImage = () => {\n previousPasteImage?.();\n void pasteClipboardImageToEditor(\n chatSessionEditorAccess(state),\n () => state.requestRender?.(),\n { showWarning: (message) => notifyChatSessionWarning(state, message) },\n );\n };\n const previousEscape = actionEditor.onEscape;\n actionEditor.onEscape = () => {\n if (state.compacting) {\n void callbacks.abortCompaction();\n return;\n }\n if (isChatSessionStreaming(state)) {\n void callbacks.interrupt();\n return;\n }\n if (isChatSessionBashRunning(state)) {\n void callbacks.abortBash();\n return;\n }\n if (state.isBashMode) {\n setChatSessionEditorText(state, \"\");\n notifyChatSessionStatus(state, \"Bash mode cleared\");\n return;\n }\n previousEscape?.();\n };\n return editor;\n}\n\nexport function handleChatSessionInput<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n data: string,\n callbacks: ChatSessionEditorCallbacks,\n): boolean {\n if (state.bodyViewport.handleInput(data)) return true;\n if (matchesKey(data, \"alt+up\")) {\n callbacks.restoreQueuedMessagesToEditor();\n return true;\n }\n if (matchesKey(data, \"ctrl+f\")) {\n void callbacks.submit(\"followUp\");\n return true;\n }\n if (matchesKey(data, \"escape\")) {\n if (state.compacting) {\n void callbacks.abortCompaction();\n return true;\n }\n if (isChatSessionStreaming(state)) {\n void callbacks.interrupt();\n return true;\n }\n if (isChatSessionBashRunning(state)) {\n void callbacks.abortBash();\n return true;\n }\n if (state.isBashMode) {\n setChatSessionEditorText(state, \"\");\n notifyChatSessionStatus(state, \"Bash mode cleared\");\n return true;\n }\n }\n if (state.editor) {\n state.editor.handleInput(data);\n return true;\n }\n if (matchesKey(data, \"enter\")) {\n void callbacks.submit(\"auto\");\n return true;\n }\n if (matchesKey(data, \"backspace\")) {\n setChatSessionEditorText(state, state.inputBuffer.slice(0, -1));\n return true;\n }\n if (data.length === 1 && data >= \" \" && data <= \"~\") {\n setChatSessionEditorText(state, `${state.inputBuffer}${data}`);\n return true;\n }\n return false;\n}\n\nexport function setChatSessionEditorText<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>, text: string): void {\n state.inputBuffer = text;\n state.isBashMode = text.trimStart().startsWith(\"!\");\n state.editor?.setText(text);\n}\n\nexport function setEditorPlaceholder(\n editor: EditorComponent,\n placeholder: string | undefined,\n): void {\n const candidate = editor as EditorComponent & {\n setPlaceholder?: (value: string | undefined) => void;\n };\n candidate.setPlaceholder?.(placeholder);\n}\n\nexport function setEditorBorderColor(\n editor: EditorComponent,\n borderColor: (text: string) => string,\n): void {\n const candidate = editor as EditorComponent & {\n borderColor?: (text: string) => string;\n };\n if (candidate.borderColor !== undefined) candidate.borderColor = borderColor;\n}\n\nexport function setEditorFocused(editor: EditorComponent, focused: boolean): void {\n const candidate = editor as EditorComponent & Partial<Focusable>;\n if (\"focused\" in candidate) candidate.focused = focused;\n}\n\nfunction createInheritedEditor<TExtraEntry extends ChatTranscriptEntryLike>(\n tui: TUI,\n editorTheme: EditorTheme,\n keybindings: unknown,\n editorFactory: ChatSessionHostOpts<TExtraEntry>[\"editorFactory\"],\n): EditorComponent | undefined {\n if (!editorFactory) return undefined;\n try {\n return editorFactory(tui, editorTheme, keybindings);\n } catch {\n return undefined;\n }\n}\n\nfunction chatSessionEditorAccess<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): {\n insertTextAtCursor: (text: string) => void;\n getText: () => string;\n setText: (text: string) => void;\n} {\n return {\n insertTextAtCursor: (text: string) => {\n if (state.editor?.insertTextAtCursor) {\n state.editor.insertTextAtCursor(text);\n return;\n }\n setChatSessionEditorText(state, `${state.inputBuffer}${text}`);\n },\n getText: () => state.inputBuffer,\n setText: (text: string) => setChatSessionEditorText(state, text),\n };\n}\n\nfunction openChatSessionExternalEditor<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): void {\n if (!state.editor) return;\n const host = state.tui;\n if (!host) return;\n const currentText = state.editor.getExpandedText?.() ?? state.editor.getText();\n const updated = openExternalEditorForText(currentText, host, {\n showWarning: (message) => notifyChatSessionWarning(state, message),\n });\n if (updated !== undefined) setChatSessionEditorText(state, updated);\n}\n"]}
1
+ {"version":3,"file":"chat-session-host-editor.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-editor.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,WAAW,EAEhB,KAAK,GAAG,EACT,MAAM,wBAAwB,CAAC;AAMhC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AASxE,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,aAAa,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpF,6BAA6B,EAAE,MAAM,OAAO,CAAC;IAC7C,eAAe,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,wBAAgB,uBAAuB,CACrC,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,GAAG,EAAE,GAAG,GAAG,SAAS,EACpB,WAAW,EAAE,OAAO,EACpB,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC,eAAe,CAAC,EAChE,SAAS,EAAE,0BAA0B,GACpC,eAAe,GAAG,SAAS,CAoE7B;AAED,wBAAgB,sBAAsB,CACpC,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,0BAA0B,GACpC,OAAO,CA8CT;AAED,wBAAgB,wBAAwB,CACtC,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAI9D;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,eAAe,EACvB,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,IAAI,CAKN;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,eAAe,EACvB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GACpC,IAAI,CAKN;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAGhF"}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-session-host-events.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAOxE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAQpE,wBAAgB,0BAA0B,CACxC,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAqIT","sourcesContent":["import type { AgentSessionEvent } from \"../../../core/agent-session.ts\";\nimport { pickWhimsicalWorkingMessage } from \"../whimsical-messages.ts\";\nimport { flushChatSessionCompactionQueue } from \"./chat-session-host-actions.ts\";\nimport {\n afterChatSessionEvent,\n decrementOptimisticUserSignature,\n} from \"./chat-session-host-runtime.ts\";\nimport type { ChatSessionHostState } from \"./chat-session-host-state.ts\";\nimport type { ChatTranscriptEntryLike } from \"./chat-transcript.ts\";\nimport {\n extractMessageText,\n isMessageLike,\n isUserMessageLike,\n userMessageSignature,\n} from \"./chat-session-host-utils.ts\";\n\nexport function applyChatSessionAgentEvent<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n event: AgentSessionEvent,\n): boolean {\n const type = String((event as { type?: unknown }).type ?? \"\");\n if (type === \"message_start\") {\n const message = (event as { message?: unknown }).message;\n if (isUserMessageLike(message)) {\n const signature = userMessageSignature(extractMessageText(message.content));\n const count = state.optimisticUserSignatureCounts.get(signature) ?? 0;\n if (count > 0) {\n decrementOptimisticUserSignature(state, signature);\n return false;\n }\n }\n }\n if (isSharedLiveChatEvent(type)) {\n const changed = state.liveChat.applyEvent(event);\n const toolCallEvent = assistantToolCallEvent(event);\n const changedByToolCall = toolCallEvent !== undefined\n ? state.liveChat.applyEvent(toolCallEvent)\n : false;\n afterChatSessionEvent(state, changed || changedByToolCall);\n return changed || changedByToolCall;\n }\n let changed = false;\n switch (type) {\n case \"agent_start\":\n state.sdkBusy = true;\n state.liveChat.clearPendingTools();\n state.statusMessage = \"\";\n changed = true;\n break;\n case \"agent_end\":\n state.sdkBusy = false;\n state.workingMessage = undefined;\n state.liveChat.clearPendingTools();\n state.statusMessage = \"\";\n changed = true;\n break;\n case \"turn_start\":\n state.workingMessage = pickWhimsicalWorkingMessage();\n changed = true;\n break;\n case \"turn_end\":\n state.workingMessage = undefined;\n changed = true;\n break;\n case \"queue_update\": {\n const queue = event as { steering?: unknown; followUp?: unknown };\n state.pendingSteeringMessages = Array.isArray(queue.steering)\n ? queue.steering.filter((item): item is string => typeof item === \"string\")\n : [];\n state.pendingFollowUpMessages = Array.isArray(queue.followUp)\n ? queue.followUp.filter((item): item is string => typeof item === \"string\")\n : [];\n changed = true;\n break;\n }\n case \"tool_call\":\n case \"tool_use\":\n changed = state.liveChat.applyEvent(legacyToolStartEvent(event));\n break;\n case \"tool_result\":\n changed = state.liveChat.applyEvent(legacyToolResultEvent(event));\n break;\n case \"thinking_delta\":\n case \"thinking\":\n changed = state.liveChat.applyEvent(legacyThinkingEvent(event));\n break;\n case \"compaction_start\":\n state.compacting = true;\n state.sdkBusy = true;\n state.statusMessage = \"compacting context…\";\n changed = true;\n break;\n case \"compaction_end\": {\n const compaction = event as Extract<AgentSessionEvent, { type: \"compaction_end\" }>;\n state.compacting = false;\n state.sdkBusy = false;\n state.statusMessage = compaction.errorMessage ?? \"\";\n if (!compaction.aborted && !compaction.errorMessage && compaction.result) {\n const compactedMessages = state.getAgentSession?.()?.messages;\n if (compactedMessages) {\n state.liveChat.replaceMessages(compactedMessages, state.extraEntries);\n }\n }\n if (!compaction.aborted && !compaction.errorMessage && state.compactionQueuedMessages.length > 0) {\n void flushChatSessionCompactionQueue(state);\n }\n changed = true;\n break;\n }\n case \"auto_retry_start\":\n state.sdkBusy = true;\n state.statusMessage = \"retrying…\";\n changed = true;\n break;\n case \"model_fallback_start\":\n state.sdkBusy = true;\n state.statusMessage = \"switching model…\";\n changed = true;\n break;\n case \"model_fallback_end\": {\n const fallback = event as Extract<AgentSessionEvent, { type: \"model_fallback_end\" }>;\n state.statusMessage = fallback.success ? \"\" : (fallback.finalError ?? \"model fallback failed\");\n if (!fallback.success) {\n state.sdkBusy = false;\n state.workingMessage = undefined;\n }\n changed = true;\n break;\n }\n case \"auto_retry_end\": {\n const retry = event as Extract<AgentSessionEvent, { type: \"auto_retry_end\" }>;\n state.statusMessage = \"\";\n if (!retry.success) {\n state.sdkBusy = false;\n state.workingMessage = undefined;\n }\n changed = true;\n break;\n }\n case \"agent_continue_error\": {\n const continueError = event as Extract<AgentSessionEvent, { type: \"agent_continue_error\" }>;\n state.sdkBusy = false;\n state.statusMessage = continueError.errorMessage;\n state.workingMessage = undefined;\n changed = true;\n break;\n }\n default:\n changed = false;\n }\n afterChatSessionEvent(state, changed);\n return changed;\n}\n\nfunction isSharedLiveChatEvent(type: string): boolean {\n return (\n type === \"message_start\" ||\n type === \"message_update\" ||\n type === \"message_end\" ||\n type === \"tool_execution_start\" ||\n type === \"tool_execution_update\" ||\n type === \"tool_execution_end\"\n );\n}\n\nfunction assistantToolCallEvent(event: AgentSessionEvent): {\n type: \"tool_execution_start\";\n toolCallId: string;\n toolName: string;\n args: unknown;\n} | undefined {\n const assistantEvent = (event as {\n assistantMessageEvent?: {\n type?: unknown;\n contentIndex?: unknown;\n partial?: unknown;\n toolCall?: unknown;\n };\n }).assistantMessageEvent;\n const streamType = String(assistantEvent?.type ?? \"\");\n if (!streamType.startsWith(\"toolcall_\")) return undefined;\n const explicit = toolCallPayload(assistantEvent?.toolCall);\n if (explicit) return explicit;\n const contentIndex = typeof assistantEvent?.contentIndex === \"number\" ? assistantEvent.contentIndex : undefined;\n if (contentIndex === undefined) return undefined;\n const partial = assistantEvent?.partial;\n if (!isMessageLike(partial) || partial.role !== \"assistant\") return undefined;\n const content = partial.content;\n if (!Array.isArray(content)) return undefined;\n return toolCallPayload(content[contentIndex]);\n}\n\nfunction toolCallPayload(value: unknown): {\n type: \"tool_execution_start\";\n toolCallId: string;\n toolName: string;\n args: unknown;\n} | undefined {\n if (value === null || typeof value !== \"object\") return undefined;\n const candidate = value as { type?: unknown; id?: unknown; name?: unknown; arguments?: unknown };\n if (candidate.type !== \"toolCall\") return undefined;\n if (typeof candidate.id !== \"string\" || typeof candidate.name !== \"string\") return undefined;\n return {\n type: \"tool_execution_start\",\n toolCallId: candidate.id,\n toolName: candidate.name,\n args: candidate.arguments ?? {},\n };\n}\n\nfunction legacyToolStartEvent(event: AgentSessionEvent): {\n type: \"tool_execution_start\";\n toolCallId: string;\n toolName: string;\n args: unknown;\n} {\n const payload = event as { toolCallId?: unknown; name?: unknown; input?: unknown; args?: unknown };\n const toolName = typeof payload.name === \"string\" ? payload.name : \"tool\";\n const toolCallId =\n typeof payload.toolCallId === \"string\" ? payload.toolCallId : `live-${toolName}`;\n return {\n type: \"tool_execution_start\",\n toolCallId,\n toolName,\n args: payload.input ?? payload.args ?? {},\n };\n}\n\nfunction legacyToolResultEvent(event: AgentSessionEvent): {\n type: \"tool_execution_end\";\n toolCallId: string;\n toolName: string;\n result: unknown;\n isError: boolean;\n} {\n const payload = event as {\n toolCallId?: unknown;\n name?: unknown;\n output?: unknown;\n isError?: unknown;\n };\n const toolName = typeof payload.name === \"string\" ? payload.name : \"tool\";\n const toolCallId =\n typeof payload.toolCallId === \"string\" ? payload.toolCallId : `live-${toolName}`;\n const output = payload.output;\n return {\n type: \"tool_execution_end\",\n toolCallId,\n toolName,\n result:\n output !== null && typeof output === \"object\" && \"content\" in output\n ? output\n : { content: typeof output === \"string\" ? [{ type: \"text\", text: output }] : [] },\n isError: payload.isError === true,\n };\n}\n\nfunction legacyThinkingEvent(event: AgentSessionEvent): {\n type: \"message_update\";\n assistantMessageEvent: { type: \"thinking_delta\"; delta: string };\n message: { role: \"assistant\"; content: [] };\n} {\n const delta = String(\n (event as { delta?: unknown }).delta ??\n (event as { text?: unknown }).text ??\n \"\",\n );\n return {\n type: \"message_update\",\n assistantMessageEvent: { type: \"thinking_delta\", delta },\n message: { role: \"assistant\", content: [] },\n };\n}\n"]}
1
+ {"version":3,"file":"chat-session-host-events.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAOxE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAQpE,wBAAgB,0BAA0B,CACxC,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAqIT"}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-session-host-rendering.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-rendering.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EAMf,MAAM,wBAAwB,CAAC;AAOhC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAgBzE,wBAAgB,qBAAqB,CACnC,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,MAAM,EAAE,CAaV;AAED,wBAAgB,gCAAgC,CAC9C,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBnE;AAED,wBAAgB,8BAA8B,CAC5C,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CASnE;AAED,wBAAgB,sBAAsB,CAAC,WAAW,SAAS,uBAAuB,EAChF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,KAAK,EAAE,MAAM,GACZ,MAAM,EAAE,CAIV;AAED,wBAAgB,uBAAuB,CAAC,WAAW,SAAS,uBAAuB,EACjF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,GACf,MAAM,EAAE,CAwBV;AAED,wBAAgB,uBAAuB,CAAC,WAAW,SAAS,uBAAuB,EACjF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,KAAK,EAAE,MAAM,GACZ,MAAM,EAAE,CAMV;AAED,wBAAgB,sBAAsB,CACpC,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,SAAS,CAcX;AAED,wBAAgB,kBAAkB,CAAC,WAAW,SAAS,uBAAuB,EAC5E,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,KAAK,EAAE,MAAM,GACZ,MAAM,CAQR","sourcesContent":["import {\n type Component,\n type TUI,\n Spacer,\n Text,\n truncateToWidth,\n visibleWidth,\n} from \"@earendil-works/pi-tui\";\nimport { UsageMeterComponent, FooterComponent } from \"./footer.ts\";\nimport {\n renderChatMessageEntry,\n type ChatMessageEntry,\n type ChatMessageRenderOptions,\n} from \"./chat-message-renderer.ts\";\nimport type { ChatTranscriptEntryLike } from \"./chat-transcript.ts\";\nimport type { ChatSessionHostState } from \"./chat-session-host-state.ts\";\nimport type { ChatSessionHostEntry } from \"./chat-session-host-types.ts\";\nimport {\n setEditorBorderColor,\n setEditorFocused,\n setEditorPlaceholder,\n} from \"./chat-session-host-editor.ts\";\nimport { isChatSessionStreaming } from \"./chat-session-host-runtime.ts\";\nimport {\n cacheKey,\n isChatMessageEntry,\n spinnerFrame,\n stripAnsi,\n tailStreamingText,\n} from \"./chat-session-host-utils.ts\";\nimport { WorkingStatusComponent } from \"./working-status.ts\";\n\nexport function renderChatSessionBody<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n width: number,\n budget: number,\n): string[] {\n const components: Component[] = [];\n state.transcriptRenderSettingsKey = chatRenderSettingsCacheKey(state);\n if (state.transcript.length > 0) {\n components.push(state.transcriptComponent);\n }\n if (state.statusMessage) {\n components.push(new Spacer(1));\n components.push(new Text(state.style.dim(state.statusMessage), 2, 0));\n }\n state.bodyViewport.setVisibleRows(budget);\n state.bodyViewport.setComponents(components);\n return state.bodyViewport.render(width);\n}\n\nexport function renderChatSessionPendingMessages<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>, width: number): string[] {\n if (\n state.pendingSteeringMessages.length === 0 &&\n state.pendingFollowUpMessages.length === 0 &&\n state.compactionQueuedMessages.length === 0\n ) {\n return [];\n }\n const lines = [state.style.blank(width)];\n for (const message of state.pendingSteeringMessages) {\n lines.push(...pendingMessageLine(state, width, \"Steering\", message));\n }\n for (const message of state.pendingFollowUpMessages) {\n lines.push(...pendingMessageLine(state, width, \"Follow-up\", message));\n }\n for (const message of state.compactionQueuedMessages) {\n lines.push(...pendingMessageLine(state, width, \"Queued\", message));\n }\n const hint = state.getActionKeyDisplay?.(\"app.message.dequeue\") ?? \"alt+up\";\n lines.push(...new Text(state.style.dim(`↳ ${hint} to edit all queued messages`), 1, 0).render(width));\n return lines;\n}\n\nexport function renderChatSessionWorkingStatus<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>, width: number): string[] {\n if (!isChatSessionStreaming(state)) return [];\n const message = state.workingMessage ?? \"Working...\";\n return new WorkingStatusComponent({\n spinner: spinnerFrame(),\n message,\n spinnerColor: (text) => state.style.accentBold(text),\n messageColor: (text) => state.style.textMuted(text),\n }).render(width);\n}\n\nexport function renderChatSessionUsage<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n width: number,\n): string[] {\n const agentSession = state.getAgentSession?.();\n if (!agentSession) return [];\n return new UsageMeterComponent(agentSession).render(width);\n}\n\nexport function renderChatSessionEditor<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n width: number,\n focused: boolean,\n): string[] {\n const disabled = state.isDisabled?.() === true;\n const agentSession = state.getAgentSession?.();\n const ruleHex = state.style.editorRuleColor(disabled, agentSession, {\n isBashMode: state.isBashMode,\n });\n if (!disabled && state.editor) {\n setEditorFocused(state.editor, focused);\n setEditorPlaceholder(state.editor, undefined);\n setEditorBorderColor(state.editor, (text) => state.style.rule(ruleHex, text));\n return state.editor.render(width);\n }\n if (state.editor) setEditorFocused(state.editor, false);\n const rule = state.style.rule(ruleHex, \"─\".repeat(width));\n const available = Math.max(1, width - 3);\n const value = state.inputBuffer\n ? state.style.text(truncateToWidth(state.inputBuffer, available)) + state.style.cursor()\n : disabled\n ? \"\"\n : state.style.cursor();\n const left = state.style.accentBold(\"❯\") + \" \" + value;\n const gap = Math.max(0, width - visibleWidth(stripAnsi(left)));\n const body = left + \" \".repeat(gap);\n return [rule, body, rule];\n}\n\nexport function renderChatSessionFooter<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n width: number,\n): string[] {\n const agentSession = state.getAgentSession?.();\n if (agentSession && state.footerData) {\n return new FooterComponent(agentSession, state.footerData).render(width);\n }\n return [];\n}\n\nexport function renderChatSessionEntry<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n entry: ChatSessionHostEntry<TExtraEntry>,\n): Component {\n if (state.extraEntries.includes(entry as TExtraEntry)) {\n return state.renderExtraEntry?.(entry as TExtraEntry) ?? new Text(\"\", 0, 0);\n }\n if (isChatMessageEntry(entry)) {\n return renderChatMessageEntry(\n streamingWindowedEntry(state, entry),\n chatMessageRenderOptions(state),\n );\n }\n if (!state.renderExtraEntry) {\n return new Text(\"\", 0, 0);\n }\n return state.renderExtraEntry(entry);\n}\n\nexport function transcriptCacheKey<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n entry: ChatSessionHostEntry<TExtraEntry>,\n index: number,\n): string {\n return cacheKey([\n state.transcriptRenderSettingsKey,\n index,\n entry.role,\n renderIdentityKey(state, entry),\n entryContentCacheKey(state, entry),\n ]);\n}\n\nfunction streamingWindowedEntry<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n entry: ChatMessageEntry,\n): ChatMessageEntry {\n if (!isChatSessionStreaming(state) || state.bodyViewport.getScrollFromBottom() !== 0) {\n return entry;\n }\n if (entry.kind !== \"assistant\") return entry;\n const content = entry.message.content.map((item) => {\n if (item.type === \"text\") return { ...item, text: tailStreamingText(item.text) };\n if (item.type === \"thinking\") return { ...item, thinking: tailStreamingText(item.thinking) };\n return item;\n });\n return { ...entry, message: { ...entry.message, content } };\n}\n\nfunction chatMessageRenderOptions<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): ChatMessageRenderOptions {\n const inherited = state.getChatRenderSettings?.();\n return {\n ...inherited,\n ui: toolTui(state),\n cwd: state.getCwd?.() ?? state.getAgentSession?.()?.sessionManager.getCwd() ?? process.cwd(),\n markdownTheme: inherited?.markdownTheme ?? state.getMarkdownTheme?.(),\n showImages: inherited?.showImages ?? true,\n };\n}\n\nfunction toolTui<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): Pick<TUI, \"requestRender\"> {\n return { requestRender: () => state.requestRender?.() };\n}\n\nfunction chatRenderSettingsCacheKey<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): string {\n const inherited = state.getChatRenderSettings?.();\n return cacheKey([\n \"settings\",\n inherited?.hideThinkingBlock === true,\n inherited?.hiddenThinkingLabel ?? \"\",\n inherited?.toolOutputExpanded === true,\n inherited?.showImages !== false,\n inherited?.imageWidthCells ?? null,\n inherited?.outputPad ?? null,\n state.getCwd?.() ?? state.getAgentSession?.()?.sessionManager.getCwd() ?? process.cwd(),\n state.bodyViewport.getScrollFromBottom() === 0,\n isChatSessionStreaming(state),\n ]);\n}\n\nfunction entryContentCacheKey<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n entry: ChatSessionHostEntry<TExtraEntry>,\n): string {\n if (!isChatMessageEntry(entry)) return cacheKey([\"extra\"]);\n switch (entry.kind) {\n case \"assistant\":\n return cacheKey([\"assistant\", renderIdentityKey(state, entry.message)]);\n case \"tool\":\n return cacheKey([\"tool\", entry.toolCallId, entry.toolName, entry.isPartial === true, entry.result === undefined ? null : renderIdentityKey(state, entry.result)]);\n case \"bashExecution\":\n return cacheKey([\"bashExecution\", entry.isPartial === true, entry.message.command, entry.message.output, entry.message.exitCode ?? null, entry.message.cancelled, entry.message.truncated, entry.message.fullOutputPath ?? null]);\n case \"user\":\n return cacheKey([\"user\", entry.text]);\n case \"custom\":\n return cacheKey([\"custom\", renderIdentityKey(state, entry.message)]);\n case \"branchSummary\":\n return cacheKey([\"branchSummary\", renderIdentityKey(state, entry.message)]);\n case \"system\":\n return cacheKey([\"system\", entry.text]);\n }\n}\n\nfunction renderIdentityKey<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n value: object,\n): string {\n const existing = state.renderIdentityIds.get(value);\n if (existing !== undefined) return String(existing);\n const id = state.nextRenderIdentityId;\n state.nextRenderIdentityId += 1;\n state.renderIdentityIds.set(value, id);\n return String(id);\n}\n\nfunction pendingMessageLine<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n width: number,\n label: \"Steering\" | \"Follow-up\" | \"Queued\",\n message: string,\n): string[] {\n const text = `${label}: ${message}`;\n return new Text(\n state.style.dim(truncateToWidth(text, Math.max(1, width - 2))),\n 1,\n 0,\n ).render(width);\n}\n"]}
1
+ {"version":3,"file":"chat-session-host-rendering.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-rendering.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EAMf,MAAM,wBAAwB,CAAC;AAOhC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAgBzE,wBAAgB,qBAAqB,CACnC,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,MAAM,EAAE,CAaV;AAED,wBAAgB,gCAAgC,CAC9C,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBnE;AAED,wBAAgB,8BAA8B,CAC5C,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CASnE;AAED,wBAAgB,sBAAsB,CAAC,WAAW,SAAS,uBAAuB,EAChF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,KAAK,EAAE,MAAM,GACZ,MAAM,EAAE,CAIV;AAED,wBAAgB,uBAAuB,CAAC,WAAW,SAAS,uBAAuB,EACjF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,GACf,MAAM,EAAE,CAwBV;AAED,wBAAgB,uBAAuB,CAAC,WAAW,SAAS,uBAAuB,EACjF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,KAAK,EAAE,MAAM,GACZ,MAAM,EAAE,CAMV;AAED,wBAAgB,sBAAsB,CACpC,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,SAAS,CAcX;AAED,wBAAgB,kBAAkB,CAAC,WAAW,SAAS,uBAAuB,EAC5E,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,KAAK,EAAE,MAAM,GACZ,MAAM,CAQR"}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-session-host-runtime.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAOzE,wBAAgB,sBAAsB,CAAC,WAAW,SAAS,uBAAuB,EAChF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,OAAO,CAET;AAED,wBAAgB,wBAAwB,CAAC,WAAW,SAAS,uBAAuB,EAClF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,OAAO,CAET;AAED,wBAAgB,gCAAgC,CAC9C,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,SAAS,EAAE,MAAM,GAChB,IAAI,CAKN;AAED,wBAAgB,gCAAgC,CAC9C,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,SAAS,EAAE,MAAM,GAChB,IAAI,CAIN;AAED,wBAAgB,4BAA4B,CAC1C,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GAAG,IAAI,CAehD;AAED,wBAAgB,4CAA4C,CAC1D,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GAAG,IAAI,CAShD;AAED,wBAAgB,kBAAkB,CAAC,WAAW,SAAS,uBAAuB,EAC5E,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,IAAI,CAWN;AAED,wBAAgB,wBAAwB,CAAC,WAAW,SAAS,uBAAuB,EAClF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,OAAO,EAAE,MAAM,GACd,IAAI,CAIN;AAED,wBAAgB,uBAAuB,CAAC,WAAW,SAAS,uBAAuB,EACjF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,OAAO,EAAE,MAAM,GACd,IAAI,CAIN;AAED,wBAAgB,0BAA0B,CACxC,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,GAC/C,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAuBlC;AAED,wBAAgB,qBAAqB,CAAC,WAAW,SAAS,uBAAuB,EAC/E,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,OAAO,EAAE,OAAO,GACf,IAAI,CAIN","sourcesContent":["import type { ChatTranscriptEntryLike } from \"./chat-transcript.ts\";\nimport type { ChatSessionHostState } from \"./chat-session-host-state.ts\";\nimport { finalizeTerminalWorkflowToolEntries } from \"./chat-session-host-terminal-cleanup.ts\";\nimport {\n ANIMATION_FRAME_MS,\n STREAMING_RENDER_THROTTLE_MS,\n} from \"./chat-session-host-utils.ts\";\n\nexport function isChatSessionStreaming<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): boolean {\n return state.sdkBusy || state.isStreamingOverride?.() === true;\n}\n\nexport function isChatSessionBashRunning<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): boolean {\n return state.localBashRunning || state.isBashRunningOverride?.() === true;\n}\n\nexport function incrementOptimisticUserSignature<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n signature: string,\n): void {\n state.optimisticUserSignatureCounts.set(\n signature,\n (state.optimisticUserSignatureCounts.get(signature) ?? 0) + 1,\n );\n}\n\nexport function decrementOptimisticUserSignature<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n signature: string,\n): void {\n const count = state.optimisticUserSignatureCounts.get(signature) ?? 0;\n if (count <= 1) state.optimisticUserSignatureCounts.delete(signature);\n else state.optimisticUserSignatureCounts.set(signature, count - 1);\n}\n\nexport function syncChatSessionAnimationTick<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): void {\n const shouldAnimate =\n isChatSessionStreaming(state) ||\n (state.sdkBusy && state.liveChat.pendingToolIds().length > 0);\n if (shouldAnimate && !state.animationTimer) {\n state.animationTimer = setInterval(() => {\n state.requestRender?.();\n }, ANIMATION_FRAME_MS);\n state.animationTimer.unref?.();\n return;\n }\n if (!shouldAnimate && state.animationTimer) {\n clearInterval(state.animationTimer);\n state.animationTimer = undefined;\n }\n}\n\nexport function clearChatSessionBusyForTerminalWorkflowStage<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): void {\n state.sdkBusy = false;\n state.workingMessage = undefined;\n if (finalizeTerminalWorkflowToolEntries(state.transcript)) {\n state.transcriptComponent.invalidate();\n }\n state.liveChat.clearPendingTools();\n state.statusMessage = \"\";\n syncChatSessionAnimationTick(state);\n}\n\nexport function disposeChatSession<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n): void {\n if (state.animationTimer) {\n clearInterval(state.animationTimer);\n state.animationTimer = undefined;\n }\n if (state.renderThrottleTimer) {\n clearTimeout(state.renderThrottleTimer);\n state.renderThrottleTimer = undefined;\n }\n state.transcriptComponent.invalidate();\n state.editor = undefined;\n}\n\nexport function notifyChatSessionWarning<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n message: string,\n): void {\n state.statusMessage = message;\n state.showWarning?.(message);\n state.requestRender?.();\n}\n\nexport function notifyChatSessionStatus<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n message: string,\n): void {\n state.statusMessage = message;\n state.showStatus?.(message);\n state.requestRender?.();\n}\n\nexport function requiredChatSessionCommand<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(\n state: ChatSessionHostState<TExtraEntry>,\n name: \"prompt\" | \"steer\" | \"followUp\" | \"resume\",\n): (text?: string) => Promise<void> {\n switch (name) {\n case \"prompt\":\n return async (text) => {\n if (!state.commands.prompt) throw new Error(\"no prompt command configured for this chat session\");\n await state.commands.prompt(text ?? \"\");\n };\n case \"steer\":\n return async (text) => {\n if (!state.commands.steer) throw new Error(\"no steer command configured for this chat session\");\n await state.commands.steer(text ?? \"\");\n };\n case \"followUp\":\n return async (text) => {\n if (!state.commands.followUp) throw new Error(\"no followUp command configured for this chat session\");\n await state.commands.followUp(text ?? \"\");\n };\n case \"resume\":\n return async (text) => {\n if (!state.commands.resume) throw new Error(\"no resume command configured for this chat session\");\n await state.commands.resume(text);\n };\n }\n}\n\nexport function afterChatSessionEvent<TExtraEntry extends ChatTranscriptEntryLike>(\n state: ChatSessionHostState<TExtraEntry>,\n changed: boolean,\n): void {\n syncChatSessionAnimationTick(state);\n if (!changed) return;\n requestChatSessionEventRender(state);\n}\n\nfunction requestChatSessionEventRender<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(state: ChatSessionHostState<TExtraEntry>): void {\n if (!isChatSessionStreaming(state)) {\n state.requestRender?.();\n return;\n }\n if (state.renderThrottleTimer) return;\n state.renderThrottleTimer = setTimeout(() => {\n state.renderThrottleTimer = undefined;\n state.requestRender?.();\n }, STREAMING_RENDER_THROTTLE_MS);\n state.renderThrottleTimer.unref?.();\n}\n"]}
1
+ {"version":3,"file":"chat-session-host-runtime.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAOzE,wBAAgB,sBAAsB,CAAC,WAAW,SAAS,uBAAuB,EAChF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,OAAO,CAET;AAED,wBAAgB,wBAAwB,CAAC,WAAW,SAAS,uBAAuB,EAClF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,OAAO,CAET;AAED,wBAAgB,gCAAgC,CAC9C,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,SAAS,EAAE,MAAM,GAChB,IAAI,CAKN;AAED,wBAAgB,gCAAgC,CAC9C,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,SAAS,EAAE,MAAM,GAChB,IAAI,CAIN;AAED,wBAAgB,4BAA4B,CAC1C,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GAAG,IAAI,CAehD;AAED,wBAAgB,4CAA4C,CAC1D,WAAW,SAAS,uBAAuB,EAC3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GAAG,IAAI,CAShD;AAED,wBAAgB,kBAAkB,CAAC,WAAW,SAAS,uBAAuB,EAC5E,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,IAAI,CAWN;AAED,wBAAgB,wBAAwB,CAAC,WAAW,SAAS,uBAAuB,EAClF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,OAAO,EAAE,MAAM,GACd,IAAI,CAIN;AAED,wBAAgB,uBAAuB,CAAC,WAAW,SAAS,uBAAuB,EACjF,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,OAAO,EAAE,MAAM,GACd,IAAI,CAIN;AAED,wBAAgB,0BAA0B,CACxC,WAAW,SAAS,uBAAuB,EAE3C,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,GAC/C,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAuBlC;AAED,wBAAgB,qBAAqB,CAAC,WAAW,SAAS,uBAAuB,EAC/E,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,EACxC,OAAO,EAAE,OAAO,GACf,IAAI,CAIN"}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-session-host-state.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-state.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentSession } from \"../../../core/agent-session.ts\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.ts\";\nimport type {\n Component,\n EditorComponent,\n MarkdownTheme,\n TUI,\n} from \"@earendil-works/pi-tui\";\nimport { LiveChatEntriesController } from \"./chat-message-renderer.ts\";\nimport {\n ChatTranscriptComponent,\n ScrollableComponentViewport,\n type ChatTranscriptEntryLike,\n} from \"./chat-transcript.ts\";\nimport type {\n ChatSessionHostCommands,\n ChatSessionHostEntry,\n ChatSessionHostOpts,\n ChatSessionHostStyle,\n} from \"./chat-session-host-types.ts\";\n\nexport interface ChatSessionHostStateCallbacks<\n TExtraEntry extends ChatTranscriptEntryLike,\n> {\n renderEntry: (\n state: ChatSessionHostState<TExtraEntry>,\n entry: ChatSessionHostEntry<TExtraEntry>,\n ) => Component;\n transcriptCacheKey: (\n state: ChatSessionHostState<TExtraEntry>,\n entry: ChatSessionHostEntry<TExtraEntry>,\n index: number,\n ) => string;\n}\n\nexport class ChatSessionHostState<\n TExtraEntry extends ChatTranscriptEntryLike = never,\n> {\n readonly style: ChatSessionHostStyle;\n readonly commands: ChatSessionHostCommands;\n readonly requestRender: (() => void) | undefined;\n readonly getAgentSession: (() => AgentSession | undefined) | undefined;\n readonly isStreamingOverride: (() => boolean) | undefined;\n readonly isPaused: (() => boolean) | undefined;\n readonly isDisabled: (() => boolean) | undefined;\n readonly isBashRunningOverride: (() => boolean) | undefined;\n readonly showWarning: ((message: string) => void) | undefined;\n readonly showStatus: ((message: string) => void) | undefined;\n readonly actions: Record<string, () => void | Promise<void>> | undefined;\n readonly getActionKeyDisplay: ((action: string) => string) | undefined;\n readonly getMarkdownTheme: (() => MarkdownTheme) | undefined;\n readonly getChatRenderSettings: ChatSessionHostOpts<TExtraEntry>[\"getChatRenderSettings\"];\n readonly getCwd: (() => string) | undefined;\n readonly footerData: ReadonlyFooterDataProvider | undefined;\n readonly renderExtraEntry: ((entry: TExtraEntry) => Component) | undefined;\n readonly tui: TUI | undefined;\n\n inputBuffer = \"\";\n transcript: ChatSessionHostEntry<TExtraEntry>[] = [];\n extraEntries: TExtraEntry[] = [];\n statusMessage = \"\";\n isBashMode = false;\n localBashRunning = false;\n sdkBusy = false;\n workingMessage: string | undefined;\n pendingSteeringMessages: readonly string[] = [];\n pendingFollowUpMessages: readonly string[] = [];\n compactionQueuedMessages: readonly string[] = [];\n compacting = false;\n animationTimer: ReturnType<typeof setInterval> | undefined;\n renderThrottleTimer: ReturnType<typeof setTimeout> | undefined;\n bodyViewport = new ScrollableComponentViewport();\n transcriptComponent: ChatTranscriptComponent<ChatSessionHostEntry<TExtraEntry>>;\n transcriptRenderSettingsKey = \"\";\n renderIdentityIds = new WeakMap<object, number>();\n nextRenderIdentityId = 1;\n liveChat: LiveChatEntriesController;\n editor: EditorComponent | undefined;\n optimisticUserSignatureCounts = new Map<string, number>();\n\n constructor(\n opts: ChatSessionHostOpts<TExtraEntry>,\n callbacks: ChatSessionHostStateCallbacks<TExtraEntry>,\n ) {\n this.style = opts.style;\n this.commands = opts.commands ?? {};\n this.requestRender = opts.requestRender;\n this.getAgentSession = opts.getAgentSession;\n this.isStreamingOverride = opts.isStreaming;\n this.isPaused = opts.isPaused;\n this.isDisabled = opts.isDisabled;\n this.isBashRunningOverride = opts.isBashRunning;\n this.showWarning = opts.showWarning;\n this.showStatus = opts.showStatus;\n this.actions = opts.actions;\n this.getActionKeyDisplay = opts.getActionKeyDisplay;\n this.getMarkdownTheme = opts.getMarkdownTheme;\n this.getChatRenderSettings = opts.getChatRenderSettings;\n this.getCwd = opts.getCwd;\n this.footerData = opts.footerData;\n this.renderExtraEntry = opts.renderExtraEntry;\n this.tui = opts.tui;\n this.liveChat = new LiveChatEntriesController(this.transcript);\n this.transcriptComponent = new ChatTranscriptComponent(\n this.transcript,\n (entry) => callbacks.renderEntry(this, entry),\n (entry, index) => callbacks.transcriptCacheKey(this, entry, index),\n );\n }\n}\n"]}
1
+ {"version":3,"file":"chat-session-host-state.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-state.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-session-host-terminal-cleanup.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-terminal-cleanup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAMpE,wBAAgB,mCAAmC,CACjD,WAAW,SAAS,uBAAuB,EAC3C,OAAO,EAAE,oBAAoB,CAAC,WAAW,CAAC,EAAE,GAAG,OAAO,CAYvD","sourcesContent":["import type { ChatSessionHostEntry } from \"./chat-session-host-types.ts\";\nimport type { ChatTranscriptEntryLike } from \"./chat-transcript.ts\";\n\ntype ToolEntry = Extract<ChatSessionHostEntry<ChatTranscriptEntryLike>, { kind: \"tool\" }>;\ntype ToolResult = NonNullable<ToolEntry[\"result\"]>;\ntype ObjectRecord = Record<string, unknown>;\n\nexport function finalizeTerminalWorkflowToolEntries<\n TExtraEntry extends ChatTranscriptEntryLike,\n>(entries: ChatSessionHostEntry<TExtraEntry>[]): boolean {\n let changed = false;\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n if (!isToolEntry(entry)) continue;\n const finalized = finalizeToolEntry(entry);\n if (finalized !== entry) {\n entries[i] = finalized as ChatSessionHostEntry<TExtraEntry>;\n changed = true;\n }\n }\n return changed;\n}\n\nfunction finalizeToolEntry(entry: ToolEntry): ToolEntry {\n const result = entry.result ? finalizeToolResult(entry.result) : undefined;\n const resultChanged = result !== entry.result;\n if (entry.isPartial === false && !resultChanged) return entry;\n return {\n ...entry,\n ...(result ? { result } : {}),\n isPartial: false,\n };\n}\n\nfunction finalizeToolResult(result: ToolResult): ToolResult {\n const details = finalizeDetails(result.details);\n if (details === result.details) return result;\n return { ...result, details };\n}\n\nfunction finalizeDetails(details: unknown): unknown {\n if (!isRecord(details)) return details;\n let changed = false;\n const next: ObjectRecord = { ...details };\n const progress = finalizeProgressArray(next.progress);\n if (progress !== next.progress) {\n next.progress = progress;\n changed = true;\n }\n if (Array.isArray(next.results)) {\n const results = next.results.map((item) => finalizeResultEntry(item));\n if (results.some((item, index) => item !== (next.results as unknown[])[index])) {\n next.results = results;\n changed = true;\n }\n }\n const workflowGraph = finalizeWorkflowGraph(next.workflowGraph);\n if (workflowGraph !== next.workflowGraph) {\n next.workflowGraph = workflowGraph;\n changed = true;\n }\n return changed ? next : details;\n}\n\nfunction finalizeResultEntry(entry: unknown): unknown {\n if (!isRecord(entry)) return entry;\n const progress = finalizeProgress(entry.progress);\n if (progress === entry.progress) return entry;\n return { ...entry, progress };\n}\n\nfunction finalizeProgressArray(progress: unknown): unknown {\n if (!Array.isArray(progress)) return progress;\n let changed = false;\n const next = progress.map((entry) => {\n const finalized = finalizeProgress(entry);\n if (finalized !== entry) changed = true;\n return finalized;\n });\n return changed ? next : progress;\n}\n\nfunction finalizeProgress(progress: unknown): unknown {\n if (!isRecord(progress) || progress.status !== \"running\") return progress;\n return {\n ...progress,\n status: \"detached\",\n activityState: undefined,\n currentTool: undefined,\n currentToolArgs: undefined,\n currentToolStartedAt: undefined,\n };\n}\n\nfunction finalizeWorkflowGraph(graph: unknown): unknown {\n if (!isRecord(graph)) return graph;\n const nodes = finalizeWorkflowGraphNodes(graph.nodes);\n const shouldClearCurrent = graph.currentNodeId !== undefined;\n if (nodes === graph.nodes && !shouldClearCurrent) return graph;\n return { ...graph, nodes, currentNodeId: undefined };\n}\n\nfunction finalizeWorkflowGraphNodes(nodes: unknown): unknown {\n if (!Array.isArray(nodes)) return nodes;\n let changed = false;\n const next = nodes.map((node) => {\n const finalized = finalizeWorkflowGraphNode(node);\n if (finalized !== node) changed = true;\n return finalized;\n });\n return changed ? next : nodes;\n}\n\nfunction finalizeWorkflowGraphNode(node: unknown): unknown {\n if (!isRecord(node)) return node;\n let changed = false;\n const next: ObjectRecord = { ...node };\n if (next.status === \"running\") {\n next.status = \"detached\";\n changed = true;\n }\n const children = finalizeWorkflowGraphNodes(next.children);\n if (children !== next.children) {\n next.children = children;\n changed = true;\n }\n return changed ? next : node;\n}\n\nfunction isToolEntry(entry: ChatSessionHostEntry<ChatTranscriptEntryLike>): entry is ToolEntry {\n return entry.role === \"tool\" && \"kind\" in entry && entry.kind === \"tool\";\n}\n\nfunction isRecord(value: unknown): value is ObjectRecord {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n"]}
1
+ {"version":3,"file":"chat-session-host-terminal-cleanup.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-terminal-cleanup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAMpE,wBAAgB,mCAAmC,CACjD,WAAW,SAAS,uBAAuB,EAC3C,OAAO,EAAE,oBAAoB,CAAC,WAAW,CAAC,EAAE,GAAG,OAAO,CAYvD"}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-session-host-types.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AACxF,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EACf,WAAW,EACX,aAAa,EACb,GAAG,EACJ,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EACV,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAEpE,MAAM,WAAW,oBAAoB;IACnC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACxC,MAAM,IAAI,MAAM,CAAC;IACjB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,eAAe,CACb,QAAQ,EAAE,OAAO,EACjB,YAAY,EAAE,YAAY,GAAG,SAAS,EACtC,KAAK,CAAC,EAAE;QAAE,UAAU,EAAE,OAAO,CAAA;KAAE,GAC9B,MAAM,CAAC;CACX;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,uBAAuB;IACtC,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,0BAA0B,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IACvE,SAAS,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,eAAe,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CACnE;AAED,MAAM,WAAW,mBAAmB,CAClC,WAAW,SAAS,uBAAuB,GAAG,KAAK;IAEnD,KAAK,EAAE,oBAAoB,CAAC;IAC5B,QAAQ,CAAC,EAAE,uBAAuB,CAAC;IACnC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,YAAY,GAAG,SAAS,CAAC;IACjD,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC;IAC9B,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACrD,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IACjD,gBAAgB,CAAC,EAAE,MAAM,aAAa,CAAC;IACvC,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,CACd,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,WAAW,EAClB,WAAW,EAAE,OAAO,KACjB,eAAe,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;IACzB,qBAAqB,CAAC,EAAE,MACpB,OAAO,CAAC,IAAI,CAAC,wBAAwB,EAAE,IAAI,GAAG,KAAK,CAAC,CAAC,GACrD,SAAS,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,0BAA0B,CAAC;IACxC,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,SAAS,CAAC;CACtD;AAED,MAAM,MAAM,oBAAoB,CAC9B,WAAW,SAAS,uBAAuB,GAAG,KAAK,IACjD,gBAAgB,GAAG,WAAW,CAAC;AAEnC,MAAM,MAAM,oBAAoB,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AACpE,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC","sourcesContent":["import type { AgentSession } from \"../../../core/agent-session.ts\";\nimport type { BashResult } from \"../../../core/bash-executor.ts\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.ts\";\nimport type {\n Component,\n EditorComponent,\n EditorTheme,\n MarkdownTheme,\n TUI,\n} from \"@earendil-works/pi-tui\";\nimport type {\n ChatMessageEntry,\n ChatMessageRenderOptions,\n} from \"./chat-message-renderer.ts\";\nimport type { ChatTranscriptEntryLike } from \"./chat-transcript.ts\";\n\nexport interface ChatSessionHostStyle {\n dim(text: string): string;\n text(text: string): string;\n textMuted(text: string): string;\n accent(text: string): string;\n accentBold(text: string): string;\n rule(hex: string, text: string): string;\n cursor(): string;\n blank(width: number): string;\n editorRuleColor(\n disabled: boolean,\n agentSession: AgentSession | undefined,\n state?: { isBashMode: boolean },\n ): string;\n}\n\nexport interface ChatSessionHostBashRequest {\n command: string;\n excludeFromContext: boolean;\n onChunk: (chunk: string) => void;\n}\n\nexport interface ChatSessionHostCommands {\n ensureAttached?: () => Promise<void>;\n prompt?: (text: string) => Promise<void>;\n steer?: (text: string) => Promise<void>;\n followUp?: (text: string) => Promise<void>;\n interrupt?: () => Promise<void>;\n resume?: (message?: string) => Promise<void>;\n runBash?: (request: ChatSessionHostBashRequest) => Promise<BashResult>;\n abortBash?: () => void | Promise<void>;\n abortCompaction?: () => void | Promise<void>;\n handleSlashCommand?: (text: string) => Promise<boolean> | boolean;\n}\n\nexport interface ChatSessionHostOpts<\n TExtraEntry extends ChatTranscriptEntryLike = never,\n> {\n style: ChatSessionHostStyle;\n commands?: ChatSessionHostCommands;\n requestRender?: () => void;\n getAgentSession?: () => AgentSession | undefined;\n isStreaming?: () => boolean;\n isPaused?: () => boolean;\n isDisabled?: () => boolean;\n isBashRunning?: () => boolean;\n showWarning?: (message: string) => void;\n showStatus?: (message: string) => void;\n actions?: Record<string, () => void | Promise<void>>;\n getActionKeyDisplay?: (action: string) => string;\n getMarkdownTheme?: () => MarkdownTheme;\n tui?: TUI;\n keybindings?: unknown;\n editorFactory?: (\n tui: TUI,\n theme: EditorTheme,\n keybindings: unknown,\n ) => EditorComponent;\n editorTheme: EditorTheme;\n getChatRenderSettings?: () =>\n | Partial<Omit<ChatMessageRenderOptions, \"ui\" | \"cwd\">>\n | undefined;\n getCwd?: () => string;\n footerData?: ReadonlyFooterDataProvider;\n renderExtraEntry?: (entry: TExtraEntry) => Component;\n}\n\nexport type ChatSessionHostEntry<\n TExtraEntry extends ChatTranscriptEntryLike = never,\n> = ChatMessageEntry | TExtraEntry;\n\nexport type AgentSnapshotMessage = AgentSession[\"messages\"][number];\nexport type CacheKeyPart = string | number | boolean | null;\n"]}
1
+ {"version":3,"file":"chat-session-host-types.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-session-host-utils.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EACrB,MAAM,8BAA8B,CAAC;AAEtC,eAAO,MAAM,cAAc,UAAqD,CAAC;AACjF,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAI/C,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,OAAO,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAC1D,OAAO,CAMT;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GACvC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,OAAO,CAAA;CAAE,GAChD,SAAS,CAKZ;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,CAE/D;AAED,wBAAgB,kBAAkB,CAAC,WAAW,SAAS,uBAAuB,EAC5E,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,KAAK,IAAI,gBAAgB,CAqB3B;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAEhG;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,OAAO,GACf,OAAO,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAEhD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAe3D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CActD;AAED,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEnD","sourcesContent":["import { matchesKey as tuiMatchesKey } from \"@earendil-works/pi-tui\";\nimport type { ChatMessageEntry } from \"./chat-message-renderer.ts\";\nimport type { ChatTranscriptEntryLike } from \"./chat-transcript.ts\";\nimport type {\n CacheKeyPart,\n ChatSessionHostEntry,\n} from \"./chat-session-host-types.ts\";\n\nexport const SPINNER_FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\nexport const ANIMATION_FRAME_MS = 80;\nexport const STREAMING_RENDER_THROTTLE_MS = 80;\nconst STREAMING_TEXT_TAIL_LINES = 240;\nconst STREAMING_TEXT_TAIL_CHARS = 16_000;\n\nexport function matchesKey(\n data: string,\n key: \"enter\" | \"backspace\" | \"escape\" | \"ctrl+f\" | \"alt+up\",\n): boolean {\n if (key === \"enter\" && (data === \"\\r\" || data === \"\\n\")) return true;\n if (key === \"backspace\" && (data === \"\\x7f\" || data === \"\\b\")) return true;\n if (key === \"escape\" && data === \"\\x1b\") return true;\n if (key === \"ctrl+f\" && data === \"\\x06\") return true;\n return tuiMatchesKey(data, key);\n}\n\nexport function parseBashInput(text: string):\n | { command: string; excludeFromContext: boolean }\n | undefined {\n if (!text.startsWith(\"!\")) return undefined;\n const excludeFromContext = text.startsWith(\"!!\");\n const command = text.slice(excludeFromContext ? 2 : 1).trim();\n return { command, excludeFromContext };\n}\n\nexport function cacheKey(parts: readonly CacheKeyPart[]): string {\n return JSON.stringify(parts);\n}\n\nexport function isChatMessageEntry<TExtraEntry extends ChatTranscriptEntryLike>(\n entry: ChatSessionHostEntry<TExtraEntry>,\n): entry is ChatMessageEntry {\n if (!(\"role\" in entry) || !(\"kind\" in entry)) return false;\n const candidate = entry as { role?: unknown; kind?: unknown; message?: unknown; text?: unknown };\n switch (candidate.kind) {\n case \"assistant\":\n return candidate.role === \"assistant\" && candidate.message !== undefined;\n case \"tool\":\n return candidate.role === \"tool\" && \"toolName\" in candidate && \"toolCallId\" in candidate && \"args\" in candidate;\n case \"bashExecution\":\n return candidate.role === \"tool\" && candidate.message !== undefined;\n case \"user\":\n return candidate.role === \"user\" && typeof candidate.text === \"string\";\n case \"custom\":\n return candidate.role === \"custom\" && candidate.message !== undefined;\n case \"branchSummary\":\n return candidate.role === \"summary\" && candidate.message !== undefined;\n case \"system\":\n return candidate.role === \"system\" && typeof candidate.text === \"string\";\n default:\n return false;\n }\n}\n\nexport function isMessageLike(message: unknown): message is { role?: unknown; content?: unknown } {\n return message !== null && typeof message === \"object\" && \"role\" in message;\n}\n\nexport function isUserMessageLike(\n message: unknown,\n): message is { role: \"user\"; content?: unknown } {\n return isMessageLike(message) && message.role === \"user\";\n}\n\nexport function userMessageSignature(text: string): string {\n return text.trim();\n}\n\nexport function extractMessageText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n const parts: string[] = [];\n for (const item of content) {\n if (item == null) continue;\n if (typeof item === \"string\") {\n parts.push(item);\n continue;\n }\n const obj = item as { type?: unknown; text?: unknown };\n if (typeof obj.text === \"string\") parts.push(obj.text);\n else if (obj.type === \"text\" && typeof obj.text === \"string\") parts.push(obj.text);\n }\n return parts.join(\"\");\n}\n\nexport function tailStreamingText(text: string): string {\n if (\n text.length <= STREAMING_TEXT_TAIL_CHARS &&\n text.split(\"\\n\").length <= STREAMING_TEXT_TAIL_LINES\n ) {\n return text;\n }\n const byChars = text.slice(-STREAMING_TEXT_TAIL_CHARS);\n const lines = byChars.split(\"\\n\");\n const tail =\n lines.length > STREAMING_TEXT_TAIL_LINES\n ? lines.slice(-STREAMING_TEXT_TAIL_LINES).join(\"\\n\")\n : byChars;\n return `[earlier streaming output hidden while attached]\\n\\n${tail.trimStart()}`;\n}\n\nexport function spinnerFrame(): string {\n const idx = Math.floor(Date.now() / ANIMATION_FRAME_MS) % SPINNER_FRAMES.length;\n return SPINNER_FRAMES[idx]!;\n}\n\nexport function stripAnsi(s: string): string {\n return s.replace(/\\x1B\\[[0-?]*[ -/]*[@-~]/g, \"\");\n}\n\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"]}
1
+ {"version":3,"file":"chat-session-host-utils.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host-utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EACrB,MAAM,8BAA8B,CAAC;AAEtC,eAAO,MAAM,cAAc,UAAqD,CAAC;AACjF,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAI/C,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,OAAO,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAC1D,OAAO,CAMT;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GACvC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,OAAO,CAAA;CAAE,GAChD,SAAS,CAKZ;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,CAE/D;AAED,wBAAgB,kBAAkB,CAAC,WAAW,SAAS,uBAAuB,EAC5E,KAAK,EAAE,oBAAoB,CAAC,WAAW,CAAC,GACvC,KAAK,IAAI,gBAAgB,CAqB3B;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAEhG;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,OAAO,GACf,OAAO,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAEhD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAe3D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CActD;AAED,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEnD"}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-session-host.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AA+BpE,OAAO,KAAK,EACV,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,8BAA8B,CAAC;AAEtC,YAAY,EACV,0BAA0B,EAC1B,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,8BAA8B,CAAC;AAEtC,qBAAa,eAAe,CAAC,WAAW,SAAS,uBAAuB,GAAG,KAAK,CAC9E,YAAW,SAAS,EAAE,SAAS;IAE/B,OAAO,UAAQ;IAEf,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoC;IAE1D,YAAY,IAAI,EAAE,mBAAmB,CAAC,WAAW,CAAC,EAcjD;IAED,cAAc,CAAC,QAAQ,EAAE,SAAS,oBAAoB,EAAE,GAAG,IAAI,CAE9D;IAED,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAUrD;IAED,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAGzC;IAED,OAAO,IAAI,SAAS,oBAAoB,CAAC,WAAW,CAAC,EAAE,CAEtD;IAED,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAEjD;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAE9B;IAED,UAAU,IAAI,IAAI,CAIjB;IAED,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAElD;IAED,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAE7C;IAED,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAE3C;IAED,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAEnC;IAED,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAEpC;IAED,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAEpC;IAED,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEvC;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjC;IAEK,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAE/B;IAEK,MAAM,CAAC,IAAI,GAAE,MAAM,GAAG,UAAmB,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtF;IAED,WAAW,IAAI,OAAO,CAErB;IAED,aAAa,IAAI,OAAO,CAEvB;IAED,oBAAoB,IAAI,OAAO,CAE9B;IAED,YAAY,IAAI,OAAO,CAEtB;IAED,YAAY,IAAI,OAAO,CAEtB;IAED,gBAAgB,IAAI,OAAO,CAE1B;IAED,oBAAoB,IAAI,MAAM,CAE7B;IAED,aAAa,IAAI,MAAM,CAEtB;IAED,SAAS,IAAI,MAAM,CAElB;IAED,UAAU,IAAI,MAAM,CAEnB;IAED,cAAc,IAAI,IAAI,CAErB;IAED,iBAAiB,IAAI,IAAI,CAExB;IAED,iCAAiC,IAAI,IAAI,CAExC;IAED,OAAO,IAAI,IAAI,CAEd;IAED,6BAA6B,IAAI,OAAO,CAEvC;IAED,OAAO,CAAC,eAAe;CAexB","sourcesContent":["import type { AgentSessionEvent } from \"../../../core/agent-session.ts\";\nimport { type Component, type Focusable } from \"@earendil-works/pi-tui\";\nimport { SessionManager } from \"../../../core/session-manager.ts\";\nimport type { ChatTranscriptEntryLike } from \"./chat-transcript.ts\";\nimport {\n abortChatSessionBash,\n abortChatSessionCompaction,\n interruptChatSession,\n restoreQueuedMessagesToEditor,\n submitChatSession,\n} from \"./chat-session-host-actions.ts\";\nimport {\n createChatSessionEditor,\n handleChatSessionInput,\n} from \"./chat-session-host-editor.ts\";\nimport { applyChatSessionAgentEvent } from \"./chat-session-host-events.ts\";\nimport {\n renderChatSessionBody,\n renderChatSessionEditor,\n renderChatSessionEntry,\n renderChatSessionFooter,\n renderChatSessionPendingMessages,\n renderChatSessionUsage,\n renderChatSessionWorkingStatus,\n transcriptCacheKey,\n} from \"./chat-session-host-rendering.ts\";\nimport {\n clearChatSessionBusyForTerminalWorkflowStage,\n disposeChatSession,\n isChatSessionBashRunning,\n isChatSessionStreaming,\n syncChatSessionAnimationTick,\n} from \"./chat-session-host-runtime.ts\";\nimport { ChatSessionHostState } from \"./chat-session-host-state.ts\";\nimport type {\n AgentSnapshotMessage,\n ChatSessionHostEntry,\n ChatSessionHostOpts,\n} from \"./chat-session-host-types.ts\";\n\nexport type {\n ChatSessionHostBashRequest,\n ChatSessionHostCommands,\n ChatSessionHostEntry,\n ChatSessionHostOpts,\n ChatSessionHostStyle,\n} from \"./chat-session-host-types.ts\";\n\nexport class ChatSessionHost<TExtraEntry extends ChatTranscriptEntryLike = never>\n implements Component, Focusable\n{\n focused = true;\n\n private readonly state: ChatSessionHostState<TExtraEntry>;\n\n constructor(opts: ChatSessionHostOpts<TExtraEntry>) {\n this.state = new ChatSessionHostState(opts, {\n renderEntry: (state, entry) => renderChatSessionEntry(state, entry),\n transcriptCacheKey: (state, entry, index) => transcriptCacheKey(state, entry, index),\n });\n this.state.editor = createChatSessionEditor(\n this.state,\n opts.tui,\n opts.keybindings,\n opts.editorTheme,\n opts.editorFactory,\n this.editorCallbacks(),\n );\n this.syncAnimationTick();\n }\n\n appendMessages(messages: readonly AgentSnapshotMessage[]): void {\n this.state.liveChat.appendMessages(messages);\n }\n\n loadSessionFile(sessionFile: string | undefined): void {\n if (this.state.transcript.length > 0 || sessionFile === undefined) return;\n let messages: readonly AgentSnapshotMessage[];\n try {\n messages = SessionManager.open(sessionFile).buildSessionContext()\n .messages as readonly AgentSnapshotMessage[];\n } catch {\n return;\n }\n this.state.liveChat.appendMessages(messages);\n }\n\n appendExtraEntry(entry: TExtraEntry): void {\n this.state.extraEntries.push(entry);\n this.state.transcript.push(entry);\n }\n\n entries(): readonly ChatSessionHostEntry<TExtraEntry>[] {\n return this.state.transcript;\n }\n\n applyAgentEvent(event: AgentSessionEvent): boolean {\n return applyChatSessionAgentEvent(this.state, event);\n }\n\n render(width: number): string[] {\n return this.renderBody(width, 1);\n }\n\n invalidate(): void {\n this.state.transcriptComponent.invalidate();\n this.state.bodyViewport.invalidate();\n this.state.editor?.invalidate();\n }\n\n renderBody(width: number, budget: number): string[] {\n return renderChatSessionBody(this.state, width, budget);\n }\n\n renderPendingMessages(width: number): string[] {\n return renderChatSessionPendingMessages(this.state, width);\n }\n\n renderWorkingStatus(width: number): string[] {\n return renderChatSessionWorkingStatus(this.state, width);\n }\n\n renderUsage(width: number): string[] {\n return renderChatSessionUsage(this.state, width);\n }\n\n renderEditor(width: number): string[] {\n return renderChatSessionEditor(this.state, width, this.focused);\n }\n\n renderFooter(width: number): string[] {\n return renderChatSessionFooter(this.state, width);\n }\n\n handleScrollInput(data: string): boolean {\n return this.state.bodyViewport.handleInput(data);\n }\n\n handleInput(data: string): boolean {\n return handleChatSessionInput(this.state, data, this.editorCallbacks());\n }\n\n async interrupt(): Promise<void> {\n await interruptChatSession(this.state);\n }\n\n async submit(mode: \"auto\" | \"followUp\" = \"auto\", submittedText?: string): Promise<void> {\n await submitChatSession(this.state, mode, submittedText);\n }\n\n isStreaming(): boolean {\n return isChatSessionStreaming(this.state);\n }\n\n isBashRunning(): boolean {\n return isChatSessionBashRunning(this.state);\n }\n\n isEditingBashCommand(): boolean {\n return this.state.isBashMode;\n }\n\n isCompacting(): boolean {\n return this.state.compacting;\n }\n\n hasInputText(): boolean {\n return this.state.inputBuffer.length > 0;\n }\n\n hasAnimationTick(): boolean {\n return this.state.animationTimer !== undefined;\n }\n\n bodyScrollFromBottom(): number {\n return this.state.bodyViewport.getScrollFromBottom();\n }\n\n bodyMaxScroll(): number {\n return this.state.bodyViewport.getMaxScroll();\n }\n\n inputText(): string {\n return this.state.inputBuffer;\n }\n\n statusText(): string {\n return this.state.statusMessage;\n }\n\n scrollToBottom(): void {\n this.state.bodyViewport.scrollToBottom();\n }\n\n syncAnimationTick(): void {\n syncChatSessionAnimationTick(this.state);\n }\n\n clearBusyForTerminalWorkflowStage(): void {\n clearChatSessionBusyForTerminalWorkflowStage(this.state);\n }\n\n dispose(): void {\n disposeChatSession(this.state);\n }\n\n restoreQueuedMessagesToEditor(): boolean {\n return restoreQueuedMessagesToEditor(this.state);\n }\n\n private editorCallbacks(): {\n submit: (mode: \"auto\" | \"followUp\", submittedText?: string) => void | Promise<void>;\n restoreQueuedMessagesToEditor: () => boolean;\n abortCompaction: () => void | Promise<void>;\n interrupt: () => void | Promise<void>;\n abortBash: () => void | Promise<void>;\n } {\n return {\n submit: (mode, submittedText) => this.submit(mode, submittedText),\n restoreQueuedMessagesToEditor: () => this.restoreQueuedMessagesToEditor(),\n abortCompaction: () => abortChatSessionCompaction(this.state),\n interrupt: () => this.interrupt(),\n abortBash: () => abortChatSessionBash(this.state),\n };\n }\n}\n"]}
1
+ {"version":3,"file":"chat-session-host.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AA+BpE,OAAO,KAAK,EACV,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,8BAA8B,CAAC;AAEtC,YAAY,EACV,0BAA0B,EAC1B,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,8BAA8B,CAAC;AAEtC,qBAAa,eAAe,CAAC,WAAW,SAAS,uBAAuB,GAAG,KAAK,CAC9E,YAAW,SAAS,EAAE,SAAS;IAE/B,OAAO,UAAQ;IAEf,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoC;IAE1D,YAAY,IAAI,EAAE,mBAAmB,CAAC,WAAW,CAAC,EAcjD;IAED,cAAc,CAAC,QAAQ,EAAE,SAAS,oBAAoB,EAAE,GAAG,IAAI,CAE9D;IAED,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAUrD;IAED,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAGzC;IAED,OAAO,IAAI,SAAS,oBAAoB,CAAC,WAAW,CAAC,EAAE,CAEtD;IAED,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAEjD;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAE9B;IAED,UAAU,IAAI,IAAI,CAIjB;IAED,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAElD;IAED,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAE7C;IAED,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAE3C;IAED,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAEnC;IAED,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAEpC;IAED,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAEpC;IAED,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEvC;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjC;IAEK,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAE/B;IAEK,MAAM,CAAC,IAAI,GAAE,MAAM,GAAG,UAAmB,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtF;IAED,WAAW,IAAI,OAAO,CAErB;IAED,aAAa,IAAI,OAAO,CAEvB;IAED,oBAAoB,IAAI,OAAO,CAE9B;IAED,YAAY,IAAI,OAAO,CAEtB;IAED,YAAY,IAAI,OAAO,CAEtB;IAED,gBAAgB,IAAI,OAAO,CAE1B;IAED,oBAAoB,IAAI,MAAM,CAE7B;IAED,aAAa,IAAI,MAAM,CAEtB;IAED,SAAS,IAAI,MAAM,CAElB;IAED,UAAU,IAAI,MAAM,CAEnB;IAED,cAAc,IAAI,IAAI,CAErB;IAED,iBAAiB,IAAI,IAAI,CAExB;IAED,iCAAiC,IAAI,IAAI,CAExC;IAED,OAAO,IAAI,IAAI,CAEd;IAED,6BAA6B,IAAI,OAAO,CAEvC;IAED,OAAO,CAAC,eAAe;CAexB"}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-transcript.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-transcript.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n matchesKey,\n type Component,\n Container,\n Spacer,\n} from \"@earendil-works/pi-tui\";\n\n/**\n * Roles that participate in pi's chat spacing contract.\n *\n * Assistant turns own their leading whitespace internally, and tool rows attach\n * directly under the assistant/tool-call row they belong to. User-like rows get\n * one blank line when they are not the first row in the transcript.\n */\nexport type ChatTranscriptRole =\n | \"assistant\"\n | \"thinking\"\n | \"tool\"\n | \"user\"\n | \"custom\"\n | \"notice\"\n | \"system\"\n | \"summary\";\n\nexport interface ChatTranscriptEntryLike {\n readonly role: ChatTranscriptRole;\n}\n\nexport type ChatTranscriptRenderer<TEntry extends ChatTranscriptEntryLike> = (\n entry: TEntry,\n) => Component;\n\nexport type ChatTranscriptCacheKey<TEntry extends ChatTranscriptEntryLike> = (\n entry: TEntry,\n index: number,\n) => string;\n\ninterface CachedChatTranscriptBlock<TEntry extends ChatTranscriptEntryLike> {\n readonly entry: TEntry;\n readonly key: string;\n readonly width: number;\n readonly component: Component;\n readonly lines: readonly string[];\n}\n\ntype DisposableComponent = Component & { dispose?: () => void };\n\ninterface RowWindowComponent extends Component {\n readonly supportsRowWindow: true;\n rowCount(width: number): number;\n renderRows(width: number, startRow: number, endRow: number): string[];\n}\n\ninterface WindowedComponentRows {\n readonly kind: \"windowed\";\n readonly component: RowWindowComponent;\n readonly rowCount: number;\n}\n\ninterface StaticComponentRows {\n readonly kind: \"static\";\n readonly lines: readonly string[];\n readonly rowCount: number;\n}\n\ntype ComponentRows = WindowedComponentRows | StaticComponentRows;\n\nexport function addChatTranscriptEntry(\n container: Container,\n component: Component,\n role: ChatTranscriptRole,\n): void {\n if (needsLeadingSpacer(role) && container.children.length > 0) {\n container.addChild(new Spacer(1));\n }\n container.addChild(component);\n}\n\nfunction needsLeadingSpacer(role: ChatTranscriptRole): boolean {\n return (\n role === \"user\" ||\n role === \"custom\" ||\n role === \"notice\" ||\n role === \"system\" ||\n role === \"summary\"\n );\n}\n\n/**\n * Reusable pi chat transcript scaffold for extension surfaces.\n *\n * This intentionally mirrors InteractiveMode.addMessageToChat spacing without\n * coupling consumers to a full AgentSession. Extension UIs can bring their own\n * message model while still rendering inside the same Container/Spacer rhythm\n * as the main chat.\n */\nexport class ChatTranscriptComponent<TEntry extends ChatTranscriptEntryLike>\n implements Component\n{\n private readonly entries: readonly TEntry[];\n private readonly renderEntry: ChatTranscriptRenderer<TEntry>;\n readonly supportsRowWindow: boolean;\n\n private readonly cacheKey: ChatTranscriptCacheKey<TEntry> | undefined;\n private blockCache: Array<CachedChatTranscriptBlock<TEntry> | undefined> = [];\n\n constructor(\n entries: readonly TEntry[],\n renderEntry: ChatTranscriptRenderer<TEntry>,\n cacheKey?: ChatTranscriptCacheKey<TEntry>,\n ) {\n this.entries = entries;\n this.renderEntry = renderEntry;\n this.cacheKey = cacheKey;\n this.supportsRowWindow = cacheKey !== undefined;\n }\n\n render(width: number): string[] {\n if (!this.supportsRowWindow) return this.renderAllRows(width);\n return this.renderRows(width, 0, this.rowCount(width));\n }\n\n rowCount(width: number): number {\n if (!this.supportsRowWindow) return this.renderAllRows(width).length;\n this.ensureBlockCache(width);\n let count = 0;\n for (const block of this.blockCache) {\n if (block !== undefined) count += block.lines.length;\n }\n return count;\n }\n\n renderRows(width: number, startRow: number, endRow: number): string[] {\n const start = Math.max(0, Math.floor(startRow));\n const end = Math.max(start, Math.floor(endRow));\n if (end <= start) return [];\n if (!this.supportsRowWindow) return this.renderAllRows(width).slice(start, end);\n\n this.ensureBlockCache(width);\n const lines: string[] = [];\n let cursor = 0;\n for (let index = 0; index < this.entries.length; index += 1) {\n const block = this.blockCache[index];\n if (block === undefined) continue;\n const blockStart = cursor;\n const blockEnd = blockStart + block.lines.length;\n if (blockEnd > start && blockStart < end) {\n const localStart = Math.max(0, start - blockStart);\n const localEnd = Math.min(block.lines.length, end - blockStart);\n lines.push(...block.lines.slice(localStart, localEnd));\n }\n cursor = blockEnd;\n if (cursor >= end) break;\n }\n return lines;\n }\n\n invalidate(): void {\n for (const block of this.blockCache) disposeComponent(block?.component);\n this.blockCache = [];\n }\n\n private ensureBlockCache(width: number): void {\n if (this.blockCache.length > this.entries.length) {\n for (let index = this.entries.length; index < this.blockCache.length; index += 1) {\n disposeComponent(this.blockCache[index]?.component);\n }\n this.blockCache.length = this.entries.length;\n }\n for (let index = 0; index < this.entries.length; index += 1) {\n const entry = this.entries[index];\n if (entry === undefined) continue;\n const key = this.cacheKey?.(entry, index) ?? `${index}:${entry.role}`;\n const cached = this.blockCache[index];\n if (\n cached !== undefined &&\n cached.entry === entry &&\n cached.key === key &&\n cached.width === width\n ) {\n continue;\n }\n disposeComponent(cached?.component);\n const component = this.renderEntry(entry);\n this.blockCache[index] = {\n entry,\n key,\n width,\n component,\n lines: this.renderEntryBlock(component, entry, index, width),\n };\n }\n }\n\n private renderAllRows(width: number): string[] {\n const lines: string[] = [];\n for (let index = 0; index < this.entries.length; index += 1) {\n const entry = this.entries[index];\n if (entry !== undefined) lines.push(...this.renderEntryBlock(this.renderEntry(entry), entry, index, width));\n }\n return lines;\n }\n\n private renderEntryBlock(\n component: Component,\n entry: TEntry,\n index: number,\n width: number,\n ): string[] {\n const lines: string[] = [];\n if (index > 0 && needsLeadingSpacer(entry.role)) lines.push(\"\");\n lines.push(...component.render(width));\n return lines;\n }\n}\n\nfunction disposeComponent(component: Component | undefined): void {\n (component as DisposableComponent | undefined)?.dispose?.();\n}\n\nconst DEFAULT_SCROLL_STEP_ROWS = 4;\n\n/**\n * Sticky-bottom, scrollable viewport for chat-like component stacks.\n *\n * Pi's main interactive chat gets terminal scrollback for free. Extension\n * overlays render into a fixed rectangle, so they need an explicit viewport\n * with the same sticky-bottom default plus keyboard and mouse history controls.\n */\nexport class ScrollableComponentViewport implements Component {\n private components: readonly Component[] = [];\n private visibleRows = 1;\n private scrollFromBottom = 0;\n private lastLineCount = 0;\n private lastWidth = 0;\n private maxScroll = 0;\n\n setComponents(components: readonly Component[]): void {\n this.components = components;\n }\n\n setVisibleRows(rows: number): void {\n this.visibleRows = Math.max(1, Math.floor(rows));\n this.clampScroll();\n }\n\n getScrollFromBottom(): number {\n return this.scrollFromBottom;\n }\n\n getMaxScroll(): number {\n return this.maxScroll;\n }\n\n scrollToBottom(): void {\n this.scrollFromBottom = 0;\n }\n\n scrollToTop(): void {\n this.scrollFromBottom = this.maxScroll;\n }\n\n scrollBy(deltaRows: number): void {\n // Positive deltas move toward newer content; negative deltas move up\n // into older history. Store the offset from the sticky bottom so new\n // streaming output can keep following when the offset is zero.\n this.scrollFromBottom -= deltaRows;\n this.clampScroll();\n }\n\n handleInput(data: string): boolean {\n const wheelDeltaRows = mouseWheelDeltaRows(data);\n if (wheelDeltaRows !== 0) {\n this.scrollBy(wheelDeltaRows);\n return true;\n }\n if (isMouseSequence(data)) return true;\n if (matchesKey(data, \"pageUp\")) {\n this.scrollBy(-this.pageSize());\n return true;\n }\n if (matchesKey(data, \"pageDown\")) {\n this.scrollBy(this.pageSize());\n return true;\n }\n if (matchesKey(data, \"home\")) {\n this.scrollToTop();\n return true;\n }\n if (matchesKey(data, \"end\")) {\n this.scrollToBottom();\n return true;\n }\n return false;\n }\n\n render(width: number): string[] {\n const componentRows = this.measureComponentRows(width);\n const lineCount = componentRows.reduce((sum, rows) => sum + rows.rowCount, 0);\n const maxScroll = Math.max(0, lineCount - this.visibleRows);\n if (this.scrollFromBottom > 0 && this.lastWidth === width && lineCount > this.lastLineCount) {\n this.scrollFromBottom += lineCount - this.lastLineCount;\n }\n this.lastLineCount = lineCount;\n this.lastWidth = width;\n this.maxScroll = maxScroll;\n this.clampScroll();\n\n const start = Math.max(0, maxScroll - this.scrollFromBottom);\n const visible = this.renderVisibleRows(\n componentRows,\n width,\n start,\n start + this.visibleRows,\n );\n while (visible.length < this.visibleRows) visible.push(\" \".repeat(width));\n return visible;\n }\n\n invalidate(): void {\n for (const component of this.components) component.invalidate();\n }\n\n private measureComponentRows(width: number): ComponentRows[] {\n return this.components.map((component) => {\n if (isRowWindowComponent(component)) {\n return {\n kind: \"windowed\",\n component,\n rowCount: component.rowCount(width),\n };\n }\n const lines = component.render(width);\n return {\n kind: \"static\",\n lines,\n rowCount: lines.length,\n };\n });\n }\n\n private renderVisibleRows(\n componentRows: readonly ComponentRows[],\n width: number,\n startRow: number,\n endRow: number,\n ): string[] {\n const lines: string[] = [];\n let cursor = 0;\n for (const rows of componentRows) {\n const componentStart = cursor;\n const componentEnd = componentStart + rows.rowCount;\n if (componentEnd > startRow && componentStart < endRow) {\n const localStart = Math.max(0, startRow - componentStart);\n const localEnd = Math.min(rows.rowCount, endRow - componentStart);\n if (rows.kind === \"windowed\") {\n lines.push(...rows.component.renderRows(width, localStart, localEnd));\n } else {\n lines.push(...rows.lines.slice(localStart, localEnd));\n }\n }\n cursor = componentEnd;\n if (cursor >= endRow) break;\n }\n return lines;\n }\n\n private pageSize(): number {\n return Math.max(4, this.visibleRows - 2);\n }\n\n private clampScroll(): void {\n this.scrollFromBottom = Math.max(0, Math.min(this.maxScroll, this.scrollFromBottom));\n }\n}\n\nfunction isRowWindowComponent(component: Component): component is RowWindowComponent {\n const candidate = component as Partial<RowWindowComponent>;\n return candidate.supportsRowWindow === true &&\n typeof candidate.rowCount === \"function\" &&\n typeof candidate.renderRows === \"function\";\n}\n\nexport class ScrollableChatTranscriptComponent<TEntry extends ChatTranscriptEntryLike>\n implements Component\n{\n private readonly viewport = new ScrollableComponentViewport();\n private readonly transcript: ChatTranscriptComponent<TEntry>;\n\n constructor(\n entries: readonly TEntry[],\n renderEntry: ChatTranscriptRenderer<TEntry>,\n ) {\n this.transcript = new ChatTranscriptComponent(entries, renderEntry);\n this.viewport.setComponents([this.transcript]);\n }\n\n setVisibleRows(rows: number): void {\n this.viewport.setVisibleRows(rows);\n }\n\n handleInput(data: string): boolean {\n return this.viewport.handleInput(data);\n }\n\n render(width: number): string[] {\n return this.viewport.render(width);\n }\n\n invalidate(): void {\n this.viewport.invalidate();\n }\n\n getScrollFromBottom(): number {\n return this.viewport.getScrollFromBottom();\n }\n\n getMaxScroll(): number {\n return this.viewport.getMaxScroll();\n }\n\n scrollToBottom(): void {\n this.viewport.scrollToBottom();\n }\n}\n\nfunction mouseWheelDeltaRows(data: string): number {\n const sgr = data.match(/^\\x1b\\[<(\\d+);\\d+;\\d+M$/);\n if (sgr) return wheelDeltaForButtonCode(Number.parseInt(sgr[1]!, 10));\n if (data.startsWith(\"\\x1b[M\") && data.length >= 6) {\n return wheelDeltaForButtonCode(data.charCodeAt(3) - 32);\n }\n return 0;\n}\n\nfunction wheelDeltaForButtonCode(code: number): number {\n if ((code & 64) === 0) return 0;\n const direction = code & 3;\n if (direction === 0) return -DEFAULT_SCROLL_STEP_ROWS;\n if (direction === 1) return DEFAULT_SCROLL_STEP_ROWS;\n return 0;\n}\n\nfunction isMouseSequence(data: string): boolean {\n return /^\\x1b\\[<\\d+;\\d+;\\d+[mM]$/.test(data) || data.startsWith(\"\\x1b[M\");\n}\n"]}
1
+ {"version":3,"file":"chat-transcript.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-transcript.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"compaction-boundary-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/compaction-boundary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAgB,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AACtI,OAAO,EAA8B,KAAK,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAI3F,UAAU,YAAY;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,uBAAuB,CAAC;IAC/B,IAAI,EAAE,yBAAyB,CAAC,MAAM,CAAC,CAAC;CACxC;AAED,gFAAgF;AAChF,qBAAa,kCAAmC,SAAQ,GAAG;IAC1D,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IAEpC,YAAY,MAAM,EAAE,wBAAwB,GAAG,YAAY,EAM1D;IAED,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAoD;IAC/E,UAAU,IAAI,IAAI,CAA8C;IAEzE,OAAO,CAAC,aAAa;CAuBrB;AAGD,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,GAAG,kCAAkC,CAY3H","sourcesContent":["import { Box, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { VerbatimCompactionDetails, VerbatimCompactionResult, VerbatimCompactionStats } from \"../../../core/compaction/index.ts\";\nimport { VERBATIM_COMPACTION_PREFIX, type CustomMessage } from \"../../../core/messages.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\ninterface BoundaryView {\n\ttext: string;\n\tstats: VerbatimCompactionStats;\n\trung: VerbatimCompactionDetails[\"rung\"];\n}\n\n/** Renders the durable verbatim compaction boundary without markdown reflow. */\nexport class CompactionBoundaryMessageComponent extends Box {\n\tprivate expanded = false;\n\tprivate readonly view: BoundaryView;\n\n\tconstructor(result: VerbatimCompactionResult | BoundaryView) {\n\t\tsuper(1, 1, (text) => theme.bg(\"customMessageBg\", text));\n\t\tthis.view = \"compactedText\" in result\n\t\t\t? { text: result.compactedText, stats: result.stats, rung: result.rung }\n\t\t\t: result;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void { this.expanded = expanded; this.updateDisplay(); }\n\toverride invalidate(): void { super.invalidate(); this.updateDisplay(); }\n\n\tprivate updateDisplay(): void {\n\t\tthis.clear();\n\t\tconst tokenStr = this.view.stats.tokensBefore.toLocaleString();\n\t\tconst label = theme.fg(\"customMessageLabel\", theme.bold(\"✻ Context compacted\"));\n\t\tthis.addChild(new Text(label, 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tif (this.expanded) {\n\t\t\tthis.addChild(new Text(theme.bold(theme.fg(\"customMessageText\", `Compacted from ${tokenStr} tokens`)), 0, 0));\n\t\t\tthis.addChild(new Spacer(1));\n\t\t\tconst rendered = this.view.text.split(\"\\n\").map((line) => /^\\(filtered \\d+ lines\\)$/.test(line) ? theme.fg(\"dim\", line) : theme.fg(\"customMessageText\", line)).join(\"\\n\");\n\t\t\tthis.addChild(new Text(rendered, 0, 0));\n\t\t\treturn;\n\t\t}\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\ttheme.fg(\"customMessageText\", `Compacted from ${tokenStr} tokens (`) +\n\t\t\t\t\ttheme.fg(\"dim\", keyText(\"app.tools.expand\")) +\n\t\t\t\t\ttheme.fg(\"customMessageText\", \" to expand)\"),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t}\n}\n\n\nexport function compactionBoundaryFromMessage(message: CustomMessage, expanded: boolean): CompactionBoundaryMessageComponent {\n\tconst details = message.details as VerbatimCompactionDetails;\n\tconst content = Array.isArray(message.content)\n\t\t? message.content.filter((block) => block.type === \"text\").map((block) => block.text).join(\"\\n\")\n\t\t: message.content;\n\tconst component = new CompactionBoundaryMessageComponent({\n\t\ttext: content.startsWith(VERBATIM_COMPACTION_PREFIX) ? content.slice(VERBATIM_COMPACTION_PREFIX.length) : content,\n\t\tstats: details.stats,\n\t\trung: details.rung,\n\t});\n\tcomponent.setExpanded(expanded);\n\treturn component;\n}\n"]}
1
+ {"version":3,"file":"compaction-boundary-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/compaction-boundary-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAgB,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AACtI,OAAO,EAA8B,KAAK,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAI3F,UAAU,YAAY;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,uBAAuB,CAAC;IAC/B,IAAI,EAAE,yBAAyB,CAAC,MAAM,CAAC,CAAC;CACxC;AAED,gFAAgF;AAChF,qBAAa,kCAAmC,SAAQ,GAAG;IAC1D,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IAEpC,YAAY,MAAM,EAAE,wBAAwB,GAAG,YAAY,EAM1D;IAED,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAoD;IAC/E,UAAU,IAAI,IAAI,CAA8C;IAEzE,OAAO,CAAC,aAAa;CAuBrB;AAGD,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,GAAG,kCAAkC,CAY3H"}
@@ -1 +1 @@
1
- {"version":3,"file":"config-selector-list.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/config-selector-list.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAoE,MAAM,wBAAwB,CAAC;AAE1I,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAoB,MAAM,kCAAkC,CAAC;AACtG,OAAO,KAAK,EAAiB,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAIxF,KAAK,YAAY,GAAG,YAAY,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;AASnE,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,YAAY,CAAC;IACvB,YAAY,EAAE,YAAY,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,gBAAgB;IACzB,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,YAAY,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,CAAC;IACxC,MAAM,EAAE,SAAS,GAAG,WAAW,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAmCD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,EAAE,CA+EtF;AAKD,qBAAa,oBAAqB,YAAW,SAAS;IACrD,UAAU,IAAI,IAAI,CAAG;IACrB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAW9B;CACD;AACD,qBAAa,YAAa,YAAW,SAAS,EAAE,SAAS;IACxD,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,aAAa,CAAmB;IACxC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,UAAU,CAAM;IACxB,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,QAAQ,CAAS;IAClB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IACpE,OAAO,CAAC,QAAQ,CAAS;IACzB,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IACD,YAAY,MAAM,EAAE,aAAa,EAAE,EAAE,eAAe,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAQnG;IACD,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,WAAW;IA6CnB,OAAO,CAAC,eAAe;IAIvB,UAAU,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAYrD;IACD,UAAU,IAAI,IAAI,CAAG;IACrB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA2C9B;IACD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAqD9B;IACD,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,sBAAsB;IA0C9B,OAAO,CAAC,qBAAqB;IA+C7B,OAAO,CAAC,kBAAkB;IAG1B,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,yBAAyB;CAIjC","sourcesContent":["import { homedir } from \"node:os\";\nimport { basename, dirname, join, relative } from \"node:path\";\nimport { type Component, type Focusable, getKeybindings, Input, matchesKey, truncateToWidth, visibleWidth } from \"@earendil-works/pi-tui\";\nimport { CONFIG_DIR_NAME } from \"../../../config.ts\";\nimport type { PathMetadata, ResolvedPaths, ResolvedResource } from \"../../../core/package-manager.ts\";\nimport type { PackageSource, SettingsManager } from \"../../../core/settings-manager.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { rawKeyHint } from \"./keybinding-hints.ts\";\n\ntype ResourceType = \"extensions\" | \"skills\" | \"prompts\" | \"themes\";\n\nconst RESOURCE_TYPE_LABELS: Record<ResourceType, string> = {\n\textensions: \"Extensions\",\n\tskills: \"Skills\",\n\tprompts: \"Prompts\",\n\tthemes: \"Themes\",\n};\n\nexport interface ResourceItem {\n\tpath: string;\n\tenabled: boolean;\n\tmetadata: PathMetadata;\n\tresourceType: ResourceType;\n\tdisplayName: string;\n\tgroupKey: string;\n\tsubgroupKey: string;\n}\n\ninterface ResourceSubgroup {\n\ttype: ResourceType;\n\tlabel: string;\n\titems: ResourceItem[];\n}\n\nexport interface ResourceGroup {\n\tkey: string;\n\tlabel: string;\n\tscope: \"user\" | \"project\" | \"temporary\";\n\torigin: \"package\" | \"top-level\";\n\tsource: string;\n\tsubgroups: ResourceSubgroup[];\n}\n\nfunction formatBaseDir(baseDir: string): string {\n\tconst homeDir = homedir();\n\tlet displayPath: string;\n\n\tif (baseDir === homeDir) {\n\t\tdisplayPath = \"~\";\n\t} else if (baseDir.startsWith(homeDir)) {\n\t\t// Replace home prefix with ~, normalize separators for display\n\t\tconst rest = baseDir.slice(homeDir.length);\n\t\tdisplayPath = `~${rest.replace(/\\\\/g, \"/\")}`;\n\t} else {\n\t\tdisplayPath = baseDir.replace(/\\\\/g, \"/\");\n\t}\n\n\treturn displayPath.endsWith(\"/\") ? displayPath : `${displayPath}/`;\n}\n\nfunction getGroupLabel(metadata: PathMetadata, agentDir: string): string {\n\tif (metadata.origin === \"package\") {\n\t\treturn `${metadata.source} (${metadata.scope})`;\n\t}\n\t// Top-level resources\n\tif (metadata.source === \"auto\") {\n\t\tif (metadata.baseDir) {\n\t\t\treturn metadata.scope === \"user\"\n\t\t\t\t? `User (${formatBaseDir(metadata.baseDir)})`\n\t\t\t\t: `Project (${formatBaseDir(metadata.baseDir)})`;\n\t\t}\n\t\treturn metadata.scope === \"user\" ? `User (${formatBaseDir(agentDir)})` : `Project (${CONFIG_DIR_NAME}/)`;\n\t}\n\treturn metadata.scope === \"user\" ? \"User settings\" : \"Project settings\";\n}\n\nexport function buildGroups(resolved: ResolvedPaths, agentDir: string): ResourceGroup[] {\n\tconst groupMap = new Map<string, ResourceGroup>();\n\n\tconst addToGroup = (resources: ResolvedResource[], resourceType: ResourceType) => {\n\t\tfor (const res of resources) {\n\t\t\tconst { path, enabled, metadata } = res;\n\t\t\tconst groupKey = `${metadata.origin}:${metadata.scope}:${metadata.source}:${metadata.baseDir ?? \"\"}`;\n\n\t\t\tif (!groupMap.has(groupKey)) {\n\t\t\t\tgroupMap.set(groupKey, {\n\t\t\t\t\tkey: groupKey,\n\t\t\t\t\tlabel: getGroupLabel(metadata, agentDir),\n\t\t\t\t\tscope: metadata.scope,\n\t\t\t\t\torigin: metadata.origin,\n\t\t\t\t\tsource: metadata.source,\n\t\t\t\t\tsubgroups: [],\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst group = groupMap.get(groupKey)!;\n\t\t\tconst subgroupKey = `${groupKey}:${resourceType}`;\n\n\t\t\tlet subgroup = group.subgroups.find((sg) => sg.type === resourceType);\n\t\t\tif (!subgroup) {\n\t\t\t\tsubgroup = {\n\t\t\t\t\ttype: resourceType,\n\t\t\t\t\tlabel: RESOURCE_TYPE_LABELS[resourceType],\n\t\t\t\t\titems: [],\n\t\t\t\t};\n\t\t\t\tgroup.subgroups.push(subgroup);\n\t\t\t}\n\n\t\t\tconst fileName = basename(path);\n\t\t\tconst parentFolder = basename(dirname(path));\n\t\t\tlet displayName: string;\n\t\t\tif (resourceType === \"extensions\" && parentFolder !== \"extensions\") {\n\t\t\t\tdisplayName = `${parentFolder}/${fileName}`;\n\t\t\t} else if (resourceType === \"skills\" && fileName === \"SKILL.md\") {\n\t\t\t\tdisplayName = parentFolder;\n\t\t\t} else {\n\t\t\t\tdisplayName = fileName;\n\t\t\t}\n\t\t\tsubgroup.items.push({\n\t\t\t\tpath,\n\t\t\t\tenabled,\n\t\t\t\tmetadata,\n\t\t\t\tresourceType,\n\t\t\t\tdisplayName,\n\t\t\t\tgroupKey,\n\t\t\t\tsubgroupKey,\n\t\t\t});\n\t\t}\n\t};\n\n\taddToGroup(resolved.extensions, \"extensions\");\n\taddToGroup(resolved.skills, \"skills\");\n\taddToGroup(resolved.prompts, \"prompts\");\n\taddToGroup(resolved.themes, \"themes\");\n\n\t// Sort groups: packages first, then top-level; user before project\n\tconst groups = Array.from(groupMap.values());\n\tgroups.sort((a, b) => {\n\t\tif (a.origin !== b.origin) {\n\t\t\treturn a.origin === \"package\" ? -1 : 1;\n\t\t}\n\t\tif (a.scope !== b.scope) {\n\t\t\treturn a.scope === \"user\" ? -1 : 1;\n\t\t}\n\t\treturn a.source.localeCompare(b.source);\n\t});\n\t// Sort subgroups within each group by type order, and items by name\n\tconst typeOrder: Record<ResourceType, number> = { extensions: 0, skills: 1, prompts: 2, themes: 3 };\n\tfor (const group of groups) {\n\t\tgroup.subgroups.sort((a, b) => typeOrder[a.type] - typeOrder[b.type]);\n\t\tfor (const subgroup of group.subgroups) {\n\t\t\tsubgroup.items.sort((a, b) => a.displayName.localeCompare(b.displayName));\n\t\t}\n\t}\n\treturn groups;\n}\ntype FlatEntry =\n\t| { type: \"group\"; group: ResourceGroup }\n\t| { type: \"subgroup\"; subgroup: ResourceSubgroup; group: ResourceGroup }\n\t| { type: \"item\"; item: ResourceItem };\nexport class ConfigSelectorHeader implements Component {\n\tinvalidate(): void {}\n\trender(width: number): string[] {\n\t\tconst title = theme.bold(\"Resource Configuration\");\n\t\tconst sep = theme.fg(\"muted\", \" · \");\n\t\tconst hint = rawKeyHint(\"space\", \"Toggle\") + sep + rawKeyHint(\"esc\", \"Close\");\n\t\tconst hintWidth = visibleWidth(hint);\n\t\tconst titleWidth = visibleWidth(title);\n\t\tconst spacing = Math.max(1, width - titleWidth - hintWidth);\n\t\treturn [\n\t\t\ttruncateToWidth(`${title}${\" \".repeat(spacing)}${hint}`, width, \"\"),\n\t\t\ttheme.fg(\"muted\", \"Type to filter resources\"),\n\t\t];\n\t}\n}\nexport class ResourceList implements Component, Focusable {\n\tprivate groups: ResourceGroup[];\n\tprivate flatItems: FlatEntry[] = [];\n\tprivate filteredItems: FlatEntry[] = [];\n\tprivate selectedIndex = 0;\n\tprivate searchInput: Input;\n\tprivate maxVisible = 15;\n\tprivate settingsManager: SettingsManager;\n\tprivate cwd: string;\n\tprivate agentDir: string;\n\tpublic onCancel?: () => void;\n\tpublic onExit?: () => void;\n\tpublic onToggle?: (item: ResourceItem, newEnabled: boolean) => void;\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\tconstructor(groups: ResourceGroup[], settingsManager: SettingsManager, cwd: string, agentDir: string) {\n\t\tthis.groups = groups;\n\t\tthis.settingsManager = settingsManager;\n\t\tthis.cwd = cwd;\n\t\tthis.agentDir = agentDir;\n\t\tthis.searchInput = new Input();\n\t\tthis.buildFlatList();\n\t\tthis.filteredItems = [...this.flatItems];\n\t}\n\tprivate buildFlatList(): void {\n\t\tthis.flatItems = [];\n\t\tfor (const group of this.groups) {\n\t\t\tthis.flatItems.push({ type: \"group\", group });\n\t\t\tfor (const subgroup of group.subgroups) {\n\t\t\t\tthis.flatItems.push({ type: \"subgroup\", subgroup, group });\n\t\t\t\tfor (const item of subgroup.items) {\n\t\t\t\t\tthis.flatItems.push({ type: \"item\", item });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Start selection on first item (not header)\n\t\tthis.selectedIndex = this.flatItems.findIndex((e) => e.type === \"item\");\n\t\tif (this.selectedIndex < 0) this.selectedIndex = 0;\n\t}\n\tprivate findNextItem(fromIndex: number, direction: 1 | -1): number {\n\t\tlet idx = fromIndex + direction;\n\t\twhile (idx >= 0 && idx < this.filteredItems.length) {\n\t\t\tif (this.filteredItems[idx].type === \"item\") {\n\t\t\t\treturn idx;\n\t\t\t}\n\t\t\tidx += direction;\n\t\t}\n\t\treturn fromIndex; // Stay at current if no item found\n\t}\n\tprivate filterItems(query: string): void {\n\t\tif (!query.trim()) {\n\t\t\tthis.filteredItems = [...this.flatItems];\n\t\t\tthis.selectFirstItem();\n\t\t\treturn;\n\t\t}\n\t\tconst lowerQuery = query.toLowerCase();\n\t\tconst matchingItems = new Set<ResourceItem>();\n\t\tconst matchingSubgroups = new Set<ResourceSubgroup>();\n\t\tconst matchingGroups = new Set<ResourceGroup>();\n\t\tfor (const entry of this.flatItems) {\n\t\t\tif (entry.type === \"item\") {\n\t\t\t\tconst item = entry.item;\n\t\t\t\tif (\n\t\t\t\t\titem.displayName.toLowerCase().includes(lowerQuery) ||\n\t\t\t\t\titem.resourceType.toLowerCase().includes(lowerQuery) ||\n\t\t\t\t\titem.path.toLowerCase().includes(lowerQuery)\n\t\t\t\t) {\n\t\t\t\t\tmatchingItems.add(item);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Find which subgroups and groups contain matching items\n\t\tfor (const group of this.groups) {\n\t\t\tfor (const subgroup of group.subgroups) {\n\t\t\t\tfor (const item of subgroup.items) {\n\t\t\t\t\tif (matchingItems.has(item)) {\n\t\t\t\t\t\tmatchingSubgroups.add(subgroup);\n\t\t\t\t\t\tmatchingGroups.add(group);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.filteredItems = [];\n\t\tfor (const entry of this.flatItems) {\n\t\t\tif (entry.type === \"group\" && matchingGroups.has(entry.group)) {\n\t\t\t\tthis.filteredItems.push(entry);\n\t\t\t} else if (entry.type === \"subgroup\" && matchingSubgroups.has(entry.subgroup)) {\n\t\t\t\tthis.filteredItems.push(entry);\n\t\t\t} else if (entry.type === \"item\" && matchingItems.has(entry.item)) {\n\t\t\t\tthis.filteredItems.push(entry);\n\t\t\t}\n\t\t}\n\t\tthis.selectFirstItem();\n\t}\n\tprivate selectFirstItem(): void {\n\t\tconst firstItemIndex = this.filteredItems.findIndex((e) => e.type === \"item\");\n\t\tthis.selectedIndex = firstItemIndex >= 0 ? firstItemIndex : 0;\n\t}\n\tupdateItem(item: ResourceItem, enabled: boolean): void {\n\t\titem.enabled = enabled;\n\t\t// Update in groups too\n\t\tfor (const group of this.groups) {\n\t\t\tfor (const subgroup of group.subgroups) {\n\t\t\t\tconst found = subgroup.items.find((i) => i.path === item.path && i.resourceType === item.resourceType);\n\t\t\t\tif (found) {\n\t\t\t\t\tfound.enabled = enabled;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tinvalidate(): void {}\n\trender(width: number): string[] {\n\t\tconst lines: string[] = [];\n\t\t// Search input\n\t\tlines.push(...this.searchInput.render(width));\n\t\tlines.push(\"\");\n\t\tif (this.filteredItems.length === 0) {\n\t\t\tlines.push(theme.fg(\"muted\", \" No resources found\"));\n\t\t\treturn lines;\n\t\t}\n\t\t// Calculate visible range\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst entry = this.filteredItems[i];\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tif (entry.type === \"group\") {\n\t\t\t\t// Main group header (no cursor)\n\t\t\t\tconst groupLine = theme.fg(\"accent\", theme.bold(entry.group.label));\n\t\t\t\tlines.push(truncateToWidth(` ${groupLine}`, width, \"\"));\n\t\t\t} else if (entry.type === \"subgroup\") {\n\t\t\t\t// Subgroup header (indented, no cursor)\n\t\t\t\tconst subgroupLine = theme.fg(\"muted\", entry.subgroup.label);\n\t\t\t\tlines.push(truncateToWidth(` ${subgroupLine}`, width, \"\"));\n\t\t\t} else {\n\t\t\t\t// Resource item (cursor only on items)\n\t\t\t\tconst item = entry.item;\n\t\t\t\tconst cursor = isSelected ? \"> \" : \" \";\n\t\t\t\tconst checkbox = item.enabled ? theme.fg(\"success\", \"[x]\") : theme.fg(\"dim\", \"[ ]\");\n\t\t\t\tconst name = isSelected ? theme.bold(item.displayName) : item.displayName;\n\t\t\t\tlines.push(truncateToWidth(`${cursor} ${checkbox} ${name}`, width, \"...\"));\n\t\t\t}\n\t\t}\n\t\t// Scroll indicator\n\t\tif (startIndex > 0 || endIndex < this.filteredItems.length) {\n\t\t\tconst itemCount = this.filteredItems.filter((e) => e.type === \"item\").length;\n\t\t\tconst currentItemIndex =\n\t\t\t\tthis.filteredItems.slice(0, this.selectedIndex).filter((e) => e.type === \"item\").length + 1;\n\t\t\tlines.push(theme.fg(\"dim\", ` (${currentItemIndex}/${itemCount})`));\n\t\t}\n\t\treturn lines;\n\t}\n\thandleInput(data: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(data, \"tui.select.up\")) {\n\t\t\tthis.selectedIndex = this.findNextItem(this.selectedIndex, -1);\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.down\")) {\n\t\t\tthis.selectedIndex = this.findNextItem(this.selectedIndex, 1);\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.pageUp\")) {\n\t\t\t// Jump up by maxVisible, then find nearest item\n\t\t\tlet target = Math.max(0, this.selectedIndex - this.maxVisible);\n\t\t\twhile (target < this.filteredItems.length && this.filteredItems[target].type !== \"item\") {\n\t\t\t\ttarget++;\n\t\t\t}\n\t\t\tif (target < this.filteredItems.length) {\n\t\t\t\tthis.selectedIndex = target;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.pageDown\")) {\n\t\t\t// Jump down by maxVisible, then find nearest item\n\t\t\tlet target = Math.min(this.filteredItems.length - 1, this.selectedIndex + this.maxVisible);\n\t\t\twhile (target >= 0 && this.filteredItems[target].type !== \"item\") {\n\t\t\t\ttarget--;\n\t\t\t}\n\t\t\tif (target >= 0) {\n\t\t\t\tthis.selectedIndex = target;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.cancel\")) {\n\t\t\tthis.onCancel?.();\n\t\t\treturn;\n\t\t}\n\t\tif (matchesKey(data, \"ctrl+c\")) {\n\t\t\tthis.onExit?.();\n\t\t\treturn;\n\t\t}\n\t\tif (data === \" \" || kb.matches(data, \"tui.select.confirm\")) {\n\t\t\tconst entry = this.filteredItems[this.selectedIndex];\n\t\t\tif (entry?.type === \"item\") {\n\t\t\t\tconst newEnabled = !entry.item.enabled;\n\t\t\t\tthis.toggleResource(entry.item, newEnabled);\n\t\t\t\tthis.updateItem(entry.item, newEnabled);\n\t\t\t\tthis.onToggle?.(entry.item, newEnabled);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\t// Pass to search input\n\t\tthis.searchInput.handleInput(data);\n\t\tthis.filterItems(this.searchInput.getValue());\n\t}\n\tprivate toggleResource(item: ResourceItem, enabled: boolean): void {\n\t\tif (item.metadata.origin === \"top-level\") {\n\t\t\tthis.toggleTopLevelResource(item, enabled);\n\t\t} else {\n\t\t\tthis.togglePackageResource(item, enabled);\n\t\t}\n\t}\n\tprivate toggleTopLevelResource(item: ResourceItem, enabled: boolean): void {\n\t\tconst scope = item.metadata.scope as \"user\" | \"project\";\n\t\tconst settings =\n\t\t\tscope === \"project\" ? this.settingsManager.getProjectSettings() : this.settingsManager.getGlobalSettings();\n\t\tconst arrayKey = item.resourceType as \"extensions\" | \"skills\" | \"prompts\" | \"themes\";\n\t\tconst current = (settings[arrayKey] ?? []) as string[];\n\t\t// Generate pattern for this resource\n\t\tconst pattern = this.getResourcePattern(item);\n\t\tconst disablePattern = `-${pattern}`;\n\t\tconst enablePattern = `+${pattern}`;\n\t\t// Filter out existing patterns for this resource\n\t\tconst updated = current.filter((p) => {\n\t\t\tconst stripped = p.startsWith(\"!\") || p.startsWith(\"+\") || p.startsWith(\"-\") ? p.slice(1) : p;\n\t\t\treturn stripped !== pattern;\n\t\t});\n\t\tif (enabled) {\n\t\t\tupdated.push(enablePattern);\n\t\t} else {\n\t\t\tupdated.push(disablePattern);\n\t\t}\n\t\tif (scope === \"project\") {\n\t\t\tif (arrayKey === \"extensions\") {\n\t\t\t\tthis.settingsManager.setProjectExtensionPaths(updated);\n\t\t\t} else if (arrayKey === \"skills\") {\n\t\t\t\tthis.settingsManager.setProjectSkillPaths(updated);\n\t\t\t} else if (arrayKey === \"prompts\") {\n\t\t\t\tthis.settingsManager.setProjectPromptTemplatePaths(updated);\n\t\t\t} else if (arrayKey === \"themes\") {\n\t\t\t\tthis.settingsManager.setProjectThemePaths(updated);\n\t\t\t}\n\t\t} else {\n\t\t\tif (arrayKey === \"extensions\") {\n\t\t\t\tthis.settingsManager.setExtensionPaths(updated);\n\t\t\t} else if (arrayKey === \"skills\") {\n\t\t\t\tthis.settingsManager.setSkillPaths(updated);\n\t\t\t} else if (arrayKey === \"prompts\") {\n\t\t\t\tthis.settingsManager.setPromptTemplatePaths(updated);\n\t\t\t} else if (arrayKey === \"themes\") {\n\t\t\t\tthis.settingsManager.setThemePaths(updated);\n\t\t\t}\n\t\t}\n\t}\n\tprivate togglePackageResource(item: ResourceItem, enabled: boolean): void {\n\t\tconst scope = item.metadata.scope as \"user\" | \"project\";\n\t\tconst settings =\n\t\t\tscope === \"project\" ? this.settingsManager.getProjectSettings() : this.settingsManager.getGlobalSettings();\n\t\tconst packages = [...(settings.packages ?? [])] as PackageSource[];\n\t\tconst pkgIndex = packages.findIndex((pkg) => {\n\t\t\tconst source = typeof pkg === \"string\" ? pkg : pkg.source;\n\t\t\treturn source === item.metadata.source;\n\t\t});\n\t\tif (pkgIndex === -1) return;\n\t\tlet pkg = packages[pkgIndex];\n\t\t// Convert string to object form if needed\n\t\tif (typeof pkg === \"string\") {\n\t\t\tpkg = { source: pkg };\n\t\t\tpackages[pkgIndex] = pkg;\n\t\t}\n\t\t// Get the resource array for this type\n\t\tconst arrayKey = item.resourceType as \"extensions\" | \"skills\" | \"prompts\" | \"themes\";\n\t\tconst current = (pkg[arrayKey] ?? []) as string[];\n\t\t// Generate pattern relative to package root\n\t\tconst pattern = this.getPackageResourcePattern(item);\n\t\tconst disablePattern = `-${pattern}`;\n\t\tconst enablePattern = `+${pattern}`;\n\t\t// Filter out existing patterns for this resource\n\t\tconst updated = current.filter((p) => {\n\t\t\tconst stripped = p.startsWith(\"!\") || p.startsWith(\"+\") || p.startsWith(\"-\") ? p.slice(1) : p;\n\t\t\treturn stripped !== pattern;\n\t\t});\n\t\tif (enabled) {\n\t\t\tupdated.push(enablePattern);\n\t\t} else {\n\t\t\tupdated.push(disablePattern);\n\t\t}\n\t\t(pkg as Record<string, unknown>)[arrayKey] = updated.length > 0 ? updated : undefined;\n\t\t// Clean up empty filter object\n\t\tconst hasFilters = [\"extensions\", \"skills\", \"prompts\", \"themes\"].some(\n\t\t\t(k) => (pkg as Record<string, unknown>)[k] !== undefined,\n\t\t);\n\t\tif (!hasFilters) {\n\t\t\tpackages[pkgIndex] = (pkg as { source: string }).source;\n\t\t}\n\t\tif (scope === \"project\") {\n\t\t\tthis.settingsManager.setProjectPackages(packages);\n\t\t} else {\n\t\t\tthis.settingsManager.setPackages(packages);\n\t\t}\n\t}\n\tprivate getTopLevelBaseDir(scope: \"user\" | \"project\"): string {\n\t\treturn scope === \"project\" ? join(this.cwd, CONFIG_DIR_NAME) : this.agentDir;\n\t}\n\tprivate getResourcePattern(item: ResourceItem): string {\n\t\tconst scope = item.metadata.scope as \"user\" | \"project\";\n\t\tconst baseDir = item.metadata.baseDir ?? this.getTopLevelBaseDir(scope);\n\t\treturn relative(baseDir, item.path);\n\t}\n\tprivate getPackageResourcePattern(item: ResourceItem): string {\n\t\tconst baseDir = item.metadata.baseDir ?? dirname(item.path);\n\t\treturn relative(baseDir, item.path);\n\t}\n}\n"]}
1
+ {"version":3,"file":"config-selector-list.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/config-selector-list.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAoE,MAAM,wBAAwB,CAAC;AAE1I,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAoB,MAAM,kCAAkC,CAAC;AACtG,OAAO,KAAK,EAAiB,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAIxF,KAAK,YAAY,GAAG,YAAY,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;AASnE,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,YAAY,CAAC;IACvB,YAAY,EAAE,YAAY,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,gBAAgB;IACzB,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,YAAY,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,CAAC;IACxC,MAAM,EAAE,SAAS,GAAG,WAAW,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAmCD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,EAAE,CA+EtF;AAKD,qBAAa,oBAAqB,YAAW,SAAS;IACrD,UAAU,IAAI,IAAI,CAAG;IACrB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAW9B;CACD;AACD,qBAAa,YAAa,YAAW,SAAS,EAAE,SAAS;IACxD,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,aAAa,CAAmB;IACxC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,UAAU,CAAM;IACxB,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,QAAQ,CAAS;IAClB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IACpE,OAAO,CAAC,QAAQ,CAAS;IACzB,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IACD,YAAY,MAAM,EAAE,aAAa,EAAE,EAAE,eAAe,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAQnG;IACD,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,WAAW;IA6CnB,OAAO,CAAC,eAAe;IAIvB,UAAU,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAYrD;IACD,UAAU,IAAI,IAAI,CAAG;IACrB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA2C9B;IACD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAqD9B;IACD,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,sBAAsB;IA0C9B,OAAO,CAAC,qBAAqB;IA+C7B,OAAO,CAAC,kBAAkB;IAG1B,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,yBAAyB;CAIjC"}
@@ -1 +1 @@
1
- {"version":3,"file":"config-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/config-selector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAU,MAAM,wBAAwB,CAAC;AAC3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAGzE,OAAO,EAAwB,YAAY,EAAe,MAAM,2BAA2B,CAAC;AAC5F,qBAAa,uBAAwB,SAAQ,SAAU,YAAW,SAAS;IAC1E,OAAO,CAAC,YAAY,CAAe;IAEnC,OAAO,CAAC,QAAQ,CAAS;IACzB,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IAED,YACC,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,EAChC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,IAAI,EACnB,MAAM,EAAE,MAAM,IAAI,EAClB,aAAa,EAAE,MAAM,IAAI,EAuBzB;IAED,eAAe,IAAI,YAAY,CAE9B;CACD","sourcesContent":["/**\n * TUI component for managing package resources (enable/disable)\n */\n\nimport { Container, type Focusable, Spacer } from \"@earendil-works/pi-tui\";\nimport type { ResolvedPaths } from \"../../../core/package-manager.ts\";\nimport type { SettingsManager } from \"../../../core/settings-manager.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\n\nimport { ConfigSelectorHeader, ResourceList, buildGroups } from \"./config-selector-list.ts\";\nexport class ConfigSelectorComponent extends Container implements Focusable {\n\tprivate resourceList: ResourceList;\n\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.resourceList.focused = value;\n\t}\n\n\tconstructor(\n\t\tresolvedPaths: ResolvedPaths,\n\t\tsettingsManager: SettingsManager,\n\t\tcwd: string,\n\t\tagentDir: string,\n\t\tonClose: () => void,\n\t\tonExit: () => void,\n\t\trequestRender: () => void,\n\t) {\n\t\tsuper();\n\n\t\tconst groups = buildGroups(resolvedPaths, agentDir);\n\n\t\t// Add header\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new ConfigSelectorHeader());\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Resource list\n\t\tthis.resourceList = new ResourceList(groups, settingsManager, cwd, agentDir);\n\t\tthis.resourceList.onCancel = onClose;\n\t\tthis.resourceList.onExit = onExit;\n\t\tthis.resourceList.onToggle = () => requestRender();\n\t\tthis.addChild(this.resourceList);\n\n\t\t// Bottom border\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tgetResourceList(): ResourceList {\n\t\treturn this.resourceList;\n\t}\n}\n"]}
1
+ {"version":3,"file":"config-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/config-selector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAU,MAAM,wBAAwB,CAAC;AAC3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAGzE,OAAO,EAAwB,YAAY,EAAe,MAAM,2BAA2B,CAAC;AAC5F,qBAAa,uBAAwB,SAAQ,SAAU,YAAW,SAAS;IAC1E,OAAO,CAAC,YAAY,CAAe;IAEnC,OAAO,CAAC,QAAQ,CAAS;IACzB,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IAED,YACC,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,EAChC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,IAAI,EACnB,MAAM,EAAE,MAAM,IAAI,EAClB,aAAa,EAAE,MAAM,IAAI,EAuBzB;IAED,eAAe,IAAI,YAAY,CAE9B;CACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"context-window-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/context-window-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAgC,MAAM,wBAAwB,CAAC;AASjF,MAAM,WAAW,mBAAmB;IACnC,4DAA4D;IAC5D,aAAa,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAC;IACd,mGAAmG;IACnG,KAAK,EAAE,MAAM,CAAC;IACd,sFAAsF;IACtF,SAAS,EAAE,OAAO,CAAC;IACnB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACpC,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACxC,uBAAuB,EAAE,SAAS,MAAM,EAAE,EAC1C,oBAAoB,EAAE,MAAM,GAC1B,oBAAoB,CAyBtB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,8BAA+B,SAAQ,SAAS;IAC5D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAChD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAY;IAC1C,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkC;IACnE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAa;IAE9C,YACC,SAAS,EAAE,MAAM,EACjB,uBAAuB,EAAE,SAAS,MAAM,EAAE,EAC1C,oBAAoB,EAAE,MAAM,EAC5B,QAAQ,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,EACzC,QAAQ,EAAE,MAAM,IAAI,EAuBpB;IAED,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,UAAU;IAuBlB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAyBjC;IAED,OAAO,CAAC,OAAO;CAMf","sourcesContent":["import { Container, getKeybindings, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport { formatContextWindow } from \"../../../core/context-window.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, rawKeyHint } from \"./keybinding-hints.ts\";\n\n/** Gap (in columns) between the label column and the right-hand token column. */\nconst TOKEN_COLUMN_GAP = 3;\n\nexport interface ContextWindowChoice {\n\t/** Raw token count; the stable identity for this choice. */\n\tcontextWindow: number;\n\t/** `String(contextWindow)` — stable selection value, independent of display label. */\n\tvalue: string;\n\t/** Semantic tier label, e.g. \"Default\" / \"Long context\" (falls back to a size for extra tiers). */\n\tlabel: string;\n\t/** True for the model's native (smallest) window, rendered with a `(default)` tag. */\n\tisDefault: boolean;\n\t/** Right-column display, e.g. \"400k tokens\" / \"1m tokens\". */\n\ttokensLabel: string;\n}\n\nexport interface ContextWindowChoices {\n\tchoices: ContextWindowChoice[];\n\tcurrentIndex: number;\n}\n\n/**\n * Build the ordered, deduped context-window choices for the picker. The smallest\n * window is the model's native default (\"Default\"), the largest is \"Long context\",\n * and any extra tiers fall back to their formatted size. Raw token counts remain the\n * stable identity so colliding display labels never affect selection.\n */\nexport function buildContextWindowChoices(\n\tavailableContextWindows: readonly number[],\n\tcurrentContextWindow: number,\n): ContextWindowChoices {\n\tconst sorted = Array.from(new Set(availableContextWindows)).sort((a, b) => a - b);\n\tconst smallest = sorted[0];\n\tconst largest = sorted[sorted.length - 1];\n\n\tconst choices = sorted.map((contextWindow): ContextWindowChoice => {\n\t\tlet label: string;\n\t\tif (contextWindow === smallest) {\n\t\t\tlabel = \"Default\";\n\t\t} else if (contextWindow === largest) {\n\t\t\tlabel = \"Long context\";\n\t\t} else {\n\t\t\tlabel = formatContextWindow(contextWindow);\n\t\t}\n\t\treturn {\n\t\t\tcontextWindow,\n\t\t\tvalue: String(contextWindow),\n\t\t\tlabel,\n\t\t\tisDefault: contextWindow === smallest,\n\t\t\ttokensLabel: `${formatContextWindow(contextWindow)} tokens`,\n\t\t};\n\t});\n\n\tconst currentIndex = sorted.indexOf(currentContextWindow);\n\treturn { choices, currentIndex: currentIndex >= 0 ? currentIndex : 0 };\n}\n\n/**\n * Faithful re-creation of the GitHub Copilot CLI context-window picker, surfaced as a\n * follow-up step in the `/model` flow for models that expose more than one window.\n *\n * Renders numbered rows with a `❯` caret, semantic tier labels, a dim `(default)` tag,\n * and right-aligned dim token counts:\n *\n * ```\n * Select Context Window for GPT-5.5\n *\n * 1. Default (default) 400k tokens\n * ❯ 2. Long context 1m tokens\n *\n * 1-2 select · up/down navigate · enter confirm · esc cancel\n * ```\n */\nexport class ContextWindowSelectorComponent extends Container {\n\tprivate readonly choices: ContextWindowChoice[];\n\tprivate readonly listContainer: Container;\n\tprivate selectedIndex: number;\n\tprivate readonly onSelectCallback: (contextWindow: number) => void;\n\tprivate readonly onCancelCallback: () => void;\n\n\tconstructor(\n\t\tmodelName: string,\n\t\tavailableContextWindows: readonly number[],\n\t\tcurrentContextWindow: number,\n\t\tonSelect: (contextWindow: number) => void,\n\t\tonCancel: () => void,\n\t) {\n\t\tsuper();\n\n\t\tconst { choices, currentIndex } = buildContextWindowChoices(availableContextWindows, currentContextWindow);\n\t\tthis.choices = choices;\n\t\tthis.selectedIndex = currentIndex;\n\t\tthis.onSelectCallback = onSelect;\n\t\tthis.onCancelCallback = onCancel;\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"accent\", `Select Context Window for ${modelName}`), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(this.getHintBar(), 0, 0));\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.updateList();\n\t}\n\n\tprivate getHintBar(): string {\n\t\tconst separator = theme.fg(\"muted\", \" · \");\n\t\treturn [\n\t\t\trawKeyHint(`1-${this.choices.length}`, \"select\"),\n\t\t\trawKeyHint(\"up/down\", \"navigate\"),\n\t\t\tkeyHint(\"tui.select.confirm\", \"confirm\"),\n\t\t\tkeyHint(\"tui.select.cancel\", \"cancel\"),\n\t\t].join(separator);\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\n\t\tconst numberColumnWidth = `${this.choices.length}.`.length;\n\t\tconst leftText = (choice: ContextWindowChoice, index: number): string => {\n\t\t\tconst number = `${index + 1}.`.padStart(numberColumnWidth);\n\t\t\tconst defaultTag = choice.isDefault ? \" (default)\" : \"\";\n\t\t\treturn `${number} ${choice.label}${defaultTag}`;\n\t\t};\n\t\tconst leftColumnWidth = Math.max(...this.choices.map((choice, index) => leftText(choice, index).length));\n\n\t\tthis.choices.forEach((choice, index) => {\n\t\t\tconst isSelected = index === this.selectedIndex;\n\t\t\tconst caret = isSelected ? theme.fg(\"accent\", \"❯ \") : \" \";\n\t\t\tconst number = theme.fg(\"muted\", `${`${index + 1}.`.padStart(numberColumnWidth)} `);\n\t\t\tconst label = isSelected ? theme.fg(\"accent\", choice.label) : choice.label;\n\t\t\tconst defaultTag = choice.isDefault ? theme.fg(\"muted\", \" (default)\") : \"\";\n\t\t\tconst padding = \" \".repeat(leftColumnWidth - leftText(choice, index).length + TOKEN_COLUMN_GAP);\n\t\t\tconst tokens = theme.fg(\"muted\", choice.tokensLabel);\n\t\t\tthis.listContainer.addChild(new Text(`${caret}${number}${label}${defaultTag}${padding}${tokens}`, 0, 0));\n\t\t});\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\n\t\tif (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.choices.length - 1 : this.selectedIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n\t\t\tthis.selectedIndex = this.selectedIndex === this.choices.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tthis.confirm(this.selectedIndex);\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.onCancelCallback();\n\t\t\treturn;\n\t\t}\n\t\t// Number shortcuts (1-9) select the matching row directly.\n\t\tif (/^[1-9]$/.test(keyData)) {\n\t\t\tthis.confirm(Number.parseInt(keyData, 10) - 1);\n\t\t}\n\t}\n\n\tprivate confirm(index: number): void {\n\t\tconst choice = this.choices[index];\n\t\tif (choice) {\n\t\t\tthis.onSelectCallback(choice.contextWindow);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"context-window-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/context-window-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAgC,MAAM,wBAAwB,CAAC;AASjF,MAAM,WAAW,mBAAmB;IACnC,4DAA4D;IAC5D,aAAa,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAC;IACd,mGAAmG;IACnG,KAAK,EAAE,MAAM,CAAC;IACd,sFAAsF;IACtF,SAAS,EAAE,OAAO,CAAC;IACnB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACpC,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACxC,uBAAuB,EAAE,SAAS,MAAM,EAAE,EAC1C,oBAAoB,EAAE,MAAM,GAC1B,oBAAoB,CAyBtB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,8BAA+B,SAAQ,SAAS;IAC5D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAChD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAY;IAC1C,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkC;IACnE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAa;IAE9C,YACC,SAAS,EAAE,MAAM,EACjB,uBAAuB,EAAE,SAAS,MAAM,EAAE,EAC1C,oBAAoB,EAAE,MAAM,EAC5B,QAAQ,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,EACzC,QAAQ,EAAE,MAAM,IAAI,EAuBpB;IAED,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,UAAU;IAuBlB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAyBjC;IAED,OAAO,CAAC,OAAO;CAMf"}
@@ -1 +1 @@
1
- {"version":3,"file":"countdown-timer.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/countdown-timer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAElD,qBAAa,cAAc;IAC1B,OAAO,CAAC,UAAU,CAA6C;IAC/D,OAAO,CAAC,gBAAgB,CAAS;IAEjC,QAAgB,GAAG,CAAkB;IACrC,QAAgB,MAAM,CAA4B;IAClD,QAAgB,QAAQ,CAAa;IAErC,YACC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,GAAG,GAAG,SAAS,EACpB,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EACjC,QAAQ,EAAE,MAAM,IAAI,EAkBpB;IAED,OAAO,IAAI,IAAI,CAKd;CACD","sourcesContent":["/**\n * Reusable countdown timer for dialog components.\n */\n\nimport type { TUI } from \"@earendil-works/pi-tui\";\n\nexport class CountdownTimer {\n\tprivate intervalId: ReturnType<typeof setInterval> | undefined;\n\tprivate remainingSeconds: number;\n\n\tdeclare private tui: TUI | undefined;\n\tdeclare private onTick: (seconds: number) => void;\n\tdeclare private onExpire: () => void;\n\n\tconstructor(\n\t\ttimeoutMs: number,\n\t\ttui: TUI | undefined,\n\t\tonTick: (seconds: number) => void,\n\t\tonExpire: () => void,\n\t) {\n\t\tthis.tui = tui;\n\t\tthis.onTick = onTick;\n\t\tthis.onExpire = onExpire;\n\t\tthis.remainingSeconds = Math.ceil(timeoutMs / 1000);\n\t\tthis.onTick(this.remainingSeconds);\n\n\t\tthis.intervalId = setInterval(() => {\n\t\t\tthis.remainingSeconds--;\n\t\t\tthis.onTick(this.remainingSeconds);\n\t\t\tthis.tui?.requestRender();\n\n\t\t\tif (this.remainingSeconds <= 0) {\n\t\t\t\tthis.dispose();\n\t\t\t\tthis.onExpire();\n\t\t\t}\n\t\t}, 1000);\n\t}\n\n\tdispose(): void {\n\t\tif (this.intervalId) {\n\t\t\tclearInterval(this.intervalId);\n\t\t\tthis.intervalId = undefined;\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"countdown-timer.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/countdown-timer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAElD,qBAAa,cAAc;IAC1B,OAAO,CAAC,UAAU,CAA6C;IAC/D,OAAO,CAAC,gBAAgB,CAAS;IAEjC,QAAgB,GAAG,CAAkB;IACrC,QAAgB,MAAM,CAA4B;IAClD,QAAgB,QAAQ,CAAa;IAErC,YACC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,GAAG,GAAG,SAAS,EACpB,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EACjC,QAAQ,EAAE,MAAM,IAAI,EAkBpB;IAED,OAAO,IAAI,IAAI,CAKd;CACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"custom-editor.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/custom-editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,MAAM,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,KAAK,GAAG,EAAiC,MAAM,wBAAwB,CAAC;AAC9I,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGtF,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;CACtC;AAKD;;GAEG;AACH,qBAAa,YAAa,SAAQ,MAAM;IACvC,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAsC;IAClD,cAAc,EAAE,GAAG,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC,CAAa;IAG3D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,2EAA2E;IACpE,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAEvD,YAAY,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,mBAAmB,EAKvG;IAED,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,GAAG,IAAI,CAErE;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAqC9B;IAED,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,OAAO;IAQf;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAEzD;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAiD9B;CACD","sourcesContent":["import { CURSOR_MARKER, Editor, type EditorOptions, type EditorTheme, type TUI, truncateToWidth, visibleWidth } from \"@earendil-works/pi-tui\";\nimport type { AppKeybinding, KeybindingsManager } from \"../../../core/keybindings.ts\";\nimport { theme } from \"../theme/theme.ts\";\n\nexport interface CustomEditorOptions extends EditorOptions {\n\tpromptPrefix?: string;\n\tplaceholder?: string | (() => string);\n}\n\nconst ANSI_ESCAPE_PATTERN = /\\x1b\\[[0-?]*[ -/]*[@-~]|\\x1b\\][^\\x07]*(?:\\x07|\\x1b\\\\)|\\x1b[PX_][\\s\\S]*?\\x1b\\\\/g;\nconst BORDER_LINE_PATTERN = /^[─ ↑↓0-9more]+$/;\n\n/**\n * Custom editor that handles app-level keybindings for coding-agent.\n */\nexport class CustomEditor extends Editor {\n\tprivate keybindings: KeybindingsManager;\n\tprivate promptPrefix: string;\n\tprivate placeholder: string | (() => string) | undefined;\n\tpublic actionHandlers: Map<AppKeybinding, () => void> = new Map();\n\n\t// Special handlers that can be dynamically replaced\n\tpublic onEscape?: () => void;\n\tpublic onCtrlD?: () => void;\n\tpublic onPasteImage?: () => void;\n\t/** Handler for extension-registered shortcuts. Returns true if handled. */\n\tpublic onExtensionShortcut?: (data: string) => boolean;\n\n\tconstructor(tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager, options?: CustomEditorOptions) {\n\t\tsuper(tui, theme, options);\n\t\tthis.keybindings = keybindings;\n\t\tthis.promptPrefix = options?.promptPrefix ?? \"❯ \";\n\t\tthis.placeholder = options?.placeholder;\n\t}\n\n\tsetPlaceholder(placeholder: string | (() => string) | undefined): void {\n\t\tthis.placeholder = placeholder;\n\t}\n\n\trender(width: number): string[] {\n\t\tconst promptWidth = visibleWidth(this.promptPrefix);\n\t\tif (promptWidth <= 0 || width <= promptWidth + 1) {\n\t\t\treturn super.render(width);\n\t\t}\n\n\t\tconst editorWidth = Math.max(1, width - promptWidth);\n\t\tconst lines = super.render(editorWidth);\n\t\tlet borderCount = 0;\n\t\tlet inPromptBox = false;\n\t\tlet promptShown = false;\n\n\t\tconst placeholder = typeof this.placeholder === \"function\" ? this.placeholder() : this.placeholder;\n\n\t\treturn lines.map((line) => {\n\t\t\tif (this.isEditorBorderLine(line)) {\n\t\t\t\tborderCount += 1;\n\t\t\t\tif (borderCount === 1) {\n\t\t\t\t\tinPromptBox = true;\n\t\t\t\t\tpromptShown = false;\n\t\t\t\t} else if (borderCount === 2) {\n\t\t\t\t\tinPromptBox = false;\n\t\t\t\t}\n\t\t\t\treturn this.extendBorderLine(line, width);\n\t\t\t}\n\n\t\t\tconst showPrompt = inPromptBox && !promptShown;\n\t\t\tconst prefix = showPrompt ? this.promptPrefix : \" \".repeat(promptWidth);\n\t\t\tlet content = line;\n\t\t\tif (showPrompt && placeholder && this.getText() === \"\") {\n\t\t\t\tcontent = this.renderPlaceholder(placeholder, editorWidth);\n\t\t\t}\n\t\t\tif (inPromptBox) {\n\t\t\t\tpromptShown = true;\n\t\t\t}\n\t\t\treturn this.padLine(`${prefix}${content}`, width);\n\t\t});\n\t}\n\n\tprivate renderPlaceholder(placeholder: string, editorWidth: number): string {\n\t\tconst cursor = `${this.focused ? CURSOR_MARKER : \"\"}\\x1b[7m \\x1b[0m`;\n\t\tconst placeholderWidth = Math.max(0, editorWidth - 1);\n\t\tconst text = truncateToWidth(placeholder, placeholderWidth, \"...\");\n\t\treturn `${cursor}${theme.fg(\"muted\", text)}`;\n\t}\n\n\tprivate isEditorBorderLine(line: string): boolean {\n\t\tconst plain = line.replace(ANSI_ESCAPE_PATTERN, \"\").trim();\n\t\treturn plain.includes(\"─\") && BORDER_LINE_PATTERN.test(plain);\n\t}\n\n\tprivate extendBorderLine(line: string, width: number): string {\n\t\tconst remainingWidth = width - visibleWidth(line);\n\t\tif (remainingWidth <= 0) {\n\t\t\treturn line;\n\t\t}\n\t\treturn `${line}${this.borderColor(\"─\".repeat(remainingWidth))}`;\n\t}\n\n\tprivate padLine(line: string, width: number): string {\n\t\tconst remainingWidth = width - visibleWidth(line);\n\t\tif (remainingWidth <= 0) {\n\t\t\treturn line;\n\t\t}\n\t\treturn `${line}${\" \".repeat(remainingWidth)}`;\n\t}\n\n\t/**\n\t * Register a handler for an app action.\n\t */\n\tonAction(action: AppKeybinding, handler: () => void): void {\n\t\tthis.actionHandlers.set(action, handler);\n\t}\n\n\thandleInput(data: string): void {\n\t\t// Check extension-registered shortcuts first\n\t\tif (this.onExtensionShortcut?.(data)) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for paste image keybinding\n\t\tif (this.keybindings.matches(data, \"app.clipboard.pasteImage\")) {\n\t\t\tthis.onPasteImage?.();\n\t\t\treturn;\n\t\t}\n\n\t\t// Check app keybindings first\n\n\t\t// Escape/interrupt - only if autocomplete is NOT active\n\t\tif (this.keybindings.matches(data, \"app.interrupt\")) {\n\t\t\tif (!this.isShowingAutocomplete()) {\n\t\t\t\t// Use dynamic onEscape if set, otherwise registered handler\n\t\t\t\tconst handler = this.onEscape ?? this.actionHandlers.get(\"app.interrupt\");\n\t\t\t\tif (handler) {\n\t\t\t\t\thandler();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Let parent handle escape for autocomplete cancellation\n\t\t\tsuper.handleInput(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// Exit (Ctrl+D) - only when editor is empty\n\t\tif (this.keybindings.matches(data, \"app.exit\")) {\n\t\t\tif (this.getText().length === 0) {\n\t\t\t\tconst handler = this.onCtrlD ?? this.actionHandlers.get(\"app.exit\");\n\t\t\t\tif (handler) handler();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Fall through to editor handling for delete-char-forward when not empty\n\t\t}\n\n\t\t// Check all other app actions\n\t\tfor (const [action, handler] of this.actionHandlers) {\n\t\t\tif (action !== \"app.interrupt\" && action !== \"app.exit\" && this.keybindings.matches(data, action)) {\n\t\t\t\thandler();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Pass to parent for editor handling\n\t\tsuper.handleInput(data);\n\t}\n}\n"]}
1
+ {"version":3,"file":"custom-editor.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/custom-editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,MAAM,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,KAAK,GAAG,EAAiC,MAAM,wBAAwB,CAAC;AAC9I,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGtF,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;CACtC;AAKD;;GAEG;AACH,qBAAa,YAAa,SAAQ,MAAM;IACvC,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAsC;IAClD,cAAc,EAAE,GAAG,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC,CAAa;IAG3D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,2EAA2E;IACpE,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAEvD,YAAY,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,mBAAmB,EAKvG;IAED,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,GAAG,IAAI,CAErE;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAqC9B;IAED,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,OAAO;IAQf;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAEzD;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAiD9B;CACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"custom-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/custom-message.ts"],"names":[],"mappings":"AAEA,OAAO,EAAO,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,wBAAwB,CAAC;AACpG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAkB/D;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,SAAS;IACpD,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,cAAc,CAAC,CAAkB;IACzC,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,eAAe,CAAC,CAAY;IACpC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,SAAS,CAAS;IAE1B,YACC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,EAC/B,cAAc,CAAC,EAAE,eAAe,EAChC,aAAa,GAAE,aAAkC,EAajD;IAED,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAKnC;IAEQ,UAAU,IAAI,IAAI,CAG1B;IAED,OAAO,CAAC,OAAO;CAoEf","sourcesContent":["import type { TextContent } from \"@earendil-works/pi-ai/compat\";\nimport type { Component } from \"@earendil-works/pi-tui\";\nimport { Box, Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { MessageRenderer } from \"../../../core/extensions/types.ts\";\nimport type { CustomMessage } from \"../../../core/messages.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\n\n/**\n * Type guard ensuring a value returned by an extension's custom renderer is a\n * real TUI Component (exposes a callable `render`). Extension renderer output is\n * untrusted at runtime: a renderer that returns a string or other non-Component\n * value would otherwise be added as a child and crash `Container.render()` with\n * \"child.render is not a function\".\n */\nfunction isRenderableComponent(value: unknown): value is Component {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\ttypeof (value as { render?: unknown }).render === \"function\"\n\t);\n}\n\n/**\n * Component that renders a custom message entry from extensions.\n * Uses distinct styling to differentiate from user messages.\n */\nexport class CustomMessageComponent extends Container {\n\tprivate message: CustomMessage<unknown>;\n\tprivate customRenderer?: MessageRenderer;\n\tprivate box: Box;\n\tprivate spacer?: Spacer;\n\tprivate customComponent?: Component;\n\tprivate markdownTheme: MarkdownTheme;\n\tprivate _expanded = false;\n\n\tconstructor(\n\t\tmessage: CustomMessage<unknown>,\n\t\tcustomRenderer?: MessageRenderer,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t) {\n\t\tsuper();\n\t\tthis.message = message;\n\t\tthis.customRenderer = customRenderer;\n\t\tthis.markdownTheme = markdownTheme;\n\n\t\t// Create box with purple background (used for default rendering)\n\t\tthis.box = new Box(1, 1, (t) => theme.bg(\"customMessageBg\", t));\n\n\t\t// The leading spacer is mounted in rebuild() alongside actual content, so a\n\t\t// renderer that suppresses output (returns null) leaves no blank row.\n\t\tthis.rebuild();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tif (this._expanded !== expanded) {\n\t\t\tthis._expanded = expanded;\n\t\t\tthis.rebuild();\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.rebuild();\n\t}\n\n\tprivate rebuild(): void {\n\t\t// Remove previously mounted content (spacer + content) before rebuilding.\n\t\tif (this.customComponent) {\n\t\t\tthis.removeChild(this.customComponent);\n\t\t\tthis.customComponent = undefined;\n\t\t}\n\t\tif (this.spacer) {\n\t\t\tthis.removeChild(this.spacer);\n\t\t\tthis.spacer = undefined;\n\t\t}\n\t\tthis.removeChild(this.box);\n\n\t\t// Try custom renderer first - it handles its own styling\n\t\tif (this.customRenderer) {\n\t\t\ttry {\n\t\t\t\tconst component = this.customRenderer(this.message, { expanded: this._expanded }, theme);\n\t\t\t\t// Explicit null = \"handled; render nothing\". Skip the leading spacer\n\t\t\t\t// and the default box entirely so the entry occupies zero rows. The\n\t\t\t\t// workflows inline-form renderer returns null for a rehydrated\n\t\t\t\t// input-form card on /resume so the input widget does not reappear.\n\t\t\t\tif (component === null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// Only mount the result if it is a real Component. A non-Component,\n\t\t\t\t// non-null return (string, number, plain object, …) is ignored so we\n\t\t\t\t// fall through to the default rendering path instead of crashing\n\t\t\t\t// Container.render().\n\t\t\t\tif (isRenderableComponent(component)) {\n\t\t\t\t\t// Custom renderer provides its own styled component\n\t\t\t\t\tthis.spacer = new Spacer(1);\n\t\t\t\t\tthis.addChild(this.spacer);\n\t\t\t\t\tthis.customComponent = component;\n\t\t\t\t\tthis.addChild(component);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Fall through to default rendering\n\t\t\t}\n\t\t}\n\n\t\t// Default rendering uses our box, preceded by the standard leading spacer.\n\t\tthis.spacer = new Spacer(1);\n\t\tthis.addChild(this.spacer);\n\t\tthis.addChild(this.box);\n\t\tthis.box.clear();\n\n\t\t// Default rendering: label + content\n\t\tconst label = theme.fg(\"customMessageLabel\", `\\x1b[1m[${this.message.customType}]\\x1b[22m`);\n\t\tthis.box.addChild(new Text(label, 0, 0));\n\t\tthis.box.addChild(new Spacer(1));\n\n\t\t// Extract text content\n\t\tlet text: string;\n\t\tif (typeof this.message.content === \"string\") {\n\t\t\ttext = this.message.content;\n\t\t} else {\n\t\t\ttext = this.message.content\n\t\t\t\t.filter((c): c is TextContent => c.type === \"text\")\n\t\t\t\t.map((c) => c.text)\n\t\t\t\t.join(\"\\n\");\n\t\t}\n\n\t\tthis.box.addChild(\n\t\t\tnew Markdown(text, 0, 0, this.markdownTheme, {\n\t\t\t\tcolor: (text: string) => theme.fg(\"customMessageText\", text),\n\t\t\t}),\n\t\t);\n\t}\n}\n"]}
1
+ {"version":3,"file":"custom-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/custom-message.ts"],"names":[],"mappings":"AAEA,OAAO,EAAO,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,wBAAwB,CAAC;AACpG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAkB/D;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,SAAS;IACpD,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,cAAc,CAAC,CAAkB;IACzC,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,eAAe,CAAC,CAAY;IACpC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,SAAS,CAAS;IAE1B,YACC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,EAC/B,cAAc,CAAC,EAAE,eAAe,EAChC,aAAa,GAAE,aAAkC,EAajD;IAED,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAKnC;IAEQ,UAAU,IAAI,IAAI,CAG1B;IAED,OAAO,CAAC,OAAO;CAoEf"}
@@ -1 +1 @@
1
- {"version":3,"file":"daxnuts.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/daxnuts.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAkD7D,qBAAa,gBAAiB,YAAW,SAAS;IACjD,OAAO,CAAC,EAAE,CAAM;IAChB,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,QAAQ,CAA+C;IAC/D,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,UAAU,CAAM;IAExB,YAAY,EAAE,EAAE,GAAG,EAIlB;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,aAAa;IAOrB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAgE9B;IAED,OAAO,IAAI,IAAI,CAEd;CACD","sourcesContent":["/**\n * POWERED BY DAXNUTS - Easter egg for OpenCode + Kimi K2.5\n *\n * A heartfelt tribute to dax (@thdxr) for providing free Kimi K2.5 access via OpenCode.\n */\n\nimport type { Component, TUI } from \"@earendil-works/pi-tui\";\nimport { theme } from \"../theme/theme.ts\";\n\n// 32x32 RGB image of dax, hex encoded (3 bytes per pixel)\nconst DAX_HEX =\n\t\"bbbab8b9b9b6b9b8b5bcbbb8b8b7b4b7b5b2b6b5b2b8b7b4b7b6b3b6b4b1bdbcb8bab8b6bbb8b5b8b5b1bbb8b4c2bebbc1bebac0bdbabfbcb9c1bebabfbebbc0bfbcc0bdbabbb8b5c1bfbcbfbcb8bbb9b6bfbcb8c2bfbcc1bfbcbfbbb8bdb9b6b8b7b5b9b8b5b8b8b5b5b5b2b6b5b2b8b7b4b9b8b5b9b8b5b6b5b3bab8b5bcbab7bbb9b6bbb8b5bfb9b5bdb2abbcb0a8beb2aabeb5afbfbab6bebab7c0bfbcbebdbabebbb8c0bdbabfbebbc2bebbbdbab7c3c0bdc3c0bdc1bebbc2bebabfbcb8bab9b6b7b6b3b2b1aeb6b5b2b5b4b1b5b4b2b6b5b2b7b6b4b9b8b6b7b6b3bbbab7b2afaba5988fb49e90b09481b79a88b39683b09583b7a395bfb6b0c0bdbabdbbb8bebcb9c1bfbcc0bebbbdbab7bebbb8c2bfbcc0bdbac0bcb9bdb9b6c0bcb8b5b4b2b4b3b0bab9b6b9b9b6b5b4b1b5b4b1b6b5b3b9b8b5b9b8b6b9b8b6b2aeaa968174a6836eaa856eab846eaf8973ac8973b08f79b18f7ab39786b7a89dbbb3aebfbab6c2c0bdbebcb9bfbdbac3c1bdc2bebbc0bcb9bdb9b6c1bdbabfbbb8b4b3b0b9b8b5b8b7b5b4b3b1b5b4b1b8b7b4b8b7b5bab9b6bbbab7b1afad8c7a719d735ca47860a87d65a98069ae8972ae8c75af8d77aa826ba98067aa8974b39e90b6a79dbbb2adc0bdbac1bfbdbfbbb8c1bdb9bebab6c0bdb9bfbbb8c1bdbab4b2b0b7b6b4b7b6b3b4b2b0bab9b7b6b5b2b6b5b2bab9b6bab9b6958c87977663aa836bac8772b08f7aad8c77b2917db0917db0907cac8971a77d64a87f67ac8972b29887b8a89dbfbab5bfbdbac1bebac0bcb9c0bcb9c0bcb9c1bebabebab7b8b7b4b7b6b4b5b4b1b5b4b2b7b6b3b5b4b2bab9b7bab9b6b4b1ada88f7fad8973ae8d78b19684b19685b29786b69a89b29582b1917daa856ea87e66a97e66ad866ea9826baf9280b8ada6bdbbb8bebab7bfbbb8c1bdbabfbbb8bcb8b4bcb8b5b6b4b2b7b5b3b6b5b2b8b7b4b3b2afb8b7b4b6b5b2b3b2b0b3a59aab856fad8d78b0917eb19886b49b8bb49a89b39785b0917eaf8f7cab866fa77d65a77a61a87d64a9816ab08f79b5a296c1bcb8c3bfbcc2bebbbebab7bfbbb7bdbab6c2bebab8b7b4b7b6b4b6b5b3b7b6b3b6b5b2b9b8b6b4b3b1b6b1acac8f7ca9826bae8f7aaf9583b49c8cb49c8bb79d8cb59987b19380ad8e79ae8c77af8e78ac8771a3775faa826bae8972b39888bbb6b2bebbb8bfbbb8bfbbb8c0bdb9bebbb7c0bdb9b6b5b2b9b8b5b4b3b1b8b7b5b4b3b0b7b6b4b6b5b3b1a7a0aa8772a77d65a88570b49887b19b8d9c887c907a6d987f71aa907faf917daf8e7aad8c78ac8b77a8836ca9836cac8770b49b8abdb6b2c0bcb9c0bdb9bfbbb8bebab7bfbcb9bebab7b9b8b6b5b4b2b9b8b5b8b7b5b8b7b4b7b6b4b5b4b2b3a9a2ad8973a1755da9856fb398858c776a65544b776358725d526e594d9c7f6eb1907ba68672ad8e7aab8771ac856db18f79b3a092beb9b5c1bdbabdb9b5bebab7bfbbb7bebab7bcb9b6b7b6b4b6b6b3b8b7b4b5b4b2b8b6b4b7b6b3b4b3b0b4aba4a6826ba3775fb08e79b19584a88e7daa8e7db29481ad8f7c997e6da38674ac8d79ac8e7aae917f9a7c6a896a599a7c6ab3a398c1bdbabdb9b6bcb8b5bebab6bebab7bdb9b5bdb9b6b5b4b1b7b5b3b5b4b2b7b6b3b7b6b4b3b3b0b3b2b0b4aca5a7846fa97f68ae8f7bae9383b59c8bb2937fae8e79ac8b76af927eaf927eb29683b39885b2988891786a72594c6e594d978d86bdbab7bab7b3c0bcb9c0bcb9bebab7bebbb7bdb9b6b3b2b0b4b3b0b5b4b2b4b4b1b4b3b1b4b3b1b4b3b0b6ada5aa8670a57a62ad8e7ab29b8cb69d8dab856fa9826aa88069ab8771af907db49987b19684b29886b59987b39480b09787b5a9a1bcb8b5bebab7bdb9b5bebab7bfbbb8bfbbb7bbb7b4b3b2afb8b7b5b8b7b5b3b2b0b5b4b2b6b5b3b6b4b1afa299a98975a9826baf907cb39988b49a89af8e7aac8973aa856eaf8c74b1917dae907dac907db39988b29785b49785b7a090b9aca3bfbab7bcb8b5bdb9b6bcb8b4bcb8b5bdb9b5bcb8b4b5b4b2b6b5b3b4b3b0b4b3b0b9b8b5b8b6b4908b88887467aa8f7ea78976ad8973b08b74b59885b69e8eb29888b1917cb1917db1937fae907cb19686b39a8ab29886b59b8ab8a192b6aaa3b7b2afbcb8b4bcb8b5bbb7b4c0bcb9bebab7c0bcb9b6b5b2b6b5b3b4b3b0bab9b7b7b6b4b1b0ae7b716ba083709b806f716158967764b08870b29481b69b8ab69f8fb39a89b69f90b49d8db39a89b29988b49c8cb6a090b8a496baa49593867f8f8986bfbbb7bdb9b5bcb7b4bab6b3b9b5b2bab6b2b4b3b1b3b3b0b6b5b3b8b7b5b4b2b0a7a5a38f837dae917ea084725a504c63544da28370b39784b59e8db2a093a698909b918b998e8790857e95877dad998bb39c8cb5a091b9a2938d827c95908dbebab6bbb7b3bdbab7bbb7b4bdb9b6bbb7b4b4b3b0b5b4b1b8b7b5b6b5b3b8b8b5b4b2af968f8ab29a8bab9485544b483a323073655d96887f70655f61595547403e453e3c453f3d57504f655e5b90847db39c8db7a090b6a09189807aaba6a3bdb9b6c0bcb9bebab7bcb7b4bebab7bbb7b4b3b2b0b6b5b3b2b1afb7b6b4b8b7b4b5b4b1aeaba8b5a89fac998d4d44412d25244d46444e4744322b293a3230423937433a37352d2a59504c534b48524a48988a81b59f8fb19c8d827974b2afacbdb9b5bcb8b4bdb9b5bcb8b5bdb9b6bab6b2b8b7b5b5b4b2b6b6b3b9b8b5b7b6b3b6b5b2b8b6b3b9b4b1b2a9a26c64612d25242d2625312a28352d2c453d3a78675c8d7a6ea09792aea6a0615854332b29524a479f8e82b09d90a49b96c1bdb9bebab7bfbbb8bbb8b4b9b5b1b8b4b0b9b4b0b7b6b4b8b7b5b8b7b4b6b5b3b8b6b3bab9b6b9b8b5b4b3b0b7b5b2a5a29f453d3b261e1d261f1e2e2625413936857268977865b19482b5a69caca5a07c7572453d3b746963a0948cc5bfbbc0bbb8beb9b6bbb7b3bbb6b3b7b3afb8b4b0b9b5b1b7b6b3b6b5b3b5b4b2b5b4b2b7b6b3b7b6b3b8b6b3b4b2afb7b6b3b3b1ae6d6765251f1e1e18172a22212d2523443b3971625ab19888b09482a89182877e792c25243e3634766d6abeb9b5bfbbb7bebab6bcb7b3bbb6b3b9b5b1b7b3afb8b4b0b4b3b0b5b4b1b5b4b1b4b3b1b5b4b2b8b6b4b5b3b0b9b6b4b5b4b1b6b4b27f79762a2322221c1b2d2524221b1a443e3c47413f6f676281766f867971675e5a3e37352a222166605dbab7b3bdb9b5beb9b5bcb7b3bcb7b3b9b4b0bab6b2bab6b2b5b3b0b6b4b2b3b2afb7b6b3b4b4b1b4b3b0b6b4b1b5b4b1b4b3b0b9b6b29a8c8252474230292828201f181212322c2c231e1d1c16162c26252923222d26252d2523332b2a8e8885bcb8b5bcb7b3bbb6b2bcb7b3b9b4b1b9b5b1b7b2afb7b2ae7a838e9b9b9caeadacb3b2b0b3b2afb7b7b4b6b5b3b6b6b3b7b6b3b9ada4a991808e7b6f50453f2b24231a14142923221f19181d17161f18182620201d17162a22215d5654b7b3b0bbb7b3bbb6b2b8b4b0bab5b1bbb6b2bab5b1b8b4b0bab6b22c496b4c5d735f68766e727a828285929090adaba8b7b2aeb6a59ab39682a28470a387748e76674e403a1a14141d1716181211221c1c1f1918221c1b2f2827342d2c8d8884bab6b3b9b5b2bab5b1bab5b1b9b4b0bab6b2b8b4b0b9b4b0b7b2ae325e8b365f8a3a5d833f5b7a545f70646469706b6aa08f84b08e78b18e769f7e689e7f6b9e816d907766584940362d2a1c1615201b1a1a1413201a1a251e1d393331a39e9bbab5b1bcb7b3bab6b2b8b3afb8b4b0b9b4b0b9b4b1bab5b2b5b0ac3d6c9843729d44719c426e98415f805a64716f6a699d8677b1927eb3947faa89749d7a649f7f6ba487749e837186716454463f2c25231e181837302e3a33317a7471beb9b6bcb8b4bbb6b2b6b2aebab5b1b9b5b1b8b3afbab6b2b6b1adb5aeaa4877a14c7aa44e7ba345719a3a5d80586b7f767475927b6eb1927faf8e79b08e78a78169a07861a17f6aa58570a688749b83738270666f66618a8480a49e99b7b2aebab6b2bcb8b4b9b5b1b7b2aebab5b1b9b4b0b6b1aeb6b1adb2aca8b2aca84876a04a78a2517fa74771973a5d80405c7a6161677c695fac8a75b08d77b4917aaf8971ad876fa5816aa6846ea78670a98a76ac9484ab9f96b2aca8bdb8b4bcb7b3bcb8b4bcb8b4b8b3afb7b2aeb9b4b0b8b3afb8b2aeb6afabb3aeaab2aeaa4878a14b7aa34c7ba44a759b3d63873b5f825b67766f5f569c7e6caf8c77b18f79b28f78b5927caf8e78a98872aa8a76a98a76ac917fada199b7b0acb9b3afbfb9b5c1bab6bdb6b2b8b3afbab5b1b9b4b0b6afabb7b1adb3ada9b3aeaab0aba8\";\n\nconst WIDTH = 32;\nconst HEIGHT = 32;\n\nfunction parseImage(): number[][][] {\n\tconst pixels: number[][][] = [];\n\tfor (let y = 0; y < HEIGHT; y++) {\n\t\tconst row: number[][] = [];\n\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\tconst idx = (y * WIDTH + x) * 6;\n\t\t\tconst r = parseInt(DAX_HEX.slice(idx, idx + 2), 16);\n\t\t\tconst g = parseInt(DAX_HEX.slice(idx + 2, idx + 4), 16);\n\t\t\tconst b = parseInt(DAX_HEX.slice(idx + 4, idx + 6), 16);\n\t\t\trow.push([r, g, b]);\n\t\t}\n\t\tpixels.push(row);\n\t}\n\treturn pixels;\n}\n\nfunction rgb(r: number, g: number, b: number, bg = false): string {\n\treturn `\\x1b[${bg ? 48 : 38};2;${r};${g};${b}m`;\n}\n\nconst RESET = \"\\x1b[0m\";\n\nfunction buildImage(): string[] {\n\tconst pixels = parseImage();\n\tconst lines: string[] = [];\n\n\t// Use half-block chars: ▄ with bg=top pixel, fg=bottom pixel\n\tfor (let row = 0; row < HEIGHT; row += 2) {\n\t\tlet line = \"\";\n\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\tconst top = pixels[row][x];\n\t\t\tconst bottom = pixels[row + 1]?.[x] ?? top;\n\t\t\tline += `${rgb(bottom[0], bottom[1], bottom[2])}${rgb(top[0], top[1], top[2], true)}▄`;\n\t\t}\n\t\tline += RESET;\n\t\tlines.push(line);\n\t}\n\treturn lines;\n}\n\nexport class DaxnutsComponent implements Component {\n\tprivate ui: TUI;\n\tprivate image: string[];\n\tprivate interval: ReturnType<typeof setInterval> | null = null;\n\tprivate tick = 0;\n\tprivate maxTicks = 25; // ~2 seconds at 80ms\n\tprivate cachedLines: string[] = [];\n\tprivate cachedWidth = 0;\n\tprivate cachedTick = -1;\n\n\tconstructor(ui: TUI) {\n\t\tthis.ui = ui;\n\t\tthis.image = buildImage();\n\t\tthis.startAnimation();\n\t}\n\n\tinvalidate(): void {\n\t\tthis.cachedWidth = 0;\n\t}\n\n\tprivate startAnimation(): void {\n\t\tthis.interval = setInterval(() => {\n\t\t\tthis.tick++;\n\t\t\tif (this.tick >= this.maxTicks) {\n\t\t\t\tthis.stopAnimation();\n\t\t\t}\n\t\t\tthis.cachedWidth = 0;\n\t\t\tthis.ui.requestRender();\n\t\t}, 80);\n\t}\n\n\tprivate stopAnimation(): void {\n\t\tif (this.interval) {\n\t\t\tclearInterval(this.interval);\n\t\t\tthis.interval = null;\n\t\t}\n\t}\n\n\trender(width: number): string[] {\n\t\tif (width === this.cachedWidth && this.cachedTick === this.tick) {\n\t\t\treturn this.cachedLines;\n\t\t}\n\n\t\tconst t = theme;\n\t\tconst lines: string[] = [];\n\n\t\tconst center = (s: string) => {\n\t\t\tconst visible = s.replace(/\\x1b\\[[0-9;]*m/g, \"\").length;\n\t\t\tconst left = Math.max(0, Math.floor((width - visible) / 2));\n\t\t\treturn \" \".repeat(left) + s;\n\t\t};\n\n\t\tlines.push(\"\");\n\n\t\t// Scanline reveal effect: show rows progressively\n\t\tconst revealedRows = Math.min(\n\t\t\tthis.image.length,\n\t\t\tMath.floor((this.tick / this.maxTicks) * (this.image.length + 3)),\n\t\t);\n\n\t\tfor (let i = 0; i < this.image.length; i++) {\n\t\t\tif (i < revealedRows) {\n\t\t\t\tlines.push(center(this.image[i]));\n\t\t\t} else {\n\t\t\t\t// Show scan line\n\t\t\t\tif (i === revealedRows) {\n\t\t\t\t\tconst scanline = \"▓\".repeat(WIDTH);\n\t\t\t\t\tlines.push(center(rgb(100, 200, 255) + scanline + RESET));\n\t\t\t\t} else {\n\t\t\t\t\tlines.push(center(\" \".repeat(WIDTH)));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlines.push(\"\");\n\n\t\t// Fade in text after image is revealed\n\t\tconst textPhase = Math.max(0, this.tick - this.maxTicks * 0.6);\n\t\tif (textPhase > 0 || this.tick >= this.maxTicks) {\n\t\t\tlines.push(center(t.fg(\"accent\", \"Free Kimi K2.5 via OpenCode Zen\")));\n\t\t\tlines.push(center(t.fg(\"success\", '\"Powered by daxnuts\"')));\n\t\t\tlines.push(center(t.fg(\"muted\", \"— @thdxr\")));\n\t\t} else {\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(\"\");\n\t\t}\n\n\t\tlines.push(\"\");\n\t\tif (textPhase > 2 || this.tick >= this.maxTicks) {\n\t\t\tlines.push(center(t.fg(\"dim\", \"Try OpenCode\")));\n\t\t\tlines.push(center(t.fg(\"mdLink\", \"https://mistral.ai/news/mistral-vibe-2-0\")));\n\t\t} else {\n\t\t\tlines.push(\"\");\n\t\t\tlines.push(\"\");\n\t\t}\n\t\tlines.push(\"\");\n\n\t\tthis.cachedLines = lines;\n\t\tthis.cachedWidth = width;\n\t\tthis.cachedTick = this.tick;\n\t\treturn lines;\n\t}\n\n\tdispose(): void {\n\t\tthis.stopAnimation();\n\t}\n}\n"]}
1
+ {"version":3,"file":"daxnuts.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/daxnuts.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAkD7D,qBAAa,gBAAiB,YAAW,SAAS;IACjD,OAAO,CAAC,EAAE,CAAM;IAChB,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,QAAQ,CAA+C;IAC/D,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,UAAU,CAAM;IAExB,YAAY,EAAE,EAAE,GAAG,EAIlB;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,aAAa;IAOrB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAgE9B;IAED,OAAO,IAAI,IAAI,CAEd;CACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/diff.ts"],"names":[],"mappings":"AAkFA,MAAM,WAAW,iBAAiB;IACjC,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAE,iBAAsB,GAAG,MAAM,CAoErF","sourcesContent":["import * as Diff from \"diff\";\nimport { theme } from \"../theme/theme.ts\";\n\n/**\n * Parse diff line to extract prefix, line number, and content.\n * Format: \"+123 content\" or \"-123 content\" or \" 123 content\" or \" ...\"\n */\nfunction parseDiffLine(line: string): { prefix: string; lineNum: string; content: string } | null {\n\tif (line.length < 2) return null;\n\tconst prefix = line[0];\n\tif (prefix !== \"+\" && prefix !== \"-\" && prefix !== \" \") return null;\n\n\tlet cursor = 1;\n\twhile (cursor < line.length && line[cursor] === \" \") cursor++;\n\twhile (cursor < line.length) {\n\t\tconst code = line.charCodeAt(cursor);\n\t\tif (code < 48 || code > 57) break;\n\t\tcursor++;\n\t}\n\tif (cursor >= line.length || line[cursor] !== \" \") return null;\n\n\treturn {\n\t\tprefix,\n\t\tlineNum: line.slice(1, cursor),\n\t\tcontent: line.slice(cursor + 1),\n\t};\n}\n\n/**\n * Replace tabs with spaces for consistent rendering.\n */\nfunction replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\n/**\n * Compute word-level diff and render with inverse on changed parts.\n * Uses diffWords which groups whitespace with adjacent words for cleaner highlighting.\n * Strips leading whitespace from inverse to avoid highlighting indentation.\n */\nfunction renderIntraLineDiff(oldContent: string, newContent: string): { removedLine: string; addedLine: string } {\n\tconst wordDiff = Diff.diffWords(oldContent, newContent);\n\n\tlet removedLine = \"\";\n\tlet addedLine = \"\";\n\tlet isFirstRemoved = true;\n\tlet isFirstAdded = true;\n\n\tfor (const part of wordDiff) {\n\t\tif (part.removed) {\n\t\t\tlet value = part.value;\n\t\t\t// Strip leading whitespace from the first removed part\n\t\t\tif (isFirstRemoved) {\n\t\t\t\tconst leadingWs = value.match(/^(\\s*)/)?.[1] || \"\";\n\t\t\t\tvalue = value.slice(leadingWs.length);\n\t\t\t\tremovedLine += leadingWs;\n\t\t\t\tisFirstRemoved = false;\n\t\t\t}\n\t\t\tif (value) {\n\t\t\t\tremovedLine += theme.inverse(value);\n\t\t\t}\n\t\t} else if (part.added) {\n\t\t\tlet value = part.value;\n\t\t\t// Strip leading whitespace from the first added part\n\t\t\tif (isFirstAdded) {\n\t\t\t\tconst leadingWs = value.match(/^(\\s*)/)?.[1] || \"\";\n\t\t\t\tvalue = value.slice(leadingWs.length);\n\t\t\t\taddedLine += leadingWs;\n\t\t\t\tisFirstAdded = false;\n\t\t\t}\n\t\t\tif (value) {\n\t\t\t\taddedLine += theme.inverse(value);\n\t\t\t}\n\t\t} else {\n\t\t\tremovedLine += part.value;\n\t\t\taddedLine += part.value;\n\t\t}\n\t}\n\n\treturn { removedLine, addedLine };\n}\n\nexport interface RenderDiffOptions {\n\t/** File path (unused, kept for API compatibility) */\n\tfilePath?: string;\n}\n\n/**\n * Render a diff string with colored lines and intra-line change highlighting.\n * - Context lines: dim/gray\n * - Removed lines: red, with inverse on changed tokens\n * - Added lines: green, with inverse on changed tokens\n */\nexport function renderDiff(diffText: string, _options: RenderDiffOptions = {}): string {\n\tconst lines = diffText.split(\"\\n\");\n\tconst result: string[] = [];\n\n\tlet i = 0;\n\twhile (i < lines.length) {\n\t\tconst line = lines[i];\n\t\tconst parsed = parseDiffLine(line);\n\n\t\tif (!parsed) {\n\t\t\tresult.push(theme.fg(\"toolDiffContext\", line));\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (parsed.prefix === \"-\") {\n\t\t\t// Collect consecutive removed lines\n\t\t\tconst removedLines: { lineNum: string; content: string }[] = [];\n\t\t\twhile (i < lines.length) {\n\t\t\t\tconst p = parseDiffLine(lines[i]);\n\t\t\t\tif (!p || p.prefix !== \"-\") break;\n\t\t\t\tremovedLines.push({ lineNum: p.lineNum, content: p.content });\n\t\t\t\ti++;\n\t\t\t}\n\n\t\t\t// Collect consecutive added lines\n\t\t\tconst addedLines: { lineNum: string; content: string }[] = [];\n\t\t\twhile (i < lines.length) {\n\t\t\t\tconst p = parseDiffLine(lines[i]);\n\t\t\t\tif (!p || p.prefix !== \"+\") break;\n\t\t\t\taddedLines.push({ lineNum: p.lineNum, content: p.content });\n\t\t\t\ti++;\n\t\t\t}\n\n\t\t\t// Only do intra-line diffing when there's exactly one removed and one added line\n\t\t\t// (indicating a single line modification). Otherwise, show lines as-is.\n\t\t\tif (removedLines.length === 1 && addedLines.length === 1) {\n\t\t\t\tconst removed = removedLines[0];\n\t\t\t\tconst added = addedLines[0];\n\n\t\t\t\tconst { removedLine, addedLine } = renderIntraLineDiff(\n\t\t\t\t\treplaceTabs(removed.content),\n\t\t\t\t\treplaceTabs(added.content),\n\t\t\t\t);\n\n\t\t\t\tresult.push(theme.fg(\"toolDiffRemoved\", `-${removed.lineNum} ${removedLine}`));\n\t\t\t\tresult.push(theme.fg(\"toolDiffAdded\", `+${added.lineNum} ${addedLine}`));\n\t\t\t} else {\n\t\t\t\t// Show all removed lines first, then all added lines\n\t\t\t\tfor (const removed of removedLines) {\n\t\t\t\t\tresult.push(theme.fg(\"toolDiffRemoved\", `-${removed.lineNum} ${replaceTabs(removed.content)}`));\n\t\t\t\t}\n\t\t\t\tfor (const added of addedLines) {\n\t\t\t\t\tresult.push(theme.fg(\"toolDiffAdded\", `+${added.lineNum} ${replaceTabs(added.content)}`));\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (parsed.prefix === \"+\") {\n\t\t\t// Standalone added line\n\t\t\tresult.push(theme.fg(\"toolDiffAdded\", `+${parsed.lineNum} ${replaceTabs(parsed.content)}`));\n\t\t\ti++;\n\t\t} else {\n\t\t\t// Context line\n\t\t\tresult.push(theme.fg(\"toolDiffContext\", ` ${parsed.lineNum} ${replaceTabs(parsed.content)}`));\n\t\t\ti++;\n\t\t}\n\t}\n\n\treturn result.join(\"\\n\");\n}\n"]}
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/diff.ts"],"names":[],"mappings":"AAkFA,MAAM,WAAW,iBAAiB;IACjC,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAE,iBAAsB,GAAG,MAAM,CAoErF"}
@@ -1 +1 @@
1
- {"version":3,"file":"dynamic-border.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/dynamic-border.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGxD;;;;;;GAMG;AACH,qBAAa,aAAc,YAAW,SAAS;IAC9C,OAAO,CAAC,KAAK,CAA0B;IAEvC,YAAY,KAAK,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAyC,EAE5E;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAE9B;CACD","sourcesContent":["import type { Component } from \"@earendil-works/pi-tui\";\nimport { theme } from \"../theme/theme.ts\";\n\n/**\n * Dynamic border component that adjusts to viewport width.\n *\n * Note: When used from extensions loaded via jiti, the global `theme` may be undefined\n * because jiti creates a separate module cache. Always pass an explicit color\n * function when using DynamicBorder in components exported for extension use.\n */\nexport class DynamicBorder implements Component {\n\tprivate color: (str: string) => string;\n\n\tconstructor(color: (str: string) => string = (str) => theme.fg(\"border\", str)) {\n\t\tthis.color = color;\n\t}\n\n\tinvalidate(): void {\n\t\t// No cached state to invalidate currently\n\t}\n\n\trender(width: number): string[] {\n\t\treturn [this.color(\"─\".repeat(Math.max(1, width)))];\n\t}\n}\n"]}
1
+ {"version":3,"file":"dynamic-border.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/dynamic-border.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGxD;;;;;;GAMG;AACH,qBAAa,aAAc,YAAW,SAAS;IAC9C,OAAO,CAAC,KAAK,CAA0B;IAEvC,YAAY,KAAK,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAyC,EAE5E;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAE9B;CACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"earendil-announcement.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/earendil-announcement.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAuB,MAAM,wBAAwB,CAAC;AAyBxE,qBAAa,6BAA8B,SAAQ,SAAS;IAC3D,cAwBC;CACD","sourcesContent":["import * as fs from \"node:fs\";\nimport { Container, Image, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport { getBundledInteractiveAssetPath } from \"../../../config.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\n\nconst BLOG_URL = \"https://mariozechner.at/posts/2026-04-08-ive-sold-out/\";\nconst IMAGE_FILENAME = \"clankolas.png\";\n\nlet cachedImageBase64: string | undefined;\nlet attemptedImageLoad = false;\n\nfunction loadImageBase64(): string | undefined {\n\tif (attemptedImageLoad) {\n\t\treturn cachedImageBase64;\n\t}\n\n\tattemptedImageLoad = true;\n\ttry {\n\t\tcachedImageBase64 = fs.readFileSync(getBundledInteractiveAssetPath(IMAGE_FILENAME)).toString(\"base64\");\n\t} catch {\n\t\tcachedImageBase64 = undefined;\n\t}\n\treturn cachedImageBase64;\n}\n\nexport class EarendilAnnouncementComponent extends Container {\n\tconstructor() {\n\t\tsuper();\n\n\t\tthis.addChild(new DynamicBorder((text) => theme.fg(\"accent\", text)));\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", \"pi has joined Earendil\")), 1, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"muted\", \"Read the blog post:\"), 1, 0));\n\t\tthis.addChild(new Text(theme.fg(\"mdLink\", BLOG_URL), 1, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tconst imageBase64 = loadImageBase64();\n\t\tif (imageBase64) {\n\t\t\tthis.addChild(\n\t\t\t\tnew Image(\n\t\t\t\t\timageBase64,\n\t\t\t\t\t\"image/png\",\n\t\t\t\t\t{ fallbackColor: (text) => theme.fg(\"muted\", text) },\n\t\t\t\t\t{ maxWidthCells: 56, filename: IMAGE_FILENAME },\n\t\t\t\t),\n\t\t\t);\n\t\t\tthis.addChild(new Spacer(1));\n\t\t}\n\n\t\tthis.addChild(new DynamicBorder((text) => theme.fg(\"accent\", text)));\n\t}\n}\n"]}
1
+ {"version":3,"file":"earendil-announcement.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/earendil-announcement.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAuB,MAAM,wBAAwB,CAAC;AAyBxE,qBAAa,6BAA8B,SAAQ,SAAS;IAC3D,cAwBC;CACD"}