@psnext/slingcli 2.5.20260607-2 → 2.5.20260615-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/node_modules/@aws-sdk/core/dist-cjs/index.js +47 -2297
  2. package/node_modules/@aws-sdk/core/dist-es/index.js +3 -3
  3. package/node_modules/@aws-sdk/core/dist-types/index.d.ts +5 -5
  4. package/node_modules/@aws-sdk/core/dist-types/ts3.4/index.d.ts +5 -5
  5. package/node_modules/@aws-sdk/core/package.json +8 -8
  6. package/node_modules/@aws-sdk/credential-provider-env/package.json +4 -4
  7. package/node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/node-http-handler/package.json +7 -7
  8. package/node_modules/@aws-sdk/credential-provider-http/package.json +6 -5
  9. package/node_modules/@aws-sdk/credential-provider-ini/package.json +11 -11
  10. package/node_modules/@aws-sdk/credential-provider-login/package.json +5 -5
  11. package/node_modules/@aws-sdk/credential-provider-node/package.json +9 -9
  12. package/node_modules/@aws-sdk/credential-provider-process/package.json +4 -4
  13. package/node_modules/@aws-sdk/credential-provider-sso/dist-cjs/index.js +4 -1
  14. package/node_modules/@aws-sdk/credential-provider-sso/dist-es/resolveSSOCredentials.js +4 -1
  15. package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/package.json +5 -5
  16. package/node_modules/@aws-sdk/credential-provider-sso/package.json +9 -7
  17. package/node_modules/@aws-sdk/credential-provider-web-identity/package.json +5 -5
  18. package/node_modules/@aws-sdk/eventstream-handler-node/package.json +3 -3
  19. package/node_modules/@aws-sdk/middleware-eventstream/package.json +3 -3
  20. package/node_modules/@aws-sdk/middleware-websocket/package.json +5 -5
  21. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/cognito-identity/index.js +1 -1
  22. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/signin/index.js +1 -1
  23. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso/index.js +1 -1
  24. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso-oidc/index.js +1 -1
  25. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sts/index.js +1 -1
  26. package/node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-http-handler/package.json +7 -7
  27. package/node_modules/@aws-sdk/nested-clients/package.json +6 -6
  28. package/node_modules/@aws-sdk/signature-v4-multi-region/package.json +7 -6
  29. package/node_modules/@aws-sdk/types/package.json +2 -2
  30. package/node_modules/@aws-sdk/util-locate-window/package.json +2 -2
  31. package/node_modules/@aws-sdk/xml-builder/package.json +2 -2
  32. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +8 -0
  33. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +1 -1
  34. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  35. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +6 -6
  36. package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +906 -873
  37. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +25 -8
  38. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +19 -12
  39. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +1 -0
  40. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js +8 -4
  41. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +2 -1
  42. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js +2 -1
  43. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +1 -0
  44. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js +1 -1
  45. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js +3 -2
  46. package/node_modules/@earendil-works/pi-ai/package.json +1 -1
  47. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js +3 -5
  48. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/project-trust.js +48 -0
  49. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/startup-ui.js +133 -0
  50. package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +14 -3
  51. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-runtime.js +4 -1
  52. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js +2 -2
  53. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +9 -2
  54. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/utils.js +1 -1
  55. package/node_modules/@earendil-works/pi-coding-agent/dist/core/experimental.js +4 -0
  56. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.js +4 -4
  57. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js +34 -0
  58. package/node_modules/@earendil-works/pi-coding-agent/dist/core/index.js +1 -0
  59. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js +5 -57
  60. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js +41 -5
  61. package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js +31 -17
  62. package/node_modules/@earendil-works/pi-coding-agent/dist/core/project-trust.js +58 -0
  63. package/node_modules/@earendil-works/pi-coding-agent/dist/core/prompt-templates.js +24 -26
  64. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js +0 -4
  65. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resource-loader.js +121 -54
  66. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +11 -2
  67. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js +26 -0
  68. package/node_modules/@earendil-works/pi-coding-agent/dist/core/trust-manager.js +89 -17
  69. package/node_modules/@earendil-works/pi-coding-agent/dist/index.js +2 -2
  70. package/node_modules/@earendil-works/pi-coding-agent/dist/main.js +65 -76
  71. package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.js +1 -118
  72. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/first-time-setup.js +103 -0
  73. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/index.js +1 -0
  74. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +7 -1
  75. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +20 -0
  76. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/tree-selector.js +87 -12
  77. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/trust-selector.js +23 -18
  78. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +104 -30
  79. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js +19 -41
  80. package/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.js +72 -18
  81. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/changelog.js +78 -0
  82. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/version-check.js +4 -27
  83. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/LICENSE +15 -0
  84. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/bin/semver.js +195 -0
  85. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/classes/comparator.js +143 -0
  86. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/classes/index.js +7 -0
  87. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/classes/range.js +557 -0
  88. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/classes/semver.js +333 -0
  89. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/clean.js +8 -0
  90. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/cmp.js +54 -0
  91. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/coerce.js +62 -0
  92. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/compare-build.js +9 -0
  93. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/compare-loose.js +5 -0
  94. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/compare.js +7 -0
  95. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/diff.js +60 -0
  96. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/eq.js +5 -0
  97. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/gt.js +5 -0
  98. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/gte.js +5 -0
  99. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/inc.js +21 -0
  100. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/lt.js +5 -0
  101. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/lte.js +5 -0
  102. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/major.js +5 -0
  103. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/minor.js +5 -0
  104. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/neq.js +5 -0
  105. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/parse.js +18 -0
  106. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/patch.js +5 -0
  107. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/prerelease.js +8 -0
  108. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/rcompare.js +5 -0
  109. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/rsort.js +5 -0
  110. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/satisfies.js +12 -0
  111. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/sort.js +5 -0
  112. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/truncate.js +48 -0
  113. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/functions/valid.js +8 -0
  114. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/index.js +93 -0
  115. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/internal/constants.js +37 -0
  116. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/internal/debug.js +11 -0
  117. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/internal/identifiers.js +29 -0
  118. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/internal/lrucache.js +42 -0
  119. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/internal/parse-options.js +17 -0
  120. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/internal/re.js +223 -0
  121. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/package.json +78 -0
  122. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/preload.js +4 -0
  123. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/range.bnf +17 -0
  124. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/gtr.js +6 -0
  125. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/intersects.js +9 -0
  126. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/ltr.js +6 -0
  127. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/max-satisfying.js +27 -0
  128. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/min-satisfying.js +26 -0
  129. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/min-version.js +63 -0
  130. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/outside.js +82 -0
  131. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/simplify.js +49 -0
  132. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/subset.js +249 -0
  133. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/to-comparators.js +10 -0
  134. package/node_modules/@earendil-works/pi-coding-agent/node_modules/semver/ranges/valid.js +13 -0
  135. package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +25 -12
  136. package/node_modules/@earendil-works/pi-coding-agent/package.json +6 -8
  137. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +102 -43
  138. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js +11 -1
  139. package/node_modules/@earendil-works/pi-tui/dist/fuzzy.js +2 -2
  140. package/node_modules/@earendil-works/pi-tui/dist/index.js +2 -0
  141. package/node_modules/@earendil-works/pi-tui/dist/terminal-colors.js +51 -0
  142. package/node_modules/@earendil-works/pi-tui/dist/terminal.js +38 -77
  143. package/node_modules/@earendil-works/pi-tui/dist/tui.js +145 -21
  144. package/node_modules/@earendil-works/pi-tui/dist/utils.js +44 -16
  145. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  146. package/node_modules/@nodable/entities/package.json +4 -1
  147. package/node_modules/@nodable/entities/src/EntityDecoder.js +104 -3
  148. package/node_modules/@nodable/entities/src/index.d.ts +77 -0
  149. package/node_modules/@nodable/entities/src/index.js +1 -1
  150. package/node_modules/@smithy/core/dist-cjs/submodules/retry/index.browser.js +3 -3
  151. package/node_modules/@smithy/core/dist-cjs/submodules/retry/index.js +3 -3
  152. package/node_modules/@smithy/core/dist-es/submodules/retry/middleware-retry/retry-pre-sra-deprecated/StandardRetryStrategy.js +2 -2
  153. package/node_modules/@smithy/core/dist-es/submodules/retry/util-retry/DefaultRateLimiter.js +1 -1
  154. package/node_modules/@smithy/core/package.json +17 -17
  155. package/node_modules/@smithy/credential-provider-imds/package.json +6 -6
  156. package/node_modules/@smithy/fetch-http-handler/package.json +9 -9
  157. package/node_modules/@smithy/signature-v4/package.json +6 -6
  158. package/node_modules/@smithy/types/package.json +9 -9
  159. package/node_modules/@types/node/README.md +1 -1
  160. package/node_modules/@types/node/http2.d.ts +1 -0
  161. package/node_modules/@types/node/package.json +2 -2
  162. package/node_modules/anynum/LICENSE +21 -0
  163. package/node_modules/anynum/README.md +142 -0
  164. package/node_modules/anynum/anynum.js +135 -0
  165. package/node_modules/anynum/digitTable.js +116 -0
  166. package/node_modules/anynum/package.json +42 -0
  167. package/node_modules/protobufjs/dist/light/protobuf.js +161 -203
  168. package/node_modules/protobufjs/dist/light/protobuf.js.map +1 -1
  169. package/node_modules/protobufjs/dist/light/protobuf.min.js +3 -3
  170. package/node_modules/protobufjs/dist/light/protobuf.min.js.map +1 -1
  171. package/node_modules/protobufjs/dist/minimal/protobuf.js +34 -77
  172. package/node_modules/protobufjs/dist/minimal/protobuf.js.map +1 -1
  173. package/node_modules/protobufjs/dist/minimal/protobuf.min.js +3 -3
  174. package/node_modules/protobufjs/dist/minimal/protobuf.min.js.map +1 -1
  175. package/node_modules/protobufjs/dist/protobuf.js +181 -223
  176. package/node_modules/protobufjs/dist/protobuf.js.map +1 -1
  177. package/node_modules/protobufjs/dist/protobuf.min.js +3 -3
  178. package/node_modules/protobufjs/dist/protobuf.min.js.map +1 -1
  179. package/node_modules/protobufjs/index.d.ts +0 -8
  180. package/node_modules/protobufjs/package.json +2 -3
  181. package/node_modules/protobufjs/src/converter.js +5 -4
  182. package/node_modules/protobufjs/src/decoder.js +1 -1
  183. package/node_modules/protobufjs/src/service.js +5 -7
  184. package/node_modules/protobufjs/src/type.js +3 -1
  185. package/node_modules/protobufjs/src/util/minimal.js +1 -4
  186. package/node_modules/protobufjs/src/verifier.js +1 -1
  187. package/node_modules/semver/classes/range.js +11 -2
  188. package/node_modules/semver/package.json +2 -2
  189. package/node_modules/strnum/CHANGELOG.md +8 -0
  190. package/node_modules/strnum/README.md +9 -0
  191. package/node_modules/strnum/package.json +4 -1
  192. package/node_modules/strnum/strnum.js +9 -1
  193. package/package.json +6 -6
  194. package/slingshot/index.js +260 -258
  195. package/node_modules/@protobufjs/inquire/CHANGELOG.md +0 -8
  196. package/node_modules/@protobufjs/inquire/LICENSE +0 -26
  197. package/node_modules/@protobufjs/inquire/README.md +0 -13
  198. package/node_modules/@protobufjs/inquire/index.d.ts +0 -10
  199. package/node_modules/@protobufjs/inquire/index.js +0 -38
  200. package/node_modules/@protobufjs/inquire/package.json +0 -21
  201. package/node_modules/@protobufjs/inquire/tests/data/array.js +0 -1
  202. package/node_modules/@protobufjs/inquire/tests/data/emptyArray.js +0 -1
  203. package/node_modules/@protobufjs/inquire/tests/data/emptyObject.js +0 -1
  204. package/node_modules/@protobufjs/inquire/tests/data/object.js +0 -1
  205. package/node_modules/@protobufjs/inquire/tests/index.js +0 -20
@@ -11,7 +11,6 @@ const TERMINAL_PROGRESS_ACTIVE_SEQUENCE = "\x1b]9;4;3\x07";
11
11
  const TERMINAL_PROGRESS_CLEAR_SEQUENCE = "\x1b]9;4;0;\x07";
12
12
  const APPLE_TERMINAL_SHIFT_ENTER_SEQUENCE = "\x1b[13;2u";
13
13
  const DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS = 7;
14
- const KITTY_KEYBOARD_PROTOCOL_FALLBACK_TIMEOUT_MS = 150;
15
14
  const KEYBOARD_PROTOCOL_RESPONSE_FRAGMENT_TIMEOUT_MS = 150;
16
15
  const KITTY_KEYBOARD_PROTOCOL_QUERY = `\x1b[>${DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS}u\x1b[?u\x1b[c`;
17
16
  export function parseKeyboardProtocolNegotiationSequence(sequence) {
@@ -24,8 +23,8 @@ export function parseKeyboardProtocolNegotiationSequence(sequence) {
24
23
  }
25
24
  return undefined;
26
25
  }
27
- function isKeyboardProtocolNegotiationSequencePrefix(sequence, allowBareEscapePrefix) {
28
- return (allowBareEscapePrefix && sequence === "\x1b") || sequence === "\x1b[" || /^\x1b\[\?[\d;]*$/.test(sequence);
26
+ function isKeyboardProtocolNegotiationSequencePrefix(sequence) {
27
+ return sequence === "\x1b[" || /^\x1b\[\?[\d;]*$/.test(sequence);
29
28
  }
30
29
  export function isAppleTerminalSession() {
31
30
  return process.platform === "darwin" && process.env.TERM_PROGRAM === "Apple_Terminal";
@@ -45,10 +44,7 @@ export class ProcessTerminal {
45
44
  _kittyProtocolActive = false;
46
45
  _modifyOtherKeysActive = false;
47
46
  keyboardProtocolPushed = false;
48
- keyboardProtocolNegotiationPending = false;
49
- keyboardProtocolLateResponsePending = false;
50
47
  keyboardProtocolNegotiationBuffer = "";
51
- keyboardProtocolFallbackTimer;
52
48
  keyboardProtocolBufferFlushTimer;
53
49
  stdinBuffer;
54
50
  stdinDataHandler;
@@ -72,6 +68,9 @@ export class ProcessTerminal {
72
68
  get kittyProtocolActive() {
73
69
  return this._kittyProtocolActive;
74
70
  }
71
+ get modifyOtherKeysActive() {
72
+ return this._modifyOtherKeysActive;
73
+ }
75
74
  start(onInput, onResize) {
76
75
  this.inputHandler = onInput;
77
76
  this.resizeHandler = onResize;
@@ -96,8 +95,7 @@ export class ProcessTerminal {
96
95
  // events that lose modifier information. Must run AFTER setRawMode(true)
97
96
  // since that resets console mode flags.
98
97
  this.enableWindowsVTInput();
99
- // Query and enable Kitty keyboard protocol
100
- // The query handler intercepts input temporarily, then installs the user's handler
98
+ // Query Kitty keyboard protocol and fall back to modifyOtherKeys when DA confirms no Kitty response.
101
99
  // See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/
102
100
  this.queryAndEnableKittyProtocol();
103
101
  }
@@ -113,24 +111,13 @@ export class ProcessTerminal {
113
111
  this.stdinBuffer = new StdinBuffer({ timeout: 10 });
114
112
  // Forward individual sequences to the input handler
115
113
  this.stdinBuffer.on("data", (sequence) => {
116
- if (this.keyboardProtocolNegotiationPending) {
117
- const negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence, true);
118
- if (negotiationSequence === "pending") {
119
- return; // Wait for the rest of a split negotiation response.
120
- }
121
- if (this.handleKeyboardProtocolNegotiationSequence(negotiationSequence)) {
122
- return;
123
- }
114
+ const negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence);
115
+ if (negotiationSequence === "pending") {
116
+ this.scheduleKeyboardProtocolNegotiationBufferFlush();
117
+ return; // Wait briefly for the rest of a split Kitty response.
124
118
  }
125
- if (this.keyboardProtocolLateResponsePending) {
126
- const negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence, false);
127
- if (negotiationSequence === "pending") {
128
- this.scheduleKeyboardProtocolNegotiationBufferFlush();
129
- return; // Wait for the rest of a split late negotiation response.
130
- }
131
- if (this.handleKeyboardProtocolNegotiationSequence(negotiationSequence)) {
132
- return;
133
- }
119
+ if (this.handleKeyboardProtocolNegotiationSequence(negotiationSequence)) {
120
+ return;
134
121
  }
135
122
  this.forwardInputSequence(sequence);
136
123
  });
@@ -150,9 +137,8 @@ export class ProcessTerminal {
150
137
  *
151
138
  * Kitty's progressive enhancement detection requires requesting the desired
152
139
  * flags before querying them. The trailing DA query is a sentinel supported by
153
- * terminals that do not know Kitty keyboard protocol. A short timeout remains
154
- * as a backup for terminals, PTYs, and SSH sessions that delay, split, or drop
155
- * the DA response.
140
+ * terminals that do not know Kitty keyboard protocol; receiving DA before a
141
+ * Kitty response enables modifyOtherKeys fallback without a startup timeout.
156
142
  *
157
143
  * The requested flags are:
158
144
  * - 1 = disambiguate escape codes
@@ -163,45 +149,32 @@ export class ProcessTerminal {
163
149
  this.setupStdinBuffer();
164
150
  process.stdin.on("data", this.stdinDataHandler);
165
151
  this.keyboardProtocolPushed = true;
166
- this.keyboardProtocolNegotiationPending = true;
167
- this.keyboardProtocolLateResponsePending = false;
168
152
  this.clearKeyboardProtocolNegotiationBuffer();
169
153
  process.stdout.write(KITTY_KEYBOARD_PROTOCOL_QUERY);
170
- this.keyboardProtocolFallbackTimer = setTimeout(() => {
171
- this.keyboardProtocolFallbackTimer = undefined;
172
- this.keyboardProtocolNegotiationPending = false;
173
- this.keyboardProtocolLateResponsePending = true;
174
- if (this.keyboardProtocolNegotiationBuffer === "\x1b") {
175
- this.flushKeyboardProtocolNegotiationBufferAsInput();
176
- }
177
- else {
178
- this.scheduleKeyboardProtocolNegotiationBufferFlush();
179
- }
180
- this.enableModifyOtherKeys();
181
- }, KITTY_KEYBOARD_PROTOCOL_FALLBACK_TIMEOUT_MS);
182
154
  }
183
155
  handleKeyboardProtocolNegotiationSequence(negotiationSequence) {
184
156
  if (!negotiationSequence)
185
157
  return false;
158
+ this.clearKeyboardProtocolNegotiationBuffer();
186
159
  if (negotiationSequence.type === "kitty-flags") {
187
- if (negotiationSequence.flags !== 0 && !this._kittyProtocolActive) {
188
- this._kittyProtocolActive = true;
189
- setKittyProtocolActive(true);
190
- this.keyboardProtocolNegotiationPending = false;
191
- this.keyboardProtocolLateResponsePending = true;
192
- this.clearKeyboardProtocolNegotiationBuffer();
193
- this.clearKeyboardProtocolFallbackTimer();
160
+ if (negotiationSequence.flags !== 0) {
161
+ this.disableModifyOtherKeys();
162
+ if (!this._kittyProtocolActive) {
163
+ this._kittyProtocolActive = true;
164
+ setKittyProtocolActive(true);
165
+ }
166
+ }
167
+ else {
168
+ this.enableModifyOtherKeys();
194
169
  }
195
170
  return true;
196
171
  }
197
- this.keyboardProtocolNegotiationPending = false;
198
- this.keyboardProtocolLateResponsePending = true;
199
- this.clearKeyboardProtocolNegotiationBuffer();
200
- this.clearKeyboardProtocolFallbackTimer();
201
- this.enableModifyOtherKeys();
172
+ if (!this._kittyProtocolActive) {
173
+ this.enableModifyOtherKeys();
174
+ }
202
175
  return true;
203
176
  }
204
- readKeyboardProtocolNegotiationSequence(sequence, allowBareEscapePrefix) {
177
+ readKeyboardProtocolNegotiationSequence(sequence) {
205
178
  if (this.keyboardProtocolNegotiationBuffer) {
206
179
  const bufferedSequence = this.keyboardProtocolNegotiationBuffer + sequence;
207
180
  const negotiationSequence = parseKeyboardProtocolNegotiationSequence(bufferedSequence);
@@ -209,7 +182,7 @@ export class ProcessTerminal {
209
182
  this.clearKeyboardProtocolNegotiationBuffer();
210
183
  return negotiationSequence;
211
184
  }
212
- if (isKeyboardProtocolNegotiationSequencePrefix(bufferedSequence, allowBareEscapePrefix)) {
185
+ if (isKeyboardProtocolNegotiationSequencePrefix(bufferedSequence)) {
213
186
  this.setKeyboardProtocolNegotiationBuffer(bufferedSequence);
214
187
  return "pending";
215
188
  }
@@ -218,7 +191,7 @@ export class ProcessTerminal {
218
191
  const negotiationSequence = parseKeyboardProtocolNegotiationSequence(sequence);
219
192
  if (negotiationSequence)
220
193
  return negotiationSequence;
221
- if (isKeyboardProtocolNegotiationSequencePrefix(sequence, allowBareEscapePrefix)) {
194
+ if (isKeyboardProtocolNegotiationSequencePrefix(sequence)) {
222
195
  this.setKeyboardProtocolNegotiationBuffer(sequence);
223
196
  return "pending";
224
197
  }
@@ -266,11 +239,11 @@ export class ProcessTerminal {
266
239
  process.stdout.write("\x1b[>4;2m");
267
240
  this._modifyOtherKeysActive = true;
268
241
  }
269
- clearKeyboardProtocolFallbackTimer() {
270
- if (!this.keyboardProtocolFallbackTimer)
242
+ disableModifyOtherKeys() {
243
+ if (!this._modifyOtherKeysActive)
271
244
  return;
272
- clearTimeout(this.keyboardProtocolFallbackTimer);
273
- this.keyboardProtocolFallbackTimer = undefined;
245
+ process.stdout.write("\x1b[>4;0m");
246
+ this._modifyOtherKeysActive = false;
274
247
  }
275
248
  /**
276
249
  * On Windows, add ENABLE_VIRTUAL_TERMINAL_INPUT (0x0200) to the stdin
@@ -311,10 +284,8 @@ export class ProcessTerminal {
311
284
  }
312
285
  }
313
286
  async drainInput(maxMs = 1000, idleMs = 50) {
314
- const shouldDisableKittyProtocol = this.keyboardProtocolPushed || this._kittyProtocolActive || this.keyboardProtocolNegotiationPending;
315
- this.keyboardProtocolLateResponsePending = false;
287
+ const shouldDisableKittyProtocol = this.keyboardProtocolPushed || this._kittyProtocolActive;
316
288
  this.clearKeyboardProtocolNegotiationBuffer();
317
- this.clearKeyboardProtocolFallbackTimer();
318
289
  if (shouldDisableKittyProtocol) {
319
290
  // Disable Kitty keyboard protocol first so any late key releases
320
291
  // do not generate new Kitty escape sequences.
@@ -323,11 +294,7 @@ export class ProcessTerminal {
323
294
  this._kittyProtocolActive = false;
324
295
  setKittyProtocolActive(false);
325
296
  }
326
- this.keyboardProtocolNegotiationPending = false;
327
- if (this._modifyOtherKeysActive) {
328
- process.stdout.write("\x1b[>4;0m");
329
- this._modifyOtherKeysActive = false;
330
- }
297
+ this.disableModifyOtherKeys();
331
298
  const previousHandler = this.inputHandler;
332
299
  this.inputHandler = undefined;
333
300
  let lastDataTime = Date.now();
@@ -358,10 +325,8 @@ export class ProcessTerminal {
358
325
  }
359
326
  // Disable bracketed paste mode
360
327
  process.stdout.write("\x1b[?2004l");
361
- const shouldDisableKittyProtocol = this.keyboardProtocolPushed || this._kittyProtocolActive || this.keyboardProtocolNegotiationPending;
362
- this.keyboardProtocolLateResponsePending = false;
328
+ const shouldDisableKittyProtocol = this.keyboardProtocolPushed || this._kittyProtocolActive;
363
329
  this.clearKeyboardProtocolNegotiationBuffer();
364
- this.clearKeyboardProtocolFallbackTimer();
365
330
  // Disable Kitty keyboard protocol if not already done by drainInput()
366
331
  if (shouldDisableKittyProtocol) {
367
332
  process.stdout.write("\x1b[<u");
@@ -369,11 +334,7 @@ export class ProcessTerminal {
369
334
  this._kittyProtocolActive = false;
370
335
  setKittyProtocolActive(false);
371
336
  }
372
- this.keyboardProtocolNegotiationPending = false;
373
- if (this._modifyOtherKeysActive) {
374
- process.stdout.write("\x1b[>4;0m");
375
- this._modifyOtherKeysActive = false;
376
- }
337
+ this.disableModifyOtherKeys();
377
338
  // Clean up StdinBuffer
378
339
  if (this.stdinBuffer) {
379
340
  this.stdinBuffer.destroy();
@@ -6,28 +6,42 @@ import * as os from "node:os";
6
6
  import * as path from "node:path";
7
7
  import { performance } from "node:perf_hooks";
8
8
  import { isKeyRelease, matchesKey } from "./keys.js";
9
+ import { isOsc11BackgroundColorResponse, parseOsc11BackgroundColor } from "./terminal-colors.js";
9
10
  import { deleteKittyImage, getCapabilities, isImageLine, setCellDimensions } from "./terminal-image.js";
10
11
  import { extractSegments, normalizeTerminalOutput, sliceByColumn, sliceWithWidth, visibleWidth } from "./utils.js";
11
12
  const KITTY_SEQUENCE_PREFIX = "\x1b_G";
12
- function extractKittyImageIds(line) {
13
+ function parseKittyImageHeader(line) {
13
14
  const sequenceStart = line.indexOf(KITTY_SEQUENCE_PREFIX);
14
15
  if (sequenceStart === -1)
15
- return [];
16
+ return undefined;
16
17
  const paramsStart = sequenceStart + KITTY_SEQUENCE_PREFIX.length;
17
18
  const paramsEnd = line.indexOf(";", paramsStart);
18
19
  if (paramsEnd === -1)
19
- return [];
20
+ return undefined;
21
+ const ids = [];
22
+ let rows = 1;
20
23
  const params = line.slice(paramsStart, paramsEnd);
21
24
  for (const param of params.split(",")) {
22
25
  const [key, value] = param.split("=", 2);
23
- if (key !== "i" || value === undefined)
26
+ if (value === undefined)
24
27
  continue;
25
- const id = Number(value);
26
- if (Number.isInteger(id) && id > 0 && id <= 0xffffffff) {
27
- return [id];
28
+ const numberValue = Number(value);
29
+ if (!Number.isInteger(numberValue) || numberValue <= 0 || numberValue > 0xffffffff)
30
+ continue;
31
+ if (key === "i") {
32
+ ids.push(numberValue);
33
+ }
34
+ else if (key === "r") {
35
+ rows = numberValue;
28
36
  }
29
37
  }
30
- return [];
38
+ return { ids, rows };
39
+ }
40
+ function extractKittyImageIds(line) {
41
+ return parseKittyImageHeader(line)?.ids ?? [];
42
+ }
43
+ function extractKittyImageRows(line) {
44
+ return parseKittyImageHeader(line)?.rows ?? 1;
31
45
  }
32
46
  /** Type guard to check if a component implements Focusable */
33
47
  export function isFocusable(component) {
@@ -115,6 +129,8 @@ export class TUI extends Container {
115
129
  previousViewportTop = 0; // Track previous viewport top for resize-aware cursor moves
116
130
  fullRedrawCount = 0;
117
131
  stopped = false;
132
+ pendingOsc11BackgroundReplies = 0;
133
+ pendingOsc11BackgroundQueries = [];
118
134
  // Overlay stack for modal components rendered on top of base content
119
135
  focusOrderCounter = 0;
120
136
  overlayStack = [];
@@ -505,6 +521,9 @@ export class TUI extends Container {
505
521
  }, delay);
506
522
  }
507
523
  handleInput(data) {
524
+ if (this.consumeOsc11BackgroundResponse(data)) {
525
+ return;
526
+ }
508
527
  if (this.inputListeners.size > 0) {
509
528
  let current = data;
510
529
  for (const listener of this.inputListeners) {
@@ -570,6 +589,27 @@ export class TUI extends Container {
570
589
  this.requestRender();
571
590
  }
572
591
  }
592
+ consumeOsc11BackgroundResponse(data) {
593
+ if (this.pendingOsc11BackgroundReplies <= 0) {
594
+ return false;
595
+ }
596
+ if (!isOsc11BackgroundColorResponse(data)) {
597
+ return false;
598
+ }
599
+ const rgb = parseOsc11BackgroundColor(data);
600
+ this.pendingOsc11BackgroundReplies -= 1;
601
+ const query = this.pendingOsc11BackgroundQueries.shift();
602
+ if (query && !query.settled) {
603
+ query.settled = true;
604
+ if (query.timer) {
605
+ clearTimeout(query.timer);
606
+ query.timer = undefined;
607
+ }
608
+ query.resolve?.(rgb);
609
+ query.resolve = undefined;
610
+ }
611
+ return true;
612
+ }
573
613
  consumeCellSizeResponse(data) {
574
614
  // Response format: ESC [ 6 ; height ; width t
575
615
  const match = data.match(/^\x1b\[6;(\d+);(\d+)t$/);
@@ -789,14 +829,37 @@ export class TUI extends Container {
789
829
  }
790
830
  return buffer;
791
831
  }
792
- expandLastChangedForKittyImages(firstChanged, lastChanged) {
832
+ getKittyImageReservedRows(lines, index, maxIndex = lines.length - 1) {
833
+ const rows = extractKittyImageRows(lines[index] ?? "");
834
+ if (rows <= 1)
835
+ return 1;
836
+ const maxRows = Math.min(rows, maxIndex - index + 1, lines.length - index);
837
+ let reservedRows = 1;
838
+ while (reservedRows < maxRows) {
839
+ const line = lines[index + reservedRows] ?? "";
840
+ if (isImageLine(line) || visibleWidth(line) > 0)
841
+ break;
842
+ reservedRows++;
843
+ }
844
+ return reservedRows;
845
+ }
846
+ expandChangedRangeForKittyImages(firstChanged, lastChanged, newLines) {
847
+ let expandedFirstChanged = firstChanged;
793
848
  let expandedLastChanged = lastChanged;
794
- for (let i = firstChanged; i < this.previousLines.length; i++) {
795
- if (extractKittyImageIds(this.previousLines[i]).length > 0) {
796
- expandedLastChanged = Math.max(expandedLastChanged, i);
849
+ const expandForLines = (lines) => {
850
+ for (let i = 0; i < lines.length; i++) {
851
+ if (extractKittyImageIds(lines[i]).length === 0)
852
+ continue;
853
+ const blockEnd = i + this.getKittyImageReservedRows(lines, i) - 1;
854
+ if (i >= firstChanged || (i <= lastChanged && blockEnd >= firstChanged)) {
855
+ expandedFirstChanged = Math.min(expandedFirstChanged, i);
856
+ expandedLastChanged = Math.max(expandedLastChanged, blockEnd);
857
+ }
797
858
  }
798
- }
799
- return expandedLastChanged;
859
+ };
860
+ expandForLines(this.previousLines);
861
+ expandForLines(newLines);
862
+ return { firstChanged: expandedFirstChanged, lastChanged: expandedLastChanged };
800
863
  }
801
864
  deleteChangedKittyImages(firstChanged, lastChanged) {
802
865
  if (firstChanged < 0 || lastChanged < firstChanged)
@@ -910,7 +973,20 @@ export class TUI extends Container {
910
973
  for (let i = 0; i < newLines.length; i++) {
911
974
  if (i > 0)
912
975
  buffer += "\r\n";
913
- buffer += newLines[i];
976
+ const line = newLines[i];
977
+ const isImage = isImageLine(line);
978
+ const imageReservedRows = isImage ? this.getKittyImageReservedRows(newLines, i) : 1;
979
+ if (imageReservedRows > 1 && imageReservedRows <= height) {
980
+ for (let row = 1; row < imageReservedRows; row++) {
981
+ buffer += "\r\n";
982
+ }
983
+ buffer += `\x1b[${imageReservedRows - 1}A`;
984
+ buffer += line;
985
+ buffer += `\x1b[${imageReservedRows - 1}B`;
986
+ i += imageReservedRows - 1;
987
+ continue;
988
+ }
989
+ buffer += line;
914
990
  }
915
991
  buffer += "\x1b[?2026l"; // End synchronized output
916
992
  this.terminal.write(buffer);
@@ -989,7 +1065,9 @@ export class TUI extends Container {
989
1065
  lastChanged = newLines.length - 1;
990
1066
  }
991
1067
  if (firstChanged !== -1) {
992
- lastChanged = this.expandLastChangedForKittyImages(firstChanged, lastChanged);
1068
+ const expandedRange = this.expandChangedRangeForKittyImages(firstChanged, lastChanged, newLines);
1069
+ firstChanged = expandedRange.firstChanged;
1070
+ lastChanged = expandedRange.lastChanged;
993
1071
  }
994
1072
  const appendStart = appendedLines && firstChanged === this.previousLines.length && firstChanged > 0;
995
1073
  // No changes - but still need to update hardware cursor position if it moved
@@ -1024,16 +1102,18 @@ export class TUI extends Container {
1024
1102
  fullRender(true);
1025
1103
  return;
1026
1104
  }
1027
- if (extraLines > 0) {
1028
- buffer += "\x1b[1B";
1105
+ const clearStartOffset = newLines.length === 0 ? 0 : 1;
1106
+ if (extraLines > 0 && clearStartOffset > 0) {
1107
+ buffer += `\x1b[${clearStartOffset}B`;
1029
1108
  }
1030
1109
  for (let i = 0; i < extraLines; i++) {
1031
1110
  buffer += "\r\x1b[2K";
1032
1111
  if (i < extraLines - 1)
1033
1112
  buffer += "\x1b[1B";
1034
1113
  }
1035
- if (extraLines > 0) {
1036
- buffer += `\x1b[${extraLines}A`;
1114
+ const moveBack = Math.max(0, extraLines - 1 + clearStartOffset);
1115
+ if (moveBack > 0) {
1116
+ buffer += `\x1b[${moveBack}A`;
1037
1117
  }
1038
1118
  buffer += "\x1b[?2026l";
1039
1119
  this.terminal.write(buffer);
@@ -1088,9 +1168,27 @@ export class TUI extends Container {
1088
1168
  for (let i = firstChanged; i <= renderEnd; i++) {
1089
1169
  if (i > firstChanged)
1090
1170
  buffer += "\r\n";
1091
- buffer += "\x1b[2K"; // Clear current line
1092
1171
  const line = newLines[i];
1093
1172
  const isImage = isImageLine(line);
1173
+ const imageReservedRows = isImage ? this.getKittyImageReservedRows(newLines, i, renderEnd) : 1;
1174
+ if (imageReservedRows > 1) {
1175
+ const imageStartScreenRow = i - viewportTop;
1176
+ if (imageStartScreenRow < 0 || imageStartScreenRow + imageReservedRows > height) {
1177
+ logRedraw(`kitty image pre-clear would scroll (${imageStartScreenRow} + ${imageReservedRows} > ${height})`);
1178
+ fullRender(true);
1179
+ return;
1180
+ }
1181
+ buffer += "\x1b[2K";
1182
+ for (let row = 1; row < imageReservedRows; row++) {
1183
+ buffer += "\r\n\x1b[2K";
1184
+ }
1185
+ buffer += `\x1b[${imageReservedRows - 1}A`;
1186
+ buffer += line;
1187
+ buffer += `\x1b[${imageReservedRows - 1}B`;
1188
+ i += imageReservedRows - 1;
1189
+ continue;
1190
+ }
1191
+ buffer += "\x1b[2K"; // Clear current line
1094
1192
  if (!isImage && visibleWidth(line) > width) {
1095
1193
  // Log all lines to crash file for debugging
1096
1194
  const crashLogPath = path.join(os.homedir(), ".pi", "agent", "pi-crash.log");
@@ -1217,5 +1315,31 @@ export class TUI extends Container {
1217
1315
  this.terminal.hideCursor();
1218
1316
  }
1219
1317
  }
1318
+ /**
1319
+ * Query the terminal's default background color with OSC 11 (`ESC ] 11 ; ? BEL`).
1320
+ * @param timeoutMs Query timeout in milliseconds.
1321
+ * @returns Promise containing the parsed RGB color, or undefined if it times out or fails to parse.
1322
+ */
1323
+ queryTerminalBackgroundColor({ timeoutMs }) {
1324
+ return new Promise((resolve) => {
1325
+ const query = {
1326
+ settled: false,
1327
+ resolve,
1328
+ timer: undefined,
1329
+ };
1330
+ query.timer = setTimeout(() => {
1331
+ if (query.settled) {
1332
+ return;
1333
+ }
1334
+ query.settled = true;
1335
+ query.timer = undefined;
1336
+ query.resolve?.(undefined);
1337
+ query.resolve = undefined;
1338
+ }, timeoutMs);
1339
+ this.pendingOsc11BackgroundQueries.push(query);
1340
+ this.pendingOsc11BackgroundReplies += 1;
1341
+ this.terminal.write("\x1b]11;?\x07");
1342
+ });
1343
+ }
1220
1344
  }
1221
1345
  //# sourceMappingURL=tui.js.map
@@ -37,6 +37,7 @@ const rgiEmojiRegex = /^\p{RGI_Emoji}$/v;
37
37
  // Cache for non-ASCII strings
38
38
  const WIDTH_CACHE_SIZE = 512;
39
39
  const widthCache = new Map();
40
+ export const cjkBreakRegex = /[\p{Script_Extensions=Han}\p{Script_Extensions=Hiragana}\p{Script_Extensions=Katakana}\p{Script_Extensions=Hangul}\p{Script_Extensions=Bopomofo}]/u;
40
41
  function isPrintableAscii(str) {
41
42
  for (let i = 0; i < str.length; i++) {
42
43
  const code = str.charCodeAt(i);
@@ -549,8 +550,16 @@ function splitIntoTokensWithAnsi(text) {
549
550
  const tokens = [];
550
551
  let current = "";
551
552
  let pendingAnsi = ""; // ANSI codes waiting to be attached to next visible content
552
- let inWhitespace = false;
553
+ let currentKind = null;
553
554
  let i = 0;
555
+ const flushCurrent = () => {
556
+ if (!current) {
557
+ return;
558
+ }
559
+ tokens.push(current);
560
+ current = "";
561
+ currentKind = null;
562
+ };
554
563
  while (i < text.length) {
555
564
  const ansiResult = extractAnsiCode(text, i);
556
565
  if (ansiResult) {
@@ -559,25 +568,44 @@ function splitIntoTokensWithAnsi(text) {
559
568
  i += ansiResult.length;
560
569
  continue;
561
570
  }
562
- const char = text[i];
563
- const charIsSpace = char === " ";
564
- if (charIsSpace !== inWhitespace && current) {
565
- // Switching between whitespace and non-whitespace, push current token
566
- tokens.push(current);
567
- current = "";
571
+ let end = i;
572
+ while (end < text.length && !extractAnsiCode(text, end)) {
573
+ end++;
568
574
  }
569
- // Attach any pending ANSI codes to this visible character
570
- if (pendingAnsi) {
571
- current += pendingAnsi;
572
- pendingAnsi = "";
575
+ for (const { segment } of graphemeSegmenter.segment(text.slice(i, end))) {
576
+ const segmentIsSpace = segment === " ";
577
+ if (!segmentIsSpace && cjkBreakRegex.test(segment)) {
578
+ flushCurrent();
579
+ const token = pendingAnsi + segment;
580
+ pendingAnsi = "";
581
+ tokens.push(token);
582
+ continue;
583
+ }
584
+ const segmentKind = segmentIsSpace ? "space" : "word";
585
+ if (current && currentKind !== segmentKind) {
586
+ flushCurrent();
587
+ }
588
+ // Attach any pending ANSI codes to this visible character
589
+ if (pendingAnsi) {
590
+ current += pendingAnsi;
591
+ pendingAnsi = "";
592
+ }
593
+ currentKind = segmentKind;
594
+ current += segment;
573
595
  }
574
- inWhitespace = charIsSpace;
575
- current += char;
576
- i++;
596
+ i = end;
577
597
  }
578
598
  // Handle any remaining pending ANSI codes (attach to last token)
579
599
  if (pendingAnsi) {
580
- current += pendingAnsi;
600
+ if (current) {
601
+ current += pendingAnsi;
602
+ }
603
+ else if (tokens.length > 0) {
604
+ tokens[tokens.length - 1] += pendingAnsi;
605
+ }
606
+ else {
607
+ current = pendingAnsi;
608
+ }
581
609
  }
582
610
  if (current) {
583
611
  tokens.push(current);
@@ -998,7 +1026,7 @@ export function extractSegments(line, beforeEnd, afterStart, afterLen, strictAft
998
1026
  textEnd++;
999
1027
  for (const { segment } of graphemeSegmenter.segment(line.slice(i, textEnd))) {
1000
1028
  const w = graphemeWidth(segment);
1001
- if (currentCol < beforeEnd) {
1029
+ if (currentCol < beforeEnd && currentCol + w <= beforeEnd) {
1002
1030
  if (pendingAnsiBefore) {
1003
1031
  before += pendingAnsiBefore;
1004
1032
  pendingAnsiBefore = "";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@earendil-works/pi-tui",
3
- "version": "0.78.1",
3
+ "version": "0.79.3",
4
4
  "description": "Terminal User Interface library with differential rendering for efficient text-based applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nodable/entities",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
4
4
  "description": "Entity parser for XML, HTML, External entites with security and NCR control",
5
5
  "main": "./src/index.js",
6
6
  "type": "module",
@@ -25,10 +25,13 @@
25
25
  "xml",
26
26
  "html",
27
27
  "entity",
28
+ "entities",
29
+ "stringify",
28
30
  "encode",
29
31
  "decode",
30
32
  "ncr",
31
33
  "security",
34
+ "safe",
32
35
  "performance"
33
36
  ],
34
37
  "author": "Amit Gupta (https://solothought.com)",