Skip to content

feat(terminal): add shared terminal package#362

Open
skulidropek wants to merge 1 commit into
mainfrom
issue-361
Open

feat(terminal): add shared terminal package#362
skulidropek wants to merge 1 commit into
mainfrom
issue-361

Conversation

@skulidropek
Copy link
Copy Markdown
Member

@skulidropek skulidropek commented May 30, 2026

Source TZ / Issues

Summary

  • Added @prover-coder-ai/docker-git-terminal as a workspace package with contracts, core, server, web, cli, and shell entrypoints plus an Effect-style app shell.
  • Moved shared terminal contracts, output replay buffering, image paste planning, and image fetch planning into the terminal package.
  • Rewired API/app consumers through terminal package imports while keeping thin compatibility facades for existing module paths.
  • Added package tests, boundary tests, workspace wiring, lockfile updates, Docker workspace wiring, and CI checks for the new package.

Requirements Alignment

  • Implemented: shared terminal contracts/core/server helpers that API, web, and CLI-facing code can import without depending on each other.
  • Implemented: packages/api terminal services now consume shared contracts/helpers instead of owning duplicate schema/core code.
  • Implemented: packages/app browser and CLI terminal clients now share the terminal contract package without publishing terminal as a runtime dependency of the CLI tarball.
  • Out of scope: moving the full node-pty runtime service and the full React/xterm UI into packages/terminal; those remain in API/app and are now prepared for a follow-up extraction.
  • Security-sensitive changes: image path and image paste validation were moved, not relaxed, and are covered by carried-forward plus package-local tests.

Verification

  • bun run --cwd packages/terminal typecheck
  • bun run --cwd packages/terminal build
  • bun run --cwd packages/terminal test
  • bun run --cwd packages/terminal lint
  • bun run --cwd packages/terminal lint:effect
  • bun run --cwd packages/api typecheck
  • bun run --cwd packages/api lint
  • bun run --cwd packages/api vitest run tests/terminal-output-buffer.test.ts tests/terminal-image-paste-core.test.ts tests/terminal-image-fetch-core.test.ts
  • bun run --cwd packages/app typecheck
  • bun run --cwd packages/app lint
  • bun run --cwd packages/app vitest run tests/docker-git/terminal.test.ts tests/docker-git/terminal-session-client.test.ts
  • bun run --cwd packages/app build:docker-git:reuse-install
  • bash scripts/e2e/local-package-cli.sh
  • docker build -f packages/api/Dockerfile --target workspace-static --build-arg DOCKER_GIT_CONTROLLER_BUILD_SKILLER=0 .
  • bun run build
  • bun run --cwd packages/app build:web:strict
  • bun run check:dist-deps-prune
  • bun run typecheck
  • bun run test
  • git diff --check

@skulidropek
Copy link
Copy Markdown
Member Author

skulidropek commented May 30, 2026

AI Session Backup

Commit: 000c86c
Status: success
Files: 9 (4.67 MB)
Links: README | Manifest

git status

On branch issue-361
Your branch is up to date with 'origin/issue-361'.

nothing to commit, working tree clean

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 30, 2026

Review Change Stack

Warning

Review limit reached

@skulidropek, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 46 minutes and 18 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e8df04b3-0b31-471e-abec-416bdc8e7bdd

📥 Commits

Reviewing files that changed from the base of the PR and between 000c86c and 62ce9bc.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (46)
  • .github/workflows/check.yml
  • package.json
  • packages/api/Dockerfile
  • packages/api/package.json
  • packages/api/src/services/auth-terminal-sessions.ts
  • packages/api/src/services/terminal-image-fetch-core.ts
  • packages/api/src/services/terminal-image-paste-core.ts
  • packages/api/src/services/terminal-output-buffer.ts
  • packages/api/src/services/terminal-sessions.ts
  • packages/api/tests/terminal-image-fetch-core.test.ts
  • packages/api/tests/terminal-image-paste-core.test.ts
  • packages/api/tests/terminal-output-buffer.test.ts
  • packages/app/package.json
  • packages/app/src/docker-git/api-terminal-codec.ts
  • packages/app/src/docker-git/terminal-session-client.ts
  • packages/app/src/shared/terminal-session-schema.ts
  • packages/app/src/web/api-terminal-schema.ts
  • packages/app/src/web/api-types.ts
  • packages/app/src/web/terminal.ts
  • packages/app/tests/docker-git/core-templates.test.ts
  • packages/terminal/biome.json
  • packages/terminal/eslint.config.mjs
  • packages/terminal/eslint.effect-ts-check.config.mjs
  • packages/terminal/package.json
  • packages/terminal/src/app/main.ts
  • packages/terminal/src/app/program.ts
  • packages/terminal/src/cli/index.ts
  • packages/terminal/src/contracts/index.ts
  • packages/terminal/src/contracts/session.ts
  • packages/terminal/src/core/image-paste.ts
  • packages/terminal/src/core/index.ts
  • packages/terminal/src/core/output-buffer.ts
  • packages/terminal/src/index.ts
  • packages/terminal/src/server/image-fetch.ts
  • packages/terminal/src/server/index.ts
  • packages/terminal/src/shell/index.ts
  • packages/terminal/src/web/index.ts
  • packages/terminal/tests/architecture/boundaries.test.ts
  • packages/terminal/tests/contracts/session.test.ts
  • packages/terminal/tests/core/image-paste.test.ts
  • packages/terminal/tests/core/output-buffer.test.ts
  • packages/terminal/tests/server/image-fetch.test.ts
  • packages/terminal/tsconfig.json
  • packages/terminal/vitest.config.ts
  • pnpm-workspace.yaml
  • scripts/e2e/_lib.sh
📝 Walkthrough

Пошаговый обзор

Этот PR создаёт новый пакет @prover-coder-ai/docker-git-terminal в директории packages/terminal и мигрирует терминальное функциональное из локальных реализаций в пакетах api и app в этот централизованный пакет.

Изменения

Создание и настройка пакета terminal

Слой / Файл(ы) Описание
Интеграция в workspace и CI
pnpm-workspace.yaml, .github/workflows/check.yml, package.json
Пакет packages/terminal добавлен в pnpm workspace; в CI workflow добавлены шаги для сборки, типизации, линтинга, тестирования и проверки Effect-TS для терминального пакета; root скрипты обновлены для включения терминального пакета в цепочки сборки и проверки.
Конфигурация инструментов
packages/terminal/tsconfig.json, packages/terminal/vitest.config.ts, packages/terminal/eslint.config.mjs, packages/terminal/eslint.effect-ts-check.config.mjs, packages/terminal/biome.json, packages/terminal/package.json
Настроены TypeScript, Vitest, ESLint с проверкой типов, Biome; определены зависимости на effect и @effect/*; заданы точки входа (contracts, core, server, web, cli, shell) с маппингом на dist/*; включены скрипты сборки и проверок.

Контракты и ядро функционала терминала

Слой / Файл(ы) Описание
Контракты терминальной сессии
packages/terminal/src/contracts/session.ts, packages/terminal/src/contracts/index.ts
Определены Effect-схемы для статуса сессии, структуры сессии с полями (команда, идентификатор, время, коды выхода), клиентских сообщений (input, resize, image, close) и серверных сообщений (ready, output, exit) с JSON-парсерами.
Буфер повторного воспроизведения
packages/terminal/src/core/output-buffer.ts, packages/terminal/src/core/index.ts
Реализован TerminalOutputBuffer с функциями appendTerminalOutput и renderTerminalOutputBuffer для накопления вывода с ограничением по размеру (2 МБ по умолчанию) с обрезкой старых чанков при переполнении.
Обработка вставленных изображений
packages/terminal/src/core/image-paste.ts
Реализована валидация base64-изображений с проверкой поддерживаемого media type (jpeg/png/gif/webp), ограничением по размеру, корректностью base64 и согласованностью размера; формирует безопасное имя файла и контейнерный путь.
Границы runtime
packages/terminal/src/cli/index.ts, packages/terminal/src/shell/index.ts, packages/terminal/src/web/index.ts
Определены дискриминирующие типы для маркировки границ runtime различных адаптеров (CLI, shell, web).
Верхнеуровневый экспорт
packages/terminal/src/index.ts
Переэкспорт контрактов и ядровых утилит через корневой индекс пакета.

Серверная функциональность терминала

Слой / Файл(ы) Описание
Загрузка изображений
packages/terminal/src/server/image-fetch.ts
Функция planTerminalImageFetch валидирует локальные пути с поддержкой file:// URL, проверяет расширения (gif, jpeg, jpg, png, webp), запрещает path traversal сегменты (., .., опасные разделители), преобразует в абсолютный POSIX-путь; ограничение 10 МБ.
Контракты серверной части
packages/terminal/src/server/index.ts
Определены типы TerminalProjectRuntime (контракт эффектов), TerminalShellCommand (команда с опциональными cwd/env), TerminalSessionEvent (union событий Created/Ready/Output/Exited/Failed).

Рефакторинг пакета api

Слой / Файл(ы) Описание
Утилиты буфера
packages/api/src/services/terminal-output-buffer.ts, packages/api/src/services/auth-terminal-sessions.ts
Локальная реализация буфера терминала удалена; файл terminal-output-buffer.ts теперь переэкспортирует appendTerminalOutput, emptyTerminalOutputBuffer, renderTerminalOutputBuffer из @prover-coder-ai/docker-git-terminal/core.
Утилиты работы с изображениями
packages/api/src/services/terminal-image-paste-core.ts, packages/api/src/services/terminal-image-fetch-core.ts
Локальные реализации валидации и планирования изображений удалены; файлы переэкспортируют createTerminalImagePastePlan, sanitizeTerminalImageBaseName, planTerminalImageFetch и константы из терминального пакета.
Сервис сессий
packages/api/src/services/terminal-sessions.ts
Импорты обновлены на использование TerminalClientMessageSchema из контрактов и утилит из core/server терминального пакета вместо локальных модулей.
Конфигурация и тесты
packages/api/package.json, packages/api/tests/*
Добавлена зависимость на @prover-coder-ai/docker-git-terminal; скрипты предсборки обновлены для сборки терминального пакета; тесты переведены на использование импортов из нового пакета.

Рефакторинг пакета app

Слой / Файл(ы) Описание
Миграция контрактов
packages/app/src/shared/terminal-session-schema.ts
Файл полностью заменён на переэкспорт контрактов из @prover-coder-ai/docker-git-terminal/contracts; локальные Effect-схемы удалены; добавлены клиентские сообщения и статус сессии.
Обновление компонентов
packages/app/src/docker-git/api-terminal-codec.ts, packages/app/src/docker-git/terminal-session-client.ts, packages/app/src/web/api-terminal-schema.ts, packages/app/src/web/api-types.ts, packages/app/src/web/terminal.ts
Импорты контрактов и типов переведены с локального terminal-session-schema.js на @prover-coder-ai/docker-git-terminal/contracts.
Конфигурация
packages/app/package.json
Добавлена зависимость на @prover-coder-ai/docker-git-terminal; скрипты обновлены для сборки терминального пакета.

Тесты

Слой / Файл(ы) Описание
Новые тесты терминала
packages/terminal/tests/contracts/session.test.ts, packages/terminal/tests/core/output-buffer.test.ts, packages/terminal/tests/core/image-paste.test.ts, packages/terminal/tests/server/image-fetch.test.ts, packages/terminal/tests/architecture/boundaries.test.ts
Добавлены комплексные тесты для контрактов (декодирование сессий, сообщений), буфера вывода (порядок, обрезка по бюджету), обработки вставленных изображений, загрузки изображений (абсолютные пути, relative paths, path traversal); тест архитектуры проверяет отсутствие недозволенных зависимостей в core-модулях.
Обновлённые тесты api
packages/api/tests/terminal-image-fetch-core.test.ts, packages/api/tests/terminal-image-paste-core.test.ts, packages/api/tests/terminal-output-buffer.test.ts
Обновлены импорты функций и утилит на источники из @prover-coder-ai/docker-git-terminal; логика тестов без изменений.
Обновлённые тесты app
packages/app/tests/docker-git/core-templates.test.ts
Обновлены утверждения для многострочного формата генерируемого скрипта.

🎯 4 (Complex) | ⏱️ ~60 minutes

Возможно связанные PRs

  • ProverCoderAI/docker-git#309: Оба PR изменяют обработку терминальных сессий — данный PR мигрирует общий функционал в пакет @prover-coder-ai/docker-git-terminal, тогда как PR #309 существенно рефакторит тот же файл terminal-sessions.ts для добавления персистентности и поведения активных сессий.

Important

Pre-merge checks failed

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

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Requirements Alignment ❌ Error Multiple violations: missing TSDoc/PURITY in core modules; prohibited CORE mutations; redundant | undefined in optional props; no property-based tests; RuntimeBoundary violates FCIS pattern. Add TSDoc with @pure/@invariant; replace Array.push with immutable reduce; remove | undefined on optionals; add fast-check tests; refactor RuntimeBoundary as Effect.Layer Context.Tag.
Description check ⚠️ Warning Описание pull request отсутствует полностью. Не заполнены обязательные разделы шаблона, включая Source TZ/Issues, Summary и Requirements Alignment. Заполните описание согласно шаблону: укажите связанные задачи (Fixes #361), кратко опишите суть изменений в разделе Summary и уточните, какие требования реализованы.
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Заголовок чётко и кратко описывает основное изменение: добавление нового общего пакета terminal.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Security Regression ✅ Passed PR adds terminal package with path traversal protection, base64 validation, 10MB size limits, file extension whitelist, and safe process spawning. No security regressions found.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-361

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@skulidropek
Copy link
Copy Markdown
Member Author

skulidropek commented May 30, 2026

AI Session Backup

Commit: 62ce9bc
Status: success
Files: 9 (5.09 MB)
Links: README | Manifest

git status

On branch issue-361
Your branch is up to date with 'origin/issue-361'.

nothing to commit, working tree clean

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: 17

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/api/tests/terminal-image-paste-core.test.ts (1)

8-70: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Рекомендуется обновить стиль тестов для консистентности с терминальным пакетом.

Импорт корректно обновлён на @prover-coder-ai/docker-git-terminal/core, но тесты используют plain it() вместо it.effect(), что не соответствует стилю терминального пакета (packages/terminal/tests/core/image-paste.test.ts должен использовать аналогичный стиль).

Для консистентности и явного следования Effect-паттернам рекомендуется обновить все тесты на использование it.effect(() => Effect.sync(...)).

♻️ Пример обновления
-  it("creates a safe project-container path for supported images", () => {
-    const plan = createTerminalImagePastePlan({
+  it.effect("creates a safe project-container path for supported images", () =>
+    Effect.sync(() => {
+      const plan = createTerminalImagePastePlan({
+        data: "aGVsbG8=",
+        mediaType: "image/png",
+        name: "../screen shot.png",
+        size: 5
+      }, "paste-id")
+
+      expect(plan).toEqual({
+        _tag: "ValidTerminalImagePaste",
+        containerPath: `${terminalImagePasteDirectory}/paste-id-screen-shot.png`,
+        decodedBytes: 5,
+        normalizedBase64: "aGVsbG8="
+      })
+    }))
-      data: "aGVsbG8=",
-      mediaType: "image/png",
-      name: "../screen shot.png",
-      size: 5
-    }, "paste-id")
-
-    expect(plan).toEqual({
-      _tag: "ValidTerminalImagePaste",
-      containerPath: `${terminalImagePasteDirectory}/paste-id-screen-shot.png`,
-      decodedBytes: 5,
-      normalizedBase64: "aGVsbG8="
-    })
-  })
🤖 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/api/tests/terminal-image-paste-core.test.ts` around lines 8 - 70,
Tests use plain it() but should follow the terminal package Effect style; update
each test block that calls createTerminalImagePastePlan and
sanitizeTerminalImageBaseName to use it.effect(() => Effect.sync(() => {
...expect assertions... })), wrapping the existing setup and expect(...)
assertions inside Effect.sync; ensure you preserve references to
createTerminalImagePastePlan, sanitizeTerminalImageBaseName,
terminalImagePasteDirectory and terminalImagePasteMaxBytes and return the Effect
from each it.effect wrapper so test runner executes the effect.
packages/api/tests/terminal-image-fetch-core.test.ts (1)

3-155: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Рекомендуется обновить стиль тестов для консистентности с терминальным пакетом.

Импорт корректно обновлён на @prover-coder-ai/docker-git-terminal/server, но стиль тестов не соответствует новому пакету:

  • Терминальный пакет (packages/terminal/tests/server/image-fetch.test.ts): использует it.effect(() => Effect.sync(...))
  • Этот файл: использует plain it(() => { ... })

Для консистентности и строгого следования Effect-TS паттернам рекомендуется обновить тесты на стиль с it.effect.

♻️ Пример обновления стиля тестов
-  it("continues to accept an absolute path with a supported image extension", () => {
-    expect(planTerminalImageFetch("/tmp/issue232-main.png")).toEqual({
+  it.effect("continues to accept an absolute path with a supported image extension", () =>
+    Effect.sync(() => {
+      expect(planTerminalImageFetch("/tmp/issue232-main.png")).toEqual({
+        _tag: "ValidTerminalImageFetch",
+        containerPath: "/tmp/issue232-main.png",
+        mediaType: "image/png"
+      })
+    }))
-      _tag: "ValidTerminalImageFetch",
-      containerPath: "/tmp/issue232-main.png",
-      mediaType: "image/png"
-    })
-  })

Применить аналогичное изменение ко всем тестам в файле.

🤖 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/api/tests/terminal-image-fetch-core.test.ts` around lines 3 - 155,
Tests use plain Jest-style it(...) blocks but should follow the terminal package
pattern using it.effect with Effect.sync; update each test that calls
planTerminalImageFetch to use it.effect("...", () => Effect.sync(() => { /* same
assertions */ })) so assertions remain inside an Effect, preserve existing
expect(...) calls and messages, and apply this change consistently for all it
blocks in the file (keep the import of planTerminalImageFetch as-is).
🤖 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/terminal/src/app/main.ts`:
- Around line 6-16: The EFFECT comment is incorrect: the constant main is
created by piping program through Effect.provide(NodeContext.layer) so
NodeContext is already provided and main has type Effect<void, never, never>;
update the EFFECT annotation in the comment to read EFFECT: Effect<void, never,
never> (referencing main, program, NodeContext.layer and Effect.provide to
locate the code) so the comment reflects the actual signature of main.

In `@packages/terminal/src/cli/index.ts`:
- Around line 1-3: The current TerminalCliRuntimeBoundary is only a type-level
marker; replace it with an Effect-TS Context.Tag class (retain the name
TerminalCliRuntimeBoundary) that declares real methods returning Effect types
(e.g., executeCliCommand: (cmd: string) => Effect.Effect<unknown, CliError,
string>, readStdin: Effect.Effect<unknown, CliError, string>, etc.), and provide
a production Layer implementation (e.g., TerminalCliRuntimeBoundaryLive =
Layer.effect(...)) which uses Effect.gen to create the runtime methods; ensure
the implementation lives in the SHELL, pure logic remains in CORE, and all
consumers require the Tag rather than relying on the old _tag marker.

In `@packages/terminal/src/contracts/session.ts`:
- Around line 3-81: The exported schema contracts (TerminalSessionStatusSchema,
TerminalSessionSchema, TerminalClientMessageSchema, TerminalServerMessageSchema
and the underlying
TerminalServerMessagePayloadSchema/TerminalClientMessagePayloadSchema) lack the
required TSDoc and functional markers; add a TSDoc block above each exported
symbol containing `@pure` and the requested lifecycle/behavior tags
(`@precondition/`@postcondition or `@invariant` as applicable), an `@complexity`
annotation, and include the repository functional comment markers CHANGE, WHY,
PURITY, INVARIANT plus a QUOTE(ТЗ)/REF that links to the source specification
for the contract; ensure the docs describe expected inputs/outputs (types), any
invariants (e.g., allowed status literals), side‑effects (none — mark `@pure`),
and complexity so the exported schemas satisfy the repo guidelines.

In `@packages/terminal/src/core/image-paste.ts`:
- Around line 80-130: Add comprehensive TSDoc to the CORE pure functions
(createTerminalImagePastePlan and its helpers like terminalImageFileName,
normalizeBase64, decodedBase64Bytes) including the required functional markers
and tags: add `@pure` and a PURITY marker, an `@invariant` and INVARIANT marker that
states decodedBytes === payload.size and that mediaType/fileName are supported,
`@precondition` listing valid inputs (payload.mediaType present and lowercaseable,
payload.size is finite > 0 and ≤ terminalImagePasteMaxBytes, normalizedBase64
length ≤ terminalImagePasteMaxBase64Length), `@postcondition` describing the
returned union (_tag either "ValidTerminalImagePaste" with containerPath,
decodedBytes, normalizedBase64 or "InvalidTerminalImagePaste" with message), and
`@complexity` with O(n) where n is payload.data length; also include a REF or
QUOTE(ТЗ) marker linking to the validation requirements and mention any helper
invariants for terminalImageFileName and decodedBase64Bytes to guide future
reviewers.
- Around line 68-78: The terminalImageFileName function currently interpolates
id directly into the file name, risking path traversal if id ever contains
slashes or dots; update terminalImageFileName to validate/sanitize id (similar
to sanitizeTerminalImageBaseName) before composing the name: remove or reject
path separators (/, \), path-traversal segments (..), and any characters outside
a safe whitelist (e.g., [A-Za-z0-9_-]); if the sanitized id is empty or invalid,
return null (or throw) so callers like createTerminalImagePastePlan cannot
create names that escape terminalImagePasteDirectory. Ensure you reference
terminalImageFileName and reuse or mirror the sanitization approach used by
sanitizeTerminalImageBaseName so behavior is consistent.

In `@packages/terminal/src/core/output-buffer.ts`:
- Around line 16-35: trimTerminalOutputChunks mutates local state (kept array
and remainingOverflow) which violates CORE immutability rules; rewrite it to use
an immutable fold (e.g., Array.prototype.reduce) or a tail-recursive helper that
returns a new ReadonlyArray<string> and remainingOverflow as part of the
accumulator instead of push/reassignment, keeping the same behavior for cases
where chunk lengths exceed overflow, and ensure the function signature still
returns ReadonlyArray<string>. Add a TSDoc block on trimTerminalOutputChunks
with `@invariant` describing immutability guarantees, `@complexity` Big-O for
time/space, and include a short variant function note (or a small pure helper
name) to document the decreasing measure (remainingOverflow or index) that
proves termination.
- Around line 37-69: Add comprehensive TSDoc comments to both public functions
appendTerminalOutput and renderTerminalOutputBuffer: describe purpose,
parameters and return value, and include the required markers — add `@pure`, a
mathematical `@invariant` that specifies behavior (e.g., when boundedMax === 0
returns empty buffer; when data.length === 0 returns original buffer; result
contains at most boundedMax characters and is the suffix of the concatenated
input), and `@complexity` in Big-O (for appendTerminalOutput state the cost in
terms of data length/number of chunks; for renderTerminalOutputBuffer state O(n)
in total output length). Also include standard tags (`@param`, `@returns`) so the
functions meet the CORE TSDoc requirements.

In `@packages/terminal/src/server/image-fetch.ts`:
- Around line 151-213: Add TSDoc to the exported function
planTerminalImageFetch: place a docblock immediately above its declaration
describing purpose and behavior, and include the required tags `@pure`,
`@invariant`, `@precondition`, `@postcondition`, and `@complexity`; reference the
parameter TerminalImageFetchOptions and return type TerminalImageFetchPlan,
summarize input validation rules (empty path, normalization, baseDir rules,
invalid characters/traversal, extension and media type checks) in the pre/post
conditions, state that the function is pure in `@pure`, list any invariants (e.g.
returned ValidTerminalImageFetch always has containerPath and mediaType), and
note time/space complexity in `@complexity`. Ensure the text is concise and
written as standard TSDoc above planTerminalImageFetch.

In `@packages/terminal/src/server/index.ts`:
- Around line 23-27: В типе TerminalShellCommand уберите избыточные "|
undefined" у опциональных свойств: оставьте readonly cwd?: string; и readonly
env?: Readonly<Record<string, string>>; вместо текущих cwd?: string | undefined
и env?: Readonly<Record<string, string>> | undefined; (сохраните readonly и
неизменность типа command).

In `@packages/terminal/src/shell/index.ts`:
- Around line 1-3: The TerminalShellRuntimeBoundary currently is only a
type-level marker and must be replaced with an Effect-TS Context.Tag service and
a production Layer implementation: define TerminalShellRuntimeBoundary as a
Context.Tag class exposing methods (e.g., executeShellCommand, getEnvironment)
whose signatures return Effect types, then implement
TerminalShellRuntimeBoundaryLive as a Layer.effect (using Effect.gen or similar)
that provides the concrete implementations and wraps errors in a ShellError;
update all consumers to require the Context.Tag service instead of the plain
type marker.
- Around line 1-3: The exported type TerminalShellRuntimeBoundary lacks the
required TSDoc/functional comment; add a comprehensive TSDoc block above the
export for TerminalShellRuntimeBoundary that includes CHANGE, WHY, QUOTE or n/a,
REF, SOURCE or n/a, FORMAT THEOREM, PURITY (CORE|SHELL), INVARIANT, COMPLEXITY,
a short description of its purpose and invariants, and a minimal usage example
showing how to consume the type; ensure the comment follows the project's coding
guidelines and documents the readonly _tag invariant and typical use case.

In `@packages/terminal/src/web/index.ts`:
- Around line 1-3: The current TerminalWebRuntimeBoundary is only a type-level
marker and must be converted into a runtime Effect-TS Layer-based service:
replace the plain exported type TerminalWebRuntimeBoundary with a
Context.Tag-based service (using Context.Tag("TerminalWebRuntimeBoundary")) that
exposes concrete methods like handleWebSocketMessage and sendToClient typed to
return Effect.Effect, then provide a production Layer (e.g.,
TerminalWebRuntimeBoundaryLive) built via Layer.effect/Effect.gen that
implements those methods and wraps runtime side-effects (websocket send/receive)
in Effect/Either-style error handling; ensure all consumers inject this Layer
instead of relying on the marker type so the boundary enforces runtime
separation between SHELL and CORE.
- Around line 1-3: The exported type TerminalWebRuntimeBoundary lacks required
TSDoc/functional comments; add a comprehensive TSDoc block immediately above the
exported type TerminalWebRuntimeBoundary that describes its purpose, invariants,
and usage, includes the mandated fields CHANGE, WHY, QUOTE (or n/a), REF, SOURCE
(or n/a), FORMAT THEOREM, PURITY (CORE|SHELL), INVARIANT, and COMPLEXITY, and
provide a brief usage example showing how to construct/consume the boundary;
ensure the comment follows existing coding-guidelines formatting and covers any
invariants about the _tag literal.

In `@packages/terminal/tests/architecture/boundaries.test.ts`:
- Around line 1-2: Tests directly call node:fs/node:path (readFileSync,
readdirSync) and rely on a regex-based import parser; wrap all filesystem access
in typed Effect wrappers (e.g., implement readFile(path): Effect.Effect<string,
Error> and listFiles(directory): Effect.Effect<ReadonlyArray<string>, Error>
that internally call readFileSync/readdirSync) and replace the fragile regex
import extraction with a TypeScript AST-based extractor (e.g., use
ts.createSourceFile and an extractImports(sourceFile: ts.SourceFile) function
that traverses nodes and collects moduleSpecifier texts for
ImportDeclaration/ExportDeclaration), then update the test code to call these
new readFile/listFiles/extractImports helpers instead of direct fs calls and the
regex.

In `@packages/terminal/tests/core/image-paste.test.ts`:
- Around line 26-30: Add a property-based test for the
sanitizeTerminalImageBaseName invariant: write an it.effect test (in the same
test suite) that uses fast-check (fc.assert + fc.property(fc.string(), ...)) to
feed arbitrary strings to sanitizeTerminalImageBaseName and assert the returned
name never contains "/", "\\" or the sequence ".." (and choose a descriptive
test title like "санитизированное имя никогда не содержит разделителей пути");
use the existing Effect.sync wrapper as in other tests and keep the assertion
boolean style used in the repo.

In `@packages/terminal/tests/core/output-buffer.test.ts`:
- Around line 22-40: Add a property-based test using fast-check that verifies
the buffer invariant charLength <= budget for any sequence of appends: generate
an array of strings and a budget (e.g., 1..256), reduce the chunks with
appendTerminalOutput starting from emptyTerminalOutputBuffer using the generated
budget, and assert buffer.charLength <= budget (wrap in Effect.sync and use
fc.assert/fc.property as in other tests); reference appendTerminalOutput,
emptyTerminalOutputBuffer, and charLength so the test locates the right
functions/fields.

In `@packages/terminal/tests/server/image-fetch.test.ts`:
- Around line 6-32: Add property-based tests using fast-check that exercise
planTerminalImageFetch: assert idempotence of normalization
(normalize(normalize(p)) === normalize(p)), assert any path containing '.' or
'..' segments yields an InvalidTerminalImageFetch, and assert deterministic
mapping from file extension to mediaType for all valid paths; implement these as
new it.effect cases calling fc.assert + fc.property and use
planTerminalImageFetch inside the property functions to check _tag or equality,
referencing the existing tests for pattern and reusing the same error/message
expectations.

---

Outside diff comments:
In `@packages/api/tests/terminal-image-fetch-core.test.ts`:
- Around line 3-155: Tests use plain Jest-style it(...) blocks but should follow
the terminal package pattern using it.effect with Effect.sync; update each test
that calls planTerminalImageFetch to use it.effect("...", () => Effect.sync(()
=> { /* same assertions */ })) so assertions remain inside an Effect, preserve
existing expect(...) calls and messages, and apply this change consistently for
all it blocks in the file (keep the import of planTerminalImageFetch as-is).

In `@packages/api/tests/terminal-image-paste-core.test.ts`:
- Around line 8-70: Tests use plain it() but should follow the terminal package
Effect style; update each test block that calls createTerminalImagePastePlan and
sanitizeTerminalImageBaseName to use it.effect(() => Effect.sync(() => {
...expect assertions... })), wrapping the existing setup and expect(...)
assertions inside Effect.sync; ensure you preserve references to
createTerminalImagePastePlan, sanitizeTerminalImageBaseName,
terminalImagePasteDirectory and terminalImagePasteMaxBytes and return the Effect
from each it.effect wrapper so test runner executes the effect.
🪄 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: 7479afaf-03f8-4fbe-be81-b656e322b86d

📥 Commits

Reviewing files that changed from the base of the PR and between 48355fd and 000c86c.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (44)
  • .github/workflows/check.yml
  • package.json
  • packages/api/package.json
  • packages/api/src/services/auth-terminal-sessions.ts
  • packages/api/src/services/terminal-image-fetch-core.ts
  • packages/api/src/services/terminal-image-paste-core.ts
  • packages/api/src/services/terminal-output-buffer.ts
  • packages/api/src/services/terminal-sessions.ts
  • packages/api/tests/terminal-image-fetch-core.test.ts
  • packages/api/tests/terminal-image-paste-core.test.ts
  • packages/api/tests/terminal-output-buffer.test.ts
  • packages/app/package.json
  • packages/app/src/docker-git/api-terminal-codec.ts
  • packages/app/src/docker-git/terminal-session-client.ts
  • packages/app/src/shared/terminal-session-schema.ts
  • packages/app/src/web/api-terminal-schema.ts
  • packages/app/src/web/api-types.ts
  • packages/app/src/web/terminal.ts
  • packages/app/tests/docker-git/core-templates.test.ts
  • packages/terminal/biome.json
  • packages/terminal/eslint.config.mjs
  • packages/terminal/eslint.effect-ts-check.config.mjs
  • packages/terminal/package.json
  • packages/terminal/src/app/main.ts
  • packages/terminal/src/app/program.ts
  • packages/terminal/src/cli/index.ts
  • packages/terminal/src/contracts/index.ts
  • packages/terminal/src/contracts/session.ts
  • packages/terminal/src/core/image-paste.ts
  • packages/terminal/src/core/index.ts
  • packages/terminal/src/core/output-buffer.ts
  • packages/terminal/src/index.ts
  • packages/terminal/src/server/image-fetch.ts
  • packages/terminal/src/server/index.ts
  • packages/terminal/src/shell/index.ts
  • packages/terminal/src/web/index.ts
  • packages/terminal/tests/architecture/boundaries.test.ts
  • packages/terminal/tests/contracts/session.test.ts
  • packages/terminal/tests/core/image-paste.test.ts
  • packages/terminal/tests/core/output-buffer.test.ts
  • packages/terminal/tests/server/image-fetch.test.ts
  • packages/terminal/tsconfig.json
  • packages/terminal/vitest.config.ts
  • pnpm-workspace.yaml
📜 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). (1)
  • GitHub Check: Lint
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{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/terminal/src/app/program.ts
  • packages/app/src/docker-git/api-terminal-codec.ts
  • packages/app/tests/docker-git/core-templates.test.ts
  • packages/terminal/src/contracts/index.ts
  • packages/terminal/src/core/index.ts
  • packages/terminal/vitest.config.ts
  • packages/terminal/src/cli/index.ts
  • packages/terminal/tests/server/image-fetch.test.ts
  • packages/terminal/src/web/index.ts
  • packages/app/src/docker-git/terminal-session-client.ts
  • packages/terminal/src/server/index.ts
  • packages/terminal/src/shell/index.ts
  • packages/app/src/web/api-types.ts
  • packages/api/tests/terminal-image-fetch-core.test.ts
  • packages/api/tests/terminal-image-paste-core.test.ts
  • packages/terminal/src/app/main.ts
  • packages/terminal/tests/contracts/session.test.ts
  • packages/app/src/web/api-terminal-schema.ts
  • packages/terminal/src/index.ts
  • packages/api/tests/terminal-output-buffer.test.ts
  • packages/terminal/src/core/output-buffer.ts
  • packages/api/src/services/terminal-output-buffer.ts
  • packages/terminal/tests/architecture/boundaries.test.ts
  • packages/api/src/services/terminal-image-paste-core.ts
  • packages/app/src/shared/terminal-session-schema.ts
  • packages/terminal/src/contracts/session.ts
  • packages/terminal/tests/core/output-buffer.test.ts
  • packages/terminal/tests/core/image-paste.test.ts
  • packages/api/src/services/terminal-image-fetch-core.ts
  • packages/terminal/src/server/image-fetch.ts
  • packages/app/src/web/terminal.ts
  • packages/terminal/src/core/image-paste.ts
  • packages/api/src/services/terminal-sessions.ts
  • packages/api/src/services/auth-terminal-sessions.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/terminal/src/app/program.ts
  • packages/app/src/docker-git/api-terminal-codec.ts
  • packages/app/tests/docker-git/core-templates.test.ts
  • packages/terminal/src/contracts/index.ts
  • packages/terminal/src/core/index.ts
  • packages/terminal/vitest.config.ts
  • packages/terminal/src/cli/index.ts
  • packages/terminal/tests/server/image-fetch.test.ts
  • packages/terminal/src/web/index.ts
  • packages/app/src/docker-git/terminal-session-client.ts
  • packages/terminal/src/server/index.ts
  • packages/terminal/src/shell/index.ts
  • packages/app/src/web/api-types.ts
  • packages/api/tests/terminal-image-fetch-core.test.ts
  • packages/api/tests/terminal-image-paste-core.test.ts
  • packages/terminal/src/app/main.ts
  • packages/terminal/tests/contracts/session.test.ts
  • packages/app/src/web/api-terminal-schema.ts
  • packages/terminal/src/index.ts
  • packages/api/tests/terminal-output-buffer.test.ts
  • packages/terminal/src/core/output-buffer.ts
  • packages/api/src/services/terminal-output-buffer.ts
  • packages/terminal/tests/architecture/boundaries.test.ts
  • packages/api/src/services/terminal-image-paste-core.ts
  • packages/app/src/shared/terminal-session-schema.ts
  • packages/terminal/src/contracts/session.ts
  • packages/terminal/tests/core/output-buffer.test.ts
  • packages/terminal/tests/core/image-paste.test.ts
  • packages/api/src/services/terminal-image-fetch-core.ts
  • packages/terminal/src/server/image-fetch.ts
  • packages/app/src/web/terminal.ts
  • packages/terminal/src/core/image-paste.ts
  • packages/api/src/services/terminal-sessions.ts
  • packages/api/src/services/auth-terminal-sessions.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/terminal/src/app/program.ts
  • packages/app/src/docker-git/api-terminal-codec.ts
  • packages/app/tests/docker-git/core-templates.test.ts
  • packages/terminal/src/contracts/index.ts
  • packages/terminal/src/core/index.ts
  • packages/terminal/vitest.config.ts
  • packages/terminal/src/cli/index.ts
  • packages/terminal/tests/server/image-fetch.test.ts
  • packages/terminal/src/web/index.ts
  • packages/app/src/docker-git/terminal-session-client.ts
  • packages/terminal/src/server/index.ts
  • packages/terminal/src/shell/index.ts
  • packages/app/src/web/api-types.ts
  • packages/api/tests/terminal-image-fetch-core.test.ts
  • packages/api/tests/terminal-image-paste-core.test.ts
  • packages/terminal/src/app/main.ts
  • packages/terminal/tests/contracts/session.test.ts
  • packages/app/src/web/api-terminal-schema.ts
  • packages/terminal/src/index.ts
  • packages/api/tests/terminal-output-buffer.test.ts
  • packages/terminal/src/core/output-buffer.ts
  • packages/api/src/services/terminal-output-buffer.ts
  • packages/terminal/tests/architecture/boundaries.test.ts
  • packages/api/src/services/terminal-image-paste-core.ts
  • packages/app/src/shared/terminal-session-schema.ts
  • packages/terminal/src/contracts/session.ts
  • packages/terminal/tests/core/output-buffer.test.ts
  • packages/terminal/tests/core/image-paste.test.ts
  • packages/api/src/services/terminal-image-fetch-core.ts
  • packages/terminal/src/server/image-fetch.ts
  • packages/app/src/web/terminal.ts
  • packages/terminal/src/core/image-paste.ts
  • packages/api/src/services/terminal-sessions.ts
  • packages/api/src/services/auth-terminal-sessions.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/terminal/src/app/program.ts
  • packages/app/src/docker-git/api-terminal-codec.ts
  • packages/app/tests/docker-git/core-templates.test.ts
  • packages/terminal/src/contracts/index.ts
  • packages/terminal/src/core/index.ts
  • packages/terminal/vitest.config.ts
  • packages/terminal/src/cli/index.ts
  • packages/terminal/tests/server/image-fetch.test.ts
  • packages/terminal/src/web/index.ts
  • packages/app/src/docker-git/terminal-session-client.ts
  • packages/terminal/src/server/index.ts
  • packages/terminal/src/shell/index.ts
  • packages/app/src/web/api-types.ts
  • packages/api/tests/terminal-image-fetch-core.test.ts
  • packages/api/tests/terminal-image-paste-core.test.ts
  • packages/terminal/src/app/main.ts
  • packages/terminal/tests/contracts/session.test.ts
  • packages/app/src/web/api-terminal-schema.ts
  • packages/terminal/src/index.ts
  • packages/api/tests/terminal-output-buffer.test.ts
  • packages/terminal/src/core/output-buffer.ts
  • packages/api/src/services/terminal-output-buffer.ts
  • packages/terminal/tests/architecture/boundaries.test.ts
  • packages/api/src/services/terminal-image-paste-core.ts
  • packages/app/src/shared/terminal-session-schema.ts
  • packages/terminal/src/contracts/session.ts
  • packages/terminal/tests/core/output-buffer.test.ts
  • packages/terminal/tests/core/image-paste.test.ts
  • packages/api/src/services/terminal-image-fetch-core.ts
  • packages/terminal/src/server/image-fetch.ts
  • packages/app/src/web/terminal.ts
  • packages/terminal/src/core/image-paste.ts
  • packages/api/src/services/terminal-sessions.ts
  • packages/api/src/services/auth-terminal-sessions.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/terminal/src/app/program.ts
  • packages/app/src/docker-git/api-terminal-codec.ts
  • pnpm-workspace.yaml
  • packages/app/tests/docker-git/core-templates.test.ts
  • packages/terminal/src/contracts/index.ts
  • packages/terminal/src/core/index.ts
  • packages/terminal/vitest.config.ts
  • packages/terminal/src/cli/index.ts
  • packages/terminal/tests/server/image-fetch.test.ts
  • packages/terminal/biome.json
  • packages/terminal/src/web/index.ts
  • packages/app/src/docker-git/terminal-session-client.ts
  • packages/terminal/src/server/index.ts
  • packages/terminal/src/shell/index.ts
  • packages/app/src/web/api-types.ts
  • packages/api/tests/terminal-image-fetch-core.test.ts
  • packages/terminal/tsconfig.json
  • packages/api/tests/terminal-image-paste-core.test.ts
  • packages/terminal/src/app/main.ts
  • packages/terminal/tests/contracts/session.test.ts
  • packages/app/src/web/api-terminal-schema.ts
  • packages/terminal/src/index.ts
  • packages/api/tests/terminal-output-buffer.test.ts
  • packages/terminal/src/core/output-buffer.ts
  • packages/api/src/services/terminal-output-buffer.ts
  • packages/terminal/tests/architecture/boundaries.test.ts
  • packages/terminal/package.json
  • packages/api/src/services/terminal-image-paste-core.ts
  • packages/app/src/shared/terminal-session-schema.ts
  • packages/terminal/src/contracts/session.ts
  • packages/api/package.json
  • packages/terminal/tests/core/output-buffer.test.ts
  • packages/terminal/tests/core/image-paste.test.ts
  • packages/app/package.json
  • packages/api/src/services/terminal-image-fetch-core.ts
  • packages/terminal/src/server/image-fetch.ts
  • packages/app/src/web/terminal.ts
  • packages/terminal/src/core/image-paste.ts
  • packages/api/src/services/terminal-sessions.ts
  • packages/api/src/services/auth-terminal-sessions.ts
  • package.json
**/*

⚙️ CodeRabbit configuration file

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

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

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

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

Files:

  • packages/terminal/src/app/program.ts
  • packages/app/src/docker-git/api-terminal-codec.ts
  • pnpm-workspace.yaml
  • packages/app/tests/docker-git/core-templates.test.ts
  • packages/terminal/src/contracts/index.ts
  • packages/terminal/src/core/index.ts
  • packages/terminal/vitest.config.ts
  • packages/terminal/src/cli/index.ts
  • packages/terminal/tests/server/image-fetch.test.ts
  • packages/terminal/biome.json
  • packages/terminal/eslint.effect-ts-check.config.mjs
  • packages/terminal/src/web/index.ts
  • packages/app/src/docker-git/terminal-session-client.ts
  • packages/terminal/src/server/index.ts
  • packages/terminal/src/shell/index.ts
  • packages/app/src/web/api-types.ts
  • packages/api/tests/terminal-image-fetch-core.test.ts
  • packages/terminal/tsconfig.json
  • packages/terminal/eslint.config.mjs
  • packages/api/tests/terminal-image-paste-core.test.ts
  • packages/terminal/src/app/main.ts
  • packages/terminal/tests/contracts/session.test.ts
  • packages/app/src/web/api-terminal-schema.ts
  • packages/terminal/src/index.ts
  • packages/api/tests/terminal-output-buffer.test.ts
  • packages/terminal/src/core/output-buffer.ts
  • packages/api/src/services/terminal-output-buffer.ts
  • packages/terminal/tests/architecture/boundaries.test.ts
  • packages/terminal/package.json
  • packages/api/src/services/terminal-image-paste-core.ts
  • packages/app/src/shared/terminal-session-schema.ts
  • packages/terminal/src/contracts/session.ts
  • packages/api/package.json
  • packages/terminal/tests/core/output-buffer.test.ts
  • packages/terminal/tests/core/image-paste.test.ts
  • packages/app/package.json
  • packages/api/src/services/terminal-image-fetch-core.ts
  • packages/terminal/src/server/image-fetch.ts
  • packages/app/src/web/terminal.ts
  • packages/terminal/src/core/image-paste.ts
  • packages/api/src/services/terminal-sessions.ts
  • packages/api/src/services/auth-terminal-sessions.ts
  • package.json
**/*.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/core-templates.test.ts
  • packages/terminal/tests/server/image-fetch.test.ts
  • packages/api/tests/terminal-image-fetch-core.test.ts
  • packages/api/tests/terminal-image-paste-core.test.ts
  • packages/terminal/tests/contracts/session.test.ts
  • packages/api/tests/terminal-output-buffer.test.ts
  • packages/terminal/tests/architecture/boundaries.test.ts
  • packages/terminal/tests/core/output-buffer.test.ts
  • packages/terminal/tests/core/image-paste.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/core-templates.test.ts
  • packages/terminal/tests/server/image-fetch.test.ts
  • packages/api/tests/terminal-image-fetch-core.test.ts
  • packages/api/tests/terminal-image-paste-core.test.ts
  • packages/terminal/tests/contracts/session.test.ts
  • packages/api/tests/terminal-output-buffer.test.ts
  • packages/terminal/tests/architecture/boundaries.test.ts
  • packages/terminal/tests/core/output-buffer.test.ts
  • packages/terminal/tests/core/image-paste.test.ts
**/.github/workflows/*.{yml,yaml}

📄 CodeRabbit inference engine (Custom checks)

Fail if changed files introduce unsafe GitHub Actions configuration such as unsafe pull_request_target, or unnecessary write permissions

Files:

  • .github/workflows/check.yml
**/{package*.json,requirements*.txt,setup.py,setup.cfg,Pipfile,Pipfile.lock,pyproject.toml,pom.xml,build.gradle,Gemfile,Gemfile.lock,go.mod,go.sum,composer.json,Cargo.toml,Cargo.lock}

📄 CodeRabbit inference engine (Custom checks)

Fail if dependency or package-manager changes materially increase supply-chain risk without justification

Files:

  • packages/terminal/package.json
  • packages/api/package.json
  • packages/app/package.json
  • package.json
package.json

📄 CodeRabbit inference engine (CLAUDE.md)

Dependencies must include Effect-TS (effect: ^3.x) for monadic effects and @effect/schema: ^0.x for validation with strong typing.

Dependencies like effect (^3.x) and @effect/schema (^0.x) are mandatory; project must enforce monadic composition through Effect.

Files:

  • package.json
🧠 Learnings (2)
📚 Learning: 2026-05-22T21:08:18.083Z
Learnt from: skulidropek
Repo: ProverCoderAI/docker-git PR: 344
File: packages/app/src/docker-git/controller-compose.ts:34-40
Timestamp: 2026-05-22T21:08:18.083Z
Learning: In this repo’s docker-git controller compose generation, `${DOCKER_GIT_CONTROLLER_BUILD_SKILLER:-1}` should be treated as standard bash parameter expansion: when `DOCKER_GIT_CONTROLLER_BUILD_SKILLER` is unset, it defaults to the string "1". There is no "-1" mode. The runtime contract enforced by `packages/app/src/docker-git/controller-compose.ts` is: unset / "1" / "true" => output "1"; "0" / "false" => output "0". If review code shows branching/behavior for "-1" or any numeric value other than this 0/1 contract, flag it. Also ensure the Dockerfile ARG `DOCKER_GIT_CONTROLLER_BUILD_SKILLER` stays consistent with default `1`.

Applied to files:

  • packages/app/src/docker-git/api-terminal-codec.ts
  • packages/app/src/docker-git/terminal-session-client.ts
📚 Learning: 2026-05-18T07:43:38.131Z
Learnt from: skulidropek
Repo: ProverCoderAI/docker-git PR: 313
File: packages/api/src/services/panel-cloudflare-tunnel.ts:123-135
Timestamp: 2026-05-18T07:43:38.131Z
Learning: In this repo’s ProverCoderAI/docker-git architecture, it is intentional for service modules under packages/api/src/services/ to call Node.js APIs directly (e.g., fs, child_process, fetch). Do not treat direct Node API usage in these service modules as a dependency-injection (DI) violation. This codebase provides the NodeContext at the program boundary (entry point) rather than injecting Context.Tag/Layer services into individual service modules; reviewers should only flag DI/context issues if the expected boundary setup is missing.

Applied to files:

  • packages/api/src/services/terminal-output-buffer.ts
  • packages/api/src/services/terminal-image-paste-core.ts
  • packages/api/src/services/terminal-image-fetch-core.ts
  • packages/api/src/services/terminal-sessions.ts
  • packages/api/src/services/auth-terminal-sessions.ts
🔇 Additional comments (41)
packages/api/src/services/terminal-output-buffer.ts (1)

1-7: LGTM!

packages/api/src/services/auth-terminal-sessions.ts (1)

3-9: LGTM!

packages/api/src/services/terminal-image-paste-core.ts (1)

1-9: LGTM!

packages/api/src/services/terminal-image-fetch-core.ts (1)

1-6: LGTM!

packages/api/src/services/terminal-sessions.ts (1)

21-38: LGTM!

packages/api/package.json (1)

10-10: LGTM!

Also applies to: 15-15, 18-18, 23-23

packages/terminal/src/server/image-fetch.ts (3)

1-36: LGTM!


48-75: LGTM!


77-135: LGTM!

packages/terminal/src/server/index.ts (2)

1-5: LGTM!


29-51: LGTM!

packages/terminal/src/contracts/index.ts (1)

1-1: LGTM!

packages/terminal/src/core/index.ts (1)

1-2: LGTM!

packages/terminal/src/index.ts (1)

1-2: LGTM!

packages/terminal/src/shell/index.ts (1)

1-3: Уточнить применение TerminalShellRuntimeBoundary и соответствие issue #361

  • В репозитории (кроме packages/terminal/src/shell/index.ts) не найдено ни одной ссылки на TerminalShellRuntimeBoundary, поэтому тип выглядит неиспользуемым.
  • Требуется подтвердить реализацию требований issue #361`` и наличие тестов/проверок поведения, которые подтверждают назначение runtime boundary (например, в packages/terminal/tests и/или релевантных интеграционных сценариях).
packages/terminal/src/cli/index.ts (1)

1-3: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Отсутствует обязательная документация для публичного API.

Экспортируемый тип TerminalCliRuntimeBoundary не содержит ни TSDoc комментариев, ни функциональных комментариев. Согласно coding guidelines, все экспортируемые сущности должны быть задокументированы с описанием назначения, инвариантов и примеров использования.

📝 Предлагаемая документация
+/**
+ * Runtime boundary marker для CLI-адаптера терминального пакета.
+ * 
+ * CHANGE: Добавлен тип-маркер для разграничения CLI runtime boundary
+ * WHY: Обеспечение type-level разделения между CLI, Shell и Web runtime слоями
+ * QUOTE(ТЗ): [требуется ссылка на issue `#361` или спецификацию]
+ * REF: n/a
+ * SOURCE: n/a
+ * FORMAT THEOREM: ∀x: TerminalCliRuntimeBoundary: x._tag = "TerminalCliRuntimeBoundary"
+ * PURITY: CORE
+ * INVARIANT: _tag является string literal константой для type discrimination
+ * 
+ * `@remarks`
+ * Этот тип используется для маркировки границ между runtime слоями в FCIS архитектуре.
+ * Конкретное использование: [требуется описание, где и как используется]
+ * 
+ * `@example`
+ * ```typescript
+ * // [требуется пример использования]
+ * ```
+ */
 export type TerminalCliRuntimeBoundary = {
 	readonly _tag: "TerminalCliRuntimeBoundary";
 };

As per coding guidelines: "Functional comments must include: CHANGE, WHY, QUOTE(ТЗ) or n/a, REF, SOURCE or n/a, FORMAT THEOREM, PURITY (CORE|SHELL), INVARIANT, and COMPLEXITY" and "TypeScript functions must include comprehensive TSDoc with @pure marker, @effect dependencies, @invariant (mathematical), @precondition, @postcondition, and @complexity O-notation."

			> Likely an incorrect or invalid review comment.
packages/terminal/src/web/index.ts (1)

1-3: TerminalWebRuntimeBoundary не используется и нет web-интеграции; нужно сверить с issue #361

  • TerminalWebRuntimeBoundary найден только в packages/terminal/src/web/index.ts (других использований по TS-кодовой базе нет).
  • packages/terminal/src/index.ts экспортирует только ./contracts и ./core, ./webTerminalWebRuntimeBoundary) через root-barrel не выводится.
  • В packages/app/src/ не обнаружены ссылки вида docker-git-terminal.*web, т.е. web-client wiring не выявлен.
  • Для соответствия issue #361`` и проверки наличия/достаточности тестов нужна формулировка требований из issue (и/или результаты проверок, которые её прямо подтверждают).
packages/app/src/shared/terminal-session-schema.ts (1)

1-11: LGTM!

packages/app/src/docker-git/terminal-session-client.ts (1)

2-2: LGTM!

packages/app/src/web/api-terminal-schema.ts (1)

2-2: LGTM!

Also applies to: 32-32

packages/app/src/web/api-types.ts (1)

99-99: LGTM!

packages/app/src/web/terminal.ts (1)

2-5: LGTM!

Also applies to: 239-242

packages/app/package.json (1)

16-16: LGTM!

Also applies to: 25-25, 29-29, 31-31, 40-40, 42-42, 68-68

packages/app/src/docker-git/api-terminal-codec.ts (1)

18-21: ⚡ Quick win

Проверка type guard isTerminalSessionStatus на соответствие TerminalSessionStatusSchema

Множество статусов в guard ("ready" | "attached" | "exited" | "failed") совпадает с TerminalSessionStatusSchema из packages/terminal/src/contracts/session.ts, расхождений по текущей схеме нет.

pnpm-workspace.yaml (1)

6-6: LGTM!

.github/workflows/check.yml (1)

26-27: LGTM!

Also applies to: 63-64, 87-88, 112-113, 136-137

package.json (2)

12-12: LGTM!


16-16: LGTM!

Also applies to: 22-22, 46-46, 48-50

packages/terminal/package.json (1)

1-74: LGTM!

packages/terminal/src/app/program.ts (1)

1-13: LGTM!

packages/terminal/tsconfig.json (1)

1-15: LGTM!

packages/terminal/vitest.config.ts (1)

1-23: LGTM!

packages/terminal/eslint.config.mjs (1)

1-27: LGTM!

packages/terminal/eslint.effect-ts-check.config.mjs (1)

1-3: LGTM!

packages/terminal/biome.json (1)

1-34: LGTM!

packages/terminal/tests/contracts/session.test.ts (2)

23-58: LGTM!


1-10: Убедиться, что ParseResult импортируется из того же источника, что и схемы в контрактах

  • В packages/terminal/package.json объявлена зависимость @effect/schema (^0.75.5).
  • В контрактах (например, packages/terminal/src/contracts/session.ts) схемы импортируются из @effect/schema/Schema, что согласуется с использованием @effect/schema в тесте.
  • Нужна проверка: в packages/terminal/src/contracts/** ParseResult импортируется из @effect/schema/ParseResult (а не из effect/ParseResult), чтобы типы не разъезжались.
packages/terminal/tests/core/image-paste.test.ts (1)

10-24: LGTM!

packages/terminal/tests/core/output-buffer.test.ts (1)

11-20: LGTM!

packages/api/tests/terminal-output-buffer.test.ts (1)

3-7: LGTM!

packages/app/tests/docker-git/core-templates.test.ts (1)

75-78: LGTM!

Comment on lines +6 to +16
// CHANGE: add a thin Node runtime entrypoint for the terminal package.
// WHY: follow the effect-template shape and keep runtime provision outside core/contracts.
// QUOTE(ТЗ): "Используй так же модуль"
// REF: issue-361-terminal-package
// SOURCE: https://github.com/ProverCoderAI/effect-template/tree/main/packages/app
// FORMAT THEOREM: main = provide(program, NodeContext)
// PURITY: SHELL
// EFFECT: Effect<void, never, NodeContext>
// INVARIANT: NodeContext is provided only at the package runtime boundary.
// COMPLEXITY: O(1)/O(1)
const main = pipe(program, Effect.provide(NodeContext.layer));
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

Некорректная аннотация типа в EFFECT комментарии.

Строка 13 указывает EFFECT: Effect<void, never, NodeContext>, но константа main (строка 16) имеет тип Effect<void, never, never>, так как NodeContext.layer уже предоставлен через Effect.provide.

Согласно coding guidelines, комментарий EFFECT должен описывать Effect-сигнатуру объявляемой сущности (в данном случае — main), а не промежуточных значений. Правильная аннотация: EFFECT: Effect<void, never, never>.

Предлагаемое исправление
 // PURITY: SHELL
-// EFFECT: Effect<void, never, NodeContext>
+// EFFECT: Effect<void, never, never>
 // INVARIANT: NodeContext is provided only at the package runtime boundary.
🤖 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/terminal/src/app/main.ts` around lines 6 - 16, The EFFECT comment is
incorrect: the constant main is created by piping program through
Effect.provide(NodeContext.layer) so NodeContext is already provided and main
has type Effect<void, never, never>; update the EFFECT annotation in the comment
to read EFFECT: Effect<void, never, never> (referencing main, program,
NodeContext.layer and Effect.provide to locate the code) so the comment reflects
the actual signature of main.

Comment on lines +1 to +3
export type TerminalCliRuntimeBoundary = {
readonly _tag: "TerminalCliRuntimeBoundary";
};
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 | 🟠 Major | 🏗️ Heavy lift

Несоответствие архитектурным требованиям FCIS и Effect-TS.

Тип назван RuntimeBoundary, но реализован как простой маркер с полем _tag. Согласно coding guidelines, границы между слоями должны реализовываться через Effect-TS Layer pattern с Context.Tag и полноценными сервисами:

  • "Define all external service dependencies as Context.Tag classes with fully typed methods returning Effect types"
  • "Implement service implementations as Layer.effect with Effect.gen pattern for dependency injection"
  • "Implement Functional Core, Imperative Shell (FCIS) pattern: CORE layer contains only pure functions; SHELL layer isolates all effects. Strict dependency direction: SHELL → CORE"

Текущая реализация не обеспечивает реальную boundary - это только type-level marker без runtime гарантий разделения эффектов.

🏗️ Рекомендуемая архитектура с Effect Layer pattern

Если это действительно runtime boundary, должна быть примерно такая структура:

import { Context, Effect, Layer } from "effect";

/**
 * CLI Runtime Boundary Service
 * PURITY: SHELL
 * EFFECT: Effect<TerminalCliCapabilities, CliError, never>
 */
export class TerminalCliRuntimeBoundary extends Context.Tag("TerminalCliRuntimeBoundary")<
  TerminalCliRuntimeBoundary,
  {
    readonly executeCliCommand: (cmd: string) => Effect.Effect<string, CliError>;
    readonly readStdin: Effect.Effect<string, CliError>;
    // ... other CLI-specific capabilities
  }
>() {}

/**
 * Production implementation
 */
export const TerminalCliRuntimeBoundaryLive = Layer.effect(
  TerminalCliRuntimeBoundary,
  Effect.gen(function* (_) {
    return {
      executeCliCommand: (cmd) => Effect.tryPromise({
        try: async () => {
          // implementation
        },
        catch: (error) => new CliError({ cause: error })
      }),
      // ...
    };
  })
);

As per coding guidelines: "All external service dependencies must be wrapped through typed interfaces and injected via Effect-TS Layer pattern" and "Implement Functional Core, Imperative Shell (FCIS) pattern."

🤖 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/terminal/src/cli/index.ts` around lines 1 - 3, The current
TerminalCliRuntimeBoundary is only a type-level marker; replace it with an
Effect-TS Context.Tag class (retain the name TerminalCliRuntimeBoundary) that
declares real methods returning Effect types (e.g., executeCliCommand: (cmd:
string) => Effect.Effect<unknown, CliError, string>, readStdin:
Effect.Effect<unknown, CliError, string>, etc.), and provide a production Layer
implementation (e.g., TerminalCliRuntimeBoundaryLive = Layer.effect(...)) which
uses Effect.gen to create the runtime methods; ensure the implementation lives
in the SHELL, pure logic remains in CORE, and all consumers require the Tag
rather than relying on the old _tag marker.

Comment on lines +3 to +81
export const TerminalSessionStatusSchema = Schema.Union(
Schema.Literal("ready"),
Schema.Literal("attached"),
Schema.Literal("exited"),
Schema.Literal("failed"),
);

export const TerminalSessionSchema = Schema.Struct({
id: Schema.String,
projectId: Schema.String,
sshCommand: Schema.String,
status: TerminalSessionStatusSchema,
createdAt: Schema.String,
attachedClients: Schema.optional(Schema.Number),
startedAt: Schema.optional(Schema.String),
closedAt: Schema.optional(Schema.String),
exitCode: Schema.optional(Schema.Number),
signal: Schema.optional(Schema.Number),
});

export const TerminalClientMessagePayloadSchema = Schema.Union(
Schema.Struct({
type: Schema.Literal("input"),
data: Schema.String,
}),
Schema.Struct({
type: Schema.Literal("resize"),
cols: Schema.Number,
rows: Schema.Number,
}),
Schema.Struct({
type: Schema.Literal("image"),
data: Schema.String,
mediaType: Schema.String,
name: Schema.String,
size: Schema.Number,
}),
Schema.Struct({
type: Schema.Literal("close"),
}),
);

const TerminalServerMessagePayloadSchema = Schema.Union(
Schema.Struct({
type: Schema.Literal("ready"),
session: TerminalSessionSchema,
}),
Schema.Struct({
type: Schema.Literal("output"),
data: Schema.String,
}),
Schema.Struct({
type: Schema.Literal("exit"),
exitCode: Schema.NullOr(Schema.Number),
signal: Schema.NullOr(Schema.Number),
}),
Schema.Struct({
type: Schema.Literal("error"),
message: Schema.String,
}),
);

export const TerminalClientMessageSchema = Schema.parseJson(
TerminalClientMessagePayloadSchema,
);
export const TerminalServerMessageSchema = Schema.parseJson(
TerminalServerMessagePayloadSchema,
);

export type TerminalSessionStatus = Schema.Schema.Type<
typeof TerminalSessionStatusSchema
>;
export type TerminalSession = Schema.Schema.Type<typeof TerminalSessionSchema>;
export type TerminalClientMessage = Schema.Schema.Type<
typeof TerminalClientMessagePayloadSchema
>;
export type TerminalServerMessage = Schema.Schema.Type<
typeof TerminalServerMessagePayloadSchema
>;
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 | ⚡ Quick win

Отсутствует обязательная документация для экспортируемых контрактов.

Согласно руководящим принципам репозитория, все функции/сущности TypeScript должны сопровождаться TSDoc (@pure, @invariant, @precondition, @postcondition, @complexity) и функциональными маркерами (CHANGE, WHY, QUOTE(ТЗ), REF, PURITY, INVARIANT). Экспортируемые схемы (TerminalSessionStatusSchema, TerminalSessionSchema, TerminalClientMessageSchema, TerminalServerMessageSchema и др.) добавлены без этой документации. Пожалуйста, добавьте требуемые аннотации, в частности QUOTE(ТЗ)/REF со ссылкой на исходную спеку контракта.

As per coding guidelines: "TypeScript functions must include comprehensive TSDoc ... @pure marker, @effect dependencies, @invariant ..." и "Functional comments must include: CHANGE, WHY, QUOTE(ТЗ) ... INVARIANT, and COMPLEXITY".

🤖 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/terminal/src/contracts/session.ts` around lines 3 - 81, The exported
schema contracts (TerminalSessionStatusSchema, TerminalSessionSchema,
TerminalClientMessageSchema, TerminalServerMessageSchema and the underlying
TerminalServerMessagePayloadSchema/TerminalClientMessagePayloadSchema) lack the
required TSDoc and functional markers; add a TSDoc block above each exported
symbol containing `@pure` and the requested lifecycle/behavior tags
(`@precondition/`@postcondition or `@invariant` as applicable), an `@complexity`
annotation, and include the repository functional comment markers CHANGE, WHY,
PURITY, INVARIANT plus a QUOTE(ТЗ)/REF that links to the source specification
for the contract; ensure the docs describe expected inputs/outputs (types), any
invariants (e.g., allowed status literals), side‑effects (none — mark `@pure`),
and complexity so the exported schemas satisfy the repo guidelines.

Comment on lines +68 to +78
const terminalImageFileName = (
id: string,
name: string,
mediaType: string,
): string | null => {
const extension = extensionForMediaType(mediaType);
if (extension === null) {
return null;
}
return `${id}-${sanitizeTerminalImageBaseName(name)}.${extension}`;
};
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Найти вызовы createTerminalImagePastePlan и контекст формирования id
rg -nP -C5 '\bcreateTerminalImagePastePlan\s*\(' --type=ts

Repository: ProverCoderAI/docker-git

Length of output: 6723


Path traversal через id: текущий риск не реализуется, но инвариант лучше зафиксировать в коде

В прод-коллеках id для createTerminalImagePastePlan(...) передаётся из packages/api/src/services/terminal-sessions.ts как randomUUID(), а в тестах — строками-литералами; UUID не содержит / и .., поэтому выход за terminalImagePasteDirectory по этому пути невозможен из текущих call sites.
При этом packages/terminal/src/core/image-paste.ts строит fileName как ${id}-... без санитизации/валидации id; чтобы не полагаться на внешний инвариант и предотвратить будущий misuse, стоит добавить проверку/очистку id на уровне terminalImageFileName (аналогично name).

🤖 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/terminal/src/core/image-paste.ts` around lines 68 - 78, The
terminalImageFileName function currently interpolates id directly into the file
name, risking path traversal if id ever contains slashes or dots; update
terminalImageFileName to validate/sanitize id (similar to
sanitizeTerminalImageBaseName) before composing the name: remove or reject path
separators (/, \), path-traversal segments (..), and any characters outside a
safe whitelist (e.g., [A-Za-z0-9_-]); if the sanitized id is empty or invalid,
return null (or throw) so callers like createTerminalImagePastePlan cannot
create names that escape terminalImagePasteDirectory. Ensure you reference
terminalImageFileName and reuse or mirror the sanitization approach used by
sanitizeTerminalImageBaseName so behavior is consistent.

Comment on lines +80 to +130
export const createTerminalImagePastePlan = (
payload: TerminalImagePastePayload,
id: string,
): TerminalImagePastePlan => {
const mediaType = payload.mediaType.toLowerCase();
const fileName = terminalImageFileName(id, payload.name, mediaType);
if (fileName === null) {
return {
_tag: "InvalidTerminalImagePaste",
message: `Unsupported image type: ${payload.mediaType || "unknown"}.`,
};
}
if (!Number.isFinite(payload.size) || payload.size <= 0) {
return {
_tag: "InvalidTerminalImagePaste",
message: "Image payload is empty.",
};
}
if (payload.size > terminalImagePasteMaxBytes) {
return {
_tag: "InvalidTerminalImagePaste",
message: `Image is too large. Max size is ${terminalImagePasteMaxBytes} bytes.`,
};
}
const normalizedBase64 = normalizeBase64(payload.data);
if (normalizedBase64.length > terminalImagePasteMaxBase64Length) {
return {
_tag: "InvalidTerminalImagePaste",
message: `Image is too large. Max size is ${terminalImagePasteMaxBytes} bytes.`,
};
}
const decodedBytes = decodedBase64Bytes(normalizedBase64);
if (decodedBytes === null) {
return {
_tag: "InvalidTerminalImagePaste",
message: "Image payload is not valid base64.",
};
}
if (decodedBytes !== payload.size) {
return {
_tag: "InvalidTerminalImagePaste",
message: "Image payload size does not match its base64 data.",
};
}
return {
_tag: "ValidTerminalImagePaste",
containerPath: `${terminalImagePasteDirectory}/${fileName}`,
decodedBytes,
normalizedBase64,
};
};
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 | ⚡ Quick win

Отсутствует обязательная документация для CORE-функции планирования.

createTerminalImagePastePlan и вспомогательные функции — чистые CORE-функции, но без требуемого TSDoc (@pure, @invariant, @precondition, @postcondition, @complexity) и функциональных маркеров (PURITY, INVARIANT, QUOTE(ТЗ)/REF). Добавьте их, описав инварианты валидации (соответствие decodedBytes === payload.size, ограничения по размеру).

As per coding guidelines: "TypeScript functions must include comprehensive TSDoc ... @precondition, @postcondition, and @complexity O-notation."

🤖 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/terminal/src/core/image-paste.ts` around lines 80 - 130, Add
comprehensive TSDoc to the CORE pure functions (createTerminalImagePastePlan and
its helpers like terminalImageFileName, normalizeBase64, decodedBase64Bytes)
including the required functional markers and tags: add `@pure` and a PURITY
marker, an `@invariant` and INVARIANT marker that states decodedBytes ===
payload.size and that mediaType/fileName are supported, `@precondition` listing
valid inputs (payload.mediaType present and lowercaseable, payload.size is
finite > 0 and ≤ terminalImagePasteMaxBytes, normalizedBase64 length ≤
terminalImagePasteMaxBase64Length), `@postcondition` describing the returned union
(_tag either "ValidTerminalImagePaste" with containerPath, decodedBytes,
normalizedBase64 or "InvalidTerminalImagePaste" with message), and `@complexity`
with O(n) where n is payload.data length; also include a REF or QUOTE(ТЗ) marker
linking to the validation requirements and mention any helper invariants for
terminalImageFileName and decodedBase64Bytes to guide future reviewers.

Comment on lines +1 to +3
export type TerminalWebRuntimeBoundary = {
readonly _tag: "TerminalWebRuntimeBoundary";
};
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 | 🟠 Major | 🏗️ Heavy lift

Несоответствие архитектурным требованиям FCIS и Effect-TS.

Тип назван RuntimeBoundary, но реализован как простой маркер с полем _tag. Согласно coding guidelines, границы между слоями должны реализовываться через Effect-TS Layer pattern с Context.Tag и полноценными сервисами.

Текущая реализация не обеспечивает реальную boundary - это только type-level marker без runtime гарантий разделения эффектов между SHELL и CORE слоями.

🏗️ Рекомендуемая архитектура с Effect Layer pattern

Если это действительно runtime boundary для Web-адаптера, должна быть примерно такая структура:

import { Context, Effect, Layer } from "effect";

/**
 * Web Runtime Boundary Service
 * PURITY: SHELL
 * EFFECT: Effect<TerminalWebCapabilities, WebError, never>
 */
export class TerminalWebRuntimeBoundary extends Context.Tag("TerminalWebRuntimeBoundary")<
  TerminalWebRuntimeBoundary,
  {
    readonly handleWebSocketMessage: (msg: unknown) => Effect.Effect<void, WebError>;
    readonly sendToClient: (data: string) => Effect.Effect<void, WebError>;
    // ... other Web-specific capabilities
  }
>() {}

/**
 * Production implementation
 */
export const TerminalWebRuntimeBoundaryLive = Layer.effect(
  TerminalWebRuntimeBoundary,
  Effect.gen(function* (_) {
    return {
      handleWebSocketMessage: (msg) => Effect.tryPromise({
        try: async () => {
          // implementation
        },
        catch: (error) => new WebError({ cause: error })
      }),
      // ...
    };
  })
);

As per coding guidelines: "All external service dependencies must be wrapped through typed interfaces and injected via Effect-TS Layer pattern" and "Implement Functional Core, Imperative Shell (FCIS) pattern."

🤖 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/terminal/src/web/index.ts` around lines 1 - 3, The current
TerminalWebRuntimeBoundary is only a type-level marker and must be converted
into a runtime Effect-TS Layer-based service: replace the plain exported type
TerminalWebRuntimeBoundary with a Context.Tag-based service (using
Context.Tag("TerminalWebRuntimeBoundary")) that exposes concrete methods like
handleWebSocketMessage and sendToClient typed to return Effect.Effect, then
provide a production Layer (e.g., TerminalWebRuntimeBoundaryLive) built via
Layer.effect/Effect.gen that implements those methods and wraps runtime
side-effects (websocket send/receive) in Effect/Either-style error handling;
ensure all consumers inject this Layer instead of relying on the marker type so
the boundary enforces runtime separation between SHELL and CORE.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Отсутствует обязательная документация для публичного API.

Экспортируемый тип TerminalWebRuntimeBoundary не содержит ни TSDoc комментариев, ни функциональных комментариев. Согласно coding guidelines, все экспортируемые сущности должны быть задокументированы с описанием назначения, инвариантов и примеров использования.

📝 Предлагаемая документация
+/**
+ * Runtime boundary marker для Web-адаптера терминального пакета.
+ * 
+ * CHANGE: Добавлен тип-маркер для разграничения Web runtime boundary
+ * WHY: Обеспечение type-level разделения между CLI, Shell и Web runtime слоями
+ * QUOTE(ТЗ): [требуется ссылка на issue `#361` или спецификацию]
+ * REF: n/a
+ * SOURCE: n/a
+ * FORMAT THEOREM: ∀x: TerminalWebRuntimeBoundary: x._tag = "TerminalWebRuntimeBoundary"
+ * PURITY: CORE
+ * INVARIANT: _tag является string literal константой для type discrimination
+ * 
+ * `@remarks`
+ * Этот тип используется для маркировки границ между runtime слоями в FCIS архитектуре.
+ * Конкретное использование: [требуется описание, где и как используется]
+ * 
+ * `@example`
+ * ```typescript
+ * // [требуется пример использования]
+ * ```
+ */
 export type TerminalWebRuntimeBoundary = {
 	readonly _tag: "TerminalWebRuntimeBoundary";
 };

As per coding guidelines: "Functional comments must include: CHANGE, WHY, QUOTE(ТЗ) or n/a, REF, SOURCE or n/a, FORMAT THEOREM, PURITY (CORE|SHELL), INVARIANT, and COMPLEXITY" and "TypeScript functions must include comprehensive TSDoc."

🤖 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/terminal/src/web/index.ts` around lines 1 - 3, The exported type
TerminalWebRuntimeBoundary lacks required TSDoc/functional comments; add a
comprehensive TSDoc block immediately above the exported type
TerminalWebRuntimeBoundary that describes its purpose, invariants, and usage,
includes the mandated fields CHANGE, WHY, QUOTE (or n/a), REF, SOURCE (or n/a),
FORMAT THEOREM, PURITY (CORE|SHELL), INVARIANT, and COMPLEXITY, and provide a
brief usage example showing how to construct/consume the boundary; ensure the
comment follows existing coding-guidelines formatting and covers any invariants
about the _tag literal.

Comment on lines +1 to +2
import { readFileSync, readdirSync } from "node:fs"
import { join, relative } from "node:path"
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

Необходимо обернуть файловые операции в Effect и улучшить парсинг импортов.

Обнаружены два архитектурных несоответствия:

  1. Прямое использование node:fs/node:path: Файловые операции readFileSync, readdirSync вызываются напрямую без обёртки в Effect. Согласно coding guidelines, все внешние зависимости должны оборачиваться через типизированные интерфейсы и Effect.

  2. Хрупкий парсинг через regex: Регулярное выражение на строке 23 не обработает корректно многострочные импорты, комментарии с import-подобными строками, динамические импорты и сложные реэкспорты. Для надёжного извлечения импортов следует использовать TypeScript Compiler API или AST-парсер.

♻️ Рекомендуемые улучшения

Решение 1: Обернуть fs-операции в Effect

import { Effect } from "effect"
import { readFileSync, readdirSync } from "node:fs"

const readFile = (path: string): Effect.Effect<string, Error> =>
  Effect.try({
    try: () => readFileSync(path, "utf8"),
    catch: (error) => new Error(`Failed to read ${path}: ${error}`)
  })

const listFiles = (directory: string): Effect.Effect<ReadonlyArray<string>, Error> =>
  Effect.try({
    try: () => {
      const entries = readdirSync(directory, { withFileTypes: true })
      return entries.flatMap((entry) => {
        const path = join(directory, entry.name)
        if (entry.isDirectory()) {
          return [...sourceFiles(path)]
        }
        return entry.isFile() && path.endsWith(".ts") ? [path] : []
      })
    },
    catch: (error) => new Error(`Failed to list ${directory}: ${error}`)
  })

Решение 2: Использовать TypeScript Compiler API для надёжного парсинга

import * as ts from "typescript"

const extractImports = (sourceFile: ts.SourceFile): ReadonlyArray<string> => {
  const imports: string[] = []
  const visit = (node: ts.Node) => {
    if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) {
      const moduleSpecifier = node.moduleSpecifier
      if (moduleSpecifier && ts.isStringLiteral(moduleSpecifier)) {
        imports.push(moduleSpecifier.text)
      }
    }
    ts.forEachChild(node, visit)
  }
  visit(sourceFile)
  return imports
}

Also applies to: 9-26

🤖 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/terminal/tests/architecture/boundaries.test.ts` around lines 1 - 2,
Tests directly call node:fs/node:path (readFileSync, readdirSync) and rely on a
regex-based import parser; wrap all filesystem access in typed Effect wrappers
(e.g., implement readFile(path): Effect.Effect<string, Error> and
listFiles(directory): Effect.Effect<ReadonlyArray<string>, Error> that
internally call readFileSync/readdirSync) and replace the fragile regex import
extraction with a TypeScript AST-based extractor (e.g., use ts.createSourceFile
and an extractImports(sourceFile: ts.SourceFile) function that traverses nodes
and collects moduleSpecifier texts for ImportDeclaration/ExportDeclaration),
then update the test code to call these new readFile/listFiles/extractImports
helpers instead of direct fs calls and the regex.

Comment on lines +26 to +30
it.effect("sanitizes unsafe image names", () =>
Effect.sync(() => {
expect(sanitizeTerminalImageBaseName("../..//.bad name!!.png")).toBe("bad-name")
expect(sanitizeTerminalImageBaseName("////.png")).toBe("clipboard-image")
}))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Добавьте property-based тест для инварианта санации имени.

Санация имени — защита от path traversal, и для неё есть чёткий математический инвариант: для любого входа результат не содержит /, \ и последовательности ... Текущие два примера не покрывают пространство входов. As per coding guidelines: "Property-based tests (fast-check) must verify mathematical invariants".

♻️ Пример property-based теста
import * as fc from "fast-check"

it.effect("санитизированное имя никогда не содержит разделителей пути", () =>
  Effect.sync(() => {
    fc.assert(
      fc.property(fc.string(), (raw) => {
        const name = sanitizeTerminalImageBaseName(raw)
        return !name.includes("/") && !name.includes("\\") && !name.includes("..")
      })
    )
  }))
🤖 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/terminal/tests/core/image-paste.test.ts` around lines 26 - 30, Add a
property-based test for the sanitizeTerminalImageBaseName invariant: write an
it.effect test (in the same test suite) that uses fast-check (fc.assert +
fc.property(fc.string(), ...)) to feed arbitrary strings to
sanitizeTerminalImageBaseName and assert the returned name never contains "/",
"\\" or the sequence ".." (and choose a descriptive test title like
"санитизированное имя никогда не содержит разделителей пути"); use the existing
Effect.sync wrapper as in other tests and keep the assertion boolean style used
in the repo.

Comment on lines +22 to +40
it.effect("keeps only the newest output when the replay budget is exceeded", () =>
Effect.sync(() => {
const buffer = appendTerminalOutput(
appendTerminalOutput(emptyTerminalOutputBuffer, "abcdef", 8),
"ghij",
8
)

expect(buffer.charLength).toBe(8)
expect(renderTerminalOutputBuffer(buffer)).toBe("cdefghij")
}))

it.effect("trims an oversized chunk to the replay budget", () =>
Effect.sync(() => {
const buffer = appendTerminalOutput(emptyTerminalOutputBuffer, "0123456789", 4)

expect(buffer.charLength).toBe(4)
expect(renderTerminalOutputBuffer(buffer)).toBe("6789")
}))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Добавьте property-based тест для инварианта бюджета буфера.

Буфер обладает строгим инвариантом: charLength <= budget после любого количества appendTerminalOutput с любыми чанками. Пример-ориентированные кейсы не доказывают это в общем виде. As per coding guidelines: "Property-based tests (fast-check) must verify mathematical invariants".

♻️ Пример property-based теста
import * as fc from "fast-check"

it.effect("длина буфера никогда не превышает бюджет", () =>
  Effect.sync(() => {
    fc.assert(
      fc.property(
        fc.array(fc.string()),
        fc.integer({ min: 1, max: 256 }),
        (chunks, budget) => {
          const buffer = chunks.reduce(
            (acc, chunk) => appendTerminalOutput(acc, chunk, budget),
            emptyTerminalOutputBuffer
          )
          return buffer.charLength <= budget
        }
      )
    )
  }))
🤖 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/terminal/tests/core/output-buffer.test.ts` around lines 22 - 40, Add
a property-based test using fast-check that verifies the buffer invariant
charLength <= budget for any sequence of appends: generate an array of strings
and a budget (e.g., 1..256), reduce the chunks with appendTerminalOutput
starting from emptyTerminalOutputBuffer using the generated budget, and assert
buffer.charLength <= budget (wrap in Effect.sync and use fc.assert/fc.property
as in other tests); reference appendTerminalOutput, emptyTerminalOutputBuffer,
and charLength so the test locates the right functions/fields.

Comment on lines +6 to +32
describe("terminal image fetch planning", () => {
it.effect("accepts absolute supported image paths", () =>
Effect.sync(() => {
expect(planTerminalImageFetch("/home/dev/image.png")).toEqual({
_tag: "ValidTerminalImageFetch",
containerPath: "/home/dev/image.png",
mediaType: "image/png"
})
}))

it.effect("joins relative paths to a valid base directory", () =>
Effect.sync(() => {
expect(planTerminalImageFetch("screens/shot.webp", { baseDir: "/home/dev/project" })).toEqual({
_tag: "ValidTerminalImageFetch",
containerPath: "/home/dev/project/screens/shot.webp",
mediaType: "image/webp"
})
}))

it.effect("rejects traversal paths", () =>
Effect.sync(() => {
expect(planTerminalImageFetch("/home/dev/../secret.png")).toEqual({
_tag: "InvalidTerminalImageFetch",
message: "Image path must not contain '.' or '..' segments."
})
}))
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Рекомендуется дополнить property-based тестами для проверки инвариантов.

Текущие тесты проверяют конкретные примеры, но не покрывают математические инварианты обработки путей. Согласно coding guidelines, для математических свойств следует использовать fast-check.

Инварианты для проверки:

  • Нормализация путей идемпотентна: normalize(normalize(p)) === normalize(p)
  • Любой путь с сегментами .. или .InvalidTerminalImageFetch
  • Соответствие расширения и mediaType детерминировано для всех валидных путей
🧪 Пример property-based теста с fast-check
import * as fc from "fast-check"

describe("terminal image fetch properties", () => {
  it.effect("rejects all paths with traversal segments", () =>
    Effect.sync(() => {
      fc.assert(
        fc.property(
          fc.array(fc.constantFrom("..", "."), { minLength: 1 }),
          fc.array(fc.stringMatching(/^[a-z0-9-]+$/), { minLength: 1 }),
          (traversal, segments) => {
            const path = "/" + [...segments, ...traversal, "image.png"].join("/")
            const result = planTerminalImageFetch(path)
            expect(result._tag).toBe("InvalidTerminalImageFetch")
          }
        )
      )
    }))
    
  it.effect("maps extensions consistently to media types", () =>
    Effect.sync(() => {
      fc.assert(
        fc.property(
          fc.constantFrom("png", "jpg", "jpeg", "gif", "webp"),
          fc.stringMatching(/^\/[a-z0-9/-]+$/),
          (ext, basePath) => {
            const path = `${basePath}/file.${ext}`
            const result1 = planTerminalImageFetch(path)
            const result2 = planTerminalImageFetch(path)
            expect(result1).toEqual(result2)
          }
        )
      )
    }))
})
🤖 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/terminal/tests/server/image-fetch.test.ts` around lines 6 - 32, Add
property-based tests using fast-check that exercise planTerminalImageFetch:
assert idempotence of normalization (normalize(normalize(p)) === normalize(p)),
assert any path containing '.' or '..' segments yields an
InvalidTerminalImageFetch, and assert deterministic mapping from file extension
to mediaType for all valid paths; implement these as new it.effect cases calling
fc.assert + fc.property and use planTerminalImageFetch inside the property
functions to check _tag or equality, referencing the existing tests for pattern
and reusing the same error/message expectations.

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