@timurproko/a1 0.2.7-dev.1252 → 0.2.7-dev.1264

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 (296) hide show
  1. package/bin/ui.js +3 -3
  2. package/dist/app/session-shell/clipboard-diagnostics.d.ts +2 -2
  3. package/dist/app/session-shell/clipboard-image.d.ts +0 -1
  4. package/dist/app/session-shell/clipboard-image.js +1 -1
  5. package/dist/app/session-shell/dialog-coordinator.d.ts +6 -5
  6. package/dist/app/session-shell/dialog-coordinator.js +3 -4
  7. package/dist/app/session-shell/dock-chrome.d.ts +11 -6
  8. package/dist/app/session-shell/dock-chrome.js +5 -8
  9. package/dist/app/session-shell/editor-hyperlink-budget.d.ts +0 -2
  10. package/dist/app/session-shell/editor-hyperlink-budget.js +1 -1
  11. package/dist/app/session-shell/exit-notice.d.ts +2 -2
  12. package/dist/app/session-shell/exit-notice.js +1 -1
  13. package/dist/app/session-shell/extension-surface.d.ts +8 -7
  14. package/dist/app/session-shell/helper-pool.d.ts +3 -4
  15. package/dist/app/session-shell/helper-pool.js +1 -1
  16. package/dist/app/session-shell/image-preparation-client.d.ts +4 -3
  17. package/dist/app/session-shell/image-preparation.d.ts +0 -2
  18. package/dist/app/session-shell/image-preparation.js +2 -2
  19. package/dist/app/session-shell/image-source.d.ts +2 -3
  20. package/dist/app/session-shell/image-source.js +2 -2
  21. package/dist/app/session-shell/input-surface-switch.d.ts +9 -7
  22. package/dist/app/session-shell/input-surface-switch.js +1 -2
  23. package/dist/app/session-shell/login-interaction.d.ts +5 -4
  24. package/dist/app/session-shell/login-interaction.js +2 -3
  25. package/dist/app/session-shell/paste-executor.d.ts +4 -8
  26. package/dist/app/session-shell/paste-executor.js +2 -2
  27. package/dist/app/session-shell/paste-protocol.d.ts +2 -2
  28. package/dist/app/session-shell/path-chip-presentation.d.ts +0 -5
  29. package/dist/app/session-shell/path-chip-presentation.js +3 -3
  30. package/dist/app/session-shell/prompt-chips.d.ts +8 -7
  31. package/dist/app/session-shell/prompt-history-controller.d.ts +3 -3
  32. package/dist/app/session-shell/prompt-submission.d.ts +5 -2
  33. package/dist/app/session-shell/prompt-submission.js +13 -14
  34. package/dist/app/session-shell/quit-outro-effects.d.ts +3 -3
  35. package/dist/app/session-shell/quit-outro-effects.js +1 -4
  36. package/dist/app/session-shell/quit-outro.d.ts +9 -12
  37. package/dist/app/session-shell/quit-outro.js +11 -11
  38. package/dist/app/session-shell/resource-labels.d.ts +2 -0
  39. package/dist/app/session-shell/resource-labels.js +158 -0
  40. package/dist/app/session-shell/response-copy-protocol.d.ts +3 -2
  41. package/dist/app/session-shell/response-copy-transport.d.ts +2 -14
  42. package/dist/app/session-shell/response-copy-transport.js +1 -1
  43. package/dist/app/session-shell/session-lifecycle.d.ts +2 -1
  44. package/dist/app/session-shell/session-prompt-history.d.ts +29 -0
  45. package/dist/app/session-shell/session-prompt-history.js +80 -0
  46. package/dist/app/session-shell/session-selectors.d.ts +46 -0
  47. package/dist/app/session-shell/session-selectors.js +269 -0
  48. package/dist/app/session-shell/session-shell-root.d.ts +76 -113
  49. package/dist/app/session-shell/session-shell-root.js +103 -329
  50. package/dist/app/session-shell/session-shell.d.ts +14 -37
  51. package/dist/app/session-shell/session-shell.js +177 -612
  52. package/dist/app/session-shell/session-viewport-controller.d.ts +9 -16
  53. package/dist/app/session-shell/session-viewport-controller.js +42 -320
  54. package/dist/app/session-shell/settings-bindings.d.ts +25 -3
  55. package/dist/app/session-shell/settings-bindings.js +26 -2
  56. package/dist/app/session-shell/share-operation.d.ts +3 -3
  57. package/dist/app/session-shell/share-operation.js +4 -6
  58. package/dist/app/session-shell/shell-clipboard.d.ts +59 -0
  59. package/dist/app/session-shell/shell-clipboard.js +119 -0
  60. package/dist/app/session-shell/shell-editor-factory.d.ts +8 -4
  61. package/dist/app/session-shell/shell-editor-factory.js +13 -15
  62. package/dist/app/session-shell/shell-host.d.ts +16 -17
  63. package/dist/app/session-shell/shell-host.js +18 -19
  64. package/dist/app/session-shell/shell-layout.d.ts +2 -2
  65. package/dist/app/session-shell/shell-prompt-suggestions.d.ts +26 -0
  66. package/dist/app/session-shell/shell-prompt-suggestions.js +48 -0
  67. package/dist/app/session-shell/suggestion-surface.d.ts +1 -6
  68. package/dist/app/session-shell/suggestion-surface.js +1 -1
  69. package/dist/app/session-shell/system-clipboard.d.ts +2 -14
  70. package/dist/app/session-shell/system-clipboard.js +2 -7
  71. package/dist/app/session-shell/transcript-document.d.ts +11 -8
  72. package/dist/app/session-shell/transcript-document.js +13 -14
  73. package/dist/app/session-shell/viewport-layout.d.ts +2 -2
  74. package/dist/app/session-shell/viewport-pointer.d.ts +83 -0
  75. package/dist/app/session-shell/viewport-pointer.js +361 -0
  76. package/dist/app/session-shell/workflow-output.d.ts +5 -3
  77. package/dist/app/session-shell/workflow-output.js +13 -15
  78. package/dist/cli/package-messages.d.ts +0 -1
  79. package/dist/cli/package-messages.js +1 -1
  80. package/dist/cli/session-context.d.ts +1 -1
  81. package/dist/cli/uninstall.d.ts +3 -2
  82. package/dist/composition/owned-settings.d.ts +2 -1
  83. package/dist/composition/owned-settings.js +0 -3
  84. package/dist/composition/owned-ui.d.ts +1 -1
  85. package/dist/composition/owned-ui.js +77 -73
  86. package/dist/composition/reference-selection-options.d.ts +1 -1
  87. package/dist/composition/reference-selection-options.js +1 -1
  88. package/dist/composition/session-runtime-registry.d.ts +2 -1
  89. package/dist/composition/settings-route-host.js +3 -10
  90. package/dist/composition/settings-search-input.d.ts +2 -1
  91. package/dist/composition/startup-route.d.ts +2 -2
  92. package/dist/composition/startup-route.js +2 -2
  93. package/dist/contracts/owned-ui/extension-ui.d.ts +2 -1
  94. package/dist/contracts/owned-ui/index.d.ts +2 -1
  95. package/dist/contracts/owned-ui/index.js +1 -1
  96. package/dist/contracts/owned-ui/session-presenters.d.ts +3 -0
  97. package/dist/contracts/owned-ui/shell-components.d.ts +543 -0
  98. package/dist/contracts/owned-ui/validation.d.ts +1 -11
  99. package/dist/contracts/owned-ui/validation.js +8 -104
  100. package/dist/contracts/presentation/component.d.ts +17 -0
  101. package/dist/contracts/presentation/component.js +8 -0
  102. package/dist/contracts/presentation/index.d.ts +6 -15
  103. package/dist/contracts/presentation/index.js +2 -0
  104. package/dist/contracts/presentation/terminal.d.ts +284 -0
  105. package/dist/contracts/presentation/terminal.js +1 -0
  106. package/dist/contracts/presentation/theme.d.ts +46 -0
  107. package/dist/contracts/presentation/theme.js +1 -0
  108. package/dist/features/launch/development-launch.js +1 -1
  109. package/dist/features/launch/runtime-selection.d.ts +2 -2
  110. package/dist/features/launch/runtime-selection.js +2 -2
  111. package/dist/features/owned-ui/project-trust-prompt.d.ts +2 -2
  112. package/dist/features/owned-ui/project-trust-prompt.js +1 -1
  113. package/dist/features/owned-ui/release-note-state.d.ts +2 -1
  114. package/dist/features/owned-ui/settings-app.js +49 -425
  115. package/dist/features/owned-ui/settings-edits.d.ts +31 -0
  116. package/dist/features/owned-ui/settings-edits.js +139 -0
  117. package/dist/features/owned-ui/settings-model-dialog.d.ts +41 -0
  118. package/dist/features/owned-ui/settings-model-dialog.js +194 -0
  119. package/dist/features/owned-ui/settings-scroll-rail.d.ts +29 -0
  120. package/dist/features/owned-ui/settings-scroll-rail.js +79 -0
  121. package/dist/features/owned-ui/settings-search-input.d.ts +2 -1
  122. package/dist/features/prompt-history/service.d.ts +3 -2
  123. package/dist/foundation/lifecycle/claim-gate.d.ts +2 -1
  124. package/dist/foundation/release/automatic-update.d.ts +5 -14
  125. package/dist/foundation/release/automatic-update.js +15 -22
  126. package/dist/foundation/release/bootstrap.js +4 -4
  127. package/dist/foundation/release/dependency-certification.d.ts +0 -1
  128. package/dist/foundation/release/dependency-certification.js +1 -1
  129. package/dist/foundation/release/dependency-layer.js +3 -3
  130. package/dist/foundation/release/early-accent.d.ts +2 -2
  131. package/dist/foundation/release/early-accent.js +1 -1
  132. package/dist/foundation/release/index.d.ts +2 -2
  133. package/dist/foundation/release/index.js +1 -1
  134. package/dist/foundation/release/latest-release.d.ts +3 -18
  135. package/dist/foundation/release/latest-release.js +11 -11
  136. package/dist/foundation/release/managed-path.d.ts +10 -0
  137. package/dist/foundation/release/managed-path.js +26 -0
  138. package/dist/foundation/release/ordinary-launch-selection.d.ts +1 -1
  139. package/dist/foundation/release/ordinary-launch-selection.js +1 -1
  140. package/dist/foundation/release/release-gc.d.ts +3 -3
  141. package/dist/foundation/release/release-gc.js +10 -12
  142. package/dist/foundation/release/{cohort-state.d.ts → release-state.d.ts} +23 -23
  143. package/dist/foundation/release/{cohort-state.js → release-state.js} +8 -8
  144. package/dist/foundation/release/restart-certification.js +3 -4
  145. package/dist/foundation/release/update-activation.js +3 -3
  146. package/dist/foundation/release/update-execution-lease.d.ts +2 -3
  147. package/dist/foundation/release/update-execution-lease.js +2 -8
  148. package/dist/foundation/release/update-installer.d.ts +45 -0
  149. package/dist/foundation/release/update-installer.js +57 -0
  150. package/dist/foundation/release/update-launch.d.ts +2 -2
  151. package/dist/foundation/release/update-recovery.js +2 -9
  152. package/dist/foundation/release/update.d.ts +4 -25
  153. package/dist/foundation/release/update.js +164 -183
  154. package/dist/foundation/startup/startup-budget.d.ts +5 -5
  155. package/dist/foundation/startup/startup-budget.js +2 -2
  156. package/dist/integrations/pi/components/bracketed-paste.d.ts +33 -0
  157. package/dist/integrations/pi/components/bracketed-paste.js +123 -0
  158. package/dist/integrations/pi/components/editor-interaction.d.ts +4 -12
  159. package/dist/integrations/pi/components/index.d.ts +15 -9
  160. package/dist/integrations/pi/components/index.js +9 -5
  161. package/dist/integrations/pi/components/lazy-selectors.d.ts +2 -10
  162. package/dist/integrations/pi/components/lazy-selectors.js +1 -1
  163. package/dist/integrations/pi/components/modal-frame.d.ts +5 -22
  164. package/dist/integrations/pi/components/modal-frame.js +3 -23
  165. package/dist/integrations/pi/components/owned-editor-ux.d.ts +4 -3
  166. package/dist/integrations/pi/components/owned-editor-ux.js +46 -140
  167. package/dist/integrations/pi/components/prompt-input-port.d.ts +2 -19
  168. package/dist/integrations/pi/components/resources/builtin-themes.d.ts +2 -1
  169. package/dist/integrations/pi/components/shell-editor-autocomplete.d.ts +3 -2
  170. package/dist/integrations/pi/components/shell-footer-status.d.ts +2 -2
  171. package/dist/integrations/pi/components/shell-footer-status.js +3 -2
  172. package/dist/integrations/pi/components/shell-presenters-info.d.ts +6 -5
  173. package/dist/integrations/pi/components/shell-presenters-info.js +2 -1
  174. package/dist/integrations/pi/components/shell-session-info-reference.d.ts +2 -1
  175. package/dist/integrations/pi/components/shell-shared-facade.d.ts +33 -227
  176. package/dist/integrations/pi/components/shell-shared-facade.js +8 -1
  177. package/dist/integrations/pi/components/skills-command.d.ts +1 -9
  178. package/dist/integrations/pi/components/skills-command.js +5 -5
  179. package/dist/integrations/pi/components/theme.d.ts +9 -2
  180. package/dist/integrations/pi/components/theme.js +17 -2
  181. package/dist/integrations/pi/components/thinking-selector-dialog.d.ts +2 -1
  182. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +2 -2
  183. package/dist/integrations/pi/engine/adapter.d.ts +4 -13
  184. package/dist/integrations/pi/engine/adapter.js +9 -61
  185. package/dist/integrations/pi/engine/changelog.d.ts +2 -2
  186. package/dist/integrations/pi/engine/changelog.js +3 -3
  187. package/dist/integrations/pi/engine/compaction-progress.d.ts +2 -3
  188. package/dist/integrations/pi/engine/compaction-progress.js +1 -1
  189. package/dist/integrations/pi/engine/conformance.d.ts +2 -1
  190. package/dist/integrations/pi/engine/default-model-setting.d.ts +0 -2
  191. package/dist/integrations/pi/engine/default-model-setting.js +1 -2
  192. package/dist/integrations/pi/engine/event-delivery.d.ts +2 -1
  193. package/dist/integrations/pi/engine/extension-ui-binding.d.ts +2 -1
  194. package/dist/integrations/pi/engine/host.js +3 -3
  195. package/dist/integrations/pi/engine/message-values.d.ts +0 -1
  196. package/dist/integrations/pi/engine/message-values.js +1 -1
  197. package/dist/integrations/pi/engine/pending-delivery.d.ts +0 -4
  198. package/dist/integrations/pi/engine/pending-delivery.js +3 -3
  199. package/dist/integrations/pi/engine/ports.d.ts +7 -1
  200. package/dist/integrations/pi/engine/ports.js +4 -0
  201. package/dist/integrations/pi/engine/project-trust-preflight.d.ts +2 -1
  202. package/dist/integrations/pi/engine/prompt-suggestions.d.ts +3 -2
  203. package/dist/integrations/pi/engine/provider-authentication.d.ts +1 -1
  204. package/dist/integrations/pi/engine/public-main-entry.d.ts +1 -5
  205. package/dist/integrations/pi/engine/public-main-entry.js +1 -1
  206. package/dist/integrations/pi/engine/repository-metadata.d.ts +49 -0
  207. package/dist/integrations/pi/engine/repository-metadata.js +189 -0
  208. package/dist/integrations/pi/engine/repository-pr-rest.d.ts +1 -9
  209. package/dist/integrations/pi/engine/repository-pr-rest.js +2 -2
  210. package/dist/integrations/pi/engine/repository-pr.d.ts +1 -3
  211. package/dist/integrations/pi/engine/repository-pr.js +1 -1
  212. package/dist/integrations/pi/engine/resource-catalog.d.ts +2 -1
  213. package/dist/integrations/pi/engine/session-integration.d.ts +1 -1
  214. package/dist/integrations/pi/engine/session-runtime.d.ts +7 -12
  215. package/dist/integrations/pi/engine/session-runtime.js +21 -178
  216. package/dist/integrations/pi/engine/settings-bridge.d.ts +0 -2
  217. package/dist/integrations/pi/engine/settings-bridge.js +1 -1
  218. package/dist/integrations/pi/engine/settings-port.d.ts +3 -2
  219. package/dist/integrations/pi/engine/transcript-projection.d.ts +2 -1
  220. package/dist/integrations/pi/engine/view-state.d.ts +21 -2
  221. package/dist/integrations/pi/engine/view-state.js +129 -1
  222. package/dist/integrations/pi/engine/workflow-contexts.d.ts +1 -1
  223. package/dist/integrations/pi/engine/workflow-runner.d.ts +1 -2
  224. package/dist/integrations/pi/engine/workflow-runner.js +254 -365
  225. package/dist/integrations/pi/engine/workflow-share.d.ts +9 -0
  226. package/dist/integrations/pi/engine/workflow-share.js +168 -0
  227. package/dist/integrations/pi/engine/workflow-support.d.ts +0 -20
  228. package/dist/integrations/pi/engine/workflow-support.js +4 -65
  229. package/dist/integrations/pi/engine/workflows.d.ts +5 -5
  230. package/dist/integrations/pi/session-presenters/components.d.ts +3 -0
  231. package/dist/integrations/pi/session-presenters/components.js +75 -0
  232. package/dist/integrations/pi/session-presenters/index.d.ts +1 -0
  233. package/dist/integrations/pi/session-presenters/index.js +1 -0
  234. package/dist/integrations/pi/session-presenters/presentation.d.ts +3 -0
  235. package/dist/integrations/pi/session-presenters/presentation.js +10 -0
  236. package/dist/integrations/pi/session-presenters/presenters.d.ts +2 -1
  237. package/dist/integrations/pi/session-presenters/presenters.js +3 -1
  238. package/dist/integrations/pi/tui-runtime/adapter.d.ts +9 -19
  239. package/dist/integrations/pi/tui-runtime/adapter.js +56 -174
  240. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +9 -44
  241. package/dist/integrations/pi/tui-runtime/index.d.ts +1 -1
  242. package/dist/integrations/pi/tui-runtime/index.js +1 -0
  243. package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.d.ts +4 -6
  244. package/dist/integrations/pi/tui-runtime/overlay-geometry.d.ts +4 -10
  245. package/dist/integrations/pi/tui-runtime/overlay-geometry.js +3 -9
  246. package/dist/integrations/pi/tui-runtime/presentation-adapter.d.ts +2 -2
  247. package/dist/integrations/pi/tui-runtime/runtime-factory.d.ts +3 -0
  248. package/dist/integrations/pi/tui-runtime/runtime-factory.js +11 -0
  249. package/dist/ui/components/index.d.ts +2 -2
  250. package/dist/ui/components/index.js +1 -1
  251. package/dist/ui/components/selection-copy.d.ts +0 -1
  252. package/dist/ui/components/selection-copy.js +0 -12
  253. package/dist/ui/components/theme.d.ts +4 -19
  254. package/dist/ui/components/theme.js +6 -0
  255. package/dist/ui/components/transcript-viewport-frame.d.ts +120 -0
  256. package/dist/ui/components/transcript-viewport-frame.js +314 -0
  257. package/dist/ui/components/transcript-viewport-types.d.ts +147 -0
  258. package/dist/ui/components/transcript-viewport-types.js +1 -0
  259. package/dist/ui/components/transcript-viewport.d.ts +2 -147
  260. package/dist/ui/components/transcript-viewport.js +87 -315
  261. package/dist/ui/settings/declarations.d.ts +2 -3
  262. package/dist/ui/settings/declarations.js +2 -3
  263. package/dist/ui/settings/early-accent.js +1 -1
  264. package/dist/ui/settings/index.d.ts +3 -5
  265. package/dist/ui/settings/index.js +2 -3
  266. package/dist/ui/settings/manager.d.ts +0 -4
  267. package/dist/ui/settings/manager.js +6 -62
  268. package/dist/ui/settings/resolution.d.ts +6 -18
  269. package/dist/ui/settings/resolution.js +4 -103
  270. package/dist/ui/settings/sections.d.ts +0 -4
  271. package/dist/ui/settings/sections.js +1 -1
  272. package/docs/architecture/boundaries.md +2 -2
  273. package/docs/architecture/internal-naming.md +2 -0
  274. package/docs/architecture/project-structure.md +4 -2
  275. package/docs/validation.md +1 -1
  276. package/package.json +3 -4
  277. package/dist/integrations/pi/components/components.d.ts +0 -4
  278. package/dist/integrations/pi/components/components.js +0 -48
  279. package/dist/integrations/pi/components/conformance.d.ts +0 -18
  280. package/dist/integrations/pi/components/conformance.js +0 -70
  281. package/dist/integrations/pi/components/shell-components.d.ts +0 -7
  282. package/dist/integrations/pi/components/shell-components.js +0 -7
  283. package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +0 -33
  284. package/dist/integrations/pi/components/upstream/theme/theme-controller.js +0 -114
  285. package/dist/integrations/pi/engine/diagnostics-state.d.ts +0 -9
  286. package/dist/integrations/pi/engine/diagnostics-state.js +0 -34
  287. package/dist/integrations/pi/engine/usage-view.d.ts +0 -4
  288. package/dist/integrations/pi/engine/usage-view.js +0 -56
  289. package/dist/integrations/pi/tui-runtime/contracts.d.ts +0 -166
  290. package/dist/ui/settings/migrations.d.ts +0 -19
  291. package/dist/ui/settings/migrations.js +0 -225
  292. package/dist/ui/settings/progress-palette.generated.d.ts +0 -139
  293. package/dist/ui/settings/progress-palette.generated.js +0 -139
  294. /package/dist/{integrations/pi/tui-runtime/contracts.js → contracts/owned-ui/shell-components.js} +0 -0
  295. /package/dist/{foundation/release → contracts/presentation}/progress-palette.generated.d.ts +0 -0
  296. /package/dist/{foundation/release → contracts/presentation}/progress-palette.generated.js +0 -0
@@ -1,12 +1,13 @@
1
- import type { PiTuiPointerSurface } from "../../integrations/pi/tui-runtime/contracts.js";
1
+ import type { OwnedUiShellEditorPort } from "../../contracts/owned-ui/index.js";
2
+ import type { TerminalPointerSurface } from "../../contracts/presentation/index.js";
2
3
  import type { OwnedUiViewportSettings } from "../../contracts/owned-ui/index.js";
3
4
  import { type TranscriptViewportFrame, type TranscriptViewportFrameInput } from "../../ui/components/transcript-viewport.js";
4
5
  import type { SelectionCopySnapshot } from "../../ui/components/selection-copy.js";
5
- import type { PiShellEditorPort } from "../../integrations/pi/components/shell-shared-facade.js";
6
6
  import type { PasteEvent } from "./paste-protocol.js";
7
- export interface SessionViewportControllerOptions {
7
+ import { type TailControl, type TailControlRegion } from "./viewport-pointer.js";
8
+ interface SessionViewportControllerOptions {
8
9
  readonly enabled: boolean;
9
- readonly editor: PiShellEditorPort;
10
+ readonly editor: OwnedUiShellEditorPort;
10
11
  readonly requestRender: (force?: boolean) => void;
11
12
  readonly requestHyperlinkCleanup?: (rows?: readonly number[]) => void;
12
13
  /** Whether mutable editor URL chips need targeted link-cell cleanup on deletion. */
@@ -15,13 +16,6 @@ export interface SessionViewportControllerOptions {
15
16
  readonly pasteDiagnostics?: (event: PasteEvent) => void;
16
17
  readonly nextPasteDiagnosticRequest?: () => number;
17
18
  }
18
- /** One-based, inclusive terminal cells of a clickable viewport-tail control. */
19
- export interface TailControlRegion {
20
- readonly rowStart: number;
21
- readonly rowEnd: number;
22
- readonly columnStart: number;
23
- readonly columnEnd: number;
24
- }
25
19
  export interface SessionViewportInputResult {
26
20
  readonly data: string;
27
21
  readonly consumed: boolean;
@@ -54,15 +48,13 @@ export declare class SessionViewportController {
54
48
  readonly rowEnd: number;
55
49
  } | undefined): void;
56
50
  /** The visible close control of a viewport-tail notice, or undefined when none is on screen. */
57
- setTailControl(control: (TailControlRegion & {
58
- readonly activate: () => void;
59
- }) | undefined): void;
51
+ setTailControl(control: TailControl | undefined): void;
60
52
  /** Whether the pointer currently rests on the tail control; drives its hover paint. */
61
53
  tailControlHovered(target: TailControlRegion | undefined): boolean;
62
54
  /** Replacement input changed before its new bounds have been painted. */
63
55
  invalidateInputSurface(): void;
64
- setInputSurfaceFrame(surface: PiTuiPointerSurface | undefined): void;
65
- setOverlaySurfaces(surfaces: readonly PiTuiPointerSurface[] | null): void;
56
+ setInputSurfaceFrame(surface: TerminalPointerSurface | undefined): void;
57
+ setOverlaySurfaces(surfaces: readonly TerminalPointerSurface[] | null): void;
66
58
  get inputGeometryReady(): boolean;
67
59
  compose(input: Omit<TranscriptViewportFrameInput, "pointerPosition">): TranscriptViewportFrame;
68
60
  composeDockOnly(dockRows: readonly string[], width: number, height: number, copyableDockRows?: TranscriptViewportFrameInput["copyableDockRows"]): TranscriptViewportFrame | null;
@@ -74,3 +66,4 @@ export declare class SessionViewportController {
74
66
  clearPointerState(): void;
75
67
  handlePreInput(data: string, allowWheel?: boolean, now?: number, editorActive?: boolean): SessionViewportInputResult;
76
68
  }
69
+ export {};
@@ -1,11 +1,7 @@
1
- import { samePointerSurfaces } from "../../integrations/pi/tui-runtime/overlay-geometry.js";
1
+ import { samePointerSurfaces } from "../../contracts/presentation/index.js";
2
2
  import { TranscriptViewport } from "../../ui/components/transcript-viewport.js";
3
- import { readVisibleHyperlinks } from "../../ui/components/visible-hyperlinks.js";
4
- import { routeMouseInput } from "../../ui/components/mouse.js";
5
- import { scrollForTrackPage, scrollForThumbRow, scrollbarSelectionRows, scrollbarWheelRows } from "../../ui/components/scrollbar.js";
6
- function withinTailControl(region, column, row) {
7
- return row >= region.rowStart && row <= region.rowEnd && column >= region.columnStart && column <= region.columnEnd;
8
- }
3
+ import { scrollbarSelectionRows } from "../../ui/components/scrollbar.js";
4
+ import { ViewportPointerGestures, withinTailControl } from "./viewport-pointer.js";
9
5
  /**
10
6
  * Owns the stateful interaction policy of the bare-A1 session viewport. The
11
7
  * shell root supplies semantic rows and dock geometry; this controller owns
@@ -26,27 +22,16 @@ export class SessionViewportController {
26
22
  scrollbarStyle: "thin",
27
23
  scrollbarSpeed: "normal",
28
24
  };
29
- #dragGrabOffset = null;
30
25
  #inputSurface;
31
26
  #inputSurfacePending = false;
32
27
  #overlays = [];
33
- #pointerOwner;
34
- // Invariant: a right-click editor gesture remains owned by the dock.
35
- #dockPointerSuppressed = false;
36
- // Invariant: a gesture begun on an explicit control remains owned by that control.
37
- #tailPointerSuppressed = false;
38
- // Invariant: editor selection remains true only while its left button is held.
39
- #editorPointerSelecting = false;
40
- // Invariant: no-drag editor presses replay on release; distinct motion promotes frame selection.
41
- #pendingEditorClick;
42
28
  // Invariant: pointer routing uses the most recently composed editor rows.
43
29
  #editorPointerFrame;
44
30
  // Invariant: one clickable region in the viewport tail, located by the most recent composition.
45
31
  #tailControl;
46
32
  #selectionAutoScrollTimer;
47
33
  #selectionAutoScrollPointer;
48
- #pointerPosition;
49
- #hoveredHyperlinkKey;
34
+ #gestures;
50
35
  #lastRequestedSelectionRevision = -1;
51
36
  #presentationRevision = 0;
52
37
  #copyOnSelect = true;
@@ -62,12 +47,32 @@ export class SessionViewportController {
62
47
  this.#requestHyperlinkCleanup = options.requestHyperlinkCleanup ?? (() => { });
63
48
  this.#pasteDiagnostics = options.pasteDiagnostics;
64
49
  this.#nextPasteDiagnosticRequest = options.nextPasteDiagnosticRequest ?? (() => --this.#pasteDiagnosticRequest);
50
+ this.#gestures = new ViewportPointerGestures({
51
+ viewport: this.#viewport,
52
+ editor: this.#editor,
53
+ config: () => this.#config,
54
+ copyOnSelect: () => this.#copyOnSelect,
55
+ inputGeometryReady: () => this.inputGeometryReady,
56
+ modalAt: (column, row) => this.#modalAt(column, row),
57
+ editorFrame: () => this.#editorPointerFrame,
58
+ tailControl: () => this.#tailControl,
59
+ clearTailControl: () => { this.#tailControl = undefined; },
60
+ requestRender: () => { this.#requestRender(); },
61
+ requestHyperlinkCleanup: rows => { this.#requestHyperlinkCleanup(rows); },
62
+ updateSelectionAutoScroll: (column, row, viewportHeight, frameHeight) => { this.#updateSelectionAutoScroll(column, row, viewportHeight, frameHeight); },
63
+ stopSelectionAutoScroll: () => { this.#stopSelectionAutoScroll(); },
64
+ pasteFromPointer: () => {
65
+ const request = this.#nextPasteDiagnosticRequest();
66
+ if (this.#editor.pasteClipboard())
67
+ this.#emitPasteRoute(request, "pointer-admitted");
68
+ },
69
+ });
65
70
  }
66
71
  get config() {
67
72
  return this.#config;
68
73
  }
69
74
  get editorPointerSelecting() {
70
- return this.#editorPointerSelecting;
75
+ return this.#gestures.editorSelecting;
71
76
  }
72
77
  get transcriptPointerSelecting() {
73
78
  return this.#viewport.selectionActive;
@@ -83,7 +88,7 @@ export class SessionViewportController {
83
88
  }
84
89
  /** Latest reported coordinates; exposed without rendering for frame provenance and evidence. */
85
90
  get pointerPosition() {
86
- return this.#pointerPosition;
91
+ return this.#gestures.position;
87
92
  }
88
93
  setCopyOnSelect(enabled) {
89
94
  this.#copyOnSelect = enabled;
@@ -100,7 +105,7 @@ export class SessionViewportController {
100
105
  }
101
106
  /** Whether the pointer currently rests on the tail control; drives its hover paint. */
102
107
  tailControlHovered(target) {
103
- const pointer = this.#pointerPosition;
108
+ const pointer = this.#gestures.position;
104
109
  return target !== undefined && pointer !== undefined && withinTailControl(target, pointer.column, pointer.row);
105
110
  }
106
111
  /** Replacement input changed before its new bounds have been painted. */
@@ -143,7 +148,7 @@ export class SessionViewportController {
143
148
  })));
144
149
  const frame = this.#viewport.compose({
145
150
  ...input,
146
- ...(this.#pointerPosition === undefined ? {} : { pointerPosition: this.#pointerPosition }),
151
+ ...(this.#gestures.position === undefined ? {} : { pointerPosition: this.#gestures.position }),
147
152
  ...(coveredCells.length === 0 ? {} : { coveredCells }),
148
153
  });
149
154
  // Concurrency: if selection changed during composition, this frame truthfully carries
@@ -153,16 +158,7 @@ export class SessionViewportController {
153
158
  this.#lastRequestedSelectionRevision = this.#viewport.selectionRevision;
154
159
  this.#requestRender();
155
160
  }
156
- if (this.#pointerPosition !== undefined && !this.#viewport.selectionActive && !this.#editorPointerSelecting) {
157
- const next = this.#hyperlinkKeyAt(frame, this.#pointerPosition.column, this.#pointerPosition.row);
158
- if (this.#hoveredHyperlinkKey !== undefined && next !== this.#hoveredHyperlinkKey) {
159
- // Platform: Windows Terminal can leave its solid native-hover underline behind
160
- // when a following viewport moves the link away from a stationary pointer.
161
- this.#requestHyperlinkCleanup([this.#pointerPosition.row]);
162
- this.#requestRender();
163
- }
164
- this.#hoveredHyperlinkKey = next;
165
- }
161
+ this.#gestures.refreshHover(frame);
166
162
  return frame;
167
163
  }
168
164
  composeDockOnly(dockRows, width, height, copyableDockRows = []) {
@@ -196,32 +192,18 @@ export class SessionViewportController {
196
192
  this.#presentationRevision += 1;
197
193
  this.#clearActivityTimer();
198
194
  this.#stopSelectionAutoScroll();
199
- this.#editorPointerSelecting = false;
200
- this.#pendingEditorClick = undefined;
195
+ this.#gestures.clear();
201
196
  this.#editorPointerFrame = undefined;
202
- this.#pointerPosition = undefined;
203
- this.#hoveredHyperlinkKey = undefined;
204
197
  this.#viewport.reset();
205
- this.#pointerOwner = undefined;
206
- this.#dragGrabOffset = null;
207
- this.#dockPointerSuppressed = false;
208
- this.#tailPointerSuppressed = false;
209
198
  }
210
199
  clearPointerState() {
211
200
  this.#presentationRevision += 1;
212
201
  this.#clearActivityTimer();
213
- this.#dragGrabOffset = null;
214
- this.#dockPointerSuppressed = false;
215
- this.#tailPointerSuppressed = false;
216
- this.#editorPointerSelecting = false;
217
- this.#pendingEditorClick = undefined;
202
+ this.#gestures.clear();
218
203
  this.#editorPointerFrame = undefined;
219
- this.#pointerPosition = undefined;
220
- this.#hoveredHyperlinkKey = undefined;
221
204
  this.#stopSelectionAutoScroll();
222
205
  this.#viewport.clearSelection();
223
206
  this.#viewport.clearTransient();
224
- this.#pointerOwner = undefined;
225
207
  }
226
208
  #emitPasteRoute(request, phase) {
227
209
  try {
@@ -230,15 +212,15 @@ export class SessionViewportController {
230
212
  catch { /* Invariant: payload-free diagnostics cannot interfere with input routing. */ }
231
213
  }
232
214
  #cancelGesture() {
233
- const held = this.#pointerOwner !== undefined || this.#viewport.selectionActive || this.#editorPointerSelecting;
215
+ const held = this.#gestures.held;
234
216
  const repaint = this.#viewport.hasSelection || held;
235
- if (!repaint && this.#pointerPosition === undefined && this.#hoveredHyperlinkKey === undefined)
217
+ if (!repaint && this.#gestures.idle)
236
218
  return;
237
219
  const editorFrame = this.#editorPointerFrame;
238
220
  this.clearPointerState();
239
221
  this.#editorPointerFrame = editorFrame;
240
222
  if (held)
241
- this.#pointerOwner = "drain";
223
+ this.#gestures.drain();
242
224
  if (repaint)
243
225
  this.#requestRender();
244
226
  }
@@ -291,16 +273,8 @@ export class SessionViewportController {
291
273
  if (data === "\u0018" && editorActive && !this.#viewport.hasSelection && !this.#editor.hasSelection()) {
292
274
  return { data: "", consumed: true, copyLastMessage: true };
293
275
  }
294
- if (this.#viewport.frame === null) {
295
- // Invariant: a not-yet-painted A1 screen is not Pi's selection surface.
296
- return routeMouseInput(data, event => {
297
- if (event.kind === "press" && event.button === 0)
298
- this.#tailPointerSuppressed = true;
299
- if (event.kind === "release")
300
- this.#tailPointerSuppressed = false;
301
- return event.kind === "motion" || event.kind === "release" || (event.kind === "press" && event.button === 0);
302
- });
303
- }
276
+ if (this.#viewport.frame === null)
277
+ return this.#gestures.routeUnpainted(data);
304
278
  if ((data === "\u0003" || data === "\u0018") && this.#viewport.hasSelection) {
305
279
  // Invariant: the newest frame selection wins over an older editor selection.
306
280
  const copySelection = this.#viewport.captureSelectedText();
@@ -325,259 +299,14 @@ export class SessionViewportController {
325
299
  if (!data.includes("\u001b[<") && data !== "\u0003" && this.#viewport.clearSelection()) {
326
300
  this.#requestRender();
327
301
  }
328
- const frame = this.#viewport.frame;
329
- let repaint = false;
330
- let forceRepaint = false;
331
- let activity = false;
332
- let completedCopy;
333
- const routed = routeMouseInput(data, (event, report) => {
334
- const hits = frame.hits;
335
- const overModal = this.#modalAt(event.column, event.row);
336
- const wheel = event.kind === "wheel-up" || event.kind === "wheel-down";
337
- // Invariant: latch each gesture to one surface.
338
- if (this.#pointerOwner === "drain" || !this.inputGeometryReady) {
339
- if (event.kind === "release")
340
- this.#pointerOwner = undefined;
341
- else if (event.kind === "press")
342
- this.#pointerOwner = "drain";
343
- return true;
344
- }
345
- const owner = !wheel && this.#pointerOwner !== undefined ? this.#pointerOwner : overModal;
346
- if (owner !== undefined && owner !== "viewport") {
347
- if (event.kind === "press")
348
- this.#pointerOwner = owner;
349
- if (event.kind === "release")
350
- this.#pointerOwner = undefined;
351
- if (event.kind === "press" && this.#viewport.clearSelection())
352
- repaint = true;
353
- this.#viewport.setRailHovered(false);
354
- this.#viewport.setStickyHovered(false);
355
- this.#pointerPosition = undefined;
356
- owner.component.handleInput?.(report);
357
- repaint = true;
358
- return true;
359
- }
360
- if (event.kind === "press")
361
- this.#pointerOwner = "viewport";
362
- if (event.kind === "release")
363
- this.#pointerOwner = undefined;
364
- const overRail = overModal === undefined && hits.rail !== null
365
- && event.column === hits.rail.column
366
- && event.row >= hits.rail.rowStart
367
- && event.row < hits.rail.rowStart + hits.rail.trackHeight;
368
- const overSticky = overModal === undefined && hits.sticky !== null && event.row === hits.sticky.row && event.column <= hits.sticky.width;
369
- const overBottom = overModal === undefined && hits.bottom !== null && event.row === hits.bottom.row
370
- && event.column >= hits.bottom.columnStart && event.column <= hits.bottom.columnEnd;
371
- const tailControl = this.#tailControl;
372
- const overTailControl = overModal === undefined && tailControl !== undefined
373
- && withinTailControl(tailControl, event.column, event.row);
374
- const previousPointer = this.#pointerPosition;
375
- const wasOverBottom = hits.bottom !== null && previousPointer !== undefined
376
- && previousPointer.row === hits.bottom.row
377
- && previousPointer.column >= hits.bottom.columnStart && previousPointer.column <= hits.bottom.columnEnd;
378
- // Invariant: every report updates the pointer position.
379
- this.#pointerPosition = { column: event.column, row: event.row };
380
- repaint ||= wasOverBottom !== overBottom;
381
- const wasOverTailControl = tailControl !== undefined && previousPointer !== undefined
382
- && withinTailControl(tailControl, previousPointer.column, previousPointer.row);
383
- repaint ||= wasOverTailControl !== overTailControl;
384
- if (!this.#viewport.selectionActive && !this.#editorPointerSelecting) {
385
- const nextHyperlink = this.#hyperlinkKeyAt(frame, event.column, event.row);
386
- if (this.#hoveredHyperlinkKey !== undefined && nextHyperlink !== this.#hoveredHyperlinkKey) {
387
- // Platform: overwrite Windows Terminal's cached native-hover underline exactly once.
388
- this.#requestHyperlinkCleanup(previousPointer === undefined ? undefined : [previousPointer.row]);
389
- repaint = true;
390
- }
391
- this.#hoveredHyperlinkKey = nextHyperlink;
392
- }
393
- if (event.kind === "motion") {
394
- this.#viewport.setRailHovered(overRail);
395
- this.#viewport.setStickyHovered(overSticky);
396
- repaint = true;
397
- if (editorActive && this.#editorPointerSelecting && this.#editorPointerFrame !== undefined) {
398
- this.#editor.handlePointer({
399
- kind: "motion",
400
- button: event.button,
401
- column: event.column,
402
- row: event.row - this.#editorPointerFrame.rowStart + 1,
403
- });
404
- return true;
405
- }
406
- if (this.#dockPointerSuppressed || this.#tailPointerSuppressed)
407
- return true;
408
- const pendingEditorClick = this.#pendingEditorClick;
409
- if (pendingEditorClick !== undefined) {
410
- if (event.column === pendingEditorClick.column && event.row === pendingEditorClick.row)
411
- return true;
412
- this.#pendingEditorClick = undefined;
413
- const editorFrame = editorActive ? this.#editorPointerFrame : undefined;
414
- if (editorFrame !== undefined && this.#editor.handlePointer({ kind: "press", button: 0, column: pendingEditorClick.column, row: pendingEditorClick.row - editorFrame.rowStart + 1 })) {
415
- this.#editorPointerSelecting = true;
416
- this.#editor.handlePointer({ kind: "motion", button: event.button, column: event.column, row: event.row - editorFrame.rowStart + 1 });
417
- return true;
418
- }
419
- this.#viewport.pressSelection(pendingEditorClick.column, pendingEditorClick.row, now, { continueMultiClick: false });
420
- this.#viewport.extendSelection(event.column, event.row, now, false);
421
- this.#updateSelectionAutoScroll(event.column, event.row, hits.viewportHeight, frame.rows.length);
422
- activity = true;
423
- return true;
424
- }
425
- if (this.#viewport.selectionActive) {
426
- this.#viewport.extendSelection(event.column, event.row, now, false);
427
- this.#updateSelectionAutoScroll(event.column, event.row, hits.viewportHeight, frame.rows.length);
428
- activity = true;
429
- return true;
430
- }
431
- if (this.#dragGrabOffset !== null && hits.rail !== null) {
432
- const target = scrollForThumbRow(hits.rail.geometry, event.row - hits.rail.rowStart - this.#dragGrabOffset);
433
- this.#viewport.scrollTo(target, now);
434
- activity = true;
435
- return true;
436
- }
437
- return overRail || overSticky || overBottom || overTailControl;
438
- }
439
- if (event.kind === "wheel-up" || event.kind === "wheel-down") {
440
- if (!allowWheel || event.row < 1 || event.row > hits.viewportHeight)
441
- return false;
442
- const distance = scrollbarWheelRows(this.#config.scrollbarSpeed);
443
- this.#viewport.scrollBy(event.kind === "wheel-up" ? -distance : distance, now);
444
- activity = true;
445
- repaint = true;
446
- forceRepaint = true;
447
- return true;
448
- }
449
- if (event.kind === "press") {
450
- const editorFrame = editorActive ? this.#editorPointerFrame : undefined;
451
- if (event.button === 2 && editorFrame !== undefined
452
- && event.row >= editorFrame.rowStart && event.row <= editorFrame.rowEnd) {
453
- this.#stopSelectionAutoScroll();
454
- if (this.#viewport.clearSelection())
455
- repaint = true;
456
- const request = this.#nextPasteDiagnosticRequest();
457
- if (this.#editor.pasteClipboard())
458
- this.#emitPasteRoute(request, "pointer-admitted");
459
- this.#dockPointerSuppressed = true;
460
- repaint = true;
461
- return true;
462
- }
463
- if (event.button !== 0)
464
- return false;
465
- this.#dockPointerSuppressed = false;
466
- this.#tailPointerSuppressed = false;
467
- this.#pendingEditorClick = undefined;
468
- this.#stopSelectionAutoScroll();
469
- if (this.#viewport.clearSelection())
470
- repaint = true;
471
- if (overTailControl) {
472
- this.#tailControl = undefined;
473
- tailControl.activate();
474
- this.#tailPointerSuppressed = true;
475
- repaint = true;
476
- return true;
477
- }
478
- if (overBottom) {
479
- this.#viewport.scrollToEnd(now);
480
- this.#tailPointerSuppressed = true;
481
- activity = true;
482
- repaint = true;
483
- return true;
484
- }
485
- if (overSticky && hits.sticky !== null) {
486
- this.#viewport.scrollTo(hits.sticky.target, now);
487
- this.#tailPointerSuppressed = true;
488
- activity = true;
489
- repaint = true;
490
- return true;
491
- }
492
- if (overRail && hits.rail !== null) {
493
- const trackRow = event.row - hits.rail.rowStart;
494
- const geometry = hits.rail.geometry;
495
- if (trackRow >= geometry.thumbTop && trackRow < geometry.thumbTop + geometry.thumbHeight) {
496
- this.#dragGrabOffset = trackRow - geometry.thumbTop;
497
- this.#viewport.setRailDragging(true);
498
- }
499
- else {
500
- this.#viewport.scrollTo(scrollForTrackPage(geometry, trackRow, frame.scrollTop, hits.viewportHeight), now);
501
- this.#tailPointerSuppressed = true;
502
- }
503
- activity = true;
504
- repaint = true;
505
- return true;
506
- }
507
- if (event.row >= 1 && event.row <= frame.rows.length && event.column <= frame.descriptor.width) {
508
- if (editorFrame !== undefined && event.row >= editorFrame.rowStart && event.row <= editorFrame.rowEnd) {
509
- // Invariant: no-drag clicks remain editor-owned; first motion latches an editor drag.
510
- this.#pendingEditorClick = { column: event.column, row: event.row };
511
- }
512
- else {
513
- this.#viewport.pressSelection(event.column, event.row, now);
514
- }
515
- repaint = true;
516
- return true;
517
- }
518
- this.#tailPointerSuppressed = true;
519
- return true;
520
- }
521
- if (event.kind === "release") {
522
- if (editorActive && this.#editorPointerSelecting && this.#editorPointerFrame !== undefined) {
523
- const wasEditorSelecting = this.#editorPointerSelecting;
524
- this.#editor.handlePointer({
525
- kind: "release",
526
- button: event.button,
527
- column: event.column,
528
- row: event.row - this.#editorPointerFrame.rowStart + 1,
529
- });
530
- this.#editorPointerSelecting = false;
531
- forceRepaint ||= wasEditorSelecting;
532
- repaint = true;
533
- return true;
534
- }
535
- const pendingEditorClick = this.#pendingEditorClick;
536
- if (pendingEditorClick !== undefined) {
537
- this.#pendingEditorClick = undefined;
538
- if (this.#editorPointerFrame !== undefined) {
539
- const editorRow = pendingEditorClick.row - this.#editorPointerFrame.rowStart + 1;
540
- this.#editor.handlePointer({ kind: "press", button: 0, column: pendingEditorClick.column, row: editorRow });
541
- this.#editor.handlePointer({ kind: "release", button: 0, column: pendingEditorClick.column, row: editorRow });
542
- }
543
- forceRepaint = true;
544
- repaint = true;
545
- return true;
546
- }
547
- if (this.#viewport.releaseSelection()) {
548
- this.#stopSelectionAutoScroll();
549
- if (this.#copyOnSelect)
550
- completedCopy = this.#viewport.captureSelectedText() ?? undefined;
551
- // Platform: restore OSC 8 links only after the held-button selection paint has
552
- // ended, then overwrite any terminal-cached hover cells immediately.
553
- forceRepaint = true;
554
- repaint = true;
555
- return true;
556
- }
557
- if (this.#dragGrabOffset !== null) {
558
- this.#dragGrabOffset = null;
559
- this.#viewport.setRailDragging(false);
560
- repaint = true;
561
- return true;
562
- }
563
- if (this.#dockPointerSuppressed) {
564
- this.#dockPointerSuppressed = false;
565
- return true;
566
- }
567
- if (this.#tailPointerSuppressed) {
568
- this.#tailPointerSuppressed = false;
569
- return true;
570
- }
571
- }
572
- return false;
573
- });
574
- if (activity)
302
+ const { routed, outcome } = this.#gestures.route(data, this.#viewport.frame, { allowWheel, now, editorActive });
303
+ if (outcome.activity)
575
304
  this.#scheduleActivityExpiry();
576
- if (repaint) {
305
+ if (outcome.repaint) {
577
306
  this.#lastRequestedSelectionRevision = this.#viewport.selectionRevision;
578
- this.#requestRender(forceRepaint);
307
+ this.#requestRender(outcome.forceRepaint);
579
308
  }
580
- return completedCopy === undefined ? routed : { ...routed, copySelection: completedCopy };
309
+ return outcome.completedCopy === undefined ? routed : { ...routed, copySelection: outcome.completedCopy };
581
310
  }
582
311
  #modalAt(column, row) {
583
312
  const contains = (surface) => column >= surface.columnStart && column <= surface.columnEnd
@@ -585,13 +314,6 @@ export class SessionViewportController {
585
314
  const overlay = this.#overlays?.findLast(contains);
586
315
  return overlay ?? (this.#inputSurface !== undefined && contains(this.#inputSurface) ? this.#inputSurface : undefined);
587
316
  }
588
- #hyperlinkKeyAt(frame, column, row) {
589
- if (row < 1 || row > frame.rows.length || column < 1)
590
- return undefined;
591
- const range = readVisibleHyperlinks(frame.rows[row - 1] ?? "").ranges
592
- .find(candidate => column - 1 >= candidate.from && column - 1 < candidate.to);
593
- return range === undefined ? undefined : JSON.stringify([row, range]);
594
- }
595
317
  #updateSelectionAutoScroll(column, row, viewportHeight, frameHeight) {
596
318
  // Invariant: the last content row stays selectable; only the pointer below it scrolls,
597
319
  // unless no row exists below. The top row scrolls because nothing lies above it. A
@@ -657,6 +379,6 @@ export class SessionViewportController {
657
379
  const SELECTION_AUTO_SCROLL_INTERVAL_MS = 30;
658
380
  const EDITOR_LINK_DELETION_INPUTS = new Set(["\b", "\u007f", "\u001b[3~"]);
659
381
  // Platform: Windows Terminal may consume Shift+Arrow for native selection. Ctrl+Arrow matches
660
- // solo A1's Windows binding while retaining Shift+Arrow whenever the terminal delivers it.
382
+ // A1's Windows binding while retaining Shift+Arrow whenever the terminal delivers it.
661
383
  const PROMPT_UP_INPUTS = new Set(["\u001b[1;2A", "\u001b[1;5A"]);
662
384
  const PROMPT_DOWN_INPUTS = new Set(["\u001b[1;2B", "\u001b[1;5B"]);
@@ -1,10 +1,10 @@
1
- import type { OwnedUiSessionSettingsPort, OwnedUiSessionSettingsSnapshot } from "../../contracts/owned-ui/index.js";
1
+ import type { OwnedUiSessionSettingsPort, OwnedUiSessionSettingsSnapshot, OwnedUiViewportSettingsPort } from "../../contracts/owned-ui/index.js";
2
2
  import type { OwnedUiPresenterTerminal } from "./shell-host.js";
3
3
  import type { OwnedUiSessionShellRoot } from "./session-shell-root.js";
4
4
  /** What the session's live setting effects reach: terminal modes, root presentation, and the presenter's progress flag. */
5
- export interface SessionSettingsTargets {
5
+ interface SessionSettingsTargets {
6
6
  readonly terminal: Pick<OwnedUiPresenterTerminal, "setHardwareCursor" | "setClearOnShrink" | "setWheelScrollLines">;
7
- readonly root: Pick<OwnedUiSessionShellRoot, "setEditorPaddingX" | "setAutocompleteMaxVisible" | "setOutputPad" | "setHideThinkingBlock" | "setMermaidRenderingMode" | "setImagePresentation" | "setFullscreenCopyOnSelect">;
7
+ readonly root: Pick<OwnedUiSessionShellRoot, "setEditorPaddingX" | "setAutocompleteMaxVisible" | "setOutputPad" | "setHideThinkingBlock" | "setMermaidRenderingMode" | "setImagePresentation" | "viewport">;
8
8
  setTerminalProgress(enabled: boolean): void;
9
9
  }
10
10
  /**
@@ -15,3 +15,25 @@ export interface SessionSettingsTargets {
15
15
  export declare function bindSessionSettings(settings: Pick<OwnedUiSessionSettingsPort, "bindOwner" | "productMode">, snapshot: OwnedUiSessionSettingsSnapshot, targets: SessionSettingsTargets, options: {
16
16
  readonly customViewport: boolean;
17
17
  }): () => void;
18
+ /** The shell's own live setting sources besides the session settings; absent sources bind nothing. */
19
+ export interface ShellSettingSources {
20
+ readonly customViewport: boolean;
21
+ readonly promptImages: {
22
+ onChange(listener: () => void): () => void;
23
+ } | null;
24
+ readonly skills: {
25
+ onChange(listener: () => void): () => void;
26
+ } | null;
27
+ readonly viewport: OwnedUiViewportSettingsPort | undefined;
28
+ readonly historyScope: ((listener: (scope: "unique" | "shared") => void) => () => void) | undefined;
29
+ }
30
+ /** What those sources change: the prompt-image notice, the command menu, the viewport, and the transcript binding. */
31
+ export interface ShellSettingEffects {
32
+ readonly root: Pick<OwnedUiSessionShellRoot, "setViewportConfig">;
33
+ promptImageLimitChanged(): void;
34
+ skillsChanged(): void;
35
+ historyScopeChanged(scope: "unique" | "shared"): void;
36
+ }
37
+ /** Seeds the viewport and subscribes every shell setting source; the returned release undoes all of them. */
38
+ export declare function bindShellSettings(sources: ShellSettingSources, effects: ShellSettingEffects): () => void;
39
+ export {};
@@ -49,13 +49,13 @@ function settingBindings(targets, snapshot, customViewport, bare) {
49
49
  { owner: null, key: "imageWidthCells", live: () => { }, seed: presentImages },
50
50
  // Invariant: the custom viewport owns copy-on-select; the pinned comparison profile keeps Pi's wheel distance.
51
51
  customViewport
52
- ? setting("shell", "fullscreenCopyOnSelect", "Fullscreen copy-on-select setting is invalid", isBoolean, value => root.setFullscreenCopyOnSelect(value))
52
+ ? setting("shell", "fullscreenCopyOnSelect", "Fullscreen copy-on-select setting is invalid", isBoolean, value => root.viewport.setCopyOnSelect(value))
53
53
  : setting("shell", "fullscreenWheelScrollLines", "Fullscreen wheel-scroll distance is invalid", isWheelDistance, value => terminal.setWheelScrollLines(value), false),
54
54
  ...(customViewport ? [] : [{
55
55
  owner: null,
56
56
  key: "fullscreenCopyOnSelect",
57
57
  live: () => { },
58
- seed: (initial) => root.setFullscreenCopyOnSelect(initial.fullscreenCopyOnSelect),
58
+ seed: (initial) => root.viewport.setCopyOnSelect(initial.fullscreenCopyOnSelect),
59
59
  }]),
60
60
  ];
61
61
  }
@@ -89,3 +89,27 @@ export function bindSessionSettings(settings, snapshot, targets, options) {
89
89
  }
90
90
  return release;
91
91
  }
92
+ /** Seeds the viewport and subscribes every shell setting source; the returned release undoes all of them. */
93
+ export function bindShellSettings(sources, effects) {
94
+ const releases = [];
95
+ const release = () => { for (const unbind of releases.splice(0).reverse())
96
+ unbind(); };
97
+ try {
98
+ if (sources.promptImages !== null)
99
+ releases.push(sources.promptImages.onChange(() => effects.promptImageLimitChanged()));
100
+ // Rationale: the same listener refreshes the menu for the A1 presentation choice and for the engine's
101
+ // skill-command registration, both of which the owned settings manager reports through one change.
102
+ if (sources.skills !== null)
103
+ releases.push(sources.skills.onChange(() => effects.skillsChanged()));
104
+ effects.root.setViewportConfig(sources.viewport?.snapshot() ?? { scrollbarAppearance: "auto", scrollbarStyle: "thin", scrollbarSpeed: "normal" });
105
+ if (sources.customViewport && sources.viewport !== undefined)
106
+ releases.push(sources.viewport.onChange(settings => effects.root.setViewportConfig(settings)));
107
+ if (sources.customViewport && sources.historyScope !== undefined)
108
+ releases.push(sources.historyScope(scope => effects.historyScopeChanged(scope)));
109
+ }
110
+ catch (error) {
111
+ release();
112
+ throw error;
113
+ }
114
+ return release;
115
+ }
@@ -1,3 +1,3 @@
1
- import { createPiShellOperationLoader, createPiShellShareOperationDialog } from "../../integrations/pi/components/index.js";
2
- export { createPiShellOperationLoader, createPiShellShareOperationDialog };
3
- export declare function renderPiShellShareResult(message: string, gistUrl: string): string;
1
+ import type { UiTheme } from "../../contracts/presentation/index.js";
2
+ /** The completed share result in bare A1: dim labels with the share and gist URLs made clickable. */
3
+ export declare function renderShellShareResult(message: string, gistUrl: string, theme: UiTheme, hyperlink: (url: string) => string): string;
@@ -1,11 +1,9 @@
1
- import { createPiShellOperationLoader, createPiShellShareOperationDialog, piShellHyperlink, piTheme, } from "../../integrations/pi/components/index.js";
2
1
  import { nativeHyperlinkStyle } from "../../ui/components/index.js";
3
- export { createPiShellOperationLoader, createPiShellShareOperationDialog };
4
- export function renderPiShellShareResult(message, gistUrl) {
5
- const theme = piTheme();
2
+ /** The completed share result in bare A1: dim labels with the share and gist URLs made clickable. */
3
+ export function renderShellShareResult(message, gistUrl, theme, hyperlink) {
6
4
  const match = /^Share URL: (\S+)$/u.exec(message);
7
5
  const linked = match === null
8
6
  ? theme.fg("dim", message)
9
- : `${theme.fg("dim", "Share URL: ")}${piShellHyperlink(match[1])}`;
10
- return nativeHyperlinkStyle(`${linked}\n${theme.fg("dim", "Gist: ")}${piShellHyperlink(gistUrl)}`, text => theme.fg("mdLink", text));
7
+ : `${theme.fg("dim", "Share URL: ")}${hyperlink(match[1])}`;
8
+ return nativeHyperlinkStyle(`${linked}\n${theme.fg("dim", "Gist: ")}${hyperlink(gistUrl)}`, text => theme.fg("mdLink", text));
11
9
  }