pi-ui-extend 0.1.6 → 0.1.9

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 (174) hide show
  1. package/README.md +34 -0
  2. package/bin/pix.mjs +4 -4
  3. package/dist/app/app.js +38 -38
  4. package/dist/app/{cli.d.ts → cli/cli.d.ts} +1 -1
  5. package/dist/app/{cli.js → cli/cli.js} +1 -1
  6. package/dist/app/{install.js → cli/install.js} +2 -2
  7. package/dist/app/{command-controller.d.ts → commands/command-controller.d.ts} +1 -1
  8. package/dist/app/{command-host.d.ts → commands/command-host.d.ts} +3 -3
  9. package/dist/app/{command-model-actions.d.ts → commands/command-model-actions.d.ts} +1 -1
  10. package/dist/app/{command-model-actions.js → commands/command-model-actions.js} +2 -2
  11. package/dist/app/{command-navigation-actions.d.ts → commands/command-navigation-actions.d.ts} +1 -1
  12. package/dist/app/{command-navigation-actions.js → commands/command-navigation-actions.js} +5 -5
  13. package/dist/app/{command-registry.d.ts → commands/command-registry.d.ts} +1 -1
  14. package/dist/app/{command-runtime.js → commands/command-runtime.js} +1 -1
  15. package/dist/app/{command-session-actions.js → commands/command-session-actions.js} +3 -3
  16. package/dist/app/{shell-controller.d.ts → commands/shell-controller.d.ts} +1 -1
  17. package/dist/app/{shell-controller.js → commands/shell-controller.js} +1 -1
  18. package/dist/app/{slash-commands.d.ts → commands/slash-commands.d.ts} +2 -2
  19. package/dist/app/{slash-commands.js → commands/slash-commands.js} +1 -1
  20. package/dist/app/{extension-actions-controller.d.ts → extensions/extension-actions-controller.d.ts} +1 -1
  21. package/dist/app/{extension-actions-controller.js → extensions/extension-actions-controller.js} +1 -1
  22. package/dist/app/{extension-ui-controller.d.ts → extensions/extension-ui-controller.d.ts} +3 -3
  23. package/dist/app/{extension-ui-controller.js → extensions/extension-ui-controller.js} +4 -3
  24. package/dist/app/{input-action-controller.d.ts → input/input-action-controller.d.ts} +7 -7
  25. package/dist/app/{input-action-controller.js → input/input-action-controller.js} +3 -3
  26. package/dist/app/{input-controller.d.ts → input/input-controller.d.ts} +3 -3
  27. package/dist/app/{input-controller.js → input/input-controller.js} +1 -1
  28. package/dist/app/{input-paste-handler.d.ts → input/input-paste-handler.d.ts} +1 -1
  29. package/dist/app/{input-paste-handler.js → input/input-paste-handler.js} +3 -3
  30. package/dist/app/{native-modifiers.js → input/native-modifiers.js} +2 -2
  31. package/dist/app/{prompt-enhancer-controller.d.ts → input/prompt-enhancer-controller.d.ts} +5 -5
  32. package/dist/app/{prompt-enhancer-controller.js → input/prompt-enhancer-controller.js} +3 -3
  33. package/dist/app/{voice-controller.d.ts → input/voice-controller.d.ts} +1 -1
  34. package/dist/app/{voice-controller.js → input/voice-controller.js} +2 -2
  35. package/dist/app/{model-ref.d.ts → model/model-ref.d.ts} +1 -1
  36. package/dist/app/{model-ref.js → model/model-ref.js} +1 -1
  37. package/dist/app/{model-usage-controller.js → model/model-usage-controller.js} +1 -1
  38. package/dist/app/{model-usage-status.d.ts → model/model-usage-status.d.ts} +1 -1
  39. package/dist/app/{model-usage-status.js → model/model-usage-status.js} +1 -1
  40. package/dist/app/{menu-items-controller.d.ts → popup/menu-items-controller.d.ts} +4 -4
  41. package/dist/app/{menu-items-controller.js → popup/menu-items-controller.js} +5 -5
  42. package/dist/app/{popup-action-controller.d.ts → popup/popup-action-controller.d.ts} +4 -4
  43. package/dist/app/{popup-action-controller.js → popup/popup-action-controller.js} +2 -2
  44. package/dist/app/{popup-menu-controller.d.ts → popup/popup-menu-controller.d.ts} +4 -4
  45. package/dist/app/{popup-menu-controller.js → popup/popup-menu-controller.js} +7 -7
  46. package/dist/app/{conversation-entry-renderer.d.ts → rendering/conversation-entry-renderer.d.ts} +3 -3
  47. package/dist/app/{conversation-entry-renderer.js → rendering/conversation-entry-renderer.js} +3 -3
  48. package/dist/app/{conversation-shell-renderer.d.ts → rendering/conversation-shell-renderer.d.ts} +1 -1
  49. package/dist/app/{conversation-shell-renderer.js → rendering/conversation-shell-renderer.js} +1 -1
  50. package/dist/app/{conversation-tool-renderer.d.ts → rendering/conversation-tool-renderer.d.ts} +3 -3
  51. package/dist/app/{conversation-tool-renderer.js → rendering/conversation-tool-renderer.js} +7 -7
  52. package/dist/app/{conversation-viewport.d.ts → rendering/conversation-viewport.d.ts} +3 -3
  53. package/dist/app/{dcp-stats.js → rendering/dcp-stats.js} +1 -1
  54. package/dist/app/{editor-layout-renderer.d.ts → rendering/editor-layout-renderer.d.ts} +3 -3
  55. package/dist/app/{editor-layout-renderer.js → rendering/editor-layout-renderer.js} +2 -2
  56. package/dist/app/{editor-panels.d.ts → rendering/editor-panels.d.ts} +2 -2
  57. package/dist/app/{editor-panels.js → rendering/editor-panels.js} +4 -4
  58. package/dist/app/{message-content.d.ts → rendering/message-content.d.ts} +1 -1
  59. package/dist/app/{message-content.js → rendering/message-content.js} +1 -1
  60. package/dist/app/{render-controller.d.ts → rendering/render-controller.d.ts} +6 -6
  61. package/dist/app/{render-controller.js → rendering/render-controller.js} +5 -5
  62. package/dist/app/{render-text.d.ts → rendering/render-text.d.ts} +2 -2
  63. package/dist/app/{render-text.js → rendering/render-text.js} +3 -3
  64. package/dist/app/{status-line-renderer.d.ts → rendering/status-line-renderer.d.ts} +4 -4
  65. package/dist/app/{status-line-renderer.js → rendering/status-line-renderer.js} +4 -4
  66. package/dist/app/{tab-line-renderer.d.ts → rendering/tab-line-renderer.d.ts} +3 -3
  67. package/dist/app/{tab-line-renderer.js → rendering/tab-line-renderer.js} +2 -2
  68. package/dist/app/{toast-controller.d.ts → rendering/toast-controller.d.ts} +1 -1
  69. package/dist/app/{toast-controller.js → rendering/toast-controller.js} +2 -2
  70. package/dist/app/{toast-renderer.d.ts → rendering/toast-renderer.d.ts} +3 -3
  71. package/dist/app/{toast-renderer.js → rendering/toast-renderer.js} +3 -3
  72. package/dist/app/{tool-block-renderer.d.ts → rendering/tool-block-renderer.d.ts} +5 -5
  73. package/dist/app/{tool-block-renderer.js → rendering/tool-block-renderer.js} +2 -2
  74. package/dist/app/runtime.js +1 -1
  75. package/dist/app/{blink-controller.js → screen/blink-controller.js} +1 -1
  76. package/dist/app/{image-click-targets.d.ts → screen/image-click-targets.d.ts} +2 -2
  77. package/dist/app/{image-opener.d.ts → screen/image-opener.d.ts} +1 -1
  78. package/dist/app/{mouse-controller.d.ts → screen/mouse-controller.d.ts} +13 -9
  79. package/dist/app/{mouse-controller.js → screen/mouse-controller.js} +56 -28
  80. package/dist/app/{screen-selection.d.ts → screen/screen-selection.d.ts} +1 -1
  81. package/dist/app/{screen-styler.d.ts → screen/screen-styler.d.ts} +2 -2
  82. package/dist/app/{screen-styler.js → screen/screen-styler.js} +4 -4
  83. package/dist/app/{scroll-controller.d.ts → screen/scroll-controller.d.ts} +3 -3
  84. package/dist/app/{scroll-controller.js → screen/scroll-controller.js} +1 -1
  85. package/dist/app/{status-controller.d.ts → screen/status-controller.d.ts} +2 -2
  86. package/dist/app/{status-controller.js → screen/status-controller.js} +1 -1
  87. package/dist/app/{queued-message-controller.d.ts → session/queued-message-controller.d.ts} +2 -2
  88. package/dist/app/{queued-message-controller.js → session/queued-message-controller.js} +2 -2
  89. package/dist/app/{request-history.js → session/request-history.js} +2 -2
  90. package/dist/app/{session-event-controller.d.ts → session/session-event-controller.d.ts} +3 -3
  91. package/dist/app/{session-event-controller.js → session/session-event-controller.js} +3 -3
  92. package/dist/app/{session-history.d.ts → session/session-history.d.ts} +1 -1
  93. package/dist/app/{session-history.js → session/session-history.js} +3 -3
  94. package/dist/app/{session-lifecycle-controller.d.ts → session/session-lifecycle-controller.d.ts} +2 -2
  95. package/dist/app/{session-lifecycle-controller.js → session/session-lifecycle-controller.js} +7 -7
  96. package/dist/app/{session-search.d.ts → session/session-search.d.ts} +1 -1
  97. package/dist/app/{session-search.js → session/session-search.js} +3 -3
  98. package/dist/app/{tabs-controller.d.ts → session/tabs-controller.d.ts} +2 -2
  99. package/dist/app/{tabs-controller.js → session/tabs-controller.js} +4 -4
  100. package/dist/app/{subagents-files.d.ts → subagents/subagents-files.d.ts} +1 -1
  101. package/dist/app/{subagents-files.js → subagents/subagents-files.js} +1 -1
  102. package/dist/app/{subagents-model.d.ts → subagents/subagents-model.d.ts} +1 -1
  103. package/dist/app/{subagents-model.js → subagents/subagents-model.js} +4 -4
  104. package/dist/app/{subagents-widget-controller.d.ts → subagents/subagents-widget-controller.d.ts} +1 -1
  105. package/dist/app/{subagents-widget-controller.js → subagents/subagents-widget-controller.js} +2 -2
  106. package/dist/app/{terminal-bell-sound-controller.js → terminal/terminal-bell-sound-controller.js} +1 -1
  107. package/dist/app/{terminal-controller.js → terminal/terminal-controller.js} +2 -2
  108. package/dist/app/{todo-model.d.ts → todo/todo-model.d.ts} +1 -1
  109. package/dist/app/{todo-model.js → todo/todo-model.js} +3 -3
  110. package/dist/app/{todo-widget-controller.d.ts → todo/todo-widget-controller.d.ts} +1 -1
  111. package/dist/app/{todo-widget-controller.js → todo/todo-widget-controller.js} +2 -2
  112. package/dist/app/types.d.ts +2 -2
  113. package/dist/app/{workspace-actions-controller.d.ts → workspace/workspace-actions-controller.d.ts} +1 -1
  114. package/dist/app/{workspace-actions-controller.js → workspace/workspace-actions-controller.js} +3 -3
  115. package/dist/main.js +2 -2
  116. package/external/pi-tools-suite/README.md +82 -50
  117. package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +4 -0
  118. package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +6 -2
  119. package/external/pi-tools-suite/src/dcp/prompts.ts +4 -0
  120. package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +272 -2
  121. package/external/pi-tools-suite/src/index.ts +1 -1
  122. package/external/pi-tools-suite/src/lsp/_shared/config.ts +38 -13
  123. package/external/pi-tools-suite/src/lsp/_shared/paths.ts +11 -1
  124. package/external/pi-tools-suite/src/lsp/async.ts +6 -1
  125. package/external/pi-tools-suite/src/lsp/child-process.ts +16 -2
  126. package/external/pi-tools-suite/src/lsp/client.ts +183 -4
  127. package/external/pi-tools-suite/src/lsp/manager.ts +44 -5
  128. package/external/pi-tools-suite/src/lsp/markdown-diagnostics.ts +157 -0
  129. package/external/pi-tools-suite/src/opencode-import/commands.ts +86 -0
  130. package/external/pi-tools-suite/src/opencode-import/importer.ts +208 -0
  131. package/external/pi-tools-suite/src/opencode-import/index.ts +25 -0
  132. package/package.json +1 -1
  133. package/external/pi-tools-suite/src/terminal-bell/index.ts +0 -339
  134. /package/dist/app/{install.d.ts → cli/install.d.ts} +0 -0
  135. /package/dist/app/{startup-checks.d.ts → cli/startup-checks.d.ts} +0 -0
  136. /package/dist/app/{startup-checks.js → cli/startup-checks.js} +0 -0
  137. /package/dist/app/{startup-info.d.ts → cli/startup-info.d.ts} +0 -0
  138. /package/dist/app/{startup-info.js → cli/startup-info.js} +0 -0
  139. /package/dist/app/{update.d.ts → cli/update.d.ts} +0 -0
  140. /package/dist/app/{update.js → cli/update.js} +0 -0
  141. /package/dist/app/{command-controller.js → commands/command-controller.js} +0 -0
  142. /package/dist/app/{command-host.js → commands/command-host.js} +0 -0
  143. /package/dist/app/{command-registry.js → commands/command-registry.js} +0 -0
  144. /package/dist/app/{command-runtime.d.ts → commands/command-runtime.d.ts} +0 -0
  145. /package/dist/app/{command-session-actions.d.ts → commands/command-session-actions.d.ts} +0 -0
  146. /package/dist/app/{shell-command.d.ts → commands/shell-command.d.ts} +0 -0
  147. /package/dist/app/{shell-command.js → commands/shell-command.js} +0 -0
  148. /package/dist/app/{extension-event-bus.d.ts → extensions/extension-event-bus.d.ts} +0 -0
  149. /package/dist/app/{extension-event-bus.js → extensions/extension-event-bus.js} +0 -0
  150. /package/dist/app/{native-modifiers.d.ts → input/native-modifiers.d.ts} +0 -0
  151. /package/dist/app/{terminal-edit-shortcuts.d.ts → input/terminal-edit-shortcuts.d.ts} +0 -0
  152. /package/dist/app/{terminal-edit-shortcuts.js → input/terminal-edit-shortcuts.js} +0 -0
  153. /package/dist/app/{model-usage-controller.d.ts → model/model-usage-controller.d.ts} +0 -0
  154. /package/dist/app/{conversation-viewport.js → rendering/conversation-viewport.js} +0 -0
  155. /package/dist/app/{dcp-stats.d.ts → rendering/dcp-stats.d.ts} +0 -0
  156. /package/dist/app/{blink-controller.d.ts → screen/blink-controller.d.ts} +0 -0
  157. /package/dist/app/{clipboard.d.ts → screen/clipboard.d.ts} +0 -0
  158. /package/dist/app/{clipboard.js → screen/clipboard.js} +0 -0
  159. /package/dist/app/{file-link-opener.d.ts → screen/file-link-opener.d.ts} +0 -0
  160. /package/dist/app/{file-link-opener.js → screen/file-link-opener.js} +0 -0
  161. /package/dist/app/{file-links.d.ts → screen/file-links.d.ts} +0 -0
  162. /package/dist/app/{file-links.js → screen/file-links.js} +0 -0
  163. /package/dist/app/{image-click-targets.js → screen/image-click-targets.js} +0 -0
  164. /package/dist/app/{image-opener.js → screen/image-opener.js} +0 -0
  165. /package/dist/app/{screen-selection.js → screen/screen-selection.js} +0 -0
  166. /package/dist/app/{request-history.d.ts → session/request-history.d.ts} +0 -0
  167. /package/dist/app/{nerd-font-controller.d.ts → terminal/nerd-font-controller.d.ts} +0 -0
  168. /package/dist/app/{nerd-font-controller.js → terminal/nerd-font-controller.js} +0 -0
  169. /package/dist/app/{terminal-bell-sound-controller.d.ts → terminal/terminal-bell-sound-controller.d.ts} +0 -0
  170. /package/dist/app/{terminal-controller.d.ts → terminal/terminal-controller.d.ts} +0 -0
  171. /package/dist/app/{terminal-output-buffer.d.ts → terminal/terminal-output-buffer.d.ts} +0 -0
  172. /package/dist/app/{terminal-output-buffer.js → terminal/terminal-output-buffer.js} +0 -0
  173. /package/dist/app/{workspace-undo.d.ts → workspace/workspace-undo.d.ts} +0 -0
  174. /package/dist/app/{workspace-undo.js → workspace/workspace-undo.js} +0 -0
@@ -1,7 +1,7 @@
1
- import { type Theme } from "../theme.js";
2
- import { PopupMenu, type PopupMenuItem } from "../ui.js";
3
- import type { ScreenStyler } from "./screen-styler.js";
4
- import type { ActivePopupMenu, Entry, ModelMenuValue, ParsedSlashInput, PixMenuController, PixMenuItem, PixMenuOptions, PixMenuSelectOptions, PopupMenuPlacement, QueueMessageMenuValue, RenderedLine, ResumeMenuValue, SlashCommand, ThinkingMenuValue, UserMessageJumpMenuValue, UserMessageMenuValue } from "./types.js";
1
+ import { type Theme } from "../../theme.js";
2
+ import { PopupMenu, type PopupMenuItem } from "../../ui.js";
3
+ import type { ScreenStyler } from "../screen/screen-styler.js";
4
+ import type { ActivePopupMenu, Entry, ModelMenuValue, ParsedSlashInput, PixMenuController, PixMenuItem, PixMenuOptions, PixMenuSelectOptions, PopupMenuPlacement, QueueMessageMenuValue, RenderedLine, ResumeMenuValue, SlashCommand, ThinkingMenuValue, UserMessageJumpMenuValue, UserMessageMenuValue } from "../types.js";
5
5
  import type { AgentSession, SessionInfo } from "@earendil-works/pi-coding-agent";
6
6
  type SlashCommandMenuValue = SlashCommand;
7
7
  type ModelPopupMenuValue = ModelMenuValue;
@@ -1,11 +1,11 @@
1
1
  import { resolve } from "node:path";
2
- import { fuzzySearch } from "../fuzzy.js";
3
- import { colorLine } from "../theme.js";
4
- import { PopupMenu } from "../ui.js";
5
- import { padOrTrimPlain, ellipsizeDisplay, sanitizeText } from "./render-text.js";
6
- import { stringDisplayWidth } from "../terminal-width.js";
7
- import { RESUME_MENU_INITIAL_SESSION_ROWS, RESUME_MENU_LOAD_BATCH_ROWS, RESUME_MENU_LOAD_THRESHOLD_ROWS, RESUME_MENU_MAX_ROWS, SLASH_COMMAND_DESCRIPTION_COLUMN, SLASH_COMMAND_MENU_MAX_ROWS, THINKING_MENU_MAX_ROWS, } from "./constants.js";
8
- import { APP_ICONS } from "./icons.js";
2
+ import { fuzzySearch } from "../../fuzzy.js";
3
+ import { colorLine } from "../../theme.js";
4
+ import { PopupMenu } from "../../ui.js";
5
+ import { padOrTrimPlain, ellipsizeDisplay, sanitizeText } from "../rendering/render-text.js";
6
+ import { stringDisplayWidth } from "../../terminal-width.js";
7
+ import { RESUME_MENU_INITIAL_SESSION_ROWS, RESUME_MENU_LOAD_BATCH_ROWS, RESUME_MENU_LOAD_THRESHOLD_ROWS, RESUME_MENU_MAX_ROWS, SLASH_COMMAND_DESCRIPTION_COLUMN, SLASH_COMMAND_MENU_MAX_ROWS, THINKING_MENU_MAX_ROWS, } from "../constants.js";
8
+ import { APP_ICONS } from "../icons.js";
9
9
  const POPUP_MENU_ESCAPE_BUTTON = "Esc";
10
10
  export class AppPopupMenuController {
11
11
  host;
@@ -1,6 +1,6 @@
1
- import { type PixConfig } from "../config.js";
2
- import type { Theme } from "../theme.js";
3
- import type { Entry, RenderedLine } from "./types.js";
1
+ import { type PixConfig } from "../../config.js";
2
+ import type { Theme } from "../../theme.js";
3
+ import type { Entry, RenderedLine } from "../types.js";
4
4
  export type InlineUserMessageMenuContext = {
5
5
  userContentWidth: number;
6
6
  userContentLeft: number;
@@ -1,6 +1,6 @@
1
- import { applyOutputFilters } from "../config.js";
2
- import { renderMarkdownTextLines } from "../markdown-format.js";
3
- import { attachImageClickTargets } from "./image-click-targets.js";
1
+ import { applyOutputFilters } from "../../config.js";
2
+ import { renderMarkdownTextLines } from "../../markdown-format.js";
3
+ import { attachImageClickTargets } from "../screen/image-click-targets.js";
4
4
  import { horizontalPaddingLayout, padHorizontalText, wrapText } from "./render-text.js";
5
5
  import { renderConversationShellEntry } from "./conversation-shell-renderer.js";
6
6
  import { renderConversationToolEntry, renderThinkingEntry } from "./conversation-tool-renderer.js";
@@ -1,4 +1,4 @@
1
- import type { Entry, RenderedLine } from "./types.js";
1
+ import type { Entry, RenderedLine } from "../types.js";
2
2
  import type { ConversationToolRenderOptions } from "./conversation-tool-renderer.js";
3
3
  export declare function renderConversationShellEntry(entry: Extract<Entry, {
4
4
  kind: "shell";
@@ -1,4 +1,4 @@
1
- import { resolveToolRule } from "../config.js";
1
+ import { resolveToolRule } from "../../config.js";
2
2
  import { renderToolBlock } from "./tool-block-renderer.js";
3
3
  export function renderConversationShellEntry(entry, width, options) {
4
4
  const body = shellEntryBody(entry);
@@ -1,6 +1,6 @@
1
- import { type PixConfig } from "../config.js";
2
- import type { Theme } from "../theme.js";
3
- import type { Entry, RenderedLine } from "./types.js";
1
+ import { type PixConfig } from "../../config.js";
2
+ import type { Theme } from "../../theme.js";
3
+ import type { Entry, RenderedLine } from "../types.js";
4
4
  export type ConversationToolRenderOptions = {
5
5
  cwd: string;
6
6
  pixConfig: PixConfig;
@@ -1,11 +1,11 @@
1
- import { resolveColor, resolveToolRule } from "../config.js";
2
- import { formatMarkdownTables, markdownSyntaxHighlightsForText } from "../markdown-format.js";
3
- import { renderToolDisplay } from "../tool-renderers/index.js";
4
- import { DEFAULT_THINKING_TOOL_RULE, SUBAGENT_STATUSES, THINKING_TOOL_NAME, TODO_TOOL_NAME } from "./constants.js";
5
- import { attachImageClickTargets } from "./image-click-targets.js";
1
+ import { resolveColor, resolveToolRule } from "../../config.js";
2
+ import { formatMarkdownTables, markdownSyntaxHighlightsForText } from "../../markdown-format.js";
3
+ import { renderToolDisplay } from "../../tool-renderers/index.js";
4
+ import { DEFAULT_THINKING_TOOL_RULE, SUBAGENT_STATUSES, THINKING_TOOL_NAME, TODO_TOOL_NAME } from "../constants.js";
5
+ import { attachImageClickTargets } from "../screen/image-click-targets.js";
6
6
  import { formatStructuredText } from "./message-content.js";
7
- import { formatSubagentTimestamp, isSubagentRunRenderDetails, isSubagentsToolName, subagentRunName, subagentStatusIcon, taskPreviewMap, } from "./subagents-model.js";
8
- import { formatTodoTaskLine, isTodoDetails, visibleTodoTasks } from "./todo-model.js";
7
+ import { formatSubagentTimestamp, isSubagentRunRenderDetails, isSubagentsToolName, subagentRunName, subagentStatusIcon, taskPreviewMap, } from "../subagents/subagents-model.js";
8
+ import { formatTodoTaskLine, isTodoDetails, visibleTodoTasks } from "../todo/todo-model.js";
9
9
  import { renderToolBlock } from "./tool-block-renderer.js";
10
10
  export function renderConversationToolEntry(entry, width, options) {
11
11
  const todoLines = renderTodoToolEntry(entry, width, options);
@@ -1,8 +1,8 @@
1
1
  import type { AgentSession } from "@earendil-works/pi-coding-agent";
2
- import type { PixConfig } from "../config.js";
3
- import type { Theme } from "../theme.js";
2
+ import type { PixConfig } from "../../config.js";
3
+ import type { Theme } from "../../theme.js";
4
4
  import { type InlineUserMessageMenuContext } from "./conversation-entry-renderer.js";
5
- import type { ConversationBlockCache, Entry, RenderedLine, SubmittedUserMessage } from "./types.js";
5
+ import type { ConversationBlockCache, Entry, RenderedLine, SubmittedUserMessage } from "../types.js";
6
6
  export type ConversationViewportHost = {
7
7
  readonly entries: readonly Entry[];
8
8
  readonly session: AgentSession | undefined;
@@ -1,4 +1,4 @@
1
- import { normalizeToolName, parseArgsText } from "../tool-renderers/utils.js";
1
+ import { normalizeToolName, parseArgsText } from "../../tool-renderers/utils.js";
2
2
  const NUDGE_TYPES = ["turn", "iteration", "context-soft", "context-strong"];
3
3
  export function formatDcpStatsToast(session) {
4
4
  const stats = collectDcpSessionStats(session);
@@ -1,6 +1,6 @@
1
- import type { InputEditor } from "../input-editor.js";
2
- import type { Theme } from "../theme.js";
3
- import type { EditorLayout, ExtensionWidgetRegistration, ExtensionWidgetTheme, SubagentsWidgetState, TodoDetails, WidgetTuiHandle } from "./types.js";
1
+ import type { InputEditor } from "../../input-editor.js";
2
+ import type { Theme } from "../../theme.js";
3
+ import type { EditorLayout, ExtensionWidgetRegistration, ExtensionWidgetTheme, SubagentsWidgetState, TodoDetails, WidgetTuiHandle } from "../types.js";
4
4
  export type EditorLayoutRendererHost = {
5
5
  readonly theme: Theme;
6
6
  readonly inputEditor: InputEditor;
@@ -1,7 +1,7 @@
1
- import { ABOVE_EDITOR_WIDGET_KEY_GROUPS, BUILT_IN_SUBAGENTS_WIDGET_KEYS, INPUT_MAX_ROWS, LEGACY_TODO_WIDGET_KEYS, } from "./constants.js";
1
+ import { ABOVE_EDITOR_WIDGET_KEY_GROUPS, BUILT_IN_SUBAGENTS_WIDGET_KEYS, INPUT_MAX_ROWS, LEGACY_TODO_WIDGET_KEYS, } from "../constants.js";
2
2
  import { renderSubagentsPanel, renderTodoPanel } from "./editor-panels.js";
3
3
  import { ellipsizeDisplay, horizontalPaddingLayout, padHorizontalText, sanitizeText } from "./render-text.js";
4
- import { APP_ICONS } from "./icons.js";
4
+ import { APP_ICONS } from "../icons.js";
5
5
  const INPUT_FRAME_VERTICAL = "│";
6
6
  export class EditorLayoutRenderer {
7
7
  host;
@@ -1,4 +1,4 @@
1
- import type { Theme } from "../theme.js";
2
- import type { RenderedLine, SubagentsWidgetState, TodoDetails } from "./types.js";
1
+ import type { Theme } from "../../theme.js";
2
+ import type { RenderedLine, SubagentsWidgetState, TodoDetails } from "../types.js";
3
3
  export declare function renderTodoPanel(details: TodoDetails | undefined, expanded: boolean, width: number, colors: Theme["colors"]): RenderedLine[];
4
4
  export declare function renderSubagentsPanel(state: SubagentsWidgetState | undefined, expanded: boolean, width: number, colors: Theme["colors"]): RenderedLine[];
@@ -1,8 +1,8 @@
1
- import { stringDisplayWidth } from "../terminal-width.js";
2
- import { SUBAGENTS_WIDGET_MAX_ROWS } from "./constants.js";
1
+ import { stringDisplayWidth } from "../../terminal-width.js";
2
+ import { SUBAGENTS_WIDGET_MAX_ROWS } from "../constants.js";
3
3
  import { ellipsizeDisplay, padOrTrimPlain, wrapLine } from "./render-text.js";
4
- import { activeSubagentStates, formatElapsedSince, formatSubagentsPanelStats, subagentModelThinkingLabel, subagentRunName, subagentStatusIcon, taskPreviewMap, } from "./subagents-model.js";
5
- import { formatTodoPanelStats, formatTodoTaskLine, hasOpenTodoTasks, shiftSegmentsToSlice, todoTaskLineSegments, visibleTodoTaskRows, visibleTodoTasks, } from "./todo-model.js";
4
+ import { activeSubagentStates, formatElapsedSince, formatSubagentsPanelStats, subagentModelThinkingLabel, subagentRunName, subagentStatusIcon, taskPreviewMap, } from "../subagents/subagents-model.js";
5
+ import { formatTodoPanelStats, formatTodoTaskLine, hasOpenTodoTasks, shiftSegmentsToSlice, todoTaskLineSegments, visibleTodoTaskRows, visibleTodoTasks, } from "../todo/todo-model.js";
6
6
  export function renderTodoPanel(details, expanded, width, colors) {
7
7
  if (!details)
8
8
  return [];
@@ -1,4 +1,4 @@
1
- import type { ImageContent } from "../input-editor.js";
1
+ import type { ImageContent } from "../../input-editor.js";
2
2
  export declare function stringifyUnknown(value: unknown): string;
3
3
  export declare function formatStructuredText(value: unknown): string;
4
4
  export declare function renderContent(content: readonly unknown[]): string;
@@ -1,4 +1,4 @@
1
- import { isRecord } from "./guards.js";
1
+ import { isRecord } from "../guards.js";
2
2
  export function stringifyUnknown(value) {
3
3
  if (typeof value === "string")
4
4
  return value;
@@ -1,13 +1,13 @@
1
1
  import type { EditorLayoutRenderer } from "./editor-layout-renderer.js";
2
- import type { AppMouseController } from "./mouse-controller.js";
3
- import type { AppPopupMenuController } from "./popup-menu-controller.js";
4
- import type { AppScrollController } from "./scroll-controller.js";
5
- import type { ScreenStyler } from "./screen-styler.js";
2
+ import type { AppMouseController } from "../screen/mouse-controller.js";
3
+ import type { AppPopupMenuController } from "../popup/popup-menu-controller.js";
4
+ import type { AppScrollController } from "../screen/scroll-controller.js";
5
+ import type { ScreenStyler } from "../screen/screen-styler.js";
6
6
  import type { StatusLineRenderer } from "./status-line-renderer.js";
7
7
  import type { TabLineRenderer } from "./tab-line-renderer.js";
8
8
  import type { AppToastController } from "./toast-controller.js";
9
- import { TerminalOutputBuffer } from "./terminal-output-buffer.js";
10
- import { type Theme } from "../theme.js";
9
+ import { TerminalOutputBuffer } from "../terminal/terminal-output-buffer.js";
10
+ import { type Theme } from "../../theme.js";
11
11
  export type AppRenderControllerHost = {
12
12
  isRunning(): boolean;
13
13
  terminalColumns(): number;
@@ -1,9 +1,9 @@
1
- import { DISABLE_TERMINAL_WRAP, HIDE_CURSOR, SHOW_CURSOR } from "./constants.js";
2
- import { APP_ICONS } from "./icons.js";
1
+ import { DISABLE_TERMINAL_WRAP, HIDE_CURSOR, SHOW_CURSOR } from "../constants.js";
2
+ import { APP_ICONS } from "../icons.js";
3
3
  import { renderToastOverlays } from "./toast-renderer.js";
4
- import { TerminalOutputBuffer } from "./terminal-output-buffer.js";
5
- import { ANSI_RESET, colorLine, colorize } from "../theme.js";
6
- import { stringDisplayWidth } from "../terminal-width.js";
4
+ import { TerminalOutputBuffer } from "../terminal/terminal-output-buffer.js";
5
+ import { ANSI_RESET, colorLine, colorize } from "../../theme.js";
6
+ import { stringDisplayWidth } from "../../terminal-width.js";
7
7
  import { padOrTrimPlain } from "./render-text.js";
8
8
  const INPUT_FRAME = {
9
9
  topLeft: "╭",
@@ -1,5 +1,5 @@
1
- import type { Theme } from "../theme.js";
2
- import type { ToolStatusEntry } from "./types.js";
1
+ import type { Theme } from "../../theme.js";
2
+ import type { ToolStatusEntry } from "../types.js";
3
3
  export declare function sanitizeText(text: string): string;
4
4
  export declare function normalizePastedTextForDuplicateKey(text: string): string;
5
5
  export declare function shortHash(text: string): string;
@@ -1,8 +1,8 @@
1
1
  import { createHash } from "node:crypto";
2
- import { expandTabs, padOrTrimDisplay, sliceByDisplayWidth, stringDisplayWidth, wrapDisplayLine } from "../terminal-width.js";
3
- import { APP_ICONS } from "./icons.js";
2
+ import { expandTabs, padOrTrimDisplay, sliceByDisplayWidth, stringDisplayWidth, wrapDisplayLine } from "../../terminal-width.js";
3
+ import { APP_ICONS } from "../icons.js";
4
4
  export function sanitizeText(text) {
5
- return expandTabs(text.replace(/\x1b/g, "␛").replace(/\r/g, ""));
5
+ return expandTabs(text.replace(/⚠️?/gu, APP_ICONS.alert).replace(/\x1b/g, "␛").replace(/\r/g, ""));
6
6
  }
7
7
  export function normalizePastedTextForDuplicateKey(text) {
8
8
  return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
@@ -1,8 +1,8 @@
1
1
  import type { AgentSession } from "@earendil-works/pi-coding-agent";
2
- import type { Theme } from "../theme.js";
3
- import type { SessionActivity, StatusCompactToolsTarget, StatusContextTarget, StatusLineLayout, StatusModelTarget, StatusModelUsageTarget, StatusPromptEnhancerTarget, StatusSessionTarget, StatusTerminalBellSoundTarget, StatusThinkingExpandTarget, StatusThinkingTarget, StatusUserJumpTarget, StatusVoiceLanguageTarget, StatusVoiceMicTarget } from "./types.js";
4
- import type { ScreenStyler } from "./screen-styler.js";
5
- import { type ModelColorsConfig } from "../config.js";
2
+ import type { Theme } from "../../theme.js";
3
+ import type { SessionActivity, StatusCompactToolsTarget, StatusContextTarget, StatusLineLayout, StatusModelTarget, StatusModelUsageTarget, StatusPromptEnhancerTarget, StatusSessionTarget, StatusTerminalBellSoundTarget, StatusThinkingExpandTarget, StatusThinkingTarget, StatusUserJumpTarget, StatusVoiceLanguageTarget, StatusVoiceMicTarget } from "../types.js";
4
+ import type { ScreenStyler } from "../screen/screen-styler.js";
5
+ import { type ModelColorsConfig } from "../../config.js";
6
6
  export type StatusLineRendererHost = {
7
7
  readonly theme: Theme;
8
8
  readonly screenStyler: ScreenStyler;
@@ -1,8 +1,8 @@
1
- import { compactProgressBarSegments, formatCompactProgressBar } from "../context-progress-bar.js";
1
+ import { compactProgressBarSegments, formatCompactProgressBar } from "../../context-progress-bar.js";
2
2
  import { padOrTrimPlain } from "./render-text.js";
3
- import { stringDisplayWidth } from "../terminal-width.js";
4
- import { APP_ICONS } from "./icons.js";
5
- import { resolveColor, resolveModelColor } from "../config.js";
3
+ import { stringDisplayWidth } from "../../terminal-width.js";
4
+ import { APP_ICONS } from "../icons.js";
5
+ import { resolveColor, resolveModelColor } from "../../config.js";
6
6
  const MODEL_USAGE_PROGRESS_BAR_WIDTH = stringDisplayWidth(formatCompactProgressBar(100));
7
7
  export class StatusLineRenderer {
8
8
  host;
@@ -1,6 +1,6 @@
1
- import type { Theme } from "../theme.js";
2
- import type { ScreenStyler } from "./screen-styler.js";
3
- import type { SessionTab, TabLineLayout } from "./types.js";
1
+ import type { Theme } from "../../theme.js";
2
+ import type { ScreenStyler } from "../screen/screen-styler.js";
3
+ import type { SessionTab, TabLineLayout } from "../types.js";
4
4
  export type TabLineRendererHost = {
5
5
  readonly theme: Theme;
6
6
  readonly screenStyler: ScreenStyler;
@@ -1,5 +1,5 @@
1
- import { stringDisplayWidth } from "../terminal-width.js";
2
- import { APP_ICONS } from "./icons.js";
1
+ import { stringDisplayWidth } from "../../terminal-width.js";
2
+ import { APP_ICONS } from "../icons.js";
3
3
  import { ellipsizeDisplay } from "./render-text.js";
4
4
  const TAB_SEPARATOR = " │ ";
5
5
  const EMPTY_NEW_TAB_PREFIX = "│ ";
@@ -1,4 +1,4 @@
1
- import { Toast, type ToastKind, type ToastVariant } from "../ui.js";
1
+ import { Toast, type ToastKind, type ToastVariant } from "../../ui.js";
2
2
  export type AppToastControllerHost = {
3
3
  render(): void;
4
4
  };
@@ -1,5 +1,5 @@
1
- import { Toast } from "../ui.js";
2
- import { TOAST_DURATION_MS } from "./constants.js";
1
+ import { Toast } from "../../ui.js";
2
+ import { TOAST_DURATION_MS } from "../constants.js";
3
3
  export class AppToastController {
4
4
  host;
5
5
  toast = new Toast();
@@ -1,6 +1,6 @@
1
- import { type Theme } from "../theme.js";
2
- import type { ToastEntry } from "../ui.js";
3
- import type { ToastLineTarget } from "./types.js";
1
+ import { type Theme } from "../../theme.js";
2
+ import type { ToastEntry } from "../../ui.js";
3
+ import type { ToastLineTarget } from "../types.js";
4
4
  export type ToastOverlay = {
5
5
  id: number;
6
6
  row: number;
@@ -1,6 +1,6 @@
1
- import { colorLine } from "../theme.js";
2
- import { stringDisplayWidth, wrapDisplayLine } from "../terminal-width.js";
3
- import { APP_ICONS } from "./icons.js";
1
+ import { colorLine } from "../../theme.js";
2
+ import { stringDisplayWidth, wrapDisplayLine } from "../../terminal-width.js";
3
+ import { APP_ICONS } from "../icons.js";
4
4
  import { padOrTrimPlain, sanitizeText } from "./render-text.js";
5
5
  export function renderToastOverlays(states, width, maxRows, theme) {
6
6
  if (maxRows <= 0)
@@ -1,8 +1,8 @@
1
- import { type ResolvedToolRule } from "../config.js";
2
- import type { ToolBodySyntaxHighlights } from "../syntax-highlight.js";
3
- import type { Theme } from "../theme.js";
4
- import type { RenderedLine } from "./types.js";
5
- import type { ToolBodyLineStyle, ToolHeaderSegment } from "../tool-renderers/types.js";
1
+ import { type ResolvedToolRule } from "../../config.js";
2
+ import type { ToolBodySyntaxHighlights } from "../../syntax-highlight.js";
3
+ import type { Theme } from "../../theme.js";
4
+ import type { RenderedLine } from "../types.js";
5
+ import type { ToolBodyLineStyle, ToolHeaderSegment } from "../../tool-renderers/types.js";
6
6
  export type ToolBlockEntry = {
7
7
  id: string;
8
8
  toolName: string;
@@ -1,5 +1,5 @@
1
- import { resolveColor } from "../config.js";
2
- import { expandTabs, sliceByDisplayWidth, stringDisplayWidth, wrapDisplayLineByWords } from "../terminal-width.js";
1
+ import { resolveColor } from "../../config.js";
2
+ import { expandTabs, sliceByDisplayWidth, stringDisplayWidth, wrapDisplayLineByWords } from "../../terminal-width.js";
3
3
  import { hasToolLspDiagnosticsAfterMutation, sanitizeText, toolStatusIcon, toolStatusIconColor, wrapLine } from "./render-text.js";
4
4
  const TRUNCATED_PREVIEW_MARKER = "… ";
5
5
  export function renderToolBlock(entry, rule, width, colors, options = {}) {
@@ -5,7 +5,7 @@ import { dirname, isAbsolute, join, relative, resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, getAgentDir, SessionManager, } from "@earendil-works/pi-coding-agent";
7
7
  import { PI_FAVORITE_MODEL_REFS } from "./constants.js";
8
- import { parseModelRef, parseScopedModelRef } from "./model-ref.js";
8
+ import { parseModelRef, parseScopedModelRef } from "./model/model-ref.js";
9
9
  const BUNDLED_QUESTION_EXTENSION_NAME = "question";
10
10
  const PI_TOOLS_SUITE_EXTENSION_NAME = "pi-tools-suite";
11
11
  const BUNDLED_EXTENSIONS_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "../..", "extensions");
@@ -1,4 +1,4 @@
1
- import { STATUS_BLINK_INTERVAL_MS } from "./constants.js";
1
+ import { STATUS_BLINK_INTERVAL_MS } from "../constants.js";
2
2
  export class AppBlinkController {
3
3
  host;
4
4
  consumers = new Map();
@@ -1,5 +1,5 @@
1
- import type { ImageContent } from "../input-editor.js";
2
- import type { RenderedLine, StyledSegment } from "./types.js";
1
+ import type { ImageContent } from "../../input-editor.js";
2
+ import type { RenderedLine, StyledSegment } from "../types.js";
3
3
  type ImageLabelStyle = Omit<StyledSegment, "start" | "end">;
4
4
  export declare function attachImageClickTargets(lines: RenderedLine[], entryId: string, images: readonly ImageContent[] | undefined, style?: ImageLabelStyle): RenderedLine[];
5
5
  export {};
@@ -1,2 +1,2 @@
1
- import type { ImageContent } from "../input-editor.js";
1
+ import type { ImageContent } from "../../input-editor.js";
2
2
  export declare function openImageContent(image: ImageContent): boolean;
@@ -1,12 +1,12 @@
1
- import type { AppCommandController } from "./command-controller.js";
2
- import type { ConversationViewport } from "./conversation-viewport.js";
3
- import type { EditorLayoutRenderer } from "./editor-layout-renderer.js";
4
- import type { ImageContent, InputEditor } from "../input-editor.js";
5
- import type { ToastEntry, ToastVariant } from "../ui.js";
6
- import type { AppPopupActionController } from "./popup-action-controller.js";
7
- import type { AppPopupMenuController } from "./popup-menu-controller.js";
1
+ import type { AppCommandController } from "../commands/command-controller.js";
2
+ import type { ConversationViewport } from "../rendering/conversation-viewport.js";
3
+ import type { EditorLayoutRenderer } from "../rendering/editor-layout-renderer.js";
4
+ import type { ImageContent, InputEditor } from "../../input-editor.js";
5
+ import type { ToastEntry, ToastVariant } from "../../ui.js";
6
+ import type { AppPopupActionController } from "../popup/popup-action-controller.js";
7
+ import type { AppPopupMenuController } from "../popup/popup-menu-controller.js";
8
8
  import type { AppScrollController } from "./scroll-controller.js";
9
- import type { Entry, ImageClickTarget, MouseEvent, MouseSelection, StatusContextTarget, StatusCompactToolsTarget, StatusModelTarget, StatusModelUsageTarget, StatusPromptEnhancerTarget, StatusSessionTarget, StatusTerminalBellSoundTarget, TabLineMouseTarget, StatusThinkingExpandTarget, StatusThinkingTarget, StatusUserJumpTarget, StatusVoiceLanguageTarget, StatusVoiceMicTarget } from "./types.js";
9
+ import type { Entry, ImageClickTarget, MouseEvent, MouseSelection, StatusContextTarget, StatusCompactToolsTarget, StatusModelTarget, StatusModelUsageTarget, StatusPromptEnhancerTarget, StatusSessionTarget, StatusTerminalBellSoundTarget, TabLineMouseTarget, StatusThinkingExpandTarget, StatusThinkingTarget, StatusUserJumpTarget, StatusVoiceLanguageTarget, StatusVoiceMicTarget } from "../types.js";
10
10
  import { type RenderedLink } from "./file-links.js";
11
11
  import type { AgentSession } from "@earendil-works/pi-coding-agent";
12
12
  type ClickFlash = {
@@ -91,7 +91,7 @@ export declare class AppMouseController {
91
91
  } | {
92
92
  kind: "queue-message";
93
93
  id: string;
94
- } | import("./types.js").ToastLineTarget | undefined>;
94
+ } | import("../types.js").ToastLineTarget | undefined>;
95
95
  readonly renderedRowTexts: Map<number, string>;
96
96
  readonly renderedRowBackgrounds: Map<number, string>;
97
97
  readonly renderedImageTargets: Map<number, readonly ImageClickTarget[]>;
@@ -117,6 +117,7 @@ export declare class AppMouseController {
117
117
  private autoScrollAccumulator;
118
118
  private autoScrollLastTick;
119
119
  private autoScrollCursorX;
120
+ private leftEdgeReleaseFallbackTimer;
120
121
  private clickFlash;
121
122
  private clickFlashTimer;
122
123
  private clickFlashDirty;
@@ -165,6 +166,9 @@ export declare class AppMouseController {
165
166
  private openQueueMessageMenu;
166
167
  private copyErrorToast;
167
168
  private handleMouseSelection;
169
+ private finishMouseSelection;
170
+ private updateLeftEdgeReleaseFallback;
171
+ private cancelLeftEdgeReleaseFallback;
168
172
  syncConversationSelectionForRender(startLine: number, bodyHeight: number, topReservedRows: number, width: number): void;
169
173
  private updateSelectionCurrentFromMouse;
170
174
  private getSelectedText;
@@ -1,13 +1,14 @@
1
1
  import { copyTextToClipboard } from "./clipboard.js";
2
- import { stringifyUnknown } from "./message-content.js";
3
- import { horizontalPaddingLayout } from "./render-text.js";
2
+ import { stringifyUnknown } from "../rendering/message-content.js";
3
+ import { horizontalPaddingLayout } from "../rendering/render-text.js";
4
4
  import { orderedSelection, samePoint } from "./screen-selection.js";
5
5
  import { openImageContent as openSystemImageContent } from "./image-opener.js";
6
- import { stringDisplayWidth } from "../terminal-width.js";
7
- import { formatDcpStatsToast } from "./dcp-stats.js";
6
+ import { stringDisplayWidth } from "../../terminal-width.js";
7
+ import { formatDcpStatsToast } from "../rendering/dcp-stats.js";
8
8
  import { detectFileLinks } from "./file-links.js";
9
9
  import { openFileLink as openDetectedFileLink } from "./file-link-opener.js";
10
10
  const CLICK_FLASH_MS = 100;
11
+ const LOST_MOUSE_RELEASE_SETTLE_MS = 180;
11
12
  export class AppMouseController {
12
13
  host;
13
14
  popupMenus;
@@ -40,6 +41,7 @@ export class AppMouseController {
40
41
  autoScrollAccumulator = 0;
41
42
  autoScrollLastTick = 0;
42
43
  autoScrollCursorX = 1;
44
+ leftEdgeReleaseFallbackTimer;
43
45
  clickFlash;
44
46
  clickFlashTimer;
45
47
  clickFlashDirty = false;
@@ -350,7 +352,7 @@ export class AppMouseController {
350
352
  const baseButton = event.button & 3;
351
353
  const draggingLeftButton = (event.button & 32) !== 0 && baseButton === 0;
352
354
  if (event.released) {
353
- if (!this.scrollBarDragActive && !onScrollBar)
355
+ if (!this.scrollBarDragActive)
354
356
  return false;
355
357
  this.scrollBarDragActive = false;
356
358
  return true;
@@ -380,7 +382,7 @@ export class AppMouseController {
380
382
  const baseButton = event.button & 3;
381
383
  const draggingLeftButton = (event.button & 32) !== 0 && baseButton === 0;
382
384
  if (event.released)
383
- return this.finishInputScrollBarDrag(event, onScrollBar);
385
+ return this.finishInputScrollBarDrag(event);
384
386
  if (event.button === 0 && onScrollBar) {
385
387
  this.inputScrollBarDragActive = true;
386
388
  this.scrollInputToTrackRow(editorRow, scrollBar.trackHeight, renderedInput.totalLineCount, renderedInput.visibleRowCount);
@@ -392,10 +394,10 @@ export class AppMouseController {
392
394
  this.scrollInputToTrackRow(trackRow, scrollBar.trackHeight, renderedInput.totalLineCount, renderedInput.visibleRowCount);
393
395
  return true;
394
396
  }
395
- finishInputScrollBarDrag(event, onScrollBar = false) {
397
+ finishInputScrollBarDrag(event) {
396
398
  if (!event.released)
397
399
  return false;
398
- if (!this.inputScrollBarDragActive && !onScrollBar)
400
+ if (!this.inputScrollBarDragActive)
399
401
  return false;
400
402
  this.inputScrollBarDragActive = false;
401
403
  return true;
@@ -634,42 +636,27 @@ export class AppMouseController {
634
636
  return true;
635
637
  }
636
638
  handleMouseSelection(event) {
637
- const point = { x: event.x, y: event.y };
638
639
  const baseButton = event.button & 3;
639
640
  const draggingLeftButton = (event.button & 32) !== 0 && baseButton === 0;
640
641
  if (event.released) {
641
642
  if (!this.mouseSelection)
642
643
  return false;
643
- this.stopAutoScroll();
644
+ this.cancelLeftEdgeReleaseFallback();
644
645
  this.updateSelectionCurrentFromMouse(event, { autoScroll: false });
645
- const selection = this.mouseSelection;
646
- this.mouseSelection = undefined;
647
- if (!selection.moved && samePoint(selection.anchor, point)) {
648
- this.host.render();
649
- return false;
650
- }
651
- const selectedText = this.getSelectedText(selection);
652
- this.host.render();
653
- if (selectedText.trim().length === 0)
654
- return true;
655
- try {
656
- this.copyTextToClipboard(selectedText);
657
- this.host.showToast("Copied to clipboard", "success");
658
- }
659
- catch (error) {
660
- this.host.showToast(`Copy failed: ${stringifyUnknown(error)}`, "error");
661
- }
662
- return true;
646
+ return this.finishMouseSelection();
663
647
  }
664
648
  if (draggingLeftButton) {
665
649
  if (!this.mouseSelection)
666
650
  return false;
667
651
  this.updateSelectionCurrentFromMouse(event);
652
+ this.updateLeftEdgeReleaseFallback(event);
668
653
  this.host.render();
669
654
  return true;
670
655
  }
671
656
  if (event.button === 0) {
657
+ this.cancelLeftEdgeReleaseFallback();
672
658
  this.stopAutoScroll();
659
+ const point = { x: event.x, y: event.y };
673
660
  const conversationPoint = this.conversationPointFromMouse(event, false);
674
661
  this.mouseSelection = conversationPoint
675
662
  ? {
@@ -685,6 +672,47 @@ export class AppMouseController {
685
672
  }
686
673
  return false;
687
674
  }
675
+ finishMouseSelection() {
676
+ const selection = this.mouseSelection;
677
+ if (!selection)
678
+ return false;
679
+ this.cancelLeftEdgeReleaseFallback();
680
+ this.stopAutoScroll();
681
+ this.mouseSelection = undefined;
682
+ if (!selection.moved && samePoint(selection.anchor, selection.current)) {
683
+ this.host.render();
684
+ return false;
685
+ }
686
+ const selectedText = this.getSelectedText(selection);
687
+ this.host.render();
688
+ if (selectedText.trim().length === 0)
689
+ return true;
690
+ try {
691
+ this.copyTextToClipboard(selectedText);
692
+ this.host.showToast("Copied to clipboard", "success");
693
+ }
694
+ catch (error) {
695
+ this.host.showToast(`Copy failed: ${stringifyUnknown(error)}`, "error");
696
+ }
697
+ return true;
698
+ }
699
+ updateLeftEdgeReleaseFallback(event) {
700
+ if (!this.mouseSelection?.moved || event.x > 1) {
701
+ this.cancelLeftEdgeReleaseFallback();
702
+ return;
703
+ }
704
+ this.cancelLeftEdgeReleaseFallback();
705
+ this.leftEdgeReleaseFallbackTimer = setTimeout(() => {
706
+ this.leftEdgeReleaseFallbackTimer = undefined;
707
+ this.finishMouseSelection();
708
+ }, LOST_MOUSE_RELEASE_SETTLE_MS);
709
+ }
710
+ cancelLeftEdgeReleaseFallback() {
711
+ if (!this.leftEdgeReleaseFallbackTimer)
712
+ return;
713
+ clearTimeout(this.leftEdgeReleaseFallbackTimer);
714
+ this.leftEdgeReleaseFallbackTimer = undefined;
715
+ }
688
716
  syncConversationSelectionForRender(startLine, bodyHeight, topReservedRows, width) {
689
717
  this.renderedConversationFrame = {
690
718
  bodyHeight,
@@ -1,4 +1,4 @@
1
- import type { ScreenPoint } from "./types.js";
1
+ import type { ScreenPoint } from "../types.js";
2
2
  export declare function samePoint(left: ScreenPoint, right: ScreenPoint): boolean;
3
3
  export declare function orderedSelection(anchor: ScreenPoint, current: ScreenPoint): {
4
4
  start: ScreenPoint;
@@ -1,5 +1,5 @@
1
- import { type Theme } from "../theme.js";
2
- import type { MouseSelection, RenderedLine, StyledSegment } from "./types.js";
1
+ import { type Theme } from "../../theme.js";
2
+ import type { MouseSelection, RenderedLine, StyledSegment } from "../types.js";
3
3
  export type ScreenStylerHost = {
4
4
  readonly theme: Theme;
5
5
  readonly cwd?: string;