Skip to content

feat(auth): add Grok authentication support#305

Open
konard wants to merge 4 commits into
ProverCoderAI:mainfrom
konard:issue-304-3b5ced26375c
Open

feat(auth): add Grok authentication support#305
konard wants to merge 4 commits into
ProverCoderAI:mainfrom
konard:issue-304-3b5ced26375c

Conversation

@konard
Copy link
Copy Markdown
Contributor

@konard konard commented May 15, 2026

Fixes #304

Summary

  • Adds Grok as a first-class auth provider across CLI parsing, API contracts, TUI/web auth menus, project auth snapshots, prompt/skill provider schemas, and --auto grok agent selection.
  • Adds Grok credential use cases for API-key login, OAuth/browser login through grok login, status, logout, .docker-git/.orch/auth/grok/<label> storage, and state auto-sync.
  • Extends generated project templates to install grok-dev@latest, configure ~/.grok, disable sandbox by default, wire Playwright MCP, provide passwordless sudo, and support Grok project rules/system prompt hooks.
  • Guards generated Grok entrypoint shell against missing optional GROK_API_KEY/XAI_API_KEY under set -u by rendering real ${VAR:-} bash defaults instead of escaped literals.
  • Keeps Docker daemon probing typed by mapping missing Docker CLI spawn failures to DockerAccessError(DaemonUnavailable) instead of leaking platform exceptions into API rendering tests.

Reproduction / Verification

  1. Before this change, auth grok ..., --auto grok, Grok provider schemas, and Grok template auth paths were absent.
  2. A CI regression reproduced the generated entrypoint failure as /entrypoint.sh: line 2320: GROK_API_KEY: unbound variable when no Grok API key was mounted.
  3. The reproducing coverage now checks Grok parser commands, Grok API-key credential materialization, template rendering, auto-agent selection, API agent command rendering, and unescaped Grok bash default expansion.

Mathematical Guarantees

Invariants

  • forall label: authGrokLogin(label, key) -> exists .docker-git/.orch/auth/grok/normalize(label)/.api-key
  • forall project: grokAuthLabel(project) -> Grok credentials are mounted from the selected label only
  • forall Grok agent run: command includes sandbox disabled and Playwright MCP isolation enabled
  • forall generated Grok entrypoint: unset(GROK_API_KEY) -> no nounset failure during env refresh
  • forall credential status checks: no API key value is logged

Preconditions

  • API-key login requires a non-empty key provided by the auth boundary.
  • OAuth login requires Docker availability because it executes grok login in the auth image.

Postconditions

  • Grok project templates contain .grok/settings.json with Playwright MCP and sandbox off.
  • Grok logout removes .api-key, .env, and .grok credential material for the selected label.
  • Grok env bridge exports empty values for missing optional API-key vars instead of failing shell startup.

Tests

  • bun --cwd packages/lib vitest run tests/core/templates.test.ts
  • bun --cwd packages/lib vitest run tests/usecases/agent-auto-select.test.ts
  • bun run typecheck
  • bun run lint
  • bun run lint:effect
  • bun run --filter @effect-template/api lint
  • bun run test
  • bun run api:test
  • Targeted: packages/lib Grok auth/template/auto-select tests, packages/app Grok parser test, packages/api agent command test.

Notes

  • No screenshots: this change is functional/API/template wiring rather than visual UI work.
  • SOURCE: npm package metadata and CLI behavior for grok-dev@latest were used during implementation research.

Adding .gitkeep for PR creation (default mode).
This file will be removed when the task is complete.

Issue: ProverCoderAI#304
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Полная поддержка провайдера Grok: выбор агента в UI, OAuth и API‑key (login/status/logout), подключение/отключение в проекте, поддержка GROK.md и области навыков grok/skills, новые метки токенов (включая Gemini/Grok) и соответствующие CLI‑опции.
    • Обновлён образ/entrypoint и docker‑compose для инициализации Grok и запуска агента в изолированном режиме (--no-sandbox, Playwright‑изоляция).
  • Tests

    • Добавлены и обновлены тесты для сценариев Grok.
  • Chores

    • Обновлены проектные метаданные (.gitkeep).

Walkthrough

Добавлена интеграция провайдера Grok: контракты и схемы API, CLI/TUI и web‑опции, usecase-ы (helpers, oauth, login, logout, status), шаблоны entrypoint/Dockerfile/compose, сборка команд и тесты.

Changes

Grok интеграция

Layer / File(s) Summary
Контракты и API‑схемы
packages/api/..., packages/app/src/web/api-auth-schema.ts
Добавлены типы и схемы для провайдера grok, поля снапшотов и token labels (geminiTokenLabel, grokTokenLabel).
Auth runtime и usecases
packages/app/src/lib/usecases/*, packages/api/src/services/*, packages/api/src/auth-terminal-runner.ts
Подключены auth-grok usecase-ы (helpers, oauth, login, logout, status), расширены read/run flows, project auth и auth snapshots; auth-terminal-runner поддерживает GrokOauth.
CLI парсеры и опции
packages/app/src/docker-git/cli/*, packages/app/src/docker-git/frontend-lib/*
Добавлены опции --grok-token/--gemini-token, grokAuthPath, buildGrokCommand, парсеры и типы для новых auth-команд.
TUI / Web UI и схемы
packages/app/src/docker-git/menu-*, packages/app/src/web/*
Menu-types, menu-render, effects и web API types/schemas обновлены для отображения/управления Grok-аккаунтами и потоками.
Entrypoint / templates / Dockerfile
packages/app/src/lib/core/templates-entrypoint/grok.ts, agent.ts, project-rules.ts, dockerfile.ts
Добавлен renderEntrypointGrokConfig, grok agent mode, project rules detection, профиль и sudo настройки, Dockerfile підтримка.
Command builders / compose
packages/app/src/lib/core/command-builders*.ts, templates/docker-compose.ts
Добавлен buildTemplateConfig, resolveTokenLabels; token labels включают gemini/grok; docker‑compose env fragments для GEMINI/GROK.
Runtime helpers & docker
packages/lib/src/usecases/*, packages/lib/src/shell/docker-daemon-access.ts
Добавлены auth-grok-helpers, docker run/oauth helpers, dockerInfoPlatformError mapping и права/perm fixes.
Тесты и фикстуры
packages/app/tests/*, packages/lib/tests/*, packages/api/tests/*
Добавлены/обновлены тесты для agents, parser-auth, templates, auth-grok usecases и фикстуры.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

@konard konard changed the title [WIP] Реализовать поддержку авторизации grok feat(auth): add Grok authentication support May 15, 2026
@konard konard marked this pull request as ready for review May 15, 2026 14:44
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: 32

Caution

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

⚠️ Outside diff range comments (6)
packages/app/src/docker-git/menu-project-auth.ts (1)

132-138: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Замените if-цепочку на Match.exhaustive для исчерпывающего анализа ProjectAuthMenuAction.

Текущий код (строки 132-141) не обеспечивает compile-time гарантию покрытия всех вариантов union. При добавлении новой connect- или disconnect-ветки в ProjectAuthFlow новое значение молча попадёт в startProjectAuthPrompt, что приведёт к логической ошибке.

В том же модуле функция projectAuthSuccessMessage демонстрирует правильное применение Match.value(...).pipe(Match.when(...), Match.exhaustive) — используйте тот же паттерн здесь.

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

In `@packages/app/src/docker-git/menu-project-auth.ts` around lines 132 - 138,
Replace the manual if-chain checking action (ProjectGithubDisconnect |
ProjectGitDisconnect | ProjectClaudeDisconnect | ProjectGeminiDisconnect |
ProjectGrokDisconnect) with an exhaustive pattern match using
Match.value(action).pipe(..., Match.exhaustive) to guarantee compile-time
coverage of the ProjectAuthMenuAction union; follow the same pattern used in
projectAuthSuccessMessage (Match.value(...).pipe(Match.when(...),
Match.exhaustive)), creating Match.when clauses for each connect/disconnect
branch and delegating to startProjectAuthPrompt or the appropriate disconnect
handling so any new union variant will force a compile-time handling decision
rather than silently falling through.
packages/api/src/services/federation.ts (1)

1694-1699: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Критическая проблема: отсутствие exhaustive анализа типа провайдера.

Функция resolveAgentProvider использует тернарный оператор вместо exhaustive Match, что может пропустить неподдерживаемые значения AgentProvider. Согласно coding guidelines, все union types должны анализироваться через Match.exhaustive().

🐛 Предлагаемое исправление с exhaustive Match
 const resolveAgentProvider = (
   subscription: FollowSubscription | undefined
 ): AgentProvider => {
   const raw = subscription?.agentProvider ?? process.env["DOCKER_GIT_EXCHANGE_AGENT_PROVIDER"]
-  return raw === "claude" || raw === "opencode" || raw === "grok" || raw === "custom" ? raw : "codex"
+  return Match.value(raw).pipe(
+    Match.when("claude", () => "claude" as const),
+    Match.when("opencode", () => "opencode" as const),
+    Match.when("grok", () => "grok" as const),
+    Match.when("custom", () => "custom" as const),
+    Match.when("codex", () => "codex" as const),
+    Match.orElse(() => "codex" as const)
+  )
 }

Согласно coding guidelines: "Use exhaustive pattern matching with Effect.Match instead of switch statements."

🤖 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/src/services/federation.ts` around lines 1694 - 1699, The
resolver resolveAgentProvider must use Effect.Match.exhaustive to perform
exhaustive pattern matching on the raw provider string instead of the current
ternary; update the function to compute raw from subscription?.agentProvider ||
process.env["DOCKER_GIT_EXCHANGE_AGENT_PROVIDER"] and then call Match.exhaustive
with cases for "claude", "opencode", "grok", "custom", and "codex" (mapping each
to the corresponding AgentProvider) and an explicit default branch that returns
"codex" so all union values are handled; ensure you import Effect.Match and keep
the function signature types (FollowSubscription, AgentProvider) unchanged.
packages/api/src/services/project-auth.ts (1)

173-197: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Одобряю рефакторинг, но отсутствует TSDoc.

Параметризация hasApiKeyInEnvFile с аргументом key — отличное улучшение для переиспользования кода. Однако функция не имеет TSDoc документации.

📝 Предлагаемое дополнение TSDoc
+/**
+ * Checks if an environment file contains a non-empty API key.
+ *
+ * `@param` fs - FileSystem service
+ * `@param` envFilePath - Path to .env file to check
+ * `@param` key - Environment variable key name (e.g., "GEMINI_API_KEY")
+ * `@returns` Effect resolving to true if key exists with non-empty value
+ *
+ * `@pure` false
+ * `@effect` Reads filesystem
+ * `@invariant` returns false for non-existent files or empty values
+ * `@precondition` envFilePath should be normalized
+ * `@postcondition` does not modify filesystem
+ * `@complexity` O(n) where n is the number of lines in .env file
+ */
 const hasApiKeyInEnvFile = (
   fs: FileSystem.FileSystem,
   envFilePath: string,
   key: string
 ): Effect.Effect<boolean, PlatformError> =>

Согласно coding guidelines: "Document all functions with 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/api/src/services/project-auth.ts` around lines 173 - 197, Add a
TSDoc block to the hasApiKeyInEnvFile function that explains its purpose (checks
whether a non-empty env variable named by the `key` exists in a file), documents
parameters `fs: FileSystem.FileSystem`, `envFilePath: string`, and `key:
string`, and states the return type `Effect.Effect<boolean, PlatformError>`
along with behavior on missing files or read errors (returns false or uses
provided Effect error handling). Mention examples of expected env line formats
(e.g., KEY=value, KEY="value") and note that quotes are stripped and whitespace
trimmed so only non-empty values return true. Ensure the TSDoc appears
immediately above the hasApiKeyInEnvFile declaration.
packages/app/src/docker-git/menu-auth.ts (1)

89-107: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Рефакторинг: использовать exhaustive Match вместо boolean-цепочки.

Текущий код определяет suspendTui через ||-цепочку проверок view.flow. Это не обеспечивает exhaustive анализ и может пропустить будущие OAuth-потоки. Согласно coding guidelines, все union types должны анализироваться через .exhaustive() или Match.exhaustive().

♻️ Предлагаемый рефакторинг с exhaustive Match
 const submitAuthPrompt = (view: AuthPromptView, context: AuthInputContext) => {
   const steps = authViewSteps(view.flow)
+  const suspendTui = Match.value(view.flow).pipe(
+    Match.when("GithubOauth", () => true),
+    Match.when("ClaudeOauth", () => true),
+    Match.when("ClaudeLogout", () => true),
+    Match.when("GeminiOauth", () => true),
+    Match.when("GrokOauth", () => true),
+    Match.orElse(() => false)
+  )
   submitPromptStep(
     view,
     steps,
     context,
     () => {
       startAuthMenuWithSnapshot(view.snapshot, context)
     },
     (nextValues) => {
       const label = defaultLabel(nextValues["label"] ?? "")
       const effect = resolveAuthPromptEffect(view, context.state.cwd, nextValues)
-      runAuthPromptEffect(effect, view, label, { ...context, cwd: context.state.cwd }, {
-        suspendTui: view.flow === "GithubOauth" || view.flow === "ClaudeOauth" || view.flow === "ClaudeLogout" ||
-          view.flow === "GeminiOauth" || view.flow === "GrokOauth"
-      })
+      runAuthPromptEffect(effect, view, label, { ...context, cwd: context.state.cwd }, { suspendTui })
     }
   )
 }

Согласно coding guidelines: "Use exhaustive pattern matching with Effect.Match instead of switch statements."

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

In `@packages/app/src/docker-git/menu-auth.ts` around lines 89 - 107, Replace the
boolean OR chain used to compute suspendTui inside submitAuthPrompt with an
exhaustive pattern match over view.flow (use Effect.Match.exhaustive or
Match.exhaustive per coding guidelines) so all union cases are handled; update
the suspendTui argument passed to runAuthPromptEffect (inside submitAuthPrompt)
to be the result of that exhaustive match, and ensure the match returns a
boolean for each flow variant so future OAuth flows will cause a compile-time
failure if not handled.
packages/app/src/lib/core/templates-entrypoint/rtk.ts (1)

9-44: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Несоответствие FORMAT THEOREM и реализации: grok не поддерживается RTK.

FORMAT THEOREM (строка 9) обещает configured(codex, claude, gemini, grok, opencode), однако RTK не поддерживает флаг --grok. Строки 31–32 создают директорию ~/.grok, но строк 41–44 содержат только инициализацию для codex, claude, gemini и opencodegrok отсутствует.

Решение: либо удалите grok из FORMAT THEOREM и директорию ~/.grok, либо отложите эту часть PR до добавления поддержки --grok в RTK. В текущем состоянии математический инвариант нарушен.

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

In `@packages/app/src/lib/core/templates-entrypoint/rtk.ts` around lines 9 - 44,
The FORMAT THEOREM claims RTK configures "grok" but RTK has no --grok flag, so
update renderEntrypointRtkConfig to remove grok references: change the FORMAT
THEOREM token list to configured(codex, claude, gemini, opencode) and delete
"/home/__SSH_USER__/.grok" from the mkdir and chown paths in the template body
(and any related log text), leaving the four actual docker_git_rtk_init_as_user
invocations unchanged; this preserves the invariant without adding unsupported
RTK behavior.
packages/api/src/services/auth-menu.ts (1)

131-146: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Рекомендуется рефакторинг: заменить вложенные тернарные операторы на Match pattern.

Глубоко вложенные тернарные операторы (5+ уровней) трудно читать и поддерживать. Согласно coding guidelines, следует использовать Match.value().pipe() с .exhaustive() для исчерпывающего анализа union-типов.

♻️ Предлагаемый рефакторинг с использованием Match pattern
+import { Match } from "effect"
+
 const syncMessage = (request: AuthMenuRequest): string =>
-  request.flow === "GithubRemove"
-    ? `chore(state): auth gh logout ${canonicalLabel(request.label)}`
-    : request.flow === "GitSet"
-      ? `chore(state): auth git ${canonicalLabel(request.label)}`
-      : request.flow === "GitRemove"
-        ? `chore(state): auth git logout ${canonicalLabel(request.label)}`
-        : request.flow === "ClaudeLogout"
-          ? `chore(state): auth claude logout ${canonicalLabel(request.label)}`
-          : request.flow === "GeminiApiKey"
-            ? `chore(state): auth gemini ${canonicalLabel(request.label)}`
-            : request.flow === "GeminiLogout"
-              ? `chore(state): auth gemini logout ${canonicalLabel(request.label)}`
-              : request.flow === "GrokApiKey"
-                ? `chore(state): auth grok ${canonicalLabel(request.label)}`
-                : `chore(state): auth grok logout ${canonicalLabel(request.label)}`
+  Match.value(request.flow).pipe(
+    Match.when("GithubRemove", () => `chore(state): auth gh logout ${canonicalLabel(request.label)}`),
+    Match.when("GitSet", () => `chore(state): auth git ${canonicalLabel(request.label)}`),
+    Match.when("GitRemove", () => `chore(state): auth git logout ${canonicalLabel(request.label)}`),
+    Match.when("ClaudeLogout", () => `chore(state): auth claude logout ${canonicalLabel(request.label)}`),
+    Match.when("GeminiApiKey", () => `chore(state): auth gemini ${canonicalLabel(request.label)}`),
+    Match.when("GeminiLogout", () => `chore(state): auth gemini logout ${canonicalLabel(request.label)}`),
+    Match.when("GrokApiKey", () => `chore(state): auth grok ${canonicalLabel(request.label)}`),
+    Match.when("GrokLogout", () => `chore(state): auth grok logout ${canonicalLabel(request.label)}`),
+    Match.exhaustive
+  )
🤖 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/src/services/auth-menu.ts` around lines 131 - 146, The
syncMessage function currently uses deeply nested ternary operators to map
AuthMenuRequest.flow to commit message strings; replace that chain with a clear
Match.value() pattern match over request.flow (using
Match.value(request.flow).pipe(...).exhaustive()) that returns the same strings
by calling canonicalLabel(request.label) where needed; update syncMessage to
switch on each flow case (GithubRemove, GitSet, GitRemove, ClaudeLogout,
GeminiApiKey, GeminiLogout, GrokApiKey, GrokLogout) and return the exact
corresponding message for each case, ensuring exhaustiveness for the union type
AuthMenuRequest so future flows cause a compile-time error.
🤖 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/api/src/auth-terminal-runner.ts`:
- Around line 7-8: parseFlow currently maps any invalid or undefined value to
"ClaudeOauth" silently; change it to fail-fast instead: in the parseFlow
function (returning AuthTerminalRunnerFlow) validate that value is exactly one
of "ClaudeOauth" | "GeminiOauth" | "GrokOauth" and return it, otherwise throw a
descriptive Error (include the invalid value) so callers don't silently proceed
with the wrong provider; update any call sites expecting a default accordingly.

In `@packages/api/src/services/auth-terminal-sessions.ts`:
- Around line 72-76: The nested ternary that maps request.flow to a command
string should be replaced with an exhaustive Match-based switch to ensure
compile-time coverage of all AuthTerminalFlow variants: use
Match.value(request.flow).pipe(...) with Match.when handlers for "ClaudeOauth",
"GeminiOauth", and "GrokOauth" that each return the appropriate backtick string
including the existing suffix, and finish with Match.exhaustive() so new flows
cannot silently fall through to the wrong label; update the return expression
accordingly where request.flow is used.

In `@packages/api/src/services/project-auth.ts`:
- Around line 239-258: Add a TSDoc comment for the hasGrokAccountCredentials
function describing its purpose (checks for GROK API credentials in three
locations), its parameters (fs: FileSystem.FileSystem, accountPath: string), the
return type (Effect.Effect<boolean, PlatformError> indicating success boolean or
PlatformError), and the behavior/side-effects (it checks .api-key via
hasFileAtPath, GROK_API_KEY in .env via hasApiKeyInEnvFile, and OAuth token in
.grok/user-settings.json via hasNonEmptyOauthToken), and note possible errors
propagated from PlatformError; place the comment immediately above the
hasGrokAccountCredentials declaration.

In `@packages/app/src/docker-git/frontend-lib/core/command-builders-template.ts`:
- Around line 28-71: Add full TSDoc and functional comments to the CORE pure
function buildTemplateConfigBase: include `@pure` (true/false), `@effect` (required
services or "none"), `@invariant` (any mathematical invariants), `@precondition`
(valid shape/constraints of input Pick<BuildTemplateConfigInput,...>),
`@postcondition` (returned object matches CreateCommand["config"] subset), and
`@complexity` (time and space). Also add the functional comment block with CHANGE,
WHY, QUOTE (or n/a), REF, SOURCE (or n/a), FORMAT THEOREM, PURITY, INVARIANT,
COMPLEXITY describing intent, rationale, references and guarantees for
buildTemplateConfigBase and reference the function name and the exact fields it
maps (containerName, serviceName, sshUser, sshPort, repoUrl, repoRef, targetDir,
volumeName, dockerGitPath, authorizedKeysPath, envGlobalPath, envProjectPath,
codexAuthPath, codexSharedAuthPath, codexHome, geminiAuthPath, geminiHome,
grokAuthPath, grokHome) to make clear mapping and postconditions.
- Around line 73-93: The exported CORE function buildTemplateConfig lacks the
required comprehensive TSDoc; add a full TSDoc block immediately above the
exported function buildTemplateConfig describing the function purpose, each
parameter in BuildTemplateConfigInput (`@param`), the return type
CreateCommand["config"] (`@returns`), and include the required tags: `@pure`,
`@effect` (list any external deps such as buildTemplateConfigBase and
defaultTemplateConfig), `@invariant` (describe any invariants about returned
config), `@precondition` (validations on input fields like cpuLimit/ramLimit/gpu),
`@postcondition` (what properties will always be present in the returned config),
and `@complexity` (Big-O for any significant work); ensure references to internal
symbols buildTemplateConfigBase and defaultTemplateConfig are mentioned in the
text so readers can locate dependencies.

In `@packages/app/src/lib/core/auto-agent-flags.ts`:
- Line 23: Update the error string that sets the `reason` (currently "expected
one of: claude, codex, gemini, grok") to include "auto" so it matches the
accepted mode (`requested === "auto"`); ensure the `reason` value lists all
supported modes including "auto" and stays synchronized with any validation
logic that references `requested`.

In `@packages/app/src/lib/core/command-builders-template.ts`:
- Around line 28-94: The two exported functions buildTemplateConfigBase and
buildTemplateConfig are missing the required comprehensive TSDoc and functional
markers; add TSDoc blocks above each function documenting parameters and return
types and include the mandated tags/markers: `@pure`, `@invariant`, `@precondition`,
`@postcondition`, `@complexity` (with O-notation), and the functional comment fields
(CHANGE, WHY, QUOTE or n/a, REF, SOURCE or n/a, FORMAT THEOREM, PURITY
(CORE|SHELL), EFFECT signature if applicable, INVARIANT, COMPLEXITY). Ensure the
docs reference the function signature symbols buildTemplateConfigBase and
buildTemplateConfig and succinctly describe input: BuildTemplateConfigInput and
output: CreateCommand["config"], plus any important invariants (e.g., which
fields are mapped/copied), and place the blocks immediately above each function
declaration.

In `@packages/app/src/lib/core/templates/docker-compose.ts`:
- Around line 222-224: Комментарий после переменных окружения не соответствует
своему назначению: переменная fragments.maybeGrokAuthLabelEnv снабжена
комментарием, который сейчас стоит одновременно после
fragments.maybeAgentModeEnv и fragments.maybeAgentAutoEnv, что вводит в
заблуждение; исправьте шаблон в docker-compose.ts так, чтобы комментарий "#
Optional Grok account label selector (maps to GROK_AUTH_LABEL)" стоял
непосредственно после fragments.maybeGrokAuthLabelEnv, а для
fragments.maybeAgentModeEnv и fragments.maybeAgentAutoEnv добавьте свои
отдельные комментарии (или уберите их), чтобы каждый комментарий однозначно
относился к соответствующей переменной.

In `@packages/app/src/lib/core/templates/dockerfile.ts`:
- Around line 113-114: Строка, которая маскирует провал установки Grok CLI ("RUN
grok --version >/dev/null || true") должна быть исправлена: замените или удалите
конструкцию "|| true" и/или уберите перенаправление в /dev/null so that the
subsequent check fails the build when the CLI is not present; specifically
update the two Dockerfile RUN commands ("RUN npm install -g grok-dev@latest
--force" and the following "RUN grok --version >/dev/null || true") so that the
image build exits non‑zero if "grok --version" fails (e.g., use plain "RUN grok
--version" or an explicit check like "RUN command -v grok >/dev/null" without
"|| true").

In `@packages/app/src/lib/usecases/auth-grok-helpers.ts`:
- Around line 209-214: The code currently runs runCommandExitCode with "chmod -R
777" on credentialsDir which makes secrets world-readable/writable; change to
set owner-only permissions (e.g., directories 700 and files 600) or use a safe
recursive chmod like "chmod -R u+rwX,go-rwx" so only the owner can
read/write/execute, and remove the blanket Effect.orElse(() =>
Effect.succeed(0)) that silences failures so permission errors surface; update
the same pattern in the similar block referenced later (the other chmod usage
around the 230-255 region) to use the secure permission command and proper error
handling, locating the changes around the runCommandExitCode and credentialsDir
symbols.
- Around line 193-206: The cleanup fallback currently swallows errors
(removeFallback is defined with Effect.orElse(() => Effect.void)), so if both
fs.remove(credentialsDir) and the docker fallback fail the effect is treated as
success and code proceeds; remove the swallowing wrapper from removeFallback
(keep runCommandExitCode(...).pipe(Effect.asVoid) but do not orElse to
Effect.void) so that if the docker fallback fails the overall effect fails and
propagation stops; ensure fs.remove(...).pipe(Effect.orElse(() =>
removeFallback)) remains so the fallback is attempted but failures are not
suppressed.
- Around line 165-170: The current check in hasGrokCredentials (which uses
isRegularFile(grokUserSettingsPath(accountPath)) and then treats any non-empty
user-settings.json as valid) incorrectly treats bootstrap files created by
writeInitialGrokSettings(..., null) as authenticated; change hasGrokCredentials
to parse the JSON from fs.readFileString(grokUserSettingsPath(accountPath)) and
verify presence of real credential fields (e.g., non-null/non-empty token,
apiKey, or username fields your code uses) rather than mere file existence or
non-empty content, so resolveGrokAuthMethod() won't return "user-settings" for
bootstrap files; apply the same validation logic where similar checks exist
(around the other occurrence mentioned, lines ~250-255) and use
grokUserSettingsPath, hasGrokCredentials, resolveGrokAuthMethod, and
writeInitialGrokSettings names to locate the changes.
- Around line 55-63: The Dockerfile RUN step currently installs grok-dev using
the floating tag and force flag; replace the unstable install invocation that
uses "grok-dev@latest" and "--force" with a pinned install of grok-dev version
1.1.6 so the Docker build is deterministic (locate the RUN npm install -g
grok-dev... line in the auth-grok helper Docker snippet and change it to install
grok-dev@1.1.6 without --force).

In `@packages/app/src/lib/usecases/auth-grok-oauth.ts`:
- Around line 79-101: The fixGrokAuthPermissions function currently runs a
docker alpine container to chmod -R 777 on the Grok auth directory; change this
to set restrictive permissions or fix ownership instead: replace the chmod args
in fixGrokAuthPermissions to use "chmod -R 700" (or "750" if group-read is
required) or, preferably, run "chown -R <user>:<group>" inside the container
before applying more restrictive chmod; ensure the CommandFailedError and
runCommandWithExitCodes call remain unchanged but update the args array passed
to docker to reflect the safer permission/ownership commands.
- Around line 38-43: Replace the unsupported env vars in the env array
(currently `HOME=${containerPath}`, `NO_BROWSER=true`, `GROK_NO_BROWSER=true`,
`MCP_PLAYWRIGHT_ISOLATED=1`) with a supported approach: look up the
grok/grok-dev CLI docs and either (a) pass the official CLI flag to disable
browser opening (e.g., run the "grok login" command with the documented flag
such as "--no-browser" or the exact flag/name you find) or (b) if no flag/ENV
exists, remove `NO_BROWSER`/`GROK_NO_BROWSER` and implement a headless fallback
in the auth-grok-oauth flow that spawns "grok login", captures the printed
authorization URL from stdout, prompts the user to open it manually and paste
the callback, and include a runtime version check of grok-dev to ensure the
chosen method is supported; update the code that constructs the env array and
the place that calls "grok login" accordingly.

In `@packages/app/src/lib/usecases/auth-grok.ts`:
- Line 40: The chmod call for apiKeyFilePath is currently wrapped with
orElseSucceed which suppresses failures; change this so permission-setting
errors are not swallowed—remove the orElseSucceed around
fs.chmod(apiKeyFilePath, 0o600) (or replace it with explicit error handling that
logs and rethrows) so that failures propagate and cause the operation to fail;
locate the call to fs.chmod and the use of orElseSucceed in
usecases/auth-grok.ts (reference symbols: fs.chmod, apiKeyFilePath,
orElseSucceed) and ensure the code fails on chmod errors rather than continuing
silently.

In `@packages/app/tests/docker-git/parser-auth.test.ts`:
- Around line 22-41: Add a fast-check property-based test that repeatedly runs
parseOrThrow for Grok auth commands with generated valid label strings and
asserts the invariants instead of a single static case: generate labels
(non-empty, trimmed, maybe alphanumeric/spaces) and for each value call
parseOrThrow(["auth","grok","login","--label", label, "--web"]),
parseOrThrow(["auth","grok","status","--label", label]) and
parseOrThrow(["auth","grok","logout","--label", label]) and assert the returned
tags are AuthGrokLogin/AuthGrokStatus/AuthGrokLogout respectively, that
login.isWeb === true, and that .grokAuthPath === ".docker-git/.orch/auth/grok"
for all three results; integrate fast-check into the existing it.effect test (or
add a new one) and fail on any counterexample so the parser invariants are
validated across many generated labels.

In `@packages/lib/src/core/auto-agent-flags.ts`:
- Line 22: The error message for the --auto flag omits "auto" in the
allowed-values text; update the `reason` string in
packages/lib/src/core/auto-agent-flags.ts (the `reason` property for the --auto
flag) to include "auto" alongside "claude, codex, gemini, grok" so the hint
correctly reflects that "auto" is a valid option.

In `@packages/lib/src/core/domain.ts`:
- Line 58: The public type AgentMode was extended to include "grok" and needs a
functional comment block above the AgentMode declaration documenting the CHANGE,
WHY, QUOTE (requirement), and REF markers; update the comment for the AgentMode
type to state that "grok" was added (CHANGE), explain the architectural reason
or compatibility rationale (WHY), cite the requirement or ticket text that
mandated the addition (QUOTE), and include a reference ID (REF), ensuring the
comment is adjacent to the AgentMode type declaration to keep the public API
change discoverable.

In `@packages/lib/src/core/templates-entrypoint/agent.ts`:
- Around line 43-45: The generated AGENT_ENV_FILE currently ends up
world-readable because the script writes /etc/profile.d/grok-config.sh contents
then sets mode via "chmod 644", exposing secrets; change the post-write steps to
chown the file to the runtime user and group and tighten permissions (e.g., set
to 640 or 600) and ensure group is the runtime group used by the agent; update
the sequence around AGENT_ENV_FILE, replacing the chmod 644 usage with a chown
to the agent runtime user/group (use your runtime user symbol/variable) followed
by chmod 640 (or 600) so only the agent user/group can read the file.

In `@packages/lib/src/core/templates/docker-compose.ts`:
- Around line 221-223: Split the combined env fragment line into two separate
lines so each fragment has the correct comment: render
fragments.maybeGrokAuthLabelEnv on its own line with the "Optional Grok account
label selector (maps to GROK_AUTH_LABEL)" comment, and render
fragments.maybeAgentModeEnv and fragments.maybeAgentAutoEnv together on the next
line with a distinct comment like "Optional agent mode and auto-start
configuration"; update the template where these symbols appear so comments align
with the corresponding fragments (maybeGrokAuthLabelEnv, maybeAgentModeEnv,
maybeAgentAutoEnv).

In `@packages/lib/src/core/templates/dockerfile.ts`:
- Around line 113-114: В шаблоне Dockerfile замените установку неофициального
пакета и мягкую проверку на официальную установку или явное, зафиксированное
стороннее решение: вместо "RUN npm install -g grok-dev@latest --force" и "RUN
grok --version >/dev/null || true" либо (предпочтительно) скачайте и установите
официальное xAI Grok Build через curl/официальный инсталлятор (подставив
проверяемую версию/хеш), либо если оставляете сторонний пакет — уберите
"--force", зафиксируйте конкретную версию вместо "latest", удалите "|| true" и
добавьте явную проверку выхода с ошибкой при неуспешной установке; если
выбираете сторонний пакет, потребуйте security review/approval перед мерджем.

In `@packages/lib/src/usecases/auth-grok-helpers.ts`:
- Around line 208-214: The chmod 777 call in the runCommandExitCode invocation
grants excessive permissions to credentialsDir; replace it with a safer,
restrictive approach: run commands that set directories to 700 and files to 600
(e.g., use find to apply chmod 700 to all directories under credentialsDir and
chmod 600 to all files) instead of ["-R","777",credentialsDir], keeping the call
site runCommandExitCode({ cwd, command: "chmod", args: ... }) and credentialsDir
variable; preserve the Effect.orElse(() => Effect.succeed(0)) error handling
around the command(s).
- Around line 59-63: Replace the npm global install that uses an unpredictable
latest tag and --force: find occurrences of the literal string "npm install -g
grok-dev@latest --force" in the Dockerfile template generators and change them
to a pinned, explicit version like "npm install -g grok-dev@1.1.6" and remove
the "--force" flag; update each template function that emits the Dockerfile
snippet (the Dockerfile template generator(s) that produce the RUN curl ... &&
apt-get ... && npm install -g ... line) so they hardcode the stable version
instead of `@latest` and do not pass --force.

In `@packages/lib/src/usecases/auth-grok-oauth.ts`:
- Around line 79-101: The function fixGrokAuthPermissions currently runs chmod
-R 777 via runCommandWithExitCodes which grants world-writable access to Grok
credentials; change the chmod invocation in the args passed to
runCommandWithExitCodes (the array containing "chmod", "-R", "777",
containerPath) to a safe permission such as "700" (or "755" if group/other read
is required) so only the owner can read/write/execute the credentials directory;
keep the CommandFailedError creation and the Effect.tapError/Effect.orElse
handling unchanged.
- Around line 103-130: Add a TSDoc block above the exported
runGrokOauthLoginWithPrompt function that documents its purpose and behavior and
includes the required tags: `@pure`, `@effect` (describe the Effect type and failure
channels AuthError | CommandFailedError | PlatformError), `@invariant` (state
invariants such as cwd/accountPath resolution), `@precondition` (valid cwd and
accountPath, docker available), `@postcondition` (prints OAuth instructions, runs
docker auth flow, fixes permissions), and `@complexity` (time/space complexity).
Also document parameters (cwd, accountPath, options.image,
options.containerPath) and the return type (Effect.Effect<void, AuthError |
CommandFailedError | PlatformError, CommandExecutor.CommandExecutor>) so the
public API is fully covered for runGrokOauthLoginWithPrompt.
- Around line 46-67: Add full TSDoc to the exported function
buildDockerGrokAuthArgs (include `@pure`, `@effect`, `@invariant`, `@precondition`,
`@postcondition`, `@complexity`) and implement input validation for
spec.containerPath (referencing DockerGrokAuthSpec and buildDockerGrokAuthArgs)
so the function rejects or throws a clear error when containerPath is empty,
contains null bytes, contains path traversal patterns (e.g., "..") or is not an
absolute/normalized path; ensure you validate before using it in the args array
and document the precondition/postcondition that containerPath will be a
normalized absolute path and that the returned array contains the Docker run
args including the validated mount and workdir.

In `@packages/lib/src/usecases/auth-grok.ts`:
- Around line 50-62: Параметр _command в сигнатуре функции authGrokLoginCli не
используется; либо удалите его из сигнатуры (заменив экспорт на
authGrokLoginCli(): Effect.Effect<...>) либо начните явно использовать его
внутри Effect.gen (например передав необходимые поля в логи/логику) to satisfy
the interface; обновите все вызовы/auth signatures accordingly so they match the
new signature or continue accepting the parameter if required for interface
compatibility.
- Around line 76-78: The code currently calls prepareGrokCredentialsDir(...)
then immediately writeInitialGrokSettings(..., null) which can leave a null API
key on disk if the subsequent OAuth flow fails; update the flow in auth-grok.ts
so you only call writeInitialGrokSettings after the OAuth process completes
successfully (or, alternatively, perform the write as part of a transactional
sequence and remove/rollback the created settings on any OAuth error).
Concretely, move the writeInitialGrokSettings call to after the successful
return of the OAuth routine (or add a catch/finally that deletes or restores the
credentials file on failure), referencing prepareGrokCredentialsDir and
writeInitialGrokSettings to locate where to change behavior.
- Line 40: Хранится молчаливое подавление ошибки chmod при установке прав на
файл API-ключа: в месте с вызовом fs.chmod внутри usecases/auth-grok.ts удалите
использование Effect.orElseSucceed(() => void 0) и позвольте ошибке/эффекту
проброситься (или замените на явный Effect.fail с информативным сообщением),
чтобы не продолжать работу при неудачной установке прав; убедитесь, что ошибка
содержит контекст (путь файла и причину) и приводит к отказу
аутентификации/завершению процесса вместо бесшумного продолжения.

In `@packages/lib/tests/usecases/auth-grok.test.ts`:
- Around line 10-23: Добавьте краткую TSDoc над helper-функцией withTempDir,
объясняющую её назначение (создаёт временную директорию для теста и передаёт её
в callback), описывающую использование Effect.scoped для управления жизненным
циклом ресурса, перечисляющую параметр use (callback, получающий tempDir:
string) и возвращаемое значение (Effect, который может содержать результат теста
или FileSystem.FileSystem), и упомяните префикс временной директории; ссылаясь
на сimbols withTempDir, Effect.scoped и FileSystem.FileSystem, чтобы облегчить
поиск места вставки документации.

---

Outside diff comments:
In `@packages/api/src/services/auth-menu.ts`:
- Around line 131-146: The syncMessage function currently uses deeply nested
ternary operators to map AuthMenuRequest.flow to commit message strings; replace
that chain with a clear Match.value() pattern match over request.flow (using
Match.value(request.flow).pipe(...).exhaustive()) that returns the same strings
by calling canonicalLabel(request.label) where needed; update syncMessage to
switch on each flow case (GithubRemove, GitSet, GitRemove, ClaudeLogout,
GeminiApiKey, GeminiLogout, GrokApiKey, GrokLogout) and return the exact
corresponding message for each case, ensuring exhaustiveness for the union type
AuthMenuRequest so future flows cause a compile-time error.

In `@packages/api/src/services/federation.ts`:
- Around line 1694-1699: The resolver resolveAgentProvider must use
Effect.Match.exhaustive to perform exhaustive pattern matching on the raw
provider string instead of the current ternary; update the function to compute
raw from subscription?.agentProvider ||
process.env["DOCKER_GIT_EXCHANGE_AGENT_PROVIDER"] and then call Match.exhaustive
with cases for "claude", "opencode", "grok", "custom", and "codex" (mapping each
to the corresponding AgentProvider) and an explicit default branch that returns
"codex" so all union values are handled; ensure you import Effect.Match and keep
the function signature types (FollowSubscription, AgentProvider) unchanged.

In `@packages/api/src/services/project-auth.ts`:
- Around line 173-197: Add a TSDoc block to the hasApiKeyInEnvFile function that
explains its purpose (checks whether a non-empty env variable named by the `key`
exists in a file), documents parameters `fs: FileSystem.FileSystem`,
`envFilePath: string`, and `key: string`, and states the return type
`Effect.Effect<boolean, PlatformError>` along with behavior on missing files or
read errors (returns false or uses provided Effect error handling). Mention
examples of expected env line formats (e.g., KEY=value, KEY="value") and note
that quotes are stripped and whitespace trimmed so only non-empty values return
true. Ensure the TSDoc appears immediately above the hasApiKeyInEnvFile
declaration.

In `@packages/app/src/docker-git/menu-auth.ts`:
- Around line 89-107: Replace the boolean OR chain used to compute suspendTui
inside submitAuthPrompt with an exhaustive pattern match over view.flow (use
Effect.Match.exhaustive or Match.exhaustive per coding guidelines) so all union
cases are handled; update the suspendTui argument passed to runAuthPromptEffect
(inside submitAuthPrompt) to be the result of that exhaustive match, and ensure
the match returns a boolean for each flow variant so future OAuth flows will
cause a compile-time failure if not handled.

In `@packages/app/src/docker-git/menu-project-auth.ts`:
- Around line 132-138: Replace the manual if-chain checking action
(ProjectGithubDisconnect | ProjectGitDisconnect | ProjectClaudeDisconnect |
ProjectGeminiDisconnect | ProjectGrokDisconnect) with an exhaustive pattern
match using Match.value(action).pipe(..., Match.exhaustive) to guarantee
compile-time coverage of the ProjectAuthMenuAction union; follow the same
pattern used in projectAuthSuccessMessage
(Match.value(...).pipe(Match.when(...), Match.exhaustive)), creating Match.when
clauses for each connect/disconnect branch and delegating to
startProjectAuthPrompt or the appropriate disconnect handling so any new union
variant will force a compile-time handling decision rather than silently falling
through.

In `@packages/app/src/lib/core/templates-entrypoint/rtk.ts`:
- Around line 9-44: The FORMAT THEOREM claims RTK configures "grok" but RTK has
no --grok flag, so update renderEntrypointRtkConfig to remove grok references:
change the FORMAT THEOREM token list to configured(codex, claude, gemini,
opencode) and delete "/home/__SSH_USER__/.grok" from the mkdir and chown paths
in the template body (and any related log text), leaving the four actual
docker_git_rtk_init_as_user invocations unchanged; this preserves the invariant
without adding unsupported RTK behavior.
🪄 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: 2789038d-8dd6-4ae0-aa69-a06d1d9b5989

📥 Commits

Reviewing files that changed from the base of the PR and between da15456 and b6cb6bf.

📒 Files selected for processing (106)
  • packages/api/src/api/contracts.ts
  • packages/api/src/api/schema.ts
  • packages/api/src/auth-terminal-runner.ts
  • packages/api/src/http.ts
  • packages/api/src/services/agents.ts
  • packages/api/src/services/auth-menu.ts
  • packages/api/src/services/auth-terminal-sessions.ts
  • packages/api/src/services/container-tasks-core.ts
  • packages/api/src/services/federation.ts
  • packages/api/src/services/project-auth.ts
  • packages/api/src/services/project-prompts.ts
  • packages/api/src/services/project-skills.ts
  • packages/api/src/services/projects.ts
  • packages/api/src/ui.ts
  • packages/api/tests/agents.test.ts
  • packages/app/src/docker-git/api-auth-codec.ts
  • packages/app/src/docker-git/api-client-create.ts
  • packages/app/src/docker-git/api-client.ts
  • packages/app/src/docker-git/cli/parser-apply.ts
  • packages/app/src/docker-git/cli/parser-auth.ts
  • packages/app/src/docker-git/cli/parser-options.ts
  • packages/app/src/docker-git/frontend-lib/core/auth-domain.ts
  • packages/app/src/docker-git/frontend-lib/core/auto-agent-flags.ts
  • packages/app/src/docker-git/frontend-lib/core/command-builders-template.ts
  • packages/app/src/docker-git/frontend-lib/core/command-builders.ts
  • packages/app/src/docker-git/frontend-lib/core/command-options.ts
  • packages/app/src/docker-git/frontend-lib/core/domain.ts
  • packages/app/src/docker-git/frontend-lib/core/template-defaults.ts
  • packages/app/src/docker-git/menu-auth-effects.ts
  • packages/app/src/docker-git/menu-auth-shared.ts
  • packages/app/src/docker-git/menu-auth-snapshot-builder.ts
  • packages/app/src/docker-git/menu-auth.ts
  • packages/app/src/docker-git/menu-project-auth-shared.ts
  • packages/app/src/docker-git/menu-project-auth.ts
  • packages/app/src/docker-git/menu-render-auth.ts
  • packages/app/src/docker-git/menu-render-project-auth.ts
  • packages/app/src/docker-git/menu-types.ts
  • packages/app/src/docker-git/program-unsupported.ts
  • packages/app/src/lib/core/auth-domain.ts
  • packages/app/src/lib/core/auto-agent-flags.ts
  • packages/app/src/lib/core/command-builders-template.ts
  • packages/app/src/lib/core/command-builders.ts
  • packages/app/src/lib/core/command-options.ts
  • packages/app/src/lib/core/domain.ts
  • packages/app/src/lib/core/template-defaults.ts
  • packages/app/src/lib/core/templates-entrypoint.ts
  • packages/app/src/lib/core/templates-entrypoint/agent.ts
  • packages/app/src/lib/core/templates-entrypoint/base.ts
  • packages/app/src/lib/core/templates-entrypoint/grok.ts
  • packages/app/src/lib/core/templates-entrypoint/project-rules.ts
  • packages/app/src/lib/core/templates-entrypoint/rtk.ts
  • packages/app/src/lib/core/templates/docker-compose.ts
  • packages/app/src/lib/core/templates/dockerfile.ts
  • packages/app/src/lib/shell/config.ts
  • packages/app/src/lib/shell/docker-daemon-access.ts
  • packages/app/src/lib/usecases/apply-overrides.ts
  • packages/app/src/lib/usecases/auth-grok-helpers.ts
  • packages/app/src/lib/usecases/auth-grok-logout.ts
  • packages/app/src/lib/usecases/auth-grok-oauth.ts
  • packages/app/src/lib/usecases/auth-grok-status.ts
  • packages/app/src/lib/usecases/auth-grok.ts
  • packages/app/src/lib/usecases/auth-sync-helpers.ts
  • packages/app/src/lib/usecases/auth.ts
  • packages/app/src/web/action-prompt.ts
  • packages/app/src/web/actions-auth.ts
  • packages/app/src/web/api-auth-schema.ts
  • packages/app/src/web/api-prompts-schema.ts
  • packages/app/src/web/api-schema.ts
  • packages/app/src/web/api-skills-schema.ts
  • packages/app/src/web/api-skills.ts
  • packages/app/src/web/api-types.ts
  • packages/app/src/web/api.ts
  • packages/app/src/web/panel-auth.tsx
  • packages/app/src/web/panel-project-auth.tsx
  • packages/app/src/web/panel-project-prompts.tsx
  • packages/app/src/web/panel-project-skills.tsx
  • packages/app/tests/docker-git/actions-github-oauth.test.ts
  • packages/app/tests/docker-git/parser-auth.test.ts
  • packages/lib/src/core/auth-domain.ts
  • packages/lib/src/core/auto-agent-flags.ts
  • packages/lib/src/core/command-builders-template.ts
  • packages/lib/src/core/command-builders.ts
  • packages/lib/src/core/command-options.ts
  • packages/lib/src/core/domain.ts
  • packages/lib/src/core/template-defaults.ts
  • packages/lib/src/core/templates-entrypoint.ts
  • packages/lib/src/core/templates-entrypoint/agent.ts
  • packages/lib/src/core/templates-entrypoint/base.ts
  • packages/lib/src/core/templates-entrypoint/grok.ts
  • packages/lib/src/core/templates-entrypoint/project-rules.ts
  • packages/lib/src/core/templates-entrypoint/rtk.ts
  • packages/lib/src/core/templates/docker-compose.ts
  • packages/lib/src/core/templates/dockerfile.ts
  • packages/lib/src/shell/config.ts
  • packages/lib/src/shell/docker-daemon-access.ts
  • packages/lib/src/usecases/apply-overrides.ts
  • packages/lib/src/usecases/auth-grok-helpers.ts
  • packages/lib/src/usecases/auth-grok-logout.ts
  • packages/lib/src/usecases/auth-grok-oauth.ts
  • packages/lib/src/usecases/auth-grok-status.ts
  • packages/lib/src/usecases/auth-grok.ts
  • packages/lib/src/usecases/auth-sync-helpers.ts
  • packages/lib/src/usecases/auth.ts
  • packages/lib/tests/core/templates.test.ts
  • packages/lib/tests/usecases/agent-auto-select.test.ts
  • packages/lib/tests/usecases/auth-grok.test.ts

Comment on lines 7 to +8
const parseFlow = (value: string | undefined): AuthTerminalRunnerFlow =>
value === "ClaudeOauth" || value === "GeminiOauth" ? value : "ClaudeOauth"
value === "ClaudeOauth" || value === "GeminiOauth" || value === "GrokOauth" ? value : "ClaudeOauth"
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 | ⚡ Quick win

Не подменяйте невалидный flow значением ClaudeOauth по умолчанию.

Сейчас при ошибочном аргументе silently выбирается Claude-флоу, из-за чего можно авторизовать не того провайдера и получить ложный успех в CI/локально. Лучше fail-fast на невалидном значении.

💡 Предлагаемое исправление
-const parseFlow = (value: string | undefined): AuthTerminalRunnerFlow =>
-  value === "ClaudeOauth" || value === "GeminiOauth" || value === "GrokOauth" ? value : "ClaudeOauth"
+const parseFlow = (value: string | undefined): AuthTerminalRunnerFlow => {
+  if (value === "ClaudeOauth" || value === "GeminiOauth" || value === "GrokOauth") {
+    return value
+  }
+  throw new Error(`Unsupported auth flow: ${value ?? "<empty>"}`)
+}
🤖 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/src/auth-terminal-runner.ts` around lines 7 - 8, parseFlow
currently maps any invalid or undefined value to "ClaudeOauth" silently; change
it to fail-fast instead: in the parseFlow function (returning
AuthTerminalRunnerFlow) validate that value is exactly one of "ClaudeOauth" |
"GeminiOauth" | "GrokOauth" and return it, otherwise throw a descriptive Error
(include the invalid value) so callers don't silently proceed with the wrong
provider; update any call sites expecting a default accordingly.

Comment on lines 72 to +76
return request.flow === "ClaudeOauth"
? `docker-git menu auth claude oauth${suffix}`
: `docker-git menu auth gemini oauth${suffix}`
: request.flow === "GeminiOauth"
? `docker-git menu auth gemini oauth${suffix}`
: `docker-git menu auth grok oauth${suffix}`
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== AuthTerminalFlow declaration(s) =="
rg -n -C3 '\bAuthTerminalFlow\b|ClaudeOauth|GeminiOauth|GrokOauth' packages/api/src/api/contracts.ts packages/api/src/api/schema.ts

echo
echo "== resolveCommandLabel implementation =="
rg -n -C6 'const resolveCommandLabel' packages/api/src/services/auth-terminal-sessions.ts

Repository: ProverCoderAI/docker-git

Length of output: 1907


Используйте исчерпывающий разбор request.flow с Match.exhaustive()

Сейчас последняя ветка ternary неявно маппит любой новый flow в grok oauth, что нарушает требование к исчерпывающему анализу union-типов (coding guidelines). При расширении AuthTerminalFlow значение будет тихо отображено в неправильный label.

Замените вложенные ternary на Match.exhaustive() для проверки на уровне компилятора:

return Match.value(request.flow).pipe(
  Match.when("ClaudeOauth", () => `docker-git menu auth claude oauth${suffix}`),
  Match.when("GeminiOauth", () => `docker-git menu auth gemini oauth${suffix}`),
  Match.when("GrokOauth", () => `docker-git menu auth grok oauth${suffix}`),
  Match.exhaustive()
)
🤖 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/src/services/auth-terminal-sessions.ts` around lines 72 - 76,
The nested ternary that maps request.flow to a command string should be replaced
with an exhaustive Match-based switch to ensure compile-time coverage of all
AuthTerminalFlow variants: use Match.value(request.flow).pipe(...) with
Match.when handlers for "ClaudeOauth", "GeminiOauth", and "GrokOauth" that each
return the appropriate backtick string including the existing suffix, and finish
with Match.exhaustive() so new flows cannot silently fall through to the wrong
label; update the return expression accordingly where request.flow is used.

Comment on lines +239 to +258
const hasGrokAccountCredentials = (
fs: FileSystem.FileSystem,
accountPath: string
): Effect.Effect<boolean, PlatformError> =>
hasFileAtPath(fs, `${accountPath}/.api-key`).pipe(
Effect.flatMap((hasApiKey) => {
if (hasApiKey) {
return Effect.succeed(true)
}

return hasApiKeyInEnvFile(fs, `${accountPath}/.env`, "GROK_API_KEY").pipe(
Effect.flatMap((hasEnvApiKey) => {
if (hasEnvApiKey) {
return Effect.succeed(true)
}
return hasNonEmptyOauthToken(fs, `${accountPath}/.grok/user-settings.json`)
})
)
})
)
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

Минорная проблема: отсутствие TSDoc на новой функции.

Функция hasGrokAccountCredentials не имеет документации TSDoc, хотя является важной частью логики проверки учётных данных.

📝 Предлагаемое дополнение TSDoc
+/**
+ * Checks if Grok account directory contains valid credentials.
+ *
+ * Verifies presence of credentials via:
+ * 1. .api-key file
+ * 2. GROK_API_KEY in .env file
+ * 3. Non-empty .grok/user-settings.json (OAuth token)
+ *
+ * `@param` fs - FileSystem service
+ * `@param` accountPath - Path to Grok account directory
+ * `@returns` Effect resolving to true if valid credentials found
+ *
+ * `@pure` false
+ * `@effect` Reads filesystem
+ * `@invariant` checks credentials in priority order
+ * `@precondition` accountPath should exist as directory
+ * `@postcondition` does not modify filesystem
+ * `@complexity` O(1) - checks up to 3 file paths
+ */
 const hasGrokAccountCredentials = (
   fs: FileSystem.FileSystem,
   accountPath: string
 ): Effect.Effect<boolean, PlatformError> =>

Согласно coding guidelines: "Document all functions with 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/api/src/services/project-auth.ts` around lines 239 - 258, Add a
TSDoc comment for the hasGrokAccountCredentials function describing its purpose
(checks for GROK API credentials in three locations), its parameters (fs:
FileSystem.FileSystem, accountPath: string), the return type
(Effect.Effect<boolean, PlatformError> indicating success boolean or
PlatformError), and the behavior/side-effects (it checks .api-key via
hasFileAtPath, GROK_API_KEY in .env via hasApiKeyInEnvFile, and OAuth token in
.grok/user-settings.json via hasNonEmptyOauthToken), and note possible errors
propagated from PlatformError; place the comment immediately above the
hasGrokAccountCredentials declaration.

Comment on lines +28 to +71
const buildTemplateConfigBase = (
input: Pick<BuildTemplateConfigInput, "repo" | "names" | "paths">
): Pick<
CreateCommand["config"],
| "containerName"
| "serviceName"
| "sshUser"
| "sshPort"
| "repoUrl"
| "repoRef"
| "targetDir"
| "volumeName"
| "dockerGitPath"
| "authorizedKeysPath"
| "envGlobalPath"
| "envProjectPath"
| "codexAuthPath"
| "codexSharedAuthPath"
| "codexHome"
| "geminiAuthPath"
| "geminiHome"
| "grokAuthPath"
| "grokHome"
> => ({
containerName: input.names.containerName,
serviceName: input.names.serviceName,
sshUser: input.repo.sshUser,
sshPort: input.repo.sshPort,
repoUrl: input.repo.repoUrl,
repoRef: input.repo.repoRef,
targetDir: input.repo.targetDir,
volumeName: input.names.volumeName,
dockerGitPath: input.paths.dockerGitPath,
authorizedKeysPath: input.paths.authorizedKeysPath,
envGlobalPath: input.paths.envGlobalPath,
envProjectPath: input.paths.envProjectPath,
codexAuthPath: input.paths.codexAuthPath,
codexSharedAuthPath: input.paths.codexSharedAuthPath,
codexHome: input.paths.codexHome,
geminiAuthPath: input.paths.geminiAuthPath,
geminiHome: input.paths.geminiHome,
grokAuthPath: input.paths.grokAuthPath,
grokHome: input.paths.grokHome
})
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-функции.

Функция buildTemplateConfigBase является чистой функцией CORE-слоя и должна содержать полную TSDoc-документацию и функциональные комментарии. Согласно руководствам по кодированию, все CORE-функции должны включать:

  • TSDoc: @pure, @effect, @invariant, @precondition, @postcondition, @complexity
  • Функциональные комментарии: CHANGE, WHY, QUOTE(ТЗ) или n/a, REF, SOURCE или n/a, FORMAT THEOREM, PURITY, INVARIANT, COMPLEXITY
📝 Предлагаемый шаблон документации
+// CHANGE: extract base template config builder from repo/names/paths inputs
+// WHY: centralize config derivation logic for reuse across command builders
+// QUOTE(ТЗ): n/a
+// REF: PR-305-grok-auth-support
+// SOURCE: n/a
+// FORMAT THEOREM: ∀input: buildTemplateConfigBase(input) -> Pick<CreateCommand["config"], ...>
+// PURITY: CORE
+// INVARIANT: output config fields are derived deterministically from input
+// COMPLEXITY: O(1)/O(1)
+/**
+ * Builds the base template configuration from repository, naming, and path inputs.
+ *
+ * `@param` input - Repository basics, naming config, and path config.
+ * `@returns` Subset of CreateCommand config containing core fields.
+ * `@pure` true
+ * `@effect` none; CORE pure function.
+ * `@invariant` all output fields are deterministically derived from input.
+ * `@precondition` input.names and input.paths contain valid non-empty strings.
+ * `@postcondition` returned config includes all auth paths (codex/gemini/grok).
+ * `@complexity` O(1) time / O(1) space.
+ */
 const buildTemplateConfigBase = (

Согласно руководствам по кодированию: «Document all functions with comprehensive TSDoc including: @pure (true/false), @effect (required services), @invariant (mathematical invariants), @precondition, @postcondition, @complexity (time and space)».

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

In `@packages/app/src/docker-git/frontend-lib/core/command-builders-template.ts`
around lines 28 - 71, Add full TSDoc and functional comments to the CORE pure
function buildTemplateConfigBase: include `@pure` (true/false), `@effect` (required
services or "none"), `@invariant` (any mathematical invariants), `@precondition`
(valid shape/constraints of input Pick<BuildTemplateConfigInput,...>),
`@postcondition` (returned object matches CreateCommand["config"] subset), and
`@complexity` (time and space). Also add the functional comment block with CHANGE,
WHY, QUOTE (or n/a), REF, SOURCE (or n/a), FORMAT THEOREM, PURITY, INVARIANT,
COMPLEXITY describing intent, rationale, references and guarantees for
buildTemplateConfigBase and reference the function name and the exact fields it
maps (containerName, serviceName, sshUser, sshPort, repoUrl, repoRef, targetDir,
volumeName, dockerGitPath, authorizedKeysPath, envGlobalPath, envProjectPath,
codexAuthPath, codexSharedAuthPath, codexHome, geminiAuthPath, geminiHome,
grokAuthPath, grokHome) to make clear mapping and postconditions.

Comment on lines +73 to +93
export const buildTemplateConfig = (input: BuildTemplateConfigInput): CreateCommand["config"] => ({
...buildTemplateConfigBase(input),
gitTokenLabel: input.gitTokenLabel,
skipGithubAuth: input.skipGithubAuth,
codexAuthLabel: input.codexAuthLabel,
claudeAuthLabel: input.claudeAuthLabel,
geminiAuthLabel: input.geminiAuthLabel,
grokAuthLabel: input.grokAuthLabel,
cpuLimit: input.cpuLimit,
ramLimit: input.ramLimit,
playwrightCpuLimit: input.playwrightCpuLimit,
playwrightRamLimit: input.playwrightRamLimit,
gpu: input.gpu,
dockerNetworkMode: input.dockerNetworkMode,
dockerSharedNetworkName: input.dockerSharedNetworkName,
enableMcpPlaywright: input.enableMcpPlaywright,
bunVersion: defaultTemplateConfig.bunVersion,
agentMode: input.agentMode,
agentAuto: input.agentAuto,
clonedOnHostname: input.clonedOnHostname
})
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-функции.

Экспортируемая функция buildTemplateConfig должна содержать полную TSDoc и функциональные комментарии согласно руководствам.

📝 Предлагаемый шаблон документации
+// CHANGE: build complete template config from all input parameters
+// WHY: provide single source of truth for CreateCommand config construction
+// QUOTE(ТЗ): n/a
+// REF: PR-305-grok-auth-support
+// SOURCE: n/a
+// FORMAT THEOREM: ∀input: buildTemplateConfig(input) -> CreateCommand["config"]
+// PURITY: CORE
+// INVARIANT: output combines base config with resource limits, auth labels, and agent settings
+// COMPLEXITY: O(1)/O(1)
+/**
+ * Builds the complete template configuration from all input parameters.
+ *
+ * `@param` input - Complete build template configuration input.
+ * `@returns` Full CreateCommand configuration object.
+ * `@pure` true
+ * `@export`
+ * `@effect` none; CORE pure function.
+ * `@invariant` combines base config with all optional override fields.
+ * `@precondition` input satisfies BuildTemplateConfigInput type constraints.
+ * `@postcondition` returned config is valid CreateCommand["config"].
+ * `@complexity` O(1) time / O(1) space.
+ */
 export const buildTemplateConfig = (input: BuildTemplateConfigInput): CreateCommand["config"] => ({

Согласно руководствам по кодированию: «TypeScript functions must include comprehensive TSDoc with parameters, return types, @pure marker, @effect dependencies, @invariant (mathematical), @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/app/src/docker-git/frontend-lib/core/command-builders-template.ts`
around lines 73 - 93, The exported CORE function buildTemplateConfig lacks the
required comprehensive TSDoc; add a full TSDoc block immediately above the
exported function buildTemplateConfig describing the function purpose, each
parameter in BuildTemplateConfigInput (`@param`), the return type
CreateCommand["config"] (`@returns`), and include the required tags: `@pure`,
`@effect` (list any external deps such as buildTemplateConfigBase and
defaultTemplateConfig), `@invariant` (describe any invariants about returned
config), `@precondition` (validations on input fields like cpuLimit/ramLimit/gpu),
`@postcondition` (what properties will always be present in the returned config),
and `@complexity` (Big-O for any significant work); ensure references to internal
symbols buildTemplateConfigBase and defaultTemplateConfig are mentioned in the
text so readers can locate dependencies.

Comment on lines +103 to +130
export const runGrokOauthLoginWithPrompt = (
cwd: string,
accountPath: string,
options: {
readonly image: string
readonly containerPath: string
}
): Effect.Effect<void, AuthError | CommandFailedError | PlatformError, CommandExecutor.CommandExecutor> =>
Effect.gen(function*(_) {
yield* _(printOauthInstructions())
const hostPath = yield* _(resolveDockerVolumeHostPath(cwd, accountPath))
const spec = buildDockerGrokAuthSpec(cwd, hostPath, options.image, options.containerPath)
yield* _(
runCommandWithExitCodes(
{
cwd: spec.cwd,
command: "docker",
args: buildDockerGrokAuthArgs(spec)
},
[0],
(exitCode) =>
new AuthError({
message: `Grok CLI login failed with exit code ${exitCode}.`
})
)
)
yield* _(fixGrokAuthPermissions(spec.cwd, hostPath, spec.containerPath))
})
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

Минорная проблема: отсутствие TSDoc на основной экспортируемой функции.

Функция runGrokOauthLoginWithPrompt экспортируется как public API, но не имеет документации TSDoc. Согласно coding guidelines, все функции должны включать @pure, @effect, @invariant, @precondition, @postcondition, @complexity.

📝 Предлагаемое дополнение TSDoc
+/**
+ * Runs Grok CLI OAuth login flow inside a Docker container.
+ *
+ * Prints instructions to stderr, resolves volume paths, executes `grok login`
+ * in a containerized environment, and applies permission fixes.
+ *
+ * `@param` cwd - Current working directory for Docker commands
+ * `@param` accountPath - Host path where Grok credentials will be stored
+ * `@param` options - Container image and mount path configuration
+ * `@returns` Effect that completes when login succeeds or fails
+ *
+ * `@pure` false
+ * `@effect` Runs docker commands, writes to stderr, modifies filesystem permissions
+ * `@invariant` accountPath is resolved to absolute host path before mounting
+ * `@precondition` Docker daemon must be accessible, image must be available
+ * `@postcondition` On success, Grok credentials stored in accountPath/.grok/
+ * `@complexity` O(user_interaction) - depends on OAuth completion time
+ */
 export const runGrokOauthLoginWithPrompt = (
   cwd: string,
   accountPath: string,
   options: {
     readonly image: string
     readonly containerPath: string
   }
 ): Effect.Effect<void, AuthError | CommandFailedError | PlatformError, CommandExecutor.CommandExecutor> =>

Согласно coding guidelines: "Document all functions with comprehensive TSDoc including: @pure, @effect, @invariant, @precondition, @postcondition, @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/lib/src/usecases/auth-grok-oauth.ts` around lines 103 - 130, Add a
TSDoc block above the exported runGrokOauthLoginWithPrompt function that
documents its purpose and behavior and includes the required tags: `@pure`,
`@effect` (describe the Effect type and failure channels AuthError |
CommandFailedError | PlatformError), `@invariant` (state invariants such as
cwd/accountPath resolution), `@precondition` (valid cwd and accountPath, docker
available), `@postcondition` (prints OAuth instructions, runs docker auth flow,
fixes permissions), and `@complexity` (time/space complexity). Also document
parameters (cwd, accountPath, options.image, options.containerPath) and the
return type (Effect.Effect<void, AuthError | CommandFailedError | PlatformError,
CommandExecutor.CommandExecutor>) so the public API is fully covered for
runGrokOauthLoginWithPrompt.

const trimmedApiKey = apiKey.trim()
const apiKeyFilePath = grokApiKeyPath(accountPath)
yield* _(fs.writeFileString(apiKeyFilePath, `${trimmedApiKey}\n`))
yield* _(fs.chmod(apiKeyFilePath, 0o600), Effect.orElseSucceed(() => void 0))
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 | 🔴 Critical | ⚡ Quick win

Критическая проблема безопасности: молчаливое игнорирование ошибки установки прав доступа.

Использование Effect.orElseSucceed(() => void 0) для операции chmod скрывает ошибки установки прав доступа на файл с API-ключом. Если chmod провалится (например, на файловой системе без поддержки прав доступа или из-за проблем с разрешениями), файл останется с правами по умолчанию, которые могут быть небезопасными (например, 0o644 — readable by all users).

Для credentials файлов провал chmod должен приводить к ошибке аутентификации, а не молчаливо игнорироваться.

🔒 Предлагаемое исправление
       const apiKeyFilePath = grokApiKeyPath(accountPath)
       yield* _(fs.writeFileString(apiKeyFilePath, `${trimmedApiKey}\n`))
-      yield* _(fs.chmod(apiKeyFilePath, 0o600), Effect.orElseSucceed(() => void 0))
+      yield* _(fs.chmod(apiKeyFilePath, 0o600))
🤖 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/lib/src/usecases/auth-grok.ts` at line 40, Хранится молчаливое
подавление ошибки chmod при установке прав на файл API-ключа: в месте с вызовом
fs.chmod внутри usecases/auth-grok.ts удалите использование
Effect.orElseSucceed(() => void 0) и позвольте ошибке/эффекту проброситься (или
замените на явный Effect.fail с информативным сообщением), чтобы не продолжать
работу при неудачной установке прав; убедитесь, что ошибка содержит контекст
(путь файла и причину) и приводит к отказу аутентификации/завершению процесса
вместо бесшумного продолжения.

Comment on lines +50 to +62
export const authGrokLoginCli = (
_command: AuthGrokLoginCommand
): Effect.Effect<void, PlatformError | CommandFailedError, GrokRuntime> =>
Effect.gen(function*(_) {
yield* _(Effect.log("Grok CLI supports two authentication methods:"))
yield* _(Effect.log(""))
yield* _(Effect.log("1. API Key:"))
yield* _(Effect.log(" - Use: docker-git menu -> Auth profiles -> Grok CLI: set API key"))
yield* _(Effect.log(""))
yield* _(Effect.log("2. OAuth/browser login:"))
yield* _(Effect.log(" - Use: docker-git menu -> Auth profiles -> Grok CLI: login via OAuth"))
yield* _(Effect.log(" - Follow the Grok CLI prompts and paste the callback URL when requested"))
})
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 | 💤 Low value

Неиспользуемый параметр _command.

Параметр _command: AuthGrokLoginCommand помечен как неиспользуемый (префикс _), но не используется в теле функции. Если этот параметр необходим для соответствия интерфейсу или будет использован в будущем, оставьте как есть. В противном случае удалите его из сигнатуры.

🤖 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/lib/src/usecases/auth-grok.ts` around lines 50 - 62, Параметр
_command в сигнатуре функции authGrokLoginCli не используется; либо удалите его
из сигнатуры (заменив экспорт на authGrokLoginCli(): Effect.Effect<...>) либо
начните явно использовать его внутри Effect.gen (например передав необходимые
поля в логи/логику) to satisfy the interface; обновите все вызовы/auth
signatures accordingly so they match the new signature or continue accepting the
parameter if required for interface compatibility.

Comment on lines +76 to +78
Effect.gen(function*(_) {
const credentialsDir = yield* _(prepareGrokCredentialsDir(cwd, accountPath, fs))
yield* _(writeInitialGrokSettings(credentialsDir, fs, null))
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

Риск неконсистентного состояния при провале OAuth-авторизации.

Функция записывает initial Grok settings с null API-ключом (строка 78) перед запуском OAuth-потока (строки 80-85). Если OAuth провалится (например, пользователь закроет браузер, истечёт таймаут или произойдёт сетевая ошибка), в файловой системе останется запись с null API-ключом, что может привести к неопределённому состоянию аутентификации.

Рассмотрите запись initial settings только после успешного завершения OAuth, либо используйте транзакционный подход с откатом при ошибке.

🤖 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/lib/src/usecases/auth-grok.ts` around lines 76 - 78, The code
currently calls prepareGrokCredentialsDir(...) then immediately
writeInitialGrokSettings(..., null) which can leave a null API key on disk if
the subsequent OAuth flow fails; update the flow in auth-grok.ts so you only
call writeInitialGrokSettings after the OAuth process completes successfully
(or, alternatively, perform the write as part of a transactional sequence and
remove/rollback the created settings on any OAuth error). Concretely, move the
writeInitialGrokSettings call to after the successful return of the OAuth
routine (or add a catch/finally that deletes or restores the credentials file on
failure), referencing prepareGrokCredentialsDir and writeInitialGrokSettings to
locate where to change behavior.

Comment on lines +10 to +23
const withTempDir = <A, E, R>(
use: (tempDir: string) => Effect.Effect<A, E, R>
): Effect.Effect<A, E, R | FileSystem.FileSystem> =>
Effect.scoped(
Effect.gen(function*(_) {
const fs = yield* _(FileSystem.FileSystem)
const tempDir = yield* _(
fs.makeTempDirectoryScoped({
prefix: "docker-git-auth-grok-"
})
)
return yield* _(use(tempDir))
})
)
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

Добавить TSDoc для тестового хелпера.

Хелпер withTempDir использует Effect.scoped для управления ресурсами, что является важным паттерном. Добавьте краткую TSDoc для документирования его назначения и использования.

📝 Предлагаемая документация
+/**
+ * Runs an effect with a scoped temporary directory that is automatically cleaned up.
+ *
+ * `@param` use - Effect to run with the temporary directory path.
+ * `@returns` Scoped effect with FileSystem dependency.
+ * `@pure` true
+ * `@effect` FileSystem
+ */
 const withTempDir = <A, E, R>(
🤖 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/lib/tests/usecases/auth-grok.test.ts` around lines 10 - 23, Добавьте
краткую TSDoc над helper-функцией withTempDir, объясняющую её назначение
(создаёт временную директорию для теста и передаёт её в callback), описывающую
использование Effect.scoped для управления жизненным циклом ресурса,
перечисляющую параметр use (callback, получающий tempDir: string) и возвращаемое
значение (Effect, который может содержать результат теста или
FileSystem.FileSystem), и упомяните префикс временной директории; ссылаясь на
сimbols withTempDir, Effect.scoped и FileSystem.FileSystem, чтобы облегчить
поиск места вставки документации.

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

Caution

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

⚠️ Outside diff range comments (2)
packages/lib/src/usecases/agent-auto-select.ts (1)

1-181: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Дублирование кода между packages/lib и packages/app.

Файл идентичен packages/app/src/lib/usecases/agent-auto-select.ts. Все замечания из review того файла применимы и здесь:

  • Отсутствует TSDoc-документация для hasGrokAuth, availableAgentModes, pickRandomAutoAgentMode
  • Отсутствуют функциональные комментарии (CHANGE, WHY, PURITY, EFFECT, INVARIANT, COMPLEXITY)
  • Одноэлементные массивы-константы можно упростить

Дополнительно: дублирование кода нарушает DRY-принцип и усложняет поддержку. Рассмотрите:

  1. Если packages/lib — это shared library, то packages/app должен импортировать из неё
  2. Если это монорепозиторий, используйте workspace references для переиспользования кода
🤖 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/lib/src/usecases/agent-auto-select.ts` around lines 1 - 181, This
file duplicates logic from packages/app; remove duplication by centralizing the
agent selection code into the shared lib and have packages/app import it (or
create a single shared module/workspace reference) and, in this file, replace
the duplicated implementation with an import; while consolidating, add TSDoc and
the repository's functional comment blocks
(CHANGE/WHY/PURITY/EFFECT/INVARIANT/COMPLEXITY) for the functions hasGrokAuth,
availableAgentModes, and pickRandomAutoAgentMode, and simplify the
single-element constants claudeMode, codexMode, grokMode to plain string
literals where used (or export simple string constants) to reduce unnecessary
arrays; update resolveAvailableAgentAuth, resolveExplicitAutoAgentMode, and
pickRandomAutoAgentMode call sites to use the centralized implementation and
ensure exports/signatures match between packages.
packages/lib/tests/usecases/agent-auto-select.test.ts (1)

119-219: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Тестовое покрытие Grok добавлено, но отсутствуют property-based тесты.

Новые тесты для Grok адресуют замечание из previous review comment о недостаточном покрытии. Однако согласно coding guidelines, требуется использовать property-based testing с fast-check для проверки математических инвариантов.

Примеры инвариантов для property-based тестов:

  1. Детерминированность при одном доступном режиме: ∀available: |availableModes| = 1 ⇒ result = availableModes[0]
  2. Принадлежность результата: ∀available: result ∈ availableAgentModes(available)
  3. Идемпотентность explicit mode: ∀mode ∈ {claude, codex, grok}: agentMode=mode ∧ authAvailable(mode) ⇒ result=mode
  4. Fail when unavailable: ∀mode: agentMode=mode ∧ ¬authAvailable(mode) ⇒ Effect.fail(InvalidOption)
Пример property-based теста с fast-check
import * as fc from "fast-check"

it.effect("property: resolved mode always belongs to available modes", () =>
  Effect.gen(function*(_) {
    const property = fc.property(
      fc.record({
        claudeAvailable: fc.boolean(),
        codexAvailable: fc.boolean(),
        grokAvailable: fc.boolean()
      }).filter(avail => avail.claudeAvailable || avail.codexAvailable || avail.grokAvailable),
      (available) => {
        // Setup auth files based on available flags
        // Call resolveAutoAgentMode
        // Assert result ∈ availableAgentModes(available)
      }
    )
    fc.assert(property)
  })
)

As per coding guidelines **/*.test.{ts,tsx}: "Implement property-based testing using fast-check for mathematical properties and invariants."

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

In `@packages/lib/tests/usecases/agent-auto-select.test.ts` around lines 119 -
219, The new Grok unit tests lack property-based tests as required; add
fast-check property tests in
packages/lib/tests/usecases/agent-auto-select.test.ts that exercise
resolveAutoAgentMode across randomized availability combinations: import fc from
"fast-check" and add it.effect cases that generate boolean flags
(claudeAvailable, codexAvailable, grokAvailable) filtered to at least one true,
create auth files in the temp dir based on those flags (using
FileSystem.FileSystem and Path.Path as in existing tests), call
resolveAutoAgentMode(config) and assert the invariants: (1) if exactly one mode
is available the result equals that mode, (2) result is one of the available
modes, (3) when agentMode is explicitly set to an available mode result equals
that explicit mode, and (4) when explicit mode is set but its auth is missing
the effect fails with InvalidOption; use fc.assert to run the property and wrap
inside the existing withTempDir/Effect.gen pattern.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/app/src/docker-git/cli/usage.ts`:
- Line 79: The help text advertises Gemini but the auto-selection logic and
types lack Gemini support; update AvailableAgentAuth to include geminiAvailable,
extend availableAgentModes (in packages/lib/src/usecases/agent-auto-select.ts,
function availableAgentModes) to check available.geminiAvailable and include
AgentMode.Gemini in the returned modes when present, update the error message
that currently says "no Claude, Codex or Grok auth found" to mention Gemini, and
add/adjust unit tests to cover the Gemini path; alternatively, if you prefer to
postpone Gemini, remove "gemini" from the --auto help text and AgentMode enum
usages so the doc and logic remain consistent.

In `@packages/app/src/lib/usecases/agent-auto-select.ts`:
- Around line 137-141: Add comprehensive TSDoc to the pure CORE helper
availableAgentModes: mark it with `@pure` true, add functional comments describing
PURITY (CORE) and `@effect` (none/required services = none), specify `@invariant`
such as "∀available: |result| ≤ 3 ∧ result ⊆ {claude, codex, grok}", document
`@precondition` (none) and `@postcondition` (returns array of AgentMode containing
only enabled modes), and state `@complexity` as "time O(1), space O(1)". Place
this TSDoc immediately above the availableAgentModes declaration so tools and
reviewers can pick it up.
- Around line 143-153: Add comprehensive TSDoc to the pickRandomAutoAgentMode
function: document `@pure` false (uses process.hrtime.bigint()), `@effect`
describing the Effect<AgentMode, ParseError> and any required services,
`@invariant` stating the result ∈ availableAgentModes(available), `@precondition`
that availableAgentModes(available) is non-empty, `@postcondition` that the
returned AgentMode is one of the available modes or an error, and `@complexity`
O(n) where n = number of modes; reference the helper availableAgentModes and the
non-deterministic selection via process.hrtime.bigint() when describing WHY and
EFFECT.
- Around line 53-60: The new function hasGrokAuth lacks the required TSDoc; add
a comprehensive TSDoc block above hasGrokAuth that documents `@pure` false,
`@effect` FileSystem (since it uses FileSystem.FileSystem and returns an Effect),
`@precondition` (rootPath is a valid path string and label may be undefined),
`@postcondition` (returns true if valid Grok credentials are found at
normalizeAccountLabel(label ?? null, "default") within rootPath), `@complexity`
(time and space complexity of hasGrokCredentials call), and include the
functional comments PURITY (SHELL), EFFECT (Effect<boolean, PlatformError,
FileSystem>), and INVARIANT describing the relationship between normalized label
and lookup path; reference the helper functions normalizeAccountLabel and
hasGrokCredentials in the comment for clarity.
- Around line 24-26: The three constants claudeMode, codexMode and grokMode are
defined as one-element ReadonlyArray<AgentMode>, which is unnecessary because
availableAgentModes later spreads them; change them to use simple string
literals or single AgentMode values and insert those directly into
availableAgentModes (e.g., replace the one-item arrays with 'claude', 'codex',
'grok' or define each as const claudeMode: AgentMode = 'claude') to remove the
extra array layer and keep type-safety.

In `@packages/lib/tests/usecases/agent-auto-select.test.ts`:
- Around line 42-45: The test suite adds geminiAuthPath and geminiHome to
makeConfig but no Gemini test-cases exist; either add three tests mirroring
Grok's coverage (in packages/lib/tests/usecases/agent-auto-select.test.ts) named
it.effect("chooses Gemini when only Gemini auth exists", ...), it.effect("keeps
explicit Gemini mode when Gemini auth exists", ...), and it.effect("fails
explicit Gemini mode when Gemini auth is missing", ...) exercising the same
setup/teardowns and assertions used for Grok, or if Gemini is out of scope for
this PR, remove or comment out geminiAuthPath/geminiHome from makeConfig and add
a "// TODO: Gemini tests" comment to explain why they are omitted.

---

Outside diff comments:
In `@packages/lib/src/usecases/agent-auto-select.ts`:
- Around line 1-181: This file duplicates logic from packages/app; remove
duplication by centralizing the agent selection code into the shared lib and
have packages/app import it (or create a single shared module/workspace
reference) and, in this file, replace the duplicated implementation with an
import; while consolidating, add TSDoc and the repository's functional comment
blocks (CHANGE/WHY/PURITY/EFFECT/INVARIANT/COMPLEXITY) for the functions
hasGrokAuth, availableAgentModes, and pickRandomAutoAgentMode, and simplify the
single-element constants claudeMode, codexMode, grokMode to plain string
literals where used (or export simple string constants) to reduce unnecessary
arrays; update resolveAvailableAgentAuth, resolveExplicitAutoAgentMode, and
pickRandomAutoAgentMode call sites to use the centralized implementation and
ensure exports/signatures match between packages.

In `@packages/lib/tests/usecases/agent-auto-select.test.ts`:
- Around line 119-219: The new Grok unit tests lack property-based tests as
required; add fast-check property tests in
packages/lib/tests/usecases/agent-auto-select.test.ts that exercise
resolveAutoAgentMode across randomized availability combinations: import fc from
"fast-check" and add it.effect cases that generate boolean flags
(claudeAvailable, codexAvailable, grokAvailable) filtered to at least one true,
create auth files in the temp dir based on those flags (using
FileSystem.FileSystem and Path.Path as in existing tests), call
resolveAutoAgentMode(config) and assert the invariants: (1) if exactly one mode
is available the result equals that mode, (2) result is one of the available
modes, (3) when agentMode is explicitly set to an available mode result equals
that explicit mode, and (4) when explicit mode is set but its auth is missing
the effect fails with InvalidOption; use fc.assert to run the property and wrap
inside the existing withTempDir/Effect.gen pattern.
🪄 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: 24d7c545-cc31-4d9c-8519-8643b38d69a3

📥 Commits

Reviewing files that changed from the base of the PR and between b6cb6bf and 61978c7.

📒 Files selected for processing (4)
  • packages/app/src/docker-git/cli/usage.ts
  • packages/app/src/lib/usecases/agent-auto-select.ts
  • packages/lib/src/usecases/agent-auto-select.ts
  • packages/lib/tests/usecases/agent-auto-select.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: E2E (Clone auto-open SSH)
  • GitHub Check: E2E (OpenCode)
  • GitHub Check: E2E (Login context)
  • GitHub Check: E2E (Browser command)
  • GitHub Check: E2E (Clone cache)
  • GitHub Check: E2E (Runtime volumes + SSH)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • packages/app/src/lib/usecases/agent-auto-select.ts
  • packages/lib/tests/usecases/agent-auto-select.test.ts
  • packages/lib/src/usecases/agent-auto-select.ts
  • packages/app/src/docker-git/cli/usage.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • packages/app/src/lib/usecases/agent-auto-select.ts
  • packages/lib/tests/usecases/agent-auto-select.test.ts
  • packages/lib/src/usecases/agent-auto-select.ts
  • packages/app/src/docker-git/cli/usage.ts
**/*.{sh,bash,py,js,ts,jsx,tsx,go,java,rb,php}

📄 CodeRabbit inference engine (Custom checks)

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

Files:

  • packages/app/src/lib/usecases/agent-auto-select.ts
  • packages/lib/tests/usecases/agent-auto-select.test.ts
  • packages/lib/src/usecases/agent-auto-select.ts
  • packages/app/src/docker-git/cli/usage.ts
**/*.{py,js,ts,jsx,tsx,go,java,rb,php,sh,bash,c,cpp}

📄 CodeRabbit inference engine (Custom checks)

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

Files:

  • packages/app/src/lib/usecases/agent-auto-select.ts
  • packages/lib/tests/usecases/agent-auto-select.test.ts
  • packages/lib/src/usecases/agent-auto-select.ts
  • packages/app/src/docker-git/cli/usage.ts
**/*.{js,ts,jsx,tsx,py,java,go,rb,php,sh,bash,yml,yaml,json,env*,toml,cfg,config,dockerfile,dockerignore}

📄 CodeRabbit inference engine (Custom checks)

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

Files:

  • packages/app/src/lib/usecases/agent-auto-select.ts
  • packages/lib/tests/usecases/agent-auto-select.test.ts
  • packages/lib/src/usecases/agent-auto-select.ts
  • packages/app/src/docker-git/cli/usage.ts
**/*

⚙️ CodeRabbit configuration file

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

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

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

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

Files:

  • packages/app/src/lib/usecases/agent-auto-select.ts
  • packages/lib/tests/usecases/agent-auto-select.test.ts
  • packages/lib/src/usecases/agent-auto-select.ts
  • packages/app/src/docker-git/cli/usage.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • packages/lib/tests/usecases/agent-auto-select.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/lib/tests/usecases/agent-auto-select.test.ts
🔇 Additional comments (1)
packages/app/src/lib/usecases/agent-auto-select.ts (1)

129-133: LGTM!

--ssh | --no-ssh Auto-open SSH after create/clone (default: clone=--ssh, create=--no-ssh)
--mcp-playwright | --no-mcp-playwright Enable Playwright MCP + Chromium sidecar (default: --no-mcp-playwright)
--auto[=claude|codex] Auto-execute an agent; without value picks by auth, random if both are available
--auto[=claude|codex|gemini|grok] Auto-execute an agent; without value picks by auth, random if multiple are available
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 | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Поиск реализации Gemini-логики (hasGeminiAuth, hasGeminiCredentials и т.д.)
rg -nP --type=ts 'hasGemini(Auth|Credentials)|gemini.*Auth.*=>' -C3

Repository: ProverCoderAI/docker-git

Length of output: 4224


🏁 Script executed:

# Поиск функций проверки Gemini-аутентификации
rg -nP --type=ts 'hasGemini|getGemini' | head -30

Repository: ProverCoderAI/docker-git

Length of output: 511


🏁 Script executed:

# Проверка реализации pickRandomAutoAgentMode
rg -nP --type=ts 'pickRandomAutoAgentMode|pickByAuth' -A 20 | head -80

Repository: ProverCoderAI/docker-git

Length of output: 4077


🏁 Script executed:

# Поиск enum или type для режимов агента
rg -nP --type=ts 'type.*Mode.*=|enum.*Mode' -B 2 -A 10 | head -50

Repository: ProverCoderAI/docker-git

Length of output: 4226


🏁 Script executed:

# Контекст из usage.ts вокруг строки 79
cat -n packages/app/src/docker-git/cli/usage.ts | sed -n '70,90p'

Repository: ProverCoderAI/docker-git

Length of output: 2119


🏁 Script executed:

# Поиск реализации availableAgentModes
rg -nP --type=ts 'availableAgentModes|AgentMode' -B 2 -A 10 | head -100

Repository: ProverCoderAI/docker-git

Length of output: 9245


🏁 Script executed:

# Проверка, включен ли gemini в AgentMode type
rg -nP --type=ts 'type AgentMode|AgentMode =' -A 5

Repository: ProverCoderAI/docker-git

Length of output: 10014


🏁 Script executed:

# Проверка geminiAuthLabel в конфиге
rg -nP --type=ts 'geminiAuthLabel' -B 3 -A 3 | head -60

Repository: ProverCoderAI/docker-git

Length of output: 4805


🏁 Script executed:

# Найти определение availableAgentModes функции
rg -nP --type=ts 'const availableAgentModes|function availableAgentModes' -A 10

Repository: ProverCoderAI/docker-git

Length of output: 2313


🏁 Script executed:

# Проверить обработку режима gemini в resolveExplicitAutoAgentMode
rg -nP --type=ts 'mode === "gemini"|if.*gemini' -B 3 -A 3

Repository: ProverCoderAI/docker-git

Length of output: 4639


🏁 Script executed:

# Поиск Gemini тестов в test файле
rg -nP --type=ts 'gemini.*chooses|chooses.*Gemini|when.*Gemini' packages/lib/tests/usecases/agent-auto-select.test.ts

Repository: ProverCoderAI/docker-git

Length of output: 50


Критическая ошибка: Gemini объявлен в документации, но исключён из логики автовыбора.

В функции availableAgentModes (packages/lib/src/usecases/agent-auto-select.ts:136-140) отсутствует обработка available.geminiAvailable, хотя Gemini включён в AgentMode тип и упомянут в help тексте --auto[=claude|codex|gemini|grok].

Проблемы:

  1. При --auto без значения Gemini никогда не будет выбран случайно, даже если учётные данные существуют
  2. Сообщение об ошибке говорит "no Claude, Codex or Grok auth found" — пропущена Gemini
  3. Отсутствуют тесты для режима Gemini
  4. Поле geminiAvailable не существует в типе AvailableAgentAuth

Необходимо либо:

  • Добавить полную поддержку Gemini в availableAgentModes, AvailableAgentAuth, тесты и сообщение об ошибке
  • Либо убрать Gemini из --auto опции до полной реализации
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/app/src/docker-git/cli/usage.ts` at line 79, The help text
advertises Gemini but the auto-selection logic and types lack Gemini support;
update AvailableAgentAuth to include geminiAvailable, extend availableAgentModes
(in packages/lib/src/usecases/agent-auto-select.ts, function
availableAgentModes) to check available.geminiAvailable and include
AgentMode.Gemini in the returned modes when present, update the error message
that currently says "no Claude, Codex or Grok auth found" to mention Gemini, and
add/adjust unit tests to cover the Gemini path; alternatively, if you prefer to
postpone Gemini, remove "gemini" from the --auto help text and AgentMode enum
usages so the doc and logic remain consistent.

Comment on lines +24 to +26
const claudeMode: ReadonlyArray<AgentMode> = ["claude"]
const codexMode: ReadonlyArray<AgentMode> = ["codex"]
const grokMode: ReadonlyArray<AgentMode> = ["grok"]
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 | 💤 Low value

Рассмотрите использование литералов вместо одноэлементных массивов.

Константы claudeMode, codexMode, grokMode определены как одноэлементные ReadonlyArray<AgentMode>. Это добавляет дополнительный уровень абстракции без очевидной пользы. В availableAgentModes их всё равно приходится распаковывать через spread.

Более прямолинейное решение — использовать string literals напрямую в массиве или, если массивы нужны для типобезопасности, добавить комментарий, объясняющий WHY.

♻️ Возможное упрощение
-const claudeMode: ReadonlyArray<AgentMode> = ["claude"]
-const codexMode: ReadonlyArray<AgentMode> = ["codex"]
-const grokMode: ReadonlyArray<AgentMode> = ["grok"]
-
 const availableAgentModes = (available: AvailableAgentAuth): ReadonlyArray<AgentMode> => [
-  ...(available.claudeAvailable ? claudeMode : []),
-  ...(available.codexAvailable ? codexMode : []),
-  ...(available.grokAvailable ? grokMode : [])
+  ...(available.claudeAvailable ? ["claude" as const] : []),
+  ...(available.codexAvailable ? ["codex" as const] : []),
+  ...(available.grokAvailable ? ["grok" as const] : [])
 ]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/app/src/lib/usecases/agent-auto-select.ts` around lines 24 - 26, The
three constants claudeMode, codexMode and grokMode are defined as one-element
ReadonlyArray<AgentMode>, which is unnecessary because availableAgentModes later
spreads them; change them to use simple string literals or single AgentMode
values and insert those directly into availableAgentModes (e.g., replace the
one-item arrays with 'claude', 'codex', 'grok' or define each as const
claudeMode: AgentMode = 'claude') to remove the extra array layer and keep
type-safety.

Comment on lines +53 to +60
const hasGrokAuth = (
fs: FileSystem.FileSystem,
rootPath: string,
label: string | undefined
): Effect.Effect<boolean, PlatformError> => {
const normalized = normalizeAccountLabel(label ?? null, "default")
return hasGrokCredentials(fs, `${rootPath}/${normalized}`)
}
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 | ⚡ Quick win

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

Согласно coding guidelines, все функции должны содержать comprehensive TSDoc с указанием:

  • @pure (false, т.к. FileSystem effect)
  • @effect (FileSystem dependency)
  • @precondition (например, rootPath должен быть валидным путём)
  • @postcondition (возвращает true если найдены валидные Grok credentials)
  • @complexity (временная и пространственная)

Также требуются функциональные комментарии: PURITY (SHELL), EFFECT (Effect<boolean, PlatformError, FileSystem>), INVARIANT.

As per coding guidelines **/*.{ts,tsx}: "Document all functions with comprehensive TSDoc including: @pure (true/false), @effect (required services), @invariant (mathematical invariants), @precondition, @postcondition, @complexity (time and space)."

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

In `@packages/app/src/lib/usecases/agent-auto-select.ts` around lines 53 - 60, The
new function hasGrokAuth lacks the required TSDoc; add a comprehensive TSDoc
block above hasGrokAuth that documents `@pure` false, `@effect` FileSystem (since it
uses FileSystem.FileSystem and returns an Effect), `@precondition` (rootPath is a
valid path string and label may be undefined), `@postcondition` (returns true if
valid Grok credentials are found at normalizeAccountLabel(label ?? null,
"default") within rootPath), `@complexity` (time and space complexity of
hasGrokCredentials call), and include the functional comments PURITY (SHELL),
EFFECT (Effect<boolean, PlatformError, FileSystem>), and INVARIANT describing
the relationship between normalized label and lookup path; reference the helper
functions normalizeAccountLabel and hasGrokCredentials in the comment for
clarity.

Comment on lines +137 to +141
const availableAgentModes = (available: AvailableAgentAuth): ReadonlyArray<AgentMode> => [
...(available.claudeAvailable ? claudeMode : []),
...(available.codexAvailable ? codexMode : []),
...(available.grokAvailable ? grokMode : [])
]
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 | ⚡ Quick win

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

Функция availableAgentModes является чистой (CORE layer) и должна содержать:

  • @pure true
  • @invariant (например: "∀available: |result| ≤ 3 ∧ result ⊆ {claude, codex, grok}")
  • @complexity O(1) время, O(1) пространство (возвращает массив фиксированного размера ≤3)

Также требуются функциональные комментарии: PURITY (CORE), INVARIANT, COMPLEXITY.

As per coding guidelines **/*.{ts,tsx}: "Document all functions with comprehensive TSDoc including: @pure (true/false), @effect (required services), @invariant (mathematical invariants), @precondition, @postcondition, @complexity (time and space)."

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

In `@packages/app/src/lib/usecases/agent-auto-select.ts` around lines 137 - 141,
Add comprehensive TSDoc to the pure CORE helper availableAgentModes: mark it
with `@pure` true, add functional comments describing PURITY (CORE) and `@effect`
(none/required services = none), specify `@invariant` such as "∀available:
|result| ≤ 3 ∧ result ⊆ {claude, codex, grok}", document `@precondition` (none)
and `@postcondition` (returns array of AgentMode containing only enabled modes),
and state `@complexity` as "time O(1), space O(1)". Place this TSDoc immediately
above the availableAgentModes declaration so tools and reviewers can pick it up.

Comment on lines +143 to 153
const pickRandomAutoAgentMode = (available: AvailableAgentAuth): Effect.Effect<AgentMode, ParseError> => {
const modes = availableAgentModes(available)
const firstMode = modes[0]
if (firstMode === undefined) {
return Effect.fail(autoOptionError("no Claude, Codex or Grok auth found"))
}
if (!available.claudeAvailable && available.codexAvailable) {
return Effect.succeed("codex")
if (modes.length === 1) {
return Effect.succeed(firstMode)
}
return Effect.sync(() => (process.hrtime.bigint() % 2n === 0n ? "claude" : "codex"))
return Effect.sync(() => modes[Number(process.hrtime.bigint() % BigInt(modes.length))] ?? firstMode)
}
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 | ⚡ Quick win

Отсутствует обязательная TSDoc-документация для критической логики выбора.

Функция pickRandomAutoAgentMode реализует случайный выбор агента из доступных и требует полную документацию:

  • @pure false (использует process.hrtime.bigint())
  • @effect требует описание побочного эффекта (non-deterministic random selection)
  • @invariant (например: "result ∈ availableAgentModes(available)")
  • @precondition должны существовать доступные режимы для выбора
  • @postcondition возвращает один из доступных режимов или ошибку
  • @complexity O(n) где n = количество доступных режимов

Функциональные комментарии должны включать:

  • PURITY (SHELL)
  • EFFECT (Effect<AgentMode, ParseError>)
  • INVARIANT (результат принадлежит множеству доступных режимов)
  • WHY (почему используется process.hrtime вместо Math.random - детерминизм тестирования?)

As per coding guidelines **/*.{ts,tsx}: "Document all functions with comprehensive TSDoc including: @pure (true/false), @effect (required services), @invariant (mathematical invariants), @precondition, @postcondition, @complexity (time and space)."

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

In `@packages/app/src/lib/usecases/agent-auto-select.ts` around lines 143 - 153,
Add comprehensive TSDoc to the pickRandomAutoAgentMode function: document `@pure`
false (uses process.hrtime.bigint()), `@effect` describing the Effect<AgentMode,
ParseError> and any required services, `@invariant` stating the result ∈
availableAgentModes(available), `@precondition` that
availableAgentModes(available) is non-empty, `@postcondition` that the returned
AgentMode is one of the available modes or an error, and `@complexity` O(n) where
n = number of modes; reference the helper availableAgentModes and the
non-deterministic selection via process.hrtime.bigint() when describing WHY and
EFFECT.

Comment on lines +42 to +45
geminiAuthPath: path.join(root, ".orch/auth/gemini"),
geminiHome: "/home/dev/.gemini",
grokAuthPath: path.join(root, ".orch/auth/grok"),
grokHome: "/home/dev/.grok",
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 | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Поиск упоминаний Gemini в реализации (не только в тестах и usage)
rg -nP --type=ts -C2 'gemini|Gemini' --iglob '**/usecases/**' --iglob '!**/*.test.ts' --iglob '!**/usage.ts'

Repository: ProverCoderAI/docker-git

Length of output: 50380


🏁 Script executed:

# Посмотрим содержимое тестового файла, чтобы увидеть тест-кейсы
head -100 packages/lib/tests/usecases/agent-auto-select.test.ts

Repository: ProverCoderAI/docker-git

Length of output: 3865


🏁 Script executed:

# Получим полный список тест-кейсов (строки с it.effect)
rg -n "it\.effect" packages/lib/tests/usecases/agent-auto-select.test.ts

Repository: ProverCoderAI/docker-git

Length of output: 873


🏁 Script executed:

# Проверим, есть ли вообще упоминание Gemini в тестовом файле
rg -i "gemini" packages/lib/tests/usecases/agent-auto-select.test.ts

Repository: ProverCoderAI/docker-git

Length of output: 159


Добавьте тест-кейсы для Gemini агента или удалите неиспользуемые поля конфига.

В makeConfig добавлены geminiAuthPath и geminiHome, но в файле тестов отсутствуют тест-кейсы для Gemini. Grok имеет полное покрытие (3 теста: выбор агента, явный режим, ошибка), а Gemini не протестирован, несмотря на то, что полностью реализован в production-коде.

Выберите один из подходов:

  1. Добавьте недостающие тест-кейсы для Gemini (аналогично Grok):

    • it.effect("chooses Gemini when only Gemini auth exists", ...)
    • it.effect("keeps explicit Gemini mode when Gemini auth exists", ...)
    • it.effect("fails explicit Gemini mode when Gemini auth is missing", ...)
  2. Или добавьте комментарий // TODO: Gemini tests и откомментируйте поля конфига, если Gemini не должен быть в scope этого PR.

🤖 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/lib/tests/usecases/agent-auto-select.test.ts` around lines 42 - 45,
The test suite adds geminiAuthPath and geminiHome to makeConfig but no Gemini
test-cases exist; either add three tests mirroring Grok's coverage (in
packages/lib/tests/usecases/agent-auto-select.test.ts) named it.effect("chooses
Gemini when only Gemini auth exists", ...), it.effect("keeps explicit Gemini
mode when Gemini auth exists", ...), and it.effect("fails explicit Gemini mode
when Gemini auth is missing", ...) exercising the same setup/teardowns and
assertions used for Grok, or if Gemini is out of scope for this PR, remove or
comment out geminiAuthPath/geminiHome from makeConfig and add a "// TODO: Gemini
tests" comment to explain why they are omitted.

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

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

Inline comments:
In `@packages/app/src/lib/core/templates-entrypoint/grok.ts`:
- Around line 1-2: The file packages/app src lib core templates-entrypoint
grok.ts duplicates logic present in
packages/lib/src/core/templates-entrypoint/grok.ts; remove the duplicate by
extracting the shared code (including the TemplateConfig-related logic and any
exported helpers) into a single shared module or the lib package and have
packages/app re-export or import that module (e.g., export/import the same
symbols instead of re-defining them). Update the grok.ts in packages/app to
import TemplateConfig and any functions from the shared location (or re-export
from packages/lib) so only one source of truth remains and jscpd markers are no
longer needed.
- Around line 259-266: Экспортная функция renderEntrypointGrokConfig не имеет
TSDoc — добавьте подробный TSDoc над объявлением функции
renderEntrypointGrokConfig, описывающий назначение функции, параметры (config:
TemplateConfig) и возвращаемое значение (string), а также любые побочные эффекты
или примечания; используйте стиль и уровень детализации, согласованный с другими
файлами (например, packages/lib/src/core/templates-entrypoint/grok.ts), включая
пример использования при необходимости.

In `@packages/lib/src/core/templates-entrypoint/grok.ts`:
- Around line 258-265: Add a comprehensive TSDoc block to the exported function
renderEntrypointGrokConfig describing its purpose and behavior, and include the
required tags: `@pure`, `@effect` (describe side effects or "none"), `@invariant`,
`@precondition` (e.g., valid TemplateConfig), `@postcondition` (what string
structure is returned), and `@complexity` (time/space complexity). Place the
comment immediately above the renderEntrypointGrokConfig declaration and
reference the parameter config and returned string in the descriptions so that
consumers and linters get the full contract for this exported function.
🪄 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: 8b8093ce-8bc9-43dd-9c7b-3c14a8b15010

📥 Commits

Reviewing files that changed from the base of the PR and between 61978c7 and d4d0fe9.

📒 Files selected for processing (3)
  • packages/app/src/lib/core/templates-entrypoint/grok.ts
  • packages/lib/src/core/templates-entrypoint/grok.ts
  • packages/lib/tests/core/templates.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: E2E (OpenCode)
  • GitHub Check: E2E (Clone auto-open SSH)
  • GitHub Check: E2E (Runtime volumes + SSH)
  • GitHub Check: E2E (Login context)
  • GitHub Check: E2E (Clone cache)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • packages/lib/src/core/templates-entrypoint/grok.ts
  • packages/lib/tests/core/templates.test.ts
  • packages/app/src/lib/core/templates-entrypoint/grok.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/lib/src/core/templates-entrypoint/grok.ts
  • packages/lib/tests/core/templates.test.ts
  • packages/app/src/lib/core/templates-entrypoint/grok.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/lib/src/core/templates-entrypoint/grok.ts
  • packages/lib/tests/core/templates.test.ts
  • packages/app/src/lib/core/templates-entrypoint/grok.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/lib/src/core/templates-entrypoint/grok.ts
  • packages/lib/tests/core/templates.test.ts
  • packages/app/src/lib/core/templates-entrypoint/grok.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/lib/src/core/templates-entrypoint/grok.ts
  • packages/lib/tests/core/templates.test.ts
  • packages/app/src/lib/core/templates-entrypoint/grok.ts
**/*

⚙️ CodeRabbit configuration file

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

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

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

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

Files:

  • packages/lib/src/core/templates-entrypoint/grok.ts
  • packages/lib/tests/core/templates.test.ts
  • packages/app/src/lib/core/templates-entrypoint/grok.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • packages/lib/tests/core/templates.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/lib/tests/core/templates.test.ts
🔇 Additional comments (6)
packages/lib/src/core/templates-entrypoint/grok.ts (4)

1-12: LGTM!

Also applies to: 122-126, 144-164, 165-170, 172-188, 253-257


13-121: LGTM!


127-143: LGTM!


189-252: LGTM!

packages/lib/tests/core/templates.test.ts (1)

30-30: LGTM!

Also applies to: 216-224, 419-463, 484-496, 498-526

packages/app/src/lib/core/templates-entrypoint/grok.ts (1)

3-258: LGTM!

Comment on lines +1 to +2
/* jscpd:ignore-start */
import type { TemplateConfig } from "../domain.js"
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 | ⚖️ Poor tradeoff

Дублирование кода между packages/lib и packages/app.

Файл полностью идентичен packages/lib/src/core/templates-entrypoint/grok.ts. Маркеры jscpd:ignore подавляют предупреждения, но любое исправление потребует синхронизации обоих файлов.

Рассмотрите возможность вынести общую логику в shared-пакет или re-export из lib, если архитектура это позволяет.

Also applies to: 267-267

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

In `@packages/app/src/lib/core/templates-entrypoint/grok.ts` around lines 1 - 2,
The file packages/app src lib core templates-entrypoint grok.ts duplicates logic
present in packages/lib/src/core/templates-entrypoint/grok.ts; remove the
duplicate by extracting the shared code (including the TemplateConfig-related
logic and any exported helpers) into a single shared module or the lib package
and have packages/app re-export or import that module (e.g., export/import the
same symbols instead of re-defining them). Update the grok.ts in packages/app to
import TemplateConfig and any functions from the shared location (or re-export
from packages/lib) so only one source of truth remains and jscpd markers are no
longer needed.

Comment on lines +259 to +266
export const renderEntrypointGrokConfig = (config: TemplateConfig): string =>
[
renderGrokAuthConfig(config),
renderGrokPermissionSettingsConfig(config),
renderGrokSudoConfig(config),
renderGrokProfileSetup(config),
renderEntrypointGrokNotice(config)
].join("\n\n")
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 | 💤 Low value

Отсутствует TSDoc для экспортируемой функции.

Та же проблема, что и в packages/lib/src/core/templates-entrypoint/grok.ts. As per coding guidelines, все функции должны иметь 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/app/src/lib/core/templates-entrypoint/grok.ts` around lines 259 -
266, Экспортная функция renderEntrypointGrokConfig не имеет TSDoc — добавьте
подробный TSDoc над объявлением функции renderEntrypointGrokConfig, описывающий
назначение функции, параметры (config: TemplateConfig) и возвращаемое значение
(string), а также любые побочные эффекты или примечания; используйте стиль и
уровень детализации, согласованный с другими файлами (например,
packages/lib/src/core/templates-entrypoint/grok.ts), включая пример
использования при необходимости.

Comment on lines +258 to +265
export const renderEntrypointGrokConfig = (config: TemplateConfig): string =>
[
renderGrokAuthConfig(config),
renderGrokPermissionSettingsConfig(config),
renderGrokSudoConfig(config),
renderGrokProfileSetup(config),
renderEntrypointGrokNotice(config)
].join("\n\n")
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 | 💤 Low value

Отсутствует TSDoc для экспортируемой функции.

Согласно coding guidelines, все функции должны иметь comprehensive TSDoc с @pure, @effect, @invariant, @precondition, @postcondition, @complexity.

📝 Предлагаемый TSDoc
+/**
+ * Renders the complete Grok CLI entrypoint configuration bash script.
+ *
+ * `@param` config - Template configuration containing sshUser, grokHome, and targetDir
+ * `@returns` Valid bash script for Grok auth isolation, wrapper setup, and system prompt
+ * `@pure` true
+ * `@effect` None (pure string generation)
+ * `@invariant` Grok credentials are isolated by GROK_AUTH_LABEL
+ * `@precondition` config.sshUser, config.grokHome, config.targetDir are valid paths
+ * `@postcondition` Output is executable bash script with no unbound variable references
+ * `@complexity` O(1) - constant-time string concatenation
+ */
 export const renderEntrypointGrokConfig = (config: TemplateConfig): string =>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const renderEntrypointGrokConfig = (config: TemplateConfig): string =>
[
renderGrokAuthConfig(config),
renderGrokPermissionSettingsConfig(config),
renderGrokSudoConfig(config),
renderGrokProfileSetup(config),
renderEntrypointGrokNotice(config)
].join("\n\n")
/**
* Renders the complete Grok CLI entrypoint configuration bash script.
*
* `@param` config - Template configuration containing sshUser, grokHome, and targetDir
* `@returns` Valid bash script for Grok auth isolation, wrapper setup, and system prompt
* `@pure` true
* `@effect` None (pure string generation)
* `@invariant` Grok credentials are isolated by GROK_AUTH_LABEL
* `@precondition` config.sshUser, config.grokHome, config.targetDir are valid paths
* `@postcondition` Output is executable bash script with no unbound variable references
* `@complexity` O(1) - constant-time string concatenation
*/
export const renderEntrypointGrokConfig = (config: TemplateConfig): string =>
[
renderGrokAuthConfig(config),
renderGrokPermissionSettingsConfig(config),
renderGrokSudoConfig(config),
renderGrokProfileSetup(config),
renderEntrypointGrokNotice(config)
].join("\n\n")
🤖 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/lib/src/core/templates-entrypoint/grok.ts` around lines 258 - 265,
Add a comprehensive TSDoc block to the exported function
renderEntrypointGrokConfig describing its purpose and behavior, and include the
required tags: `@pure`, `@effect` (describe side effects or "none"), `@invariant`,
`@precondition` (e.g., valid TemplateConfig), `@postcondition` (what string
structure is returned), and `@complexity` (time/space complexity). Place the
comment immediately above the renderEntrypointGrokConfig declaration and
reference the parameter config and returned string in the descriptions so that
consumers and linters get the full contract for this exported function.

@konard
Copy link
Copy Markdown
Contributor Author

konard commented May 15, 2026

Working session summary

Готово: PR 305 обновлён и готов к ревью: #305

Что добавлено поверх основной Grok-поддержки:

  • Исправил CI-регрессию GROK_API_KEY: unbound variable в generated Grok entrypoint.
  • Добавил регрессионный тест, который проверяет, что bash defaults рендерятся как ${GROK_API_KEY:-}, без экранированного \${...}.
  • Запушил коммит d4d0fe9 fix(auth): tolerate missing grok api key in entrypoint.

Проверки:

  • Локально прошли bun run typecheck, bun run lint, bun run lint:effect, bun run test, bun run api:test.
  • GitHub checks на d4d0fe9 все зелёные, включая E2E (Clone auto-open SSH), где раньше падало.
  • gh pr checks 305 показывает pass по всем checks, включая CodeRabbit.
  • Working tree чистый.

SOURCE: n/a


This summary was automatically extracted from the AI working session output.

@skulidropek
Copy link
Copy Markdown
Member

Испраьв всё что написал rabbit coder

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.

Реализовать поддержку авторизации grok

2 participants