Skip to content

fix(app): preserve terminal selection after mouseup#332

Merged
skulidropek merged 1 commit into
mainfrom
issue-331
May 20, 2026
Merged

fix(app): preserve terminal selection after mouseup#332
skulidropek merged 1 commit into
mainfrom
issue-331

Conversation

@skulidropek
Copy link
Copy Markdown
Member

Fixes #331.

Summary

  • suppress the original forced-selection mouseup while terminal mouse tracking is active so xterm does not report it as pty input and clear the new selection
  • replay a clean document mouseup with the forced selection modifier so xterm selection finalization still runs
  • add regression coverage for active mouse tracking, inactive mouse tracking, listener cleanup, and right-click one-shot selection behavior

Verification

  • bun --cwd packages/app vitest run tests/docker-git/terminal-copy-interaction.test.ts tests/docker-git/terminal-query-suppression.test.ts tests/docker-git/terminal-panel-runtime-core.test.ts tests/docker-git/terminal-wheel-scroll.test.ts
  • bun run --cwd packages/app lint
  • bun run --cwd packages/app lint:tests
  • bun run --cwd packages/app typecheck
  • bun run --cwd packages/app build:web
  • git diff --check

Mathematical guarantees

  • Invariant: forced browser selection drag in active mouse-tracking mode does not emit the release event as terminal input.
  • Invariant: xterm still receives a forced document mouseup to finalize selection state.
  • Invariant: right-click selection context and inactive mouse-tracking behavior remain unchanged.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Refactor

    • Улучшена обработка событий мыши при копировании текста в терминале, включая более полный захват координат и состояния клавиш модификаторов.
    • Оптимизирована логика завершения drag-выделения с корректной обработкой mouseup-событий.
  • Tests

    • Добавлены новые тестовые утилиты для проверки взаимодействия с копированием и drag-операциями в терминале.

Walkthrough

PR расширяет типы mouse-событий терминала опциональными полями координат и модификаторов, добавляет логику подавления и реплея mouseup при завершении принудительного выделения текста, вынимает тестовую инфраструктуру в отдельный файл фикстур и добавляет тесты для верификации нового поведения.

Changes

Обработка завершения терминального выделения мышью

Layer / File(s) Summary
Типы mouse-событий и контракты слушателей
packages/app/src/web/terminal-copy-interaction.ts
TerminalCopyMouseEvent расширен опциональными полями (clientX, clientY, screenX, screenY, button, buttons, altKey, shiftKey). Регистрации слушателей обновлены для передачи полного типа события вместо отдельных модификаторов.
Вспомогательные функции для mouseup
packages/app/src/web/terminal-copy-interaction.ts
Добавлены функции нормализации числовых/boolean-полей, создание MouseEventInit, копирование свойств события через Reflect.defineProperty, подавление оригинального mouseup и отправка форсированного события в selectionDragTarget.
Логика контроллера при отпускании мыши
packages/app/src/web/terminal-copy-interaction.ts
При активном forcedSelectionDrag обработчик onMouseUp теперь подавляет оригинальное событие, очищает состояние выделения (clearSelectionDrag) и инициирует реплей нового mouseup в selectionDragTarget.
Инфраструктура тестовых фикстур
packages/app/tests/docker-git/fixtures/terminal-copy-interaction.ts
Новый файл фикстур с типом TerminalCopyTestMouseEvent, классами FakeTerminalCopyMouseEvent (эмуляция событий мыши с подсчётом вызовов), FakeTerminalCopyEventTarget и FakeTerminalCopyHost (симуляция регистрации и диспетчеризации событий с поддержкой capture/bubble), вспомогательные функции mouseEvent, expectNoDragListeners, expectSingleMouseEvent.
Рефакторинг и новые тесты
packages/app/tests/docker-git/terminal-copy-interaction.test.ts
Локальные определения фикстур замещены импортами из нового файла. Добавлены два новых тестовых случая: проверка подавления реального mouseup и реплея события при активном mouse tracking, проверка отсутствия подавления при неактивном tracking. Добавлено утверждение о пустом списке dispatched events в существующем тесте.

Sequence Diagram

sequenceDiagram
  participant Terminal
  participant Controller as TerminalSelectController
  participant Target as selectionDragTarget
  Terminal->>Controller: native mouseup event
  alt forcedSelectionDrag активен
    Controller->>Controller: preventDefault()
    Controller->>Controller: stopPropagation()
    Controller->>Controller: clearSelectionDrag()
    Controller->>Target: dispatchEvent(forced mouseup)
  else forcedSelectionDrag неактивен
    Controller->>Target: пропустить mouseup
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~40 minutes

Possibly related PRs

  • ProverCoderAI/docker-git#322: Основной PR реализует исходную логику терминального copy-взаимодействия в terminal-copy-interaction.ts, в то время как этот PR дополняет её расширением типов и механизмом принудительного mouseup suppression/replay.
  • ProverCoderAI/docker-git#325: Оба PR затрагивают packages/app/src/web/terminal-copy-interaction.ts с пересечением в логике принудительного drag/selection; этот PR дополнительно уточняет генерацию и реплей mouseup при завершении выделения.

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Requirements Alignment ❌ Error Two unaddressed review comments undermine spec compliance: property-based testing not implemented for mouseup invariants; copy event dispatcher missing, hiding potential copy-flow regressions. Address both review comments: (1) Add fast-check property-based tests for active/inactive tracking invariants; (2) Implement copy event dispatch in FakeTerminalCopyEventTarget.dispatchEvent as suggested in review.
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed Заголовок точно описывает основное изменение: восстановление выделения терминала после mouseup события.
Description check ✅ Passed Описание охватывает все необходимые разделы: проблема, решение, проверка и инварианты. Хорошо структурировано и детально.
Linked Issues check ✅ Passed Изменения полностью соответствуют цели #331: предотвращение исчезновения выделения при выборе текста в терминале путем подавления mouseup и реплея очищенного события.
Out of Scope Changes check ✅ Passed Все изменения относятся к решению проблемы #331. Добавлены фиксчуры для тестов, обновлены типы событий и логика обработки mouseup, добавлены тесты регрессии.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Security Regression ✅ Passed Terminal UI event handling code with no command execution, file I/O, credential exposure, or unsafe reflection patterns detected. All property names are hardcoded.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-331

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/app/tests/docker-git/fixtures/terminal-copy-interaction.ts`:
- Around line 202-208: dispatchEvent currently only routes mouse events via
dispatchMouse so "copy" listeners never run; update dispatchEvent to detect
clipboard/copy events (e.g. event.type === "copy" or a helper like
isCopyTestEventType) and invoke the appropriate handler (mirror the existing
dispatchMouse pattern — e.g. call this.dispatchCopy or this.dispatchClipboard
with the event) so addEventListener("copy", ...) registered in the fixture is
actually executed; keep existing behavior of pushing to this.dispatchedEvents
and returning !event.defaultPrevented.

In `@packages/app/tests/docker-git/terminal-copy-interaction.test.ts`:
- Around line 108-173: Add fast-check property-based tests that assert the
invariants currently covered by example cases: for attachTerminalCopyInteraction
with terminalWithSelection("any", "") (active tracking) generate arbitrary
mouseup event properties (clientX, clientY, screenX, screenY, button, buttons,
shiftKey, altKey, etc.) and assert each run that the original host-reported
mouseup is suppressed (up.preventDefaultCalls > 0,
up.stopImmediatePropagationCalls > 0, host-reported mouseReportEvents is empty),
exactly one replay is dispatched to documentTarget
(documentTarget.dispatchedEvents length === 1 and
expectSingleMouseEvent(finalizedSelectionEvents) exists and is not the original
event), and the replayed event preserves position/modifiers but normalizes
button/buttons as in the example; likewise add a property test for
terminalWithSelection("none", "") (inactive tracking) asserting no suppression
(preventDefault/stopImmediatePropagation/stopPropagation calls remain 0) and the
host mouseReportEvents contains the original event; reuse helpers from the test
(FakeTerminalCopyEventTarget, FakeTerminalCopyHost, mouseEvent,
expectSingleMouseEvent, attachTerminalCopyInteraction) and shrink inputs to
primitives for clearer failures.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2083a3f8-6099-4d08-9fcc-c50390e2b8fb

📥 Commits

Reviewing files that changed from the base of the PR and between d9e5acc and 80272a9.

📒 Files selected for processing (3)
  • packages/app/src/web/terminal-copy-interaction.ts
  • packages/app/tests/docker-git/fixtures/terminal-copy-interaction.ts
  • packages/app/tests/docker-git/terminal-copy-interaction.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: E2E (Browser command)
  • GitHub Check: E2E (OpenCode)
  • GitHub Check: E2E (Runtime volumes + SSH)
  • GitHub Check: E2E (Clone auto-open SSH)
  • GitHub Check: Test
  • GitHub Check: Lint
  • GitHub Check: E2E (Login context)
  • GitHub Check: E2E (Clone cache)
  • GitHub Check: Final build (windows-latest)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Implement Functional Core, Imperative Shell (FCIS) pattern: CORE layer contains only pure functions with immutable data and mathematical operations; SHELL layer isolates all effects (IO, network, database). Strict dependency direction: SHELL → CORE (never reverse).
Never use any, unknown, eslint-disable, ts-ignore, or as type assertions (except in rigorously justified cases with documentation). Always use exhaustive union type analysis through .exhaustive() pattern matching.
All external dependencies must be wrapped through typed interfaces and injected via Effect-TS Layer pattern. Never call external services directly from CORE functions.
Use monadic composition with Effect-TS for all effects: Effect<Success, Error, Requirements>. Compose effects through pipe() and Effect.flatMap(). Implement dependency injection via Layer pattern. Handle errors without try/catch blocks.
All functions must be pure in the CORE layer: no side effects (logging, console output, IO operations, mutations). Separate all side effects into the SHELL layer.
Use exhaustive pattern matching with Effect.Match instead of switch statements. Example: Match.value(item).pipe(Match.when(...), Match.exhaustive).
Document all functions with comprehensive TSDoc including: @pure (true/false), @effect (required services), @invariant (mathematical invariants), @precondition, @postcondition, @complexity (time and space), @throws Never (errors must be typed in Effect).
Use functional comment markers for code clarity: CHANGE (brief description), WHY (mathematical/architectural justification), QUOTE(ТЗ) (requirement citation), REF (RTM or message ID), SOURCE (external source with quote), FORMAT THEOREM (∀x ∈ Domain: P(x) → Q(f(x))), PURITY (CORE|SHELL), EFFECT (Effect type signature), INVARIANT (mathematical invariant), COMPLEXITY (time/space).
Define all external service dependencies as Context.Tag classes with fully typed methods returning Effect types. Example: `class Da...

Files:

  • packages/app/src/web/terminal-copy-interaction.ts
  • packages/app/tests/docker-git/fixtures/terminal-copy-interaction.ts
  • packages/app/tests/docker-git/terminal-copy-interaction.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Forbidden constructs in CORE code: any, eslint-disable, ts-ignore, async/await, raw Promise chains (then/catch), Promise.all, try/catch for logic control, console.*, switch statements (use Match with .exhaustive() instead)
All functions must use Effect-TS for composing effects: Effect<Success, Error, Requirements>. No direct async/await, Promise chains, or try/catch in product logic.
Functional comments must include: CHANGE, WHY, QUOTE(ТЗ) or n/a, REF, SOURCE or n/a, FORMAT THEOREM, PURITY (CORE|SHELL), EFFECT signature for SHELL functions, INVARIANT, and COMPLEXITY.
All data mutations must use immutable patterns (ReadonlyArray, readonly properties, Object.freeze); mutation in SHELL only when absolutely necessary and documented.

Files:

  • packages/app/src/web/terminal-copy-interaction.ts
  • packages/app/tests/docker-git/fixtures/terminal-copy-interaction.ts
  • packages/app/tests/docker-git/terminal-copy-interaction.test.ts
**/*.{sh,bash,py,js,ts,jsx,tsx,go,java,rb,php}

📄 CodeRabbit inference engine (Custom checks)

Fail if changed files introduce command injection or unsafe shell/process execution with user-controlled input

Files:

  • packages/app/src/web/terminal-copy-interaction.ts
  • packages/app/tests/docker-git/fixtures/terminal-copy-interaction.ts
  • packages/app/tests/docker-git/terminal-copy-interaction.test.ts
**/*.{py,js,ts,jsx,tsx,go,java,rb,php,sh,bash,c,cpp}

📄 CodeRabbit inference engine (Custom checks)

Fail if changed files introduce path traversal or writes outside intended project/container state directories

Files:

  • packages/app/src/web/terminal-copy-interaction.ts
  • packages/app/tests/docker-git/fixtures/terminal-copy-interaction.ts
  • packages/app/tests/docker-git/terminal-copy-interaction.test.ts
**/*.{js,ts,jsx,tsx,py,java,go,rb,php,sh,bash,yml,yaml,json,env*,toml,cfg,config,dockerfile,dockerignore}

📄 CodeRabbit inference engine (Custom checks)

Fail if changed files expose credentials, tokens, private-keys, or PII in source, generated config, logs, or CI output

Files:

  • packages/app/src/web/terminal-copy-interaction.ts
  • packages/app/tests/docker-git/fixtures/terminal-copy-interaction.ts
  • packages/app/tests/docker-git/terminal-copy-interaction.test.ts
**/*

⚙️ CodeRabbit configuration file

**/*: Ты строгий ревьюер SPEC DRIVEN DEVELOPMENT.

Перед выводами изучи README.md, другие *.md файлы, linked issues,
PR description, PR comments/discussion и релевантную кодовую базу.

Сверь изменения с исходным ТЗ/спекой и обсуждением. Флагай любой уход
от спеки, недокументированное изменение поведения, отсутствие тестов
для заявленного поведения и security-риск. Если спека не видна,
попроси автора добавить ее в issue или PR description.

Проверь решение с точки зрения формальной верификации: какие инварианты,
предусловия и постусловия можно доказать математически, а где доказуемость
слабая. Оцени решение с точки зрения теории игр: устойчивы ли стимулы,
нет ли выгодного обхода правил, и какое решение было бы сильнее.

Files:

  • packages/app/src/web/terminal-copy-interaction.ts
  • packages/app/tests/docker-git/fixtures/terminal-copy-interaction.ts
  • packages/app/tests/docker-git/terminal-copy-interaction.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.{ts,tsx}: Implement property-based testing using fast-check for mathematical properties and invariants. Example: fc.property(fc.array(messageArbitrary), (messages) => isChronologicallySorted(sortMessagesByTimestamp(messages))).
Mock external dependencies in unit tests using Effect's testing utilities. Run tests without Effect runtime for speed. Example: Effect.provide(MockService), Effect.runPromise.

Files:

  • packages/app/tests/docker-git/terminal-copy-interaction.test.ts
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Property-based tests (fast-check) must verify mathematical invariants; unit tests must use Effect test utilities without async/await.

Files:

  • packages/app/tests/docker-git/terminal-copy-interaction.test.ts
🔇 Additional comments (12)
packages/app/src/web/terminal-copy-interaction.ts (10)

33-45: LGTM!


47-65: LGTM!


143-145: LGTM!


147-164: LGTM!


166-192: LGTM!


194-203: LGTM!


205-209: LGTM!


211-216: LGTM!


242-258: LGTM!


235-240: LGTM!

packages/app/tests/docker-git/fixtures/terminal-copy-interaction.ts (1)

1-201: LGTM!

Also applies to: 209-265

packages/app/tests/docker-git/terminal-copy-interaction.test.ts (1)

12-19: LGTM!

Also applies to: 201-201

Comment on lines +202 to +208
dispatchEvent(event: Event): boolean {
this.dispatchedEvents.push(event)
if (isMouseTestEventType(event.type) && isTerminalCopyTestMouseEvent(event)) {
this.dispatchMouse(event.type, event)
}
return !event.defaultPrevented
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

copy-события не доставляются подписчикам в dispatchEvent.

Сейчас диспетчер вызывает обработчики только для mouse-событий. В итоге addEventListener("copy", ...) в фикстуре регистрируется, но никогда не исполняется, что может скрыть регрессии copy-flow в тестах.

💡 Предлагаемый фикс
+const isTerminalCopyTestClipboardEvent = (
+  event: Event
+): event is Event & TerminalCopyTestClipboardEvent => "clipboardData" in event
+
 export class FakeTerminalCopyEventTarget {
@@
   dispatchEvent(event: Event): boolean {
     this.dispatchedEvents.push(event)
+    if (event.type === "copy" && isTerminalCopyTestClipboardEvent(event)) {
+      for (const entry of this.listeners) {
+        if (entry.type === "copy") {
+          entry.listener(event)
+        }
+      }
+      return !event.defaultPrevented
+    }
     if (isMouseTestEventType(event.type) && isTerminalCopyTestMouseEvent(event)) {
       this.dispatchMouse(event.type, event)
     }
     return !event.defaultPrevented
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/app/tests/docker-git/fixtures/terminal-copy-interaction.ts` around
lines 202 - 208, dispatchEvent currently only routes mouse events via
dispatchMouse so "copy" listeners never run; update dispatchEvent to detect
clipboard/copy events (e.g. event.type === "copy" or a helper like
isCopyTestEventType) and invoke the appropriate handler (mirror the existing
dispatchMouse pattern — e.g. call this.dispatchCopy or this.dispatchClipboard
with the event) so addEventListener("copy", ...) registered in the fixture is
actually executed; keep existing behavior of pushing to this.dispatchedEvents
and returning !event.defaultPrevented.

Comment on lines +108 to +173
it("suppresses real mouseup reports and replays a document mouseup for selection finalization", () => {
const documentTarget = new FakeTerminalCopyEventTarget()
const host = new FakeTerminalCopyHost(documentTarget)
const finalizedSelectionEvents: Array<TerminalCopyTestMouseEvent> = []
const mouseReportEvents: Array<TerminalCopyTestMouseEvent> = []
documentTarget.addBubbleMouseListener("mouseup", (event) => {
finalizedSelectionEvents.push(event)
})
host.addBubbleMouseListener("mouseup", (event) => {
mouseReportEvents.push(event)
})
const disposable = attachTerminalCopyInteraction({ host, terminal: terminalWithSelection("any", "") })
const up = mouseEvent(0, "mouseup", {
clientX: 12,
clientY: 34,
screenX: 56,
screenY: 78
})

host.dispatchMouse("mousedown", mouseEvent(0))
host.dispatchBubblingMouse("mouseup", up)

expect(up.shiftKey).toBe(true)
expect(up.preventDefaultCalls).toBe(1)
expect(up.stopImmediatePropagationCalls).toBe(1)
expect(up.stopPropagationCalls).toBeGreaterThanOrEqual(1)
expect(mouseReportEvents).toEqual([])
expect(documentTarget.dispatchedEvents).toHaveLength(1)

const replayed = expectSingleMouseEvent(finalizedSelectionEvents)
expect(replayed).not.toBe(up)
expect(replayed.button).toBe(0)
expect(replayed.buttons).toBe(0)
expect(replayed.clientX).toBe(12)
expect(replayed.clientY).toBe(34)
expect(replayed.screenX).toBe(56)
expect(replayed.screenY).toBe(78)
expect(replayed.shiftKey).toBe(true)
expect(replayed.altKey).toBe(false)
expectNoDragListeners(documentTarget)

disposable.dispose()
})

it("does not suppress or replay mouseup when mouse tracking is inactive", () => {
const documentTarget = new FakeTerminalCopyEventTarget()
const host = new FakeTerminalCopyHost(documentTarget)
const mouseReportEvents: Array<TerminalCopyTestMouseEvent> = []
host.addBubbleMouseListener("mouseup", (event) => {
mouseReportEvents.push(event)
})
const disposable = attachTerminalCopyInteraction({ host, terminal: terminalWithSelection("none", "") })
const up = mouseEvent(0, "mouseup")

host.dispatchMouse("mousedown", mouseEvent(0))
host.dispatchBubblingMouse("mouseup", up)

expect(up.shiftKey).toBe(false)
expect(up.preventDefaultCalls).toBe(0)
expect(up.stopImmediatePropagationCalls).toBe(0)
expect(up.stopPropagationCalls).toBe(0)
expect(documentTarget.dispatchedEvents).toEqual([])
expect(mouseReportEvents).toEqual([up])

disposable.dispose()
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Добавьте property-based проверки инвариантов для новых mouseup сценариев.

Новые кейсы проверяют фиксированные примеры, но здесь удобно и нужно закрепить инварианты (active tracking: всегда suppress реального mouseup и ровно один replay; inactive tracking: never suppress/replay) через fast-check.

As per coding guidelines "Implement property-based testing using fast-check for mathematical properties and invariants."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/app/tests/docker-git/terminal-copy-interaction.test.ts` around lines
108 - 173, Add fast-check property-based tests that assert the invariants
currently covered by example cases: for attachTerminalCopyInteraction with
terminalWithSelection("any", "") (active tracking) generate arbitrary mouseup
event properties (clientX, clientY, screenX, screenY, button, buttons, shiftKey,
altKey, etc.) and assert each run that the original host-reported mouseup is
suppressed (up.preventDefaultCalls > 0, up.stopImmediatePropagationCalls > 0,
host-reported mouseReportEvents is empty), exactly one replay is dispatched to
documentTarget (documentTarget.dispatchedEvents length === 1 and
expectSingleMouseEvent(finalizedSelectionEvents) exists and is not the original
event), and the replayed event preserves position/modifiers but normalizes
button/buttons as in the example; likewise add a property test for
terminalWithSelection("none", "") (inactive tracking) asserting no suppression
(preventDefault/stopImmediatePropagation/stopPropagation calls remain 0) and the
host mouseReportEvents contains the original event; reuse helpers from the test
(FakeTerminalCopyEventTarget, FakeTerminalCopyHost, mouseEvent,
expectSingleMouseEvent, attachTerminalCopyInteraction) and shrink inputs to
primitives for clearer failures.

@skulidropek skulidropek merged commit 4ee12c9 into main May 20, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Почему-то всё равно не работает выделение в терминале

1 participant