feat(container): add first-party Android MCP module#437
Conversation
Adding .gitkeep for PR creation (default mode). This file will be removed when the task is complete. Issue: ProverCoderAI#436
📝 WalkthroughSummary by CodeRabbitПримечания к выпуску
WalkthroughPR добавляет опциональную интеграцию Android MCP ( ChangesAndroid MCP сквозная интеграция
Sequence Diagram(s)sequenceDiagram
actor User
participant CLI as docker-git CLI
participant CreateFlow as Create Wizard / API
participant Container as Container Template Engine
participant AndroidCrate as android-connection (Rust)
participant AgentConfig as Agent Config (Claude/Gemini/Grok/Codex)
User->>CLI: docker-git create --mcp-android
CLI->>CreateFlow: McpAndroidUpCommand / CreateInputs{enableMcpAndroid:true}
CreateFlow->>Container: buildComposeFragments(enableMcpAndroid=true)
Container->>Container: buildAndroidFragments → docker-android sidecar YAML
Container->>Container: renderDockerfileAndroidRuntime → cargo install android-connection
Container->>AgentConfig: renderClaudeMcpAndroidConfig / renderGeminiMcpAndroidConfig / ...
AgentConfig-->>Container: mcpServers.android = {command: "android-connection", endpoint: ...}
Container-->>CreateFlow: docker-compose.yml, Dockerfile, entrypoint.sh
CreateFlow-->>CLI: project files written
CLI->>AndroidCrate: android-connection --endpoint <adb>
AndroidCrate-->>CLI: MCP stdio server ready
CLI-->>User: project created with Android emulator sidecar
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 error, 1 warning)
✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Mirror the Playwright MCP wiring for Android (issue ProverCoderAI#436): - TemplateConfig.enableMcpAndroid + default - docker-compose: emulator sidecar service (docker-android), env vars, ADB endpoint, dedicated volume - Dockerfile: install android-tools-adb when enabled - entrypoint base env MCP_ANDROID_ENABLE - codex/claude/gemini/grok: register an 'android' MCP server (mobile-mcp) - container template tests
Add --mcp-android / --no-mcp-android flags, mcp-android subcommand parser, interactive create-flow prompt + display-settings row, and propagate enableMcpAndroid through frontend-lib config, web create draft, and API client request body. Mirrors the existing Playwright MCP integration. REF: issue-436
Add enableMcpAndroid to the create-project schema, contract type, and service request mapping, and regenerate the OpenAPI spec + typed paths. REF: issue-436
REF: issue-436
…y max-lines lint Move the Android and Playwright MCP config/sidecar builders into sibling modules so grok.ts, gemini.ts, and docker-compose.ts stay under the 300-line max-lines budget enforced by CI. Pure refactor — rendered output is unchanged (72 container tests still pass). REF: issue-436
Working session summaryThe work is complete. Here's the final status: SummaryIssue #436 ("Подключить mcp-android так же как работает MCP PLAYRIGHT") is resolved in PR #437, now ready for review with all CI green. What was deliveredAndroid emulator MCP integration mirroring the existing Playwright MCP pattern across the whole stack:
This session's workFixed the CI Verification
PR: #437 This summary was automatically extracted from the AI working session output. |
🤖 Solution Draft LogThis log file contains the complete execution trace of the AI solution draft process. 💰 Cost estimation:
📊 Context and tokens usage:Claude Opus 4.8: (6 sub-sessions)
Total: (63.2K new + 578.1K cache writes + 27.2M cache reads) input tokens, 216.4K output tokens, $25.094257 cost Claude Haiku 4.5:
Total: (52 new + 72.6K cache writes + 1.1M cache reads) input tokens, 8.0K output tokens, $0.245185 cost 🤖 Models used:
📎 Log file uploaded as Gist (12279KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
There was a problem hiding this comment.
Actionable comments posted: 9
🤖 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/container/src/core/templates-entrypoint/claude.ts`:
- Around line 268-285: The adbEndpoint variable is being directly concatenated
into a bash command string without sanitization, creating a command injection
vulnerability. In the connectPrefix variable assignment where adbEndpoint is
used with "adb connect " + adbEndpoint, you need to properly escape or sanitize
the adbEndpoint value to prevent shell metacharacters from being interpreted as
commands. Use appropriate shell escaping techniques (such as single quotes or a
proper escaping function) to ensure user-controlled input cannot break out of
the intended command context when the bash -lc command is executed.
In `@packages/container/src/core/templates-entrypoint/codex.ts`:
- Line 206: The command string passed to bash -lc in the args assignment
contains an unescaped environment variable $DOCKER_GIT_ANDROID_ADB_ENDPOINT that
could allow command injection. Wrap the endpoint variable in double quotes in
the bash command to prevent arbitrary command execution. Change
$DOCKER_GIT_ANDROID_ADB_ENDPOINT to "$DOCKER_GIT_ANDROID_ADB_ENDPOINT" within
the adb connect command string to safely interpolate the variable while
preventing shell metacharacter interpretation.
- Around line 203-207: Replace the use of `@latest` with a pinned version number
`0.0.60` for the `@mobilenext/mobile-mcp` package across all MCP Android
configuration files. In the codex.ts file, update the npx command in the args
array to use the specific version instead of `@latest`. Apply the same fix to
gemini-android-mcp.ts, grok-android-mcp.ts, and claude.ts files. Additionally,
update the test expectations in packages/container/tests/core/templates.test.ts
to expect the pinned version `0.0.60` instead of `@latest` to ensure tests pass
with the new versioning.
In `@packages/container/src/core/templates-entrypoint/gemini-android-mcp.ts`:
- Around line 24-29: The adbEndpoint value from
process.env.DOCKER_GIT_ANDROID_ADB_ENDPOINT is being concatenated directly into
a bash command without validation or sanitization, creating a command injection
vulnerability. Before using adbEndpoint in the connectPrefix string that gets
passed to the bash -lc command, add validation to ensure the endpoint contains
only safe characters (such as alphanumeric, dots, colons, and hyphens for a
typical ADB endpoint format), or properly escape it for shell safety. This will
prevent malicious input from being executed as shell commands.
In `@packages/container/src/core/templates-entrypoint/grok-android-mcp.ts`:
- Around line 24-29: The code has a command injection vulnerability where the
DOCKER_GIT_ANDROID_ADB_ENDPOINT environment variable is directly concatenated
into a bash command string without validation. To fix this, validate the
adbEndpoint variable before using it in the connectPrefix string construction.
Ensure the endpoint matches only allowed characters (likely IP address and
optional port format like "127.0.0.1:5037" or similar), and reject or skip the
android server configuration if the endpoint contains invalid characters or
fails validation. This prevents arbitrary shell commands from being injected
through the environment variable when constructing the bash -lc argument in the
nextServers.android command setup.
In `@packages/container/tests/core/templates.test.ts`:
- Line 1162: The current test assertion using toContain(" cpus: 1.5\n")
checks if the CPU limit appears anywhere in the compose output but does not
verify that the limit is specifically applied to the dg-test-android Android
sidecar service. Refactor the expect statement to first locate the
dg-test-android service configuration block within the compose output and then
verify that the cpus: 1.5 limit exists only within that specific service
section, ensuring the assertion proves the limit is correctly placed in the
Android sidecar rather than elsewhere in the configuration.
- Around line 1133-1201: The five new Android MCP tests (starting with "renders
the Android emulator sidecar service when Android MCP is enabled" through
"defaults MCP_ANDROID_ENABLE to 0 when Android MCP is disabled") use simple
example-based testing with hardcoded `it()` blocks and `expect()` statements,
which violates the established property-based testing pattern used elsewhere in
this file. Refactor these tests to use
`fc.property(generatedTemplateConfigArbitrary.chain(...), ...)` or `.map()` to
generate test cases with `enableMcpAndroid` set to both true and false,
following the same pattern already established for testing `renderDockerfile`
and `renderEntrypoint`. Convert the hardcoded assertions into parameterized
property-based checks where the invariants (like presence/absence of MCP
environment variables and service configurations based on the `enableMcpAndroid`
flag) are verified across generated configurations.
In `@packages/lib/src/usecases/apply-overrides.ts`:
- Around line 59-64: Add regression test coverage for the enableMcpAndroid
override flag in the test file that contains the "applies token and mcp
overrides from apply command" test case. Extend this existing test to include
enableMcpAndroid set to true in the applyProjectFiles command, then verify that
appliedTemplate.enableMcpAndroid equals true, that the docker-compose output
contains MCP_ANDROID_ENABLE set to "1", and that the docker-git.json output
contains enableMcpAndroid set to true, mirroring the same validation pattern
already in place for the enableMcpPlaywright flag.
In `@packages/lib/src/usecases/mcp-android.ts`:
- Around line 88-89: The ensureDockerDaemonAccess function on line 88 is
checking Docker access relative to process.cwd() while the subsequent
runDockerComposeUpWithPortCheck call uses command.projectDir, causing
inconsistent and non-deterministic behavior when working with external
directories. Replace the process.cwd() argument passed to
ensureDockerDaemonAccess with command.projectDir to ensure Docker daemon access
is verified for the same target directory that will be used for the actual
Docker Compose execution.
🪄 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: 4223cde2-527b-474a-b5fb-9c2b687e5525
📒 Files selected for processing (68)
.changeset/mcp-android-integration.mdREADME.mdpackages/api/src/api/contracts.tspackages/api/src/api/schema.tspackages/api/src/services/projects.tspackages/app/CHANGELOG.mdpackages/app/package.jsonpackages/app/src/docker-git/api-client-create.tspackages/app/src/docker-git/cli/parser-apply.tspackages/app/src/docker-git/cli/parser-mcp-android.tspackages/app/src/docker-git/cli/parser-options.tspackages/app/src/docker-git/cli/parser.tspackages/app/src/docker-git/cli/usage.tspackages/app/src/docker-git/frontend-lib/core/command-builders-template.tspackages/app/src/docker-git/frontend-lib/core/command-builders.tspackages/app/src/docker-git/frontend-lib/core/command-options.tspackages/app/src/docker-git/frontend-lib/core/domain.tspackages/app/src/docker-git/frontend-lib/core/template-defaults.tspackages/app/src/docker-git/menu-create-command-parse.tspackages/app/src/docker-git/menu-create-draft.tspackages/app/src/docker-git/menu-create-inputs.tspackages/app/src/docker-git/menu-create-labels.tspackages/app/src/docker-git/menu-create-navigation.tspackages/app/src/docker-git/menu-create-step-apply.tspackages/app/src/docker-git/menu-create-steps.tspackages/app/src/docker-git/menu-types.tspackages/app/src/docker-git/program-unsupported.tspackages/app/src/web/api-project-create-body.tspackages/app/src/web/api-types.tspackages/app/tests/docker-git/actions-project-create.test.tspackages/app/tests/docker-git/api-create-project.test.tspackages/app/tests/docker-git/app-ready-create-fixture.tspackages/app/tests/docker-git/app-ready-create-settings.test.tspackages/app/tests/docker-git/app-ready-create.test.tspackages/app/tests/docker-git/menu-create-display-settings.test.tspackages/app/tests/docker-git/menu-create-shared-properties.test.tspackages/app/tests/docker-git/menu-create-shared.test.tspackages/container/src/core/domain.tspackages/container/src/core/template-defaults.tspackages/container/src/core/templates-entrypoint.tspackages/container/src/core/templates-entrypoint/base.tspackages/container/src/core/templates-entrypoint/claude.tspackages/container/src/core/templates-entrypoint/codex.tspackages/container/src/core/templates-entrypoint/gemini-android-mcp.tspackages/container/src/core/templates-entrypoint/gemini-playwright-mcp.tspackages/container/src/core/templates-entrypoint/gemini.tspackages/container/src/core/templates-entrypoint/grok-android-mcp.tspackages/container/src/core/templates-entrypoint/grok.tspackages/container/src/core/templates/docker-compose-android.tspackages/container/src/core/templates/docker-compose-playwright.tspackages/container/src/core/templates/docker-compose.tspackages/container/src/core/templates/dockerfile.tspackages/container/tests/core/templates.test.tspackages/docker-git-session-sync/CHANGELOG.mdpackages/docker-git-session-sync/package.jsonpackages/lib/src/core/command-builders-template.tspackages/lib/src/core/command-builders.tspackages/lib/src/core/command-options.tspackages/lib/src/core/domain.tspackages/lib/src/shell/config.tspackages/lib/src/shell/errors.tspackages/lib/src/usecases/actions/create-project-conflicts.tspackages/lib/src/usecases/apply-overrides.tspackages/lib/src/usecases/errors.tspackages/lib/src/usecases/mcp-android.tspackages/lib/tests/usecases/mcp-android.test.tspackages/openapi/openapi.jsonpackages/openapi/src/openapi-paths.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (5)
- GitHub Check: E2E (Clone auto-open SSH)
- GitHub Check: E2E (Login context)
- GitHub Check: E2E (Clone cache)
- GitHub Check: E2E (OpenCode)
- GitHub Check: E2E (Runtime volumes + SSH)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{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/docker-git/cli/parser-apply.tspackages/app/tests/docker-git/app-ready-create.test.tspackages/app/src/docker-git/frontend-lib/core/command-options.tspackages/api/src/api/contracts.tspackages/app/tests/docker-git/api-create-project.test.tspackages/app/src/docker-git/menu-create-steps.tspackages/api/src/api/schema.tspackages/app/src/docker-git/cli/parser-mcp-android.tspackages/api/src/services/projects.tspackages/app/tests/docker-git/actions-project-create.test.tspackages/app/src/docker-git/api-client-create.tspackages/app/src/docker-git/cli/usage.tspackages/app/src/docker-git/menu-create-draft.tspackages/app/src/docker-git/menu-create-navigation.tspackages/lib/src/core/command-options.tspackages/openapi/src/openapi-paths.tspackages/container/src/core/templates-entrypoint.tspackages/app/src/docker-git/menu-types.tspackages/app/tests/docker-git/app-ready-create-settings.test.tspackages/container/src/core/template-defaults.tspackages/app/src/docker-git/cli/parser.tspackages/app/src/web/api-types.tspackages/lib/src/shell/config.tspackages/app/src/docker-git/frontend-lib/core/template-defaults.tspackages/app/src/docker-git/menu-create-inputs.tspackages/lib/src/shell/errors.tspackages/container/src/core/templates/docker-compose-playwright.tspackages/container/src/core/templates-entrypoint/gemini-android-mcp.tspackages/app/src/docker-git/cli/parser-options.tspackages/container/src/core/templates-entrypoint/base.tspackages/container/src/core/templates/docker-compose-android.tspackages/lib/src/usecases/mcp-android.tspackages/container/src/core/templates-entrypoint/grok-android-mcp.tspackages/container/src/core/templates-entrypoint/gemini-playwright-mcp.tspackages/app/src/docker-git/menu-create-step-apply.tspackages/app/tests/docker-git/menu-create-display-settings.test.tspackages/container/src/core/templates-entrypoint/claude.tspackages/lib/src/usecases/apply-overrides.tspackages/container/src/core/templates/dockerfile.tspackages/lib/src/core/command-builders-template.tspackages/container/src/core/domain.tspackages/app/tests/docker-git/menu-create-shared.test.tspackages/app/src/docker-git/menu-create-command-parse.tspackages/container/src/core/templates-entrypoint/grok.tspackages/lib/src/usecases/actions/create-project-conflicts.tspackages/lib/src/core/domain.tspackages/lib/src/usecases/errors.tspackages/container/src/core/templates-entrypoint/codex.tspackages/app/src/docker-git/frontend-lib/core/command-builders-template.tspackages/app/src/docker-git/frontend-lib/core/domain.tspackages/app/tests/docker-git/menu-create-shared-properties.test.tspackages/container/tests/core/templates.test.tspackages/lib/tests/usecases/mcp-android.test.tspackages/lib/src/core/command-builders.tspackages/app/src/docker-git/program-unsupported.tspackages/app/src/docker-git/frontend-lib/core/command-builders.tspackages/app/src/docker-git/menu-create-labels.tspackages/app/tests/docker-git/app-ready-create-fixture.tspackages/container/src/core/templates-entrypoint/gemini.tspackages/app/src/web/api-project-create-body.tspackages/container/src/core/templates/docker-compose.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/docker-git/cli/parser-apply.tspackages/app/tests/docker-git/app-ready-create.test.tspackages/app/src/docker-git/frontend-lib/core/command-options.tspackages/api/src/api/contracts.tspackages/app/tests/docker-git/api-create-project.test.tspackages/app/src/docker-git/menu-create-steps.tspackages/api/src/api/schema.tspackages/app/src/docker-git/cli/parser-mcp-android.tspackages/api/src/services/projects.tspackages/app/tests/docker-git/actions-project-create.test.tspackages/app/src/docker-git/api-client-create.tspackages/app/src/docker-git/cli/usage.tspackages/app/src/docker-git/menu-create-draft.tspackages/app/src/docker-git/menu-create-navigation.tspackages/lib/src/core/command-options.tspackages/openapi/src/openapi-paths.tspackages/container/src/core/templates-entrypoint.tspackages/app/src/docker-git/menu-types.tspackages/app/tests/docker-git/app-ready-create-settings.test.tspackages/container/src/core/template-defaults.tspackages/app/src/docker-git/cli/parser.tspackages/app/src/web/api-types.tspackages/lib/src/shell/config.tspackages/app/src/docker-git/frontend-lib/core/template-defaults.tspackages/app/src/docker-git/menu-create-inputs.tspackages/lib/src/shell/errors.tspackages/container/src/core/templates/docker-compose-playwright.tspackages/container/src/core/templates-entrypoint/gemini-android-mcp.tspackages/app/src/docker-git/cli/parser-options.tspackages/container/src/core/templates-entrypoint/base.tspackages/container/src/core/templates/docker-compose-android.tspackages/lib/src/usecases/mcp-android.tspackages/container/src/core/templates-entrypoint/grok-android-mcp.tspackages/container/src/core/templates-entrypoint/gemini-playwright-mcp.tspackages/app/src/docker-git/menu-create-step-apply.tspackages/app/tests/docker-git/menu-create-display-settings.test.tspackages/container/src/core/templates-entrypoint/claude.tspackages/lib/src/usecases/apply-overrides.tspackages/container/src/core/templates/dockerfile.tspackages/lib/src/core/command-builders-template.tspackages/container/src/core/domain.tspackages/app/tests/docker-git/menu-create-shared.test.tspackages/app/src/docker-git/menu-create-command-parse.tspackages/container/src/core/templates-entrypoint/grok.tspackages/lib/src/usecases/actions/create-project-conflicts.tspackages/lib/src/core/domain.tspackages/lib/src/usecases/errors.tspackages/container/src/core/templates-entrypoint/codex.tspackages/app/src/docker-git/frontend-lib/core/command-builders-template.tspackages/app/src/docker-git/frontend-lib/core/domain.tspackages/app/tests/docker-git/menu-create-shared-properties.test.tspackages/container/tests/core/templates.test.tspackages/lib/tests/usecases/mcp-android.test.tspackages/lib/src/core/command-builders.tspackages/app/src/docker-git/program-unsupported.tspackages/app/src/docker-git/frontend-lib/core/command-builders.tspackages/app/src/docker-git/menu-create-labels.tspackages/app/tests/docker-git/app-ready-create-fixture.tspackages/container/src/core/templates-entrypoint/gemini.tspackages/app/src/web/api-project-create-body.tspackages/container/src/core/templates/docker-compose.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/docker-git/cli/parser-apply.tspackages/app/package.jsonpackages/app/tests/docker-git/app-ready-create.test.tspackages/app/src/docker-git/frontend-lib/core/command-options.tspackages/api/src/api/contracts.tspackages/app/tests/docker-git/api-create-project.test.tspackages/docker-git-session-sync/package.jsonpackages/app/src/docker-git/menu-create-steps.tspackages/api/src/api/schema.tspackages/app/src/docker-git/cli/parser-mcp-android.tspackages/api/src/services/projects.tspackages/app/tests/docker-git/actions-project-create.test.tspackages/app/src/docker-git/api-client-create.tspackages/app/src/docker-git/cli/usage.tspackages/app/src/docker-git/menu-create-draft.tspackages/app/src/docker-git/menu-create-navigation.tspackages/lib/src/core/command-options.tspackages/openapi/src/openapi-paths.tspackages/container/src/core/templates-entrypoint.tspackages/app/src/docker-git/menu-types.tspackages/app/tests/docker-git/app-ready-create-settings.test.tspackages/container/src/core/template-defaults.tspackages/app/src/docker-git/cli/parser.tspackages/app/src/web/api-types.tspackages/lib/src/shell/config.tspackages/app/src/docker-git/frontend-lib/core/template-defaults.tspackages/app/src/docker-git/menu-create-inputs.tspackages/lib/src/shell/errors.tspackages/container/src/core/templates/docker-compose-playwright.tspackages/container/src/core/templates-entrypoint/gemini-android-mcp.tspackages/app/src/docker-git/cli/parser-options.tspackages/container/src/core/templates-entrypoint/base.tspackages/container/src/core/templates/docker-compose-android.tspackages/lib/src/usecases/mcp-android.tspackages/container/src/core/templates-entrypoint/grok-android-mcp.tspackages/container/src/core/templates-entrypoint/gemini-playwright-mcp.tspackages/app/src/docker-git/menu-create-step-apply.tspackages/app/tests/docker-git/menu-create-display-settings.test.tspackages/container/src/core/templates-entrypoint/claude.tspackages/lib/src/usecases/apply-overrides.tspackages/container/src/core/templates/dockerfile.tspackages/lib/src/core/command-builders-template.tspackages/container/src/core/domain.tspackages/app/tests/docker-git/menu-create-shared.test.tspackages/app/src/docker-git/menu-create-command-parse.tspackages/container/src/core/templates-entrypoint/grok.tspackages/lib/src/usecases/actions/create-project-conflicts.tspackages/lib/src/core/domain.tspackages/lib/src/usecases/errors.tspackages/container/src/core/templates-entrypoint/codex.tspackages/app/src/docker-git/frontend-lib/core/command-builders-template.tspackages/openapi/openapi.jsonpackages/app/src/docker-git/frontend-lib/core/domain.tspackages/app/tests/docker-git/menu-create-shared-properties.test.tspackages/container/tests/core/templates.test.tspackages/lib/tests/usecases/mcp-android.test.tspackages/lib/src/core/command-builders.tspackages/app/src/docker-git/program-unsupported.tspackages/app/src/docker-git/frontend-lib/core/command-builders.tspackages/app/src/docker-git/menu-create-labels.tspackages/app/tests/docker-git/app-ready-create-fixture.tspackages/container/src/core/templates-entrypoint/gemini.tspackages/app/src/web/api-project-create-body.tspackages/container/src/core/templates/docker-compose.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: FUNCTIONAL CORE: Write only pure functions with immutable data and mathematical operations in core modules; no side effects, mutations, or external service calls
IMPERATIVE SHELL: Isolate all side effects (IO, network, database, environment/process) in a thin SHELL layer; CORE never calls SHELL, only SHELL → CORE
Never useanytype annotation in TypeScript; useunknownonly at SHELL boundaries for decoding, never exportunknownoutside boundary modules
Never useastype assertions in normal code; only permitasin a single 'axiomatic' module (brands, constructors, constants) after which types flow safely without casts
Always use exhaustive pattern matching for union types through.exhaustive()orMatch.exhaustive()from effect-ts; never use switch statements or unhandled type branches
Use Effect<Success, Error, Requirements> monad from effect-ts for all effects; compose through pipe() and Effect.flatMap(); never use async/await, raw Promise chains (then/catch), or Promise.all in product code
Interoperate with Promise/exceptions only in SHELL through Effect.try/Effect.tryPromise with typed error mapping; never leave raw exceptions or untyped errors in the domain
Use Effect.acquireRelease + Effect.scoped for resource management with guaranteed finalization; never manage resources with try/finally or manual cleanup
All external services (database, HTTP, environment) must be accessed through Effect-based interfaces and Layer-based dependency injection; never call external APIs directly
Provide comprehensive TSDoc comments with mathematical notation:@pure,@effect,@invariant,@precondition,@postcondition,@complexity,@throws, and CHANGE/WHY/REF/SOURCE/FORMAT THEOREM functional comment markers
No console.*, process direct calls, or untyped environment access in product code; all such operations must be abstracted through Layer-based services in SHELL
Boundary data from external sources (HTTP, database, environment) must be decoded/valida...
Files:
packages/app/src/docker-git/cli/parser-apply.tspackages/app/tests/docker-git/app-ready-create.test.tspackages/app/src/docker-git/frontend-lib/core/command-options.tspackages/api/src/api/contracts.tspackages/app/tests/docker-git/api-create-project.test.tspackages/app/src/docker-git/menu-create-steps.tspackages/api/src/api/schema.tspackages/app/src/docker-git/cli/parser-mcp-android.tspackages/api/src/services/projects.tspackages/app/tests/docker-git/actions-project-create.test.tspackages/app/src/docker-git/api-client-create.tspackages/app/src/docker-git/cli/usage.tspackages/app/src/docker-git/menu-create-draft.tspackages/app/src/docker-git/menu-create-navigation.tspackages/lib/src/core/command-options.tspackages/openapi/src/openapi-paths.tspackages/container/src/core/templates-entrypoint.tspackages/app/src/docker-git/menu-types.tspackages/app/tests/docker-git/app-ready-create-settings.test.tspackages/container/src/core/template-defaults.tspackages/app/src/docker-git/cli/parser.tspackages/app/src/web/api-types.tspackages/lib/src/shell/config.tspackages/app/src/docker-git/frontend-lib/core/template-defaults.tspackages/app/src/docker-git/menu-create-inputs.tspackages/lib/src/shell/errors.tspackages/container/src/core/templates/docker-compose-playwright.tspackages/container/src/core/templates-entrypoint/gemini-android-mcp.tspackages/app/src/docker-git/cli/parser-options.tspackages/container/src/core/templates-entrypoint/base.tspackages/container/src/core/templates/docker-compose-android.tspackages/lib/src/usecases/mcp-android.tspackages/container/src/core/templates-entrypoint/grok-android-mcp.tspackages/container/src/core/templates-entrypoint/gemini-playwright-mcp.tspackages/app/src/docker-git/menu-create-step-apply.tspackages/app/tests/docker-git/menu-create-display-settings.test.tspackages/container/src/core/templates-entrypoint/claude.tspackages/lib/src/usecases/apply-overrides.tspackages/container/src/core/templates/dockerfile.tspackages/lib/src/core/command-builders-template.tspackages/container/src/core/domain.tspackages/app/tests/docker-git/menu-create-shared.test.tspackages/app/src/docker-git/menu-create-command-parse.tspackages/container/src/core/templates-entrypoint/grok.tspackages/lib/src/usecases/actions/create-project-conflicts.tspackages/lib/src/core/domain.tspackages/lib/src/usecases/errors.tspackages/container/src/core/templates-entrypoint/codex.tspackages/app/src/docker-git/frontend-lib/core/command-builders-template.tspackages/app/src/docker-git/frontend-lib/core/domain.tspackages/app/tests/docker-git/menu-create-shared-properties.test.tspackages/container/tests/core/templates.test.tspackages/lib/tests/usecases/mcp-android.test.tspackages/lib/src/core/command-builders.tspackages/app/src/docker-git/program-unsupported.tspackages/app/src/docker-git/frontend-lib/core/command-builders.tspackages/app/src/docker-git/menu-create-labels.tspackages/app/tests/docker-git/app-ready-create-fixture.tspackages/container/src/core/templates-entrypoint/gemini.tspackages/app/src/web/api-project-create-body.tspackages/container/src/core/templates/docker-compose.ts
**
⚙️ CodeRabbit configuration file
**: РОЛЬ: Математик-программист, специализирующийся на формально верифицируемой функциональной архитектуре.ЦЕЛЬ: Создавать математически доказуемые решения через функциональную парадигму с полным разделением чистых вычислений и контролируемых эффектов.
МОДЕЛЬ РАССУЖДЕНИЯ:
- Не выдавать “личные мнения”. Формировать вывод как результат симуляции профессионального обсуждения релевантных ролей
(архитектор Effect/FP, ревьюер типов, страж CORE↔SHELL, тест-инженер).- Если запрос сформулирован как “что думаешь”, отвечать в терминах аргументов ролей и выбирать решение
по критериям инвариантов, типовой безопасности и тестируемости (если пользователь явно просит выбор — выбрать и обосновать).ПРАВИЛО ПРОЦЕССА (НЕ ФОРМАТ ОТВЕТА):
В начале работы (внутренне) формулировать Deep Research вопрос:
"I am looking for code that does , is there existing code that can do this?"
Далее:
- если доступен проект/код — сперва искать и переиспользовать существующие паттерны (минимальный корректный diff),
- если проект недоступен — опираться на предоставленный контекст и явно фиксировать допущения,
- код писать только после формального понимания задачи (типы/инварианты → архитектура → код → тесты),
- источники указывать только если реально использован внешний материал; иначе
SOURCE: n/a.ИНСТРУМЕНТАЛЬНОЕ ПОВЕДЕНИЕ (ОБЯЗАТЕЛЬНО, НЕ ФОРМАТ ОТВЕТА):
- Агент всегда использует доступные инструменты среды (терминал, поиск по проекту, запуск тестов/скриптов, анализ сборки, web-ресёрч при необходимости)
для ресёрча, проверки гипотез и выполнения действий. Приоритет: проверяемость, воспроизводимость, минимальный риск.- Агент не предлагает “гайд” как замену действия. Если действие возможно выполнить инструментами — агент выполняет его сам,
затем сообщает, что было сделано и как повторить.- Любые инструкции (команды/процедуры) агент даёт только после собственной проверки на доступной среде.
Если проверить невозможно — явно фиксирует ограничение и перечисляе...
Files:
packages/app/src/docker-git/cli/parser-apply.tspackages/app/package.jsonpackages/app/tests/docker-git/app-ready-create.test.tspackages/app/src/docker-git/frontend-lib/core/command-options.tspackages/api/src/api/contracts.tspackages/app/tests/docker-git/api-create-project.test.tspackages/docker-git-session-sync/package.jsonpackages/docker-git-session-sync/CHANGELOG.mdpackages/app/src/docker-git/menu-create-steps.tspackages/api/src/api/schema.tsREADME.mdpackages/app/src/docker-git/cli/parser-mcp-android.tspackages/api/src/services/projects.tspackages/app/tests/docker-git/actions-project-create.test.tspackages/app/src/docker-git/api-client-create.tspackages/app/CHANGELOG.mdpackages/app/src/docker-git/cli/usage.tspackages/app/src/docker-git/menu-create-draft.tspackages/app/src/docker-git/menu-create-navigation.tspackages/lib/src/core/command-options.tspackages/openapi/src/openapi-paths.tspackages/container/src/core/templates-entrypoint.tspackages/app/src/docker-git/menu-types.tspackages/app/tests/docker-git/app-ready-create-settings.test.tspackages/container/src/core/template-defaults.tspackages/app/src/docker-git/cli/parser.tspackages/app/src/web/api-types.tspackages/lib/src/shell/config.tspackages/app/src/docker-git/frontend-lib/core/template-defaults.tspackages/app/src/docker-git/menu-create-inputs.tspackages/lib/src/shell/errors.tspackages/container/src/core/templates/docker-compose-playwright.tspackages/container/src/core/templates-entrypoint/gemini-android-mcp.tspackages/app/src/docker-git/cli/parser-options.tspackages/container/src/core/templates-entrypoint/base.tspackages/container/src/core/templates/docker-compose-android.tspackages/lib/src/usecases/mcp-android.tspackages/container/src/core/templates-entrypoint/grok-android-mcp.tspackages/container/src/core/templates-entrypoint/gemini-playwright-mcp.tspackages/app/src/docker-git/menu-create-step-apply.tspackages/app/tests/docker-git/menu-create-display-settings.test.tspackages/container/src/core/templates-entrypoint/claude.tspackages/lib/src/usecases/apply-overrides.tspackages/container/src/core/templates/dockerfile.tspackages/lib/src/core/command-builders-template.tspackages/container/src/core/domain.tspackages/app/tests/docker-git/menu-create-shared.test.tspackages/app/src/docker-git/menu-create-command-parse.tspackages/container/src/core/templates-entrypoint/grok.tspackages/lib/src/usecases/actions/create-project-conflicts.tspackages/lib/src/core/domain.tspackages/lib/src/usecases/errors.tspackages/container/src/core/templates-entrypoint/codex.tspackages/app/src/docker-git/frontend-lib/core/command-builders-template.tspackages/openapi/openapi.jsonpackages/app/src/docker-git/frontend-lib/core/domain.tspackages/app/tests/docker-git/menu-create-shared-properties.test.tspackages/container/tests/core/templates.test.tspackages/lib/tests/usecases/mcp-android.test.tspackages/lib/src/core/command-builders.tspackages/app/src/docker-git/program-unsupported.tspackages/app/src/docker-git/frontend-lib/core/command-builders.tspackages/app/src/docker-git/menu-create-labels.tspackages/app/tests/docker-git/app-ready-create-fixture.tspackages/container/src/core/templates-entrypoint/gemini.tspackages/app/src/web/api-project-create-body.tspackages/container/src/core/templates/docker-compose.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/docker-git/cli/parser-apply.tspackages/app/package.jsonpackages/app/tests/docker-git/app-ready-create.test.tspackages/app/src/docker-git/frontend-lib/core/command-options.tspackages/api/src/api/contracts.tspackages/app/tests/docker-git/api-create-project.test.tspackages/docker-git-session-sync/package.jsonpackages/docker-git-session-sync/CHANGELOG.mdpackages/app/src/docker-git/menu-create-steps.tspackages/api/src/api/schema.tsREADME.mdpackages/app/src/docker-git/cli/parser-mcp-android.tspackages/api/src/services/projects.tspackages/app/tests/docker-git/actions-project-create.test.tspackages/app/src/docker-git/api-client-create.tspackages/app/CHANGELOG.mdpackages/app/src/docker-git/cli/usage.tspackages/app/src/docker-git/menu-create-draft.tspackages/app/src/docker-git/menu-create-navigation.tspackages/lib/src/core/command-options.tspackages/openapi/src/openapi-paths.tspackages/container/src/core/templates-entrypoint.tspackages/app/src/docker-git/menu-types.tspackages/app/tests/docker-git/app-ready-create-settings.test.tspackages/container/src/core/template-defaults.tspackages/app/src/docker-git/cli/parser.tspackages/app/src/web/api-types.tspackages/lib/src/shell/config.tspackages/app/src/docker-git/frontend-lib/core/template-defaults.tspackages/app/src/docker-git/menu-create-inputs.tspackages/lib/src/shell/errors.tspackages/container/src/core/templates/docker-compose-playwright.tspackages/container/src/core/templates-entrypoint/gemini-android-mcp.tspackages/app/src/docker-git/cli/parser-options.tspackages/container/src/core/templates-entrypoint/base.tspackages/container/src/core/templates/docker-compose-android.tspackages/lib/src/usecases/mcp-android.tspackages/container/src/core/templates-entrypoint/grok-android-mcp.tspackages/container/src/core/templates-entrypoint/gemini-playwright-mcp.tspackages/app/src/docker-git/menu-create-step-apply.tspackages/app/tests/docker-git/menu-create-display-settings.test.tspackages/container/src/core/templates-entrypoint/claude.tspackages/lib/src/usecases/apply-overrides.tspackages/container/src/core/templates/dockerfile.tspackages/lib/src/core/command-builders-template.tspackages/container/src/core/domain.tspackages/app/tests/docker-git/menu-create-shared.test.tspackages/app/src/docker-git/menu-create-command-parse.tspackages/container/src/core/templates-entrypoint/grok.tspackages/lib/src/usecases/actions/create-project-conflicts.tspackages/lib/src/core/domain.tspackages/lib/src/usecases/errors.tspackages/container/src/core/templates-entrypoint/codex.tspackages/app/src/docker-git/frontend-lib/core/command-builders-template.tspackages/openapi/openapi.jsonpackages/app/src/docker-git/frontend-lib/core/domain.tspackages/app/tests/docker-git/menu-create-shared-properties.test.tspackages/container/tests/core/templates.test.tspackages/lib/tests/usecases/mcp-android.test.tspackages/lib/src/core/command-builders.tspackages/app/src/docker-git/program-unsupported.tspackages/app/src/docker-git/frontend-lib/core/command-builders.tspackages/app/src/docker-git/menu-create-labels.tspackages/app/tests/docker-git/app-ready-create-fixture.tspackages/container/src/core/templates-entrypoint/gemini.tspackages/app/src/web/api-project-create-body.tspackages/container/src/core/templates/docker-compose.ts
**/{package*.json,requirements*.txt,setup.py,setup.cfg,Pipfile,Pipfile.lock,pyproject.toml,pom.xml,build.gradle,Gemfile,Gemfile.lock,go.mod,go.sum,composer.json,Cargo.toml,Cargo.lock}
📄 CodeRabbit inference engine (Custom checks)
Fail if dependency or package-manager changes materially increase supply-chain risk without justification
Files:
packages/app/package.jsonpackages/docker-git-session-sync/package.json
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.test.{ts,tsx}: Write property-based tests using fast-check (fc.property) to verify mathematical invariants; unit tests must use Effect test utilities without async/await
Every bug fix must be accompanied by a reproducing test case; the test must fail before the fix and pass after; document the Proof of Fix with root cause and solution
Files:
packages/app/tests/docker-git/app-ready-create.test.tspackages/app/tests/docker-git/api-create-project.test.tspackages/app/tests/docker-git/actions-project-create.test.tspackages/app/tests/docker-git/app-ready-create-settings.test.tspackages/app/tests/docker-git/menu-create-display-settings.test.tspackages/app/tests/docker-git/menu-create-shared.test.tspackages/app/tests/docker-git/menu-create-shared-properties.test.tspackages/container/tests/core/templates.test.tspackages/lib/tests/usecases/mcp-android.test.ts
*.md
📄 CodeRabbit inference engine (AGENTS.md)
Document all PR changes with mathematical proof obligations: invariants, preconditions, postconditions, variant functions, and complexity analysis in Markdown format
Files:
README.md
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T16:54:52.235Z
Learning: Organize project structure with clear separation: APP (CLI + React Frontend), LIB (backend business logic), and API (API server using LIB)
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T16:54:52.235Z
Learning: APP layer must only communicate with the API layer and cannot have direct access to LIB
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T16:54:52.235Z
Learning: API layer must only work with LIB and serve as the interface between APP and LIB
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T16:54:52.235Z
Learning: Use Spec-Driven Development (SDD) process: from issue to verifiable PR, as detailed in docs/process.md
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T16:54:52.235Z
Learning: Support authentication providers via CLI: GitHub (OAuth or token), GitLab (OAuth or token), Claude, Codex, Gemini, Grok, and generic git hosts via --host and --token
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T16:54:52.235Z
Learning: Store authentication tokens in env-file as GIT_AUTH_TOKEN__<HOST> and GIT_AUTH_USER__<HOST> variables
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T16:54:52.235Z
Learning: Implement git credential helper inside containers to automatically select correct token by host for clone/push operations
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T16:54:52.235Z
Learning: Web interface (browser mode) should listen on 0.0.0.0 by default, but allow DOCKER_GIT_WEB_HOST environment variable to restrict access to 127.0.0.1
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T16:54:52.235Z
Learning: Support --force flag to recreate environment and delete project volumes
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T16:54:52.235Z
Learning: Support --mcp-playwright flag to enable Playwright MCP and Chromium sidecar for browser automation
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T16:54:52.235Z
Learning: Support --mcp-android flag to enable Android MCP and nested sidecar with Android emulator for mobile automation
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T16:54:52.235Z
Learning: Implement --auto flag for automatic agent execution with intelligent provider selection (Claude, Codex, Gemini, or Grok based on available authorization)
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T16:54:52.235Z
Learning: Auto mode agent should automatically complete tasks, create PRs, and clean up container after completion
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T16:54:52.235Z
Learning: Implement apply command to apply configuration to a single project with optional --no-up flag to skip docker compose up
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T16:54:52.235Z
Learning: Implement apply-all command to apply configuration to all projects with optional --active flag to limit to running containers
📚 Learning: 2026-05-22T21:08:18.083Z
Learnt from: skulidropek
Repo: ProverCoderAI/docker-git PR: 344
File: packages/app/src/docker-git/controller-compose.ts:34-40
Timestamp: 2026-05-22T21:08:18.083Z
Learning: In this repo’s docker-git controller compose generation, `${DOCKER_GIT_CONTROLLER_BUILD_SKILLER:-1}` should be treated as standard bash parameter expansion: when `DOCKER_GIT_CONTROLLER_BUILD_SKILLER` is unset, it defaults to the string "1". There is no "-1" mode. The runtime contract enforced by `packages/app/src/docker-git/controller-compose.ts` is: unset / "1" / "true" => output "1"; "0" / "false" => output "0". If review code shows branching/behavior for "-1" or any numeric value other than this 0/1 contract, flag it. Also ensure the Dockerfile ARG `DOCKER_GIT_CONTROLLER_BUILD_SKILLER` stays consistent with default `1`.
Applied to files:
packages/app/src/docker-git/cli/parser-apply.tspackages/app/src/docker-git/frontend-lib/core/command-options.tspackages/app/src/docker-git/menu-create-steps.tspackages/app/src/docker-git/cli/parser-mcp-android.tspackages/app/src/docker-git/api-client-create.tspackages/app/src/docker-git/cli/usage.tspackages/app/src/docker-git/menu-create-draft.tspackages/app/src/docker-git/menu-create-navigation.tspackages/app/src/docker-git/menu-types.tspackages/app/src/docker-git/cli/parser.tspackages/app/src/docker-git/frontend-lib/core/template-defaults.tspackages/app/src/docker-git/menu-create-inputs.tspackages/app/src/docker-git/cli/parser-options.tspackages/app/src/docker-git/menu-create-step-apply.tspackages/app/src/docker-git/menu-create-command-parse.tspackages/app/src/docker-git/frontend-lib/core/command-builders-template.tspackages/app/src/docker-git/frontend-lib/core/domain.tspackages/app/src/docker-git/program-unsupported.tspackages/app/src/docker-git/frontend-lib/core/command-builders.tspackages/app/src/docker-git/menu-create-labels.ts
📚 Learning: 2026-06-10T10:21:51.286Z
Learnt from: konard
Repo: ProverCoderAI/docker-git PR: 386
File: packages/app/tests/docker-git/gridland-react-singleton.test.ts:0-0
Timestamp: 2026-06-10T10:21:51.286Z
Learning: In `packages/app/tests/docker-git` tests that inspect the `packages/terminal` workspace (e.g., for React-related versions), remember that `react-dom` is intentionally declared as a `devDependency` in `packages/terminal` (the terminal exports components but does not render to the DOM itself). Therefore, test assertions should not require `react-dom` to appear in `dependencies`; when resolving versions, accept either `dependencies` or `devDependencies` (as `resolveDepVersion` does in `gridland-react-singleton.test.ts`).
Applied to files:
packages/app/tests/docker-git/app-ready-create.test.tspackages/app/tests/docker-git/api-create-project.test.tspackages/app/tests/docker-git/actions-project-create.test.tspackages/app/tests/docker-git/app-ready-create-settings.test.tspackages/app/tests/docker-git/menu-create-display-settings.test.tspackages/app/tests/docker-git/menu-create-shared.test.tspackages/app/tests/docker-git/menu-create-shared-properties.test.ts
📚 Learning: 2026-05-18T07:43:38.131Z
Learnt from: skulidropek
Repo: ProverCoderAI/docker-git PR: 313
File: packages/api/src/services/panel-cloudflare-tunnel.ts:123-135
Timestamp: 2026-05-18T07:43:38.131Z
Learning: In this repo’s ProverCoderAI/docker-git architecture, it is intentional for service modules under packages/api/src/services/ to call Node.js APIs directly (e.g., fs, child_process, fetch). Do not treat direct Node API usage in these service modules as a dependency-injection (DI) violation. This codebase provides the NodeContext at the program boundary (entry point) rather than injecting Context.Tag/Layer services into individual service modules; reviewers should only flag DI/context issues if the expected boundary setup is missing.
Applied to files:
packages/api/src/services/projects.ts
🪛 markdownlint-cli2 (0.22.1)
.changeset/mcp-android-integration.md
[warning] 5-5: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
🔇 Additional comments (62)
.changeset/mcp-android-integration.md (1)
1-14: Changeset 格式正確, но markdownlint warning можно игнорировать.Changeset файл следует стандартному формату Changesets tool — YAML frontmatter (строки 1–3) + описание (строки 5–14). Предупреждение MD041 (first-line-heading) — это ложный позитив: Changesets требует именно YAML frontmatter в начале файла, а не markdown heading.
Содержание changeset полное и точное:
- Четко указана версия изменения (minor)
- Описана фича (Android MCP integration per issue
#436)- Перечислены все пути включения (CLI флаги, mcp-android команда, interactive prompt, API)
- Упомянуты ключевые компоненты (docker-android sidecar, KVM, ADB port forwarding, headless mode,
@mobilenext/mobile-mcp)- Указано что интеграция зеркалирует Playwright MCP (feature parity)
README.md (1)
74-74: Описание --mcp-android в README соответствует path instructions и стилю документации.Строка 74 правильно документирует флаг рядом с --mcp-playwright и включает все ключевые элементы:
- Что включается (Android MCP)
- Сервер (
@mobilenext/mobile-mcp)- Инфраструктура (nested sidecar с docker-android)
- Использование (мобильная автоматизация)
Описание соответствует path instructions требованиям и согласуется со стилем соседних bullet points.
packages/app/CHANGELOG.md (1)
3-11: LGTM!packages/app/package.json (1)
3-3: LGTM!packages/docker-git-session-sync/CHANGELOG.md (1)
3-8: LGTM!packages/docker-git-session-sync/package.json (1)
3-3: LGTM!packages/api/src/api/contracts.ts (1)
479-479: LGTM!packages/api/src/api/schema.ts (1)
46-46: LGTM!packages/api/src/services/projects.ts (1)
474-474: LGTM!packages/app/src/web/api-project-create-body.ts (1)
44-57: LGTM!Also applies to: 95-101
packages/app/src/web/api-types.ts (1)
72-72: LGTM!packages/openapi/openapi.json (1)
1084-1086: LGTM!packages/openapi/src/openapi-paths.ts (1)
1191-1191: LGTM!packages/app/src/docker-git/frontend-lib/core/domain.ts (1)
117-117: LGTM!Also applies to: 208-213, 229-229, 273-273
packages/app/src/docker-git/frontend-lib/core/template-defaults.ts (1)
33-33: LGTM!Also applies to: 79-79
packages/lib/src/core/domain.ts (1)
147-152: LGTM!Also applies to: 168-168, 211-211
packages/container/src/core/domain.ts (1)
77-77: LGTM!packages/container/src/core/template-defaults.ts (1)
32-32: LGTM!Also applies to: 78-78
packages/lib/src/shell/config.ts (1)
88-90: LGTM!packages/app/src/docker-git/cli/parser-mcp-android.ts (1)
1-25: LGTM!packages/lib/src/shell/errors.ts (1)
42-43: LGTM!packages/lib/src/usecases/actions/create-project-conflicts.ts (1)
19-19: LGTM!Also applies to: 55-78
packages/app/src/docker-git/cli/parser-options.ts (1)
113-114: LGTM!packages/app/src/docker-git/menu-types.ts (1)
58-58: LGTM!Also applies to: 72-72, 82-82
packages/app/src/docker-git/api-client-create.ts (1)
44-44: LGTM!packages/app/tests/docker-git/actions-project-create.test.ts (1)
29-29: LGTM!packages/app/tests/docker-git/api-create-project.test.ts (1)
11-11: LGTM!Also applies to: 65-65
packages/app/tests/docker-git/app-ready-create-fixture.ts (1)
43-43: LGTM!packages/app/tests/docker-git/app-ready-create-settings.test.ts (1)
127-127: LGTM!Also applies to: 138-138
packages/app/tests/docker-git/app-ready-create.test.ts (1)
58-59: LGTM!packages/app/src/docker-git/cli/parser.ts (1)
10-10: LGTM!Also applies to: 97-97
packages/lib/src/core/command-builders.ts (1)
203-203: LGTM!Also applies to: 212-213, 281-281
packages/app/src/docker-git/menu-create-draft.ts (1)
15-15: LGTM!Also applies to: 27-27
packages/app/src/docker-git/menu-create-inputs.ts (1)
250-250: LGTM!packages/app/src/docker-git/menu-create-labels.ts (1)
26-32: LGTM!Also applies to: 67-72
packages/app/src/docker-git/menu-create-navigation.ts (1)
227-227: LGTM!packages/app/src/docker-git/menu-create-step-apply.ts (1)
44-50: LGTM!Also applies to: 68-68
packages/app/src/docker-git/menu-create-steps.ts (1)
22-22: LGTM!packages/app/src/docker-git/cli/usage.ts (1)
10-10: LGTM!Also applies to: 31-31, 83-83
packages/app/tests/docker-git/menu-create-display-settings.test.ts (1)
37-49: LGTM!Also applies to: 74-74, 96-96, 129-129
packages/app/tests/docker-git/menu-create-shared-properties.test.ts (1)
17-17: LGTM!Also applies to: 26-32, 65-65
packages/app/tests/docker-git/menu-create-shared.test.ts (1)
61-61: LGTM!Also applies to: 91-92, 115-115, 125-125, 310-310
packages/lib/src/usecases/apply-overrides.ts (1)
15-16: LGTM!packages/lib/src/usecases/errors.ts (1)
129-130: LGTM!packages/lib/tests/usecases/mcp-android.test.ts (1)
97-135: LGTM!packages/app/src/docker-git/cli/parser-apply.ts (1)
43-44: LGTM!packages/app/src/docker-git/program-unsupported.ts (1)
7-7: LGTM!Also applies to: 26-29
packages/app/src/docker-git/menu-create-command-parse.ts (1)
116-116: LGTM!Also applies to: 168-170, 190-190
packages/app/src/docker-git/frontend-lib/core/command-options.ts (1)
37-37: LGTM!packages/app/src/docker-git/frontend-lib/core/command-builders-template.ts (1)
23-23: LGTM!Also applies to: 100-100
packages/app/src/docker-git/frontend-lib/core/command-builders.ts (1)
204-204: LGTM!Also applies to: 213-214, 282-282
packages/lib/src/core/command-options.ts (1)
36-36: LGTM!packages/lib/src/core/command-builders-template.ts (1)
22-22: LGTM!Also applies to: 99-99
packages/container/src/core/templates/docker-compose-android.ts (1)
20-65: LGTM!packages/container/src/core/templates/docker-compose-playwright.ts (1)
29-61: LGTM!packages/container/src/core/templates/docker-compose.ts (1)
10-11: LGTM!Also applies to: 28-30, 179-196, 230-230, 247-247, 261-299
packages/container/src/core/templates/dockerfile.ts (1)
94-109: LGTM!Also applies to: 261-261
packages/container/src/core/templates-entrypoint/grok.ts (1)
2-2: LGTM!Also applies to: 348-348
packages/container/src/core/templates-entrypoint.ts (1)
20-20: LGTM!Also applies to: 64-64
packages/container/src/core/templates-entrypoint/base.ts (1)
44-44: LGTM!packages/container/src/core/templates-entrypoint/gemini-playwright-mcp.ts (1)
1-43: LGTM!packages/container/src/core/templates-entrypoint/gemini.ts (1)
2-3: LGTM!Also applies to: 303-303
| it("renders the Android emulator sidecar service when Android MCP is enabled", () => { | ||
| const compose = renderDockerCompose( | ||
| makeTemplateConfig({ | ||
| enableMcpAndroid: true, | ||
| gpu: "none", | ||
| }), | ||
| { | ||
| cpuLimit: 1.5, | ||
| ramLimit: "2g", | ||
| swapLimit: "4g" | ||
| } | ||
| ) | ||
|
|
||
| expect(compose).toContain('MCP_ANDROID_ENABLE: "1"') | ||
| expect(compose).toContain('DOCKER_GIT_ANDROID_CONTAINER_NAME: "dg-test-android"') | ||
| expect(compose).toContain( | ||
| 'DOCKER_GIT_ANDROID_ADB_ENDPOINT: "${DOCKER_GIT_ANDROID_ADB_ENDPOINT:-dg-test-android:5555}"' | ||
| ) | ||
| expect(compose).toContain( | ||
| 'DOCKER_GIT_ANDROID_EMULATOR_IMAGE: "${DOCKER_GIT_ANDROID_EMULATOR_IMAGE:-budtmo/docker-android:emulator_14.0}"' | ||
| ) | ||
| // emulator runs as a real compose service (unlike the externally-managed browser container) | ||
| expect(compose).toContain("\n dg-test-android:\n") | ||
| expect(compose).toContain(" - /dev/kvm") | ||
| expect(compose).toContain( | ||
| '- "${DOCKER_GIT_ANDROID_ADB_BIND_HOST:-127.0.0.1}:${DOCKER_GIT_ANDROID_ADB_PORT:-5555}:5555"' | ||
| ) | ||
| expect(compose).toContain(" dg-test-home-android:") | ||
| // the sidecar reuses the Playwright sidecar resource budget | ||
| expect(compose).toContain(" cpus: 1.5\n") | ||
| }) | ||
|
|
||
| it("omits all Android emulator wiring when Android MCP is disabled", () => { | ||
| const compose = renderDockerCompose(makeTemplateConfig({ enableMcpAndroid: false })) | ||
|
|
||
| expect(compose).not.toContain("MCP_ANDROID_ENABLE") | ||
| expect(compose).not.toContain("\n dg-test-android:\n") | ||
| expect(compose).not.toContain("dg-test-home-android:") | ||
| expect(compose).not.toContain("/dev/kvm") | ||
| }) | ||
|
|
||
| it("installs the ADB client in the Dockerfile only when Android MCP is enabled", () => { | ||
| const enabled = renderDockerfile(makeTemplateConfig({ enableMcpAndroid: true })) | ||
| const disabled = renderDockerfile(makeTemplateConfig({ enableMcpAndroid: false })) | ||
|
|
||
| expect(enabled).toContain("android-tools-adb") | ||
| expect(enabled).toContain("adb --version") | ||
| expect(disabled).not.toContain("android-tools-adb") | ||
| }) | ||
|
|
||
| it("configures the Android MCP server for every agent and defaults the enable flag", () => { | ||
| const entrypoint = renderEntrypoint(makeTemplateConfig({ enableMcpAndroid: true })) | ||
|
|
||
| expect(entrypoint).toContain('MCP_ANDROID_ENABLE="${MCP_ANDROID_ENABLE:-1}"') | ||
| // Codex (TOML) | ||
| expect(entrypoint).toContain("[mcp_servers.android]") | ||
| expect(entrypoint).toContain("@mobilenext/mobile-mcp@latest") | ||
| // Claude / Gemini / Grok (JSON sync helpers) | ||
| expect(entrypoint).toContain("docker_git_sync_claude_android_mcp") | ||
| expect(entrypoint).toContain("docker_git_sync_gemini_android_mcp") | ||
| expect(entrypoint).toContain("docker_git_sync_grok_android_mcp") | ||
| }) | ||
|
|
||
| it("defaults MCP_ANDROID_ENABLE to 0 when Android MCP is disabled", () => { | ||
| const entrypoint = renderEntrypoint(makeTemplateConfig({ enableMcpAndroid: false })) | ||
|
|
||
| expect(entrypoint).toContain('MCP_ANDROID_ENABLE="${MCP_ANDROID_ENABLE:-0}"') | ||
| }) | ||
|
|
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify current test style in the changed block
sed -n '1133,1201p' packages/container/tests/core/templates.test.ts
rg -n 'fc\.property|it\.effect|Effect\.' packages/container/tests/core/templates.test.tsRepository: ProverCoderAI/docker-git
Length of output: 4458
🏁 Script executed:
# Проверим контекст: есть ли другие тесты для этих функций и как они оформлены
rg -B 3 -A 10 'renderDockerCompose|renderDockerfile|renderEntrypoint' packages/container/tests/core/templates.test.ts | head -150Repository: ProverCoderAI/docker-git
Length of output: 7122
🏁 Script executed:
# Проверим, есть ли в файле пример property-based теста для похожей функциональности
rg -B 5 -A 15 'fc.property.*generatedTemplateConfigArbitrary.*renderDocker' packages/container/tests/core/templates.test.ts | head -80Repository: ProverCoderAI/docker-git
Length of output: 162
🏁 Script executed:
# Посмотрим весь контекст вокруг новых тестов - что было до строки 1133
sed -n '1100,1140p' packages/container/tests/core/templates.test.tsRepository: ProverCoderAI/docker-git
Length of output: 1688
🏁 Script executed:
# Посмотрим весь структуру describe блоков и какие тесты используют fc.property для renderDockerCompose
rg -n 'describe.*render|it\(' packages/container/tests/core/templates.test.ts | grep -A 5 -B 5 'renderDockerCompose'Repository: ProverCoderAI/docker-git
Length of output: 1107
🏁 Script executed:
# Посмотрим весь describe блок renderDockerCompose от строки 930 до конца блока (примерно до 1200+)
sed -n '930,1210p' packages/container/tests/core/templates.test.ts | head -200Repository: ProverCoderAI/docker-git
Length of output: 9771
🏁 Script executed:
# Поищем есть ли property-based тесты (fc.property) для renderDockerCompose, renderDockerfile, renderEntrypoint
rg -n 'fc\.property' packages/container/tests/core/templates.test.ts | head -20Repository: ProverCoderAI/docker-git
Length of output: 465
🏁 Script executed:
# Посмотрим контекст fc.property тестов в describe("renderDockerfile")
sed -n '450,510p' packages/container/tests/core/templates.test.tsRepository: ProverCoderAI/docker-git
Length of output: 3218
🏁 Script executed:
# Проверим используется ли it.effect в describe("renderDockerCompose")
sed -n '930,1250p' packages/container/tests/core/templates.test.ts | grep -n 'it\.\|describe'Repository: ProverCoderAI/docker-git
Length of output: 204
🏁 Script executed:
# Проверим полный список describe блоков и какие используют fc.property
rg -n 'describe\(' packages/container/tests/core/templates.test.ts | head -20Repository: ProverCoderAI/docker-git
Length of output: 613
🏁 Script executed:
# Посмотрим конец describe("renderDockerCompose") - это последний блок в файле?
tail -100 packages/container/tests/core/templates.test.tsRepository: ProverCoderAI/docker-git
Length of output: 4271
🏁 Script executed:
# Посмотрим генератор generatedTemplateConfigArbitrary - что он генерирует
rg -B 5 -A 20 'generatedTemplateConfigArbitrary' packages/container/tests/core/templates.test.ts | head -80Repository: ProverCoderAI/docker-git
Length of output: 3326
Переписать новые тесты на основе property-based паттерна fc.property().
В этом файле уже используется fc.property(generatedTemplateConfigArbitrary, ...) для тестирования renderDockerfile (строка 120) и renderEntrypoint (строка 490). Новые тесты для Android MCP нарушают этот установленный паттерн, используя простые it() + expect() вместо property-based проверок.
Функции renderDockerCompose, renderDockerfile, renderEntrypoint — чистые, детерминированные функции, идеальные для property-based тестирования. Инварианты легко формализуются:
∀config: enableMcpAndroid(config)=true → contains(compose, MCP_ANDROID_ENABLE)∀config: enableMcpAndroid(config)=false → ¬contains(compose, MCP_ANDROID_ENABLE)
Переписать 5 новых тестов (строки 1133–1201) через fc.property(generatedTemplateConfigArbitrary.chain(...), ...), добавив enableMcpAndroid в генератор либо использовав .map() для создания вариаций с enableMcpAndroid: true и enableMcpAndroid: false.
🤖 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/container/tests/core/templates.test.ts` around lines 1133 - 1201,
The five new Android MCP tests (starting with "renders the Android emulator
sidecar service when Android MCP is enabled" through "defaults
MCP_ANDROID_ENABLE to 0 when Android MCP is disabled") use simple example-based
testing with hardcoded `it()` blocks and `expect()` statements, which violates
the established property-based testing pattern used elsewhere in this file.
Refactor these tests to use
`fc.property(generatedTemplateConfigArbitrary.chain(...), ...)` or `.map()` to
generate test cases with `enableMcpAndroid` set to both true and false,
following the same pattern already established for testing `renderDockerfile`
and `renderEntrypoint`. Convert the hardcoded assertions into parameterized
property-based checks where the invariants (like presence/absence of MCP
environment variables and service configurations based on the `enableMcpAndroid`
flag) are verified across generated configurations.
Source: Coding guidelines
| ) | ||
| expect(compose).toContain(" dg-test-home-android:") | ||
| // the sidecar reuses the Playwright sidecar resource budget | ||
| expect(compose).toContain(" cpus: 1.5\n") |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Проверка CPU лимита на Line 1162 может проходить, даже если лимит не попал в Android sidecar.
toContain(" cpus: 1.5\n") матчится по всему compose и не доказывает, что лимит находится именно внутри dg-test-android.
🎯 Предлагаемое уточнение проверки
- expect(compose).toContain(" cpus: 1.5\n")
+ expect(compose).toMatch(/dg-test-android:[\s\S]*\n\s+cpus: 1\.5\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/container/tests/core/templates.test.ts` at line 1162, The current
test assertion using toContain(" cpus: 1.5\n") checks if the CPU limit
appears anywhere in the compose output but does not verify that the limit is
specifically applied to the dg-test-android Android sidecar service. Refactor
the expect statement to first locate the dg-test-android service configuration
block within the compose output and then verify that the cpus: 1.5 limit exists
only within that specific service section, ensuring the assertion proves the
limit is correctly placed in the Android sidecar rather than elsewhere in the
configuration.
✅ Ready to mergeThis pull request is now ready to be merged:
Monitored by hive-mind with --auto-restart-until-mergeable flag |
This reverts commit 1113f27.
|
Сперва нужно отдельно реализовать сам модуль и доказать что он работает |
|
🤖 AI Work Session Started Starting automated work session at 2026-06-23T19:25:21.617Z The PR has been converted to draft mode while work is in progress. This comment marks the beginning of an AI work session. Please wait for the session to finish, and provide your feedback. |
Working session summaryImplemented and pushed commit PR updated and marked ready: #437 What changed:
Verification:
This summary was automatically extracted from the AI working session output. |
🤖 Solution Draft LogThis log file contains the complete execution trace of the AI solution draft process. 💰 Cost estimation:
📊 Context and tokens usage:
Total: (890.9K + 11.3M cached) input tokens, 64.5K output tokens, $23.139343 cost 🤖 Models used:
📎 Log file uploaded as Repository (96268KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
There was a problem hiding this comment.
Actionable comments posted: 11
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
.changeset/mcp-android-integration.md (1)
5-14: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winДобавьте математические инварианты и гарантии в changeset документацию.
В соответствии с path instruction для
*.md, изменения должны быть документированы с формальными доказательствами: инвариантами, предусловиями, постусловиями и анализом сложности. Текущее описание не включает этой информации.Рекомендуемая структура:
- Инварианты: какие свойства гарантируются после включения (например:
∀ project: enabled(project) → docker-android_service_gated(project))- Предусловия: когда можно включить (например, наличие Docker daemon)
- Постусловия: что будет после (например, образы загружены, ADB порт открыт)
- Сложность: время и память для операции
🤖 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 @.changeset/mcp-android-integration.md around lines 5 - 14, The changeset documentation for mcp-android-integration.md lacks formal mathematical specifications required by the path instruction for markdown files. Add sections documenting the formal properties of the Android MCP integration feature: include invariants describing guaranteed properties after enabling (such as the relationship between enabled projects and gated docker-android services), preconditions for when the feature can be enabled (such as Docker daemon availability), postconditions describing the resulting state (such as loaded images and open ADB ports), and complexity analysis documenting the time and memory costs of the operation.Source: Path instructions
crates/android-connection/README.md (1)
1-11: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winДобавьте в README формальные proof-обязательства для этого изменения.
Сейчас описание ограничено назначением бинарей; отсутствуют инварианты, предусловия, постусловия, вариантная функция и оценка сложности, а также краткий Proof of fix для bug-fix части.
Предлагаемый минимальный шаблон
## Mathematical guarantees ### Invariants - ... ### Preconditions - ... ### Postconditions - ... ### Variant function (if applicable) - ... ### Complexity - Time: ... - Space: ... ## Proof of fix - Причина: ... - Решение: ... - Доказательство: ...As per coding guidelines, "
*.md: Document all PR changes with mathematical proof obligations: invariants, preconditions, postconditions, variant functions, and complexity analysis in Markdown format".🤖 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 `@crates/android-connection/README.md` around lines 1 - 11, The README.md file is missing formal proof-obligation documentation required by the coding guidelines. Add a new "Mathematical guarantees" section after the current content that documents the invariants, preconditions, postconditions, variant functions (if applicable), and complexity analysis (both time and space) for the android-connection and docker-git-android-connection binaries. Additionally, include a "Proof of fix" section that explains the reason for changes, the solution provided, and proof of correctness. This formal documentation ensures that the mathematical properties and behavioral guarantees of these MCP modules are explicitly captured and verifiable.Source: Coding guidelines
🤖 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 @.changeset/mcp-android-integration.md:
- Around line 7-8: The changeset text mentions "first-party Rust
`android-connection` MCP server" but does not clarify that this is a newly
introduced component. Update the changeset text to explicitly indicate that
`android-connection` is a new Rust crate being added in this PR. You can add a
parenthetical clarification such as "new Rust crate `android-connection`" or
include the location context (e.g., `crates/android-connection`) to make it
clear this is not an existing component and is being introduced for the first
time.
In `@crates/android-connection/src/lib.rs`:
- Around line 95-105: The is_safe_adb_endpoint function currently allows invalid
endpoint formats like ":", "host:", and "host:abc". Refactor the validation to
enforce strict host:port format by splitting the input string on the colon
character, ensuring exactly two parts exist, verifying both the host and port
parts are non-empty, validating that the port part contains only digits, and
checking that the numeric port value falls within the valid port range of 1 to
65535.
In `@crates/android-connection/src/mcp.rs`:
- Around line 533-547: The workspace_path function currently only validates
against absolute paths and parent directory traversal (..) but does not prevent
symlink-based path traversal attacks. To fix this, after validating the initial
path conditions, iterate through each component of the candidate path and use
symlink_metadata to check if any intermediate component is a symlink, rejecting
the path if symlinks are detected. This ensures that even if the path appears
valid, it cannot escape the workspace through symbolic links. Additionally, add
a regression test that attempts to use a path containing a symlink component
(which should fail before the fix and pass after implementation).
- Around line 68-91: The read_next_message function incorrectly assumes
Content-Length is always the first header and treats any other first non-empty
header as the JSON payload, making the parser fragile to header order
variations. Refactor the function to read all headers in a loop until an empty
line is encountered, extract the Content-Length value from any header line that
contains it (regardless of order), then only after collecting all headers and
obtaining the length value, read the payload. This requires separating the
header parsing logic from the payload reading logic so headers can be processed
in any order.
In `@packages/app/src/docker-git/menu-create-labels.ts`:
- Around line 26-29: For consistency with the technical terminology used in
usage.ts (which references "android-connection"), update the prompt label in the
Match.when case for "mcpAndroid" to include the server identifier alongside the
user-friendly description. Specifically, modify the string template to include
"(android-connection)" in addition to "(nested Android emulator)" to align the
wizard terminology with the technical details referenced in usage.ts at line 31,
ensuring consistent naming across the codebase.
In `@packages/container/src/core/templates-entrypoint/codex.ts`:
- Around line 209-215: The Android MCP server configuration block in the
codex.ts file is vulnerable to command injection because environment variables
are inserted directly into the TOML configuration without proper escaping. The
values for DOCKER_GIT_ANDROID_ADB_ENDPOINT, TARGET_DIR, and other arguments in
the args array need to be properly escaped or serialized according to TOML
specifications before being written to CODEX_CONFIG_FILE. Implement proper
escaping for all environment variables being inserted into the args array and
other configuration fields in the [mcp_servers.android] section to prevent
special characters like quotes and newlines from breaking the TOML syntax or
injecting arbitrary configurations.
In `@packages/lib/src/shell/android-connection-source.ts`:
- Around line 21-75: The shouldSkipAndroidConnectionEntry function uses a
blocklist approach that only excludes "target" and ".git", which is too
permissive and risks exposing sensitive files like credentials or local
artifacts. Replace the blocklist logic with an allowlist approach that only
permits necessary files (such as Cargo.toml, Cargo.lock, src directory, and
README.md) to be copied into the build context. Modify the
shouldSkipAndroidConnectionEntry function to return true (skip) for anything not
explicitly allowed, and also reject hidden files (starting with dot) and
symlinks to prevent accidental inclusion of sensitive local artifacts.
- Line 125: The function in android-connection-source.ts is calling
process.cwd() directly in the resolveWorkspaceRoot invocation, which violates
the guideline that process operations must be abstracted through Layer-based
services. Refactor the function to accept a cwd parameter of type string in its
signature, then pass that cwd parameter to resolveWorkspaceRoot(cwd) instead of
calling process.cwd() directly. This approach aligns with the pattern already
established in related files and improves testability.
In `@packages/lib/src/shell/files.ts`:
- Line 285: The provisionDockerGitBuildContext call should be executed earlier
in the process before any template or spec files are written, to implement
fail-fast behavior. Move the yield* _(provisionDockerGitBuildContext(fs, path,
baseDir, normalizedConfig)) statement to the beginning of the generator
function, before any other yield statements that write files or specs, ensuring
that if the Docker Git build context provisioning fails (e.g., due to
unavailable Android source), the failure occurs before the project reaches an
inconsistent state from partial file generation.
In `@packages/lib/src/usecases/mcp-android.ts`:
- Around line 88-89: Add a regression test for the mcpAndroidUp function in
mcp-android.test.ts that validates the projectDir fix by setting up a test
scenario where command.projectDir differs from process.cwd(). The test should
mock the CommandExecutor to verify that both ensureDockerDaemonAccess (which
calls docker info) and runDockerComposeUpWithPortCheck (which calls docker
compose up) are invoked with the correct working directory from
command.projectDir rather than the current process working directory. This
ensures the fix on line 88 using command.projectDir is properly tested and
prevents regression in future refactorings.
In `@README.md`:
- Line 74: The documentation line describing the --mcp-android flag contains
excessive implementation details (mentioning first-party designation, specific
component names like android-connection and docker-android) compared to the
--mcp-playwright line above it, breaking parallel structure. Simplify the
--mcp-android description by removing the implementation-specific terminology
and details to match the conciseness of the --mcp-playwright description,
keeping only the essential information about what capabilities are enabled for
mobile automation.
---
Outside diff comments:
In @.changeset/mcp-android-integration.md:
- Around line 5-14: The changeset documentation for mcp-android-integration.md
lacks formal mathematical specifications required by the path instruction for
markdown files. Add sections documenting the formal properties of the Android
MCP integration feature: include invariants describing guaranteed properties
after enabling (such as the relationship between enabled projects and gated
docker-android services), preconditions for when the feature can be enabled
(such as Docker daemon availability), postconditions describing the resulting
state (such as loaded images and open ADB ports), and complexity analysis
documenting the time and memory costs of the operation.
In `@crates/android-connection/README.md`:
- Around line 1-11: The README.md file is missing formal proof-obligation
documentation required by the coding guidelines. Add a new "Mathematical
guarantees" section after the current content that documents the invariants,
preconditions, postconditions, variant functions (if applicable), and complexity
analysis (both time and space) for the android-connection and
docker-git-android-connection binaries. Additionally, include a "Proof of fix"
section that explains the reason for changes, the solution provided, and proof
of correctness. This formal documentation ensures that the mathematical
properties and behavioral guarantees of these MCP modules are explicitly
captured and verifiable.
🪄 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: a2f78c73-beb4-4e03-977a-c83d72b3c9c3
⛔ Files ignored due to path filters (1)
crates/android-connection/Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (24)
.changeset/mcp-android-integration.md.github/workflows/check.ymlREADME.mdcrates/android-connection/.gitignorecrates/android-connection/Cargo.tomlcrates/android-connection/README.mdcrates/android-connection/src/bin/android-connection.rscrates/android-connection/src/lib.rscrates/android-connection/src/main.rscrates/android-connection/src/mcp.rspackages/app/src/docker-git/cli/usage.tspackages/app/src/docker-git/menu-create-labels.tspackages/container/src/core/templates-entrypoint/claude.tspackages/container/src/core/templates-entrypoint/codex.tspackages/container/src/core/templates-entrypoint/gemini-android-mcp.tspackages/container/src/core/templates-entrypoint/grok-android-mcp.tspackages/container/src/core/templates/docker-compose-android.tspackages/container/src/core/templates/dockerfile.tspackages/container/tests/core/templates.test.tspackages/lib/src/shell/android-connection-source.tspackages/lib/src/shell/files.tspackages/lib/src/usecases/mcp-android.tspackages/lib/tests/usecases/apply.test.tspackages/lib/tests/usecases/mcp-android.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (9)
- GitHub Check: Final build (windows-latest)
- GitHub Check: Test
- GitHub Check: E2E (Clone auto-open SSH)
- GitHub Check: E2E (OpenCode)
- GitHub Check: E2E (Login context)
- GitHub Check: E2E (Runtime volumes + SSH)
- GitHub Check: E2E (Clone cache)
- GitHub Check: E2E (Browser command)
- GitHub Check: Lint
🧰 Additional context used
📓 Path-based instructions (10)
**
⚙️ CodeRabbit configuration file
**: РОЛЬ: Математик-программист, специализирующийся на формально верифицируемой функциональной архитектуре.ЦЕЛЬ: Создавать математически доказуемые решения через функциональную парадигму с полным разделением чистых вычислений и контролируемых эффектов.
МОДЕЛЬ РАССУЖДЕНИЯ:
- Не выдавать “личные мнения”. Формировать вывод как результат симуляции профессионального обсуждения релевантных ролей
(архитектор Effect/FP, ревьюер типов, страж CORE↔SHELL, тест-инженер).- Если запрос сформулирован как “что думаешь”, отвечать в терминах аргументов ролей и выбирать решение
по критериям инвариантов, типовой безопасности и тестируемости (если пользователь явно просит выбор — выбрать и обосновать).ПРАВИЛО ПРОЦЕССА (НЕ ФОРМАТ ОТВЕТА):
В начале работы (внутренне) формулировать Deep Research вопрос:
"I am looking for code that does , is there existing code that can do this?"
Далее:
- если доступен проект/код — сперва искать и переиспользовать существующие паттерны (минимальный корректный diff),
- если проект недоступен — опираться на предоставленный контекст и явно фиксировать допущения,
- код писать только после формального понимания задачи (типы/инварианты → архитектура → код → тесты),
- источники указывать только если реально использован внешний материал; иначе
SOURCE: n/a.ИНСТРУМЕНТАЛЬНОЕ ПОВЕДЕНИЕ (ОБЯЗАТЕЛЬНО, НЕ ФОРМАТ ОТВЕТА):
- Агент всегда использует доступные инструменты среды (терминал, поиск по проекту, запуск тестов/скриптов, анализ сборки, web-ресёрч при необходимости)
для ресёрча, проверки гипотез и выполнения действий. Приоритет: проверяемость, воспроизводимость, минимальный риск.- Агент не предлагает “гайд” как замену действия. Если действие возможно выполнить инструментами — агент выполняет его сам,
затем сообщает, что было сделано и как повторить.- Любые инструкции (команды/процедуры) агент даёт только после собственной проверки на доступной среде.
Если проверить невозможно — явно фиксирует ограничение и перечисляе...
Files:
crates/android-connection/README.mdcrates/android-connection/Cargo.tomlcrates/android-connection/src/bin/android-connection.rspackages/lib/tests/usecases/mcp-android.test.tsREADME.mdpackages/lib/src/shell/files.tspackages/container/src/core/templates/dockerfile.tspackages/app/src/docker-git/menu-create-labels.tspackages/container/src/core/templates/docker-compose-android.tspackages/container/src/core/templates-entrypoint/claude.tspackages/container/src/core/templates-entrypoint/grok-android-mcp.tscrates/android-connection/src/main.rspackages/app/src/docker-git/cli/usage.tspackages/container/src/core/templates-entrypoint/codex.tspackages/lib/src/shell/android-connection-source.tspackages/lib/src/usecases/mcp-android.tspackages/container/tests/core/templates.test.tscrates/android-connection/src/lib.rspackages/lib/tests/usecases/apply.test.tspackages/container/src/core/templates-entrypoint/gemini-android-mcp.tscrates/android-connection/src/mcp.rs
**/*
⚙️ CodeRabbit configuration file
**/*: Ты строгий ревьюер SPEC DRIVEN DEVELOPMENT.Перед выводами изучи README.md, другие *.md файлы, linked issues,
PR description, PR comments/discussion и релевантную кодовую базу.Сверь изменения с исходным ТЗ/спекой и обсуждением. Флагай любой уход
от спеки, недокументированное изменение поведения, отсутствие тестов
для заявленного поведения и security-риск. Если спека не видна,
попроси автора добавить ее в issue или PR description.Проверь решение с точки зрения формальной верификации: какие инварианты,
предусловия и постусловия можно доказать математически, а где доказуемость
слабая. Оцени решение с точки зрения теории игр: устойчивы ли стимулы,
нет ли выгодного обхода правил, и какое решение было бы сильнее.
Files:
crates/android-connection/README.mdcrates/android-connection/Cargo.tomlcrates/android-connection/src/bin/android-connection.rspackages/lib/tests/usecases/mcp-android.test.tsREADME.mdpackages/lib/src/shell/files.tspackages/container/src/core/templates/dockerfile.tspackages/app/src/docker-git/menu-create-labels.tspackages/container/src/core/templates/docker-compose-android.tspackages/container/src/core/templates-entrypoint/claude.tspackages/container/src/core/templates-entrypoint/grok-android-mcp.tscrates/android-connection/src/main.rspackages/app/src/docker-git/cli/usage.tspackages/container/src/core/templates-entrypoint/codex.tspackages/lib/src/shell/android-connection-source.tspackages/lib/src/usecases/mcp-android.tspackages/container/tests/core/templates.test.tscrates/android-connection/src/lib.rspackages/lib/tests/usecases/apply.test.tspackages/container/src/core/templates-entrypoint/gemini-android-mcp.tscrates/android-connection/src/mcp.rs
**/*.{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:
crates/android-connection/Cargo.tomlpackages/lib/tests/usecases/mcp-android.test.tspackages/lib/src/shell/files.tspackages/container/src/core/templates/dockerfile.tspackages/app/src/docker-git/menu-create-labels.tspackages/container/src/core/templates/docker-compose-android.tspackages/container/src/core/templates-entrypoint/claude.tspackages/container/src/core/templates-entrypoint/grok-android-mcp.tspackages/app/src/docker-git/cli/usage.tspackages/container/src/core/templates-entrypoint/codex.tspackages/lib/src/shell/android-connection-source.tspackages/lib/src/usecases/mcp-android.tspackages/container/tests/core/templates.test.tspackages/lib/tests/usecases/apply.test.tspackages/container/src/core/templates-entrypoint/gemini-android-mcp.ts
**/{package*.json,requirements*.txt,setup.py,setup.cfg,Pipfile,Pipfile.lock,pyproject.toml,pom.xml,build.gradle,Gemfile,Gemfile.lock,go.mod,go.sum,composer.json,Cargo.toml,Cargo.lock}
📄 CodeRabbit inference engine (Custom checks)
Fail if dependency or package-manager changes materially increase supply-chain risk without justification
Files:
crates/android-connection/Cargo.toml
**/*.{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/tests/usecases/mcp-android.test.tspackages/lib/src/shell/files.tspackages/container/src/core/templates/dockerfile.tspackages/app/src/docker-git/menu-create-labels.tspackages/container/src/core/templates/docker-compose-android.tspackages/container/src/core/templates-entrypoint/claude.tspackages/container/src/core/templates-entrypoint/grok-android-mcp.tspackages/app/src/docker-git/cli/usage.tspackages/container/src/core/templates-entrypoint/codex.tspackages/lib/src/shell/android-connection-source.tspackages/lib/src/usecases/mcp-android.tspackages/container/tests/core/templates.test.tspackages/lib/tests/usecases/apply.test.tspackages/container/src/core/templates-entrypoint/gemini-android-mcp.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/tests/usecases/mcp-android.test.tspackages/lib/src/shell/files.tspackages/container/src/core/templates/dockerfile.tspackages/app/src/docker-git/menu-create-labels.tspackages/container/src/core/templates/docker-compose-android.tspackages/container/src/core/templates-entrypoint/claude.tspackages/container/src/core/templates-entrypoint/grok-android-mcp.tspackages/app/src/docker-git/cli/usage.tspackages/container/src/core/templates-entrypoint/codex.tspackages/lib/src/shell/android-connection-source.tspackages/lib/src/usecases/mcp-android.tspackages/container/tests/core/templates.test.tspackages/lib/tests/usecases/apply.test.tspackages/container/src/core/templates-entrypoint/gemini-android-mcp.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: FUNCTIONAL CORE: Write only pure functions with immutable data and mathematical operations in core modules; no side effects, mutations, or external service calls
IMPERATIVE SHELL: Isolate all side effects (IO, network, database, environment/process) in a thin SHELL layer; CORE never calls SHELL, only SHELL → CORE
Never useanytype annotation in TypeScript; useunknownonly at SHELL boundaries for decoding, never exportunknownoutside boundary modules
Never useastype assertions in normal code; only permitasin a single 'axiomatic' module (brands, constructors, constants) after which types flow safely without casts
Always use exhaustive pattern matching for union types through.exhaustive()orMatch.exhaustive()from effect-ts; never use switch statements or unhandled type branches
Use Effect<Success, Error, Requirements> monad from effect-ts for all effects; compose through pipe() and Effect.flatMap(); never use async/await, raw Promise chains (then/catch), or Promise.all in product code
Interoperate with Promise/exceptions only in SHELL through Effect.try/Effect.tryPromise with typed error mapping; never leave raw exceptions or untyped errors in the domain
Use Effect.acquireRelease + Effect.scoped for resource management with guaranteed finalization; never manage resources with try/finally or manual cleanup
All external services (database, HTTP, environment) must be accessed through Effect-based interfaces and Layer-based dependency injection; never call external APIs directly
Provide comprehensive TSDoc comments with mathematical notation:@pure,@effect,@invariant,@precondition,@postcondition,@complexity,@throws, and CHANGE/WHY/REF/SOURCE/FORMAT THEOREM functional comment markers
No console.*, process direct calls, or untyped environment access in product code; all such operations must be abstracted through Layer-based services in SHELL
Boundary data from external sources (HTTP, database, environment) must be decoded/valida...
Files:
packages/lib/tests/usecases/mcp-android.test.tspackages/lib/src/shell/files.tspackages/container/src/core/templates/dockerfile.tspackages/app/src/docker-git/menu-create-labels.tspackages/container/src/core/templates/docker-compose-android.tspackages/container/src/core/templates-entrypoint/claude.tspackages/container/src/core/templates-entrypoint/grok-android-mcp.tspackages/app/src/docker-git/cli/usage.tspackages/container/src/core/templates-entrypoint/codex.tspackages/lib/src/shell/android-connection-source.tspackages/lib/src/usecases/mcp-android.tspackages/container/tests/core/templates.test.tspackages/lib/tests/usecases/apply.test.tspackages/container/src/core/templates-entrypoint/gemini-android-mcp.ts
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.test.{ts,tsx}: Write property-based tests using fast-check (fc.property) to verify mathematical invariants; unit tests must use Effect test utilities without async/await
Every bug fix must be accompanied by a reproducing test case; the test must fail before the fix and pass after; document the Proof of Fix with root cause and solution
Files:
packages/lib/tests/usecases/mcp-android.test.tspackages/container/tests/core/templates.test.tspackages/lib/tests/usecases/apply.test.ts
*.md
📄 CodeRabbit inference engine (AGENTS.md)
Document all PR changes with mathematical proof obligations: invariants, preconditions, postconditions, variant functions, and complexity analysis in Markdown format
Files:
README.md
**/.github/workflows/*.{yml,yaml}
📄 CodeRabbit inference engine (Custom checks)
Fail if changed files introduce unsafe GitHub Actions configuration such as unsafe
pull_request_target, or unnecessary write permissions
Files:
.github/workflows/check.yml
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T20:02:08.980Z
Learning: Project structure: APP (CLI + React Frontend) should only work with API and not have direct access to LIB
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T20:02:08.980Z
Learning: Project structure: API should only work with LIB and serve as the backend layer for APP
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T20:02:08.980Z
Learning: LIB module contains all backend logic and core business logic for the docker-git project
Learnt from: CR
Repo: ProverCoderAI/docker-git
Timestamp: 2026-06-23T20:02:08.980Z
Learning: Follow Spec-Driven Development (SDD) process: from issue to verified PR as documented in docs/process.md
📚 Learning: 2026-05-22T21:08:18.083Z
Learnt from: skulidropek
Repo: ProverCoderAI/docker-git PR: 344
File: packages/app/src/docker-git/controller-compose.ts:34-40
Timestamp: 2026-05-22T21:08:18.083Z
Learning: In this repo’s docker-git controller compose generation, `${DOCKER_GIT_CONTROLLER_BUILD_SKILLER:-1}` should be treated as standard bash parameter expansion: when `DOCKER_GIT_CONTROLLER_BUILD_SKILLER` is unset, it defaults to the string "1". There is no "-1" mode. The runtime contract enforced by `packages/app/src/docker-git/controller-compose.ts` is: unset / "1" / "true" => output "1"; "0" / "false" => output "0". If review code shows branching/behavior for "-1" or any numeric value other than this 0/1 contract, flag it. Also ensure the Dockerfile ARG `DOCKER_GIT_CONTROLLER_BUILD_SKILLER` stays consistent with default `1`.
Applied to files:
packages/app/src/docker-git/menu-create-labels.tspackages/app/src/docker-git/cli/usage.ts
🪛 zizmor (1.26.1)
.github/workflows/check.yml
[warning] 47-47: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 47-47: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🔇 Additional comments (12)
packages/app/src/docker-git/cli/usage.ts (1)
10-10: LGTM!Also applies to: 31-31, 83-83
packages/container/src/core/templates-entrypoint/claude.ts (1)
254-311: LGTM!packages/container/src/core/templates-entrypoint/gemini-android-mcp.ts (1)
6-57: LGTM!packages/container/src/core/templates-entrypoint/grok-android-mcp.ts (1)
6-57: LGTM!packages/lib/tests/usecases/mcp-android.test.ts (1)
124-139: LGTM!packages/lib/tests/usecases/apply.test.ts (1)
230-262: LGTM!crates/android-connection/Cargo.toml (1)
1-24: LGTM!crates/android-connection/.gitignore (1)
1-1: LGTM!crates/android-connection/src/bin/android-connection.rs (1)
21-23: 🔒 Security & PrivacyПроверка пройдена: path traversal-защита уже реализована и протестирована.
Функция
workspace_path(строки 533–547) корректно валидирует все пути перед использованием:
- Отклоняет абсолютные пути (
candidate.is_absolute())- Отклоняет пути с компонентом
..(Component::ParentDir)- Безопасно присоединяет к workspace через
workspace.join()Обе операции, требующие файловых операций (
android_screenshotиandroid_install_apk), маршрутизируют входные пути черезworkspace_pathпередfs::create_dir_allиfs::write. Тестrejects_workspace_paths_outside_workspaceпокрывает все основные случаи escape-попыток (абсолютные пути,.., вложенные traversal).packages/container/tests/core/templates.test.ts (1)
1175-1208: Дубликат ранее оставленного замечания про формат тестов (property-based + Effect utilities).packages/container/src/core/templates/dockerfile.ts (1)
103-110: 🩺 Stability & AvailabilityПроверка подтверждает наличие Cargo.lock в
crates/android-connection/— флаг--lockedв Line 108 будет работать корректно. При копировании черезcopyTextDirectoryвесь контент crate-а (включая lockfile) переносится в/opt/docker-git/tools/android-connection, обеспечивая детерминированность сборки. Воспроизводимость гарантирована на уровне зависимостей..github/workflows/check.yml (1)
47-47: 🔒 Security & PrivacyКомментарий к проверке неточен согласно указанным рекомендациям кодирования.
Рекомендация по кодированию для этого файла требует отказать, если "изменения вводят небезопасную конфигурацию GitHub Actions, такую как небезопасный
pull_request_targetили ненужные разрешения write".В текущем workflow:
- Используется
pull_request, а неpull_request_target(безопасно)- Глобальные разрешения установлены только на
contents: read(минимальные)Хотя закрепление на SHA и явное
persist-credentials: falseмогут быть рекомендациями лучших практик, они не входят в критерии отказа, указанные в рекомендациях. Текущая конфигурация соответствует требуемым стандартам безопасности.> Likely an incorrect or invalid review comment.
| Projects can now opt into a nested Android emulator sidecar driven by the | ||
| first-party Rust `android-connection` MCP server, mirroring how Playwright MCP works. Enable it |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Уточните упоминание "first-party" и версионирование android-connection.
Строка 8 упоминает "first-party Rust android-connection MCP server", но в changeset не указывается:
- Где находится крейт (например,
crates/android-connection) - Что это — новый компонент в этом PR
Рекомендуется добавить уточнение в скобках: "новый Rust крейт android-connection" или аналогично для ясности, что это не существующий компонент.
🤖 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 @.changeset/mcp-android-integration.md around lines 7 - 8, The changeset text
mentions "first-party Rust `android-connection` MCP server" but does not clarify
that this is a newly introduced component. Update the changeset text to
explicitly indicate that `android-connection` is a new Rust crate being added in
this PR. You can add a parenthetical clarification such as "new Rust crate
`android-connection`" or include the location context (e.g.,
`crates/android-connection`) to make it clear this is not an existing component
and is being introduced for the first time.
| pub fn is_safe_adb_endpoint(value: &str) -> bool { | ||
| !value.is_empty() | ||
| && value.len() <= 255 | ||
| && value.contains(':') | ||
| && value.bytes().all(|byte| { | ||
| matches!( | ||
| byte, | ||
| b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'.' | b'-' | b'_' | b':' | ||
| ) | ||
| }) | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Сделайте валидацию ADB endpoint строгой как host:port.
Текущая проверка пропускает заведомо невалидные значения (например, ":", "host:", "host:abc"), и ошибка всплывает только поздно в runtime при вызове ADB.
Вариант точечного исправления
pub fn is_safe_adb_endpoint(value: &str) -> bool {
- !value.is_empty()
- && value.len() <= 255
- && value.contains(':')
- && value.bytes().all(|byte| {
- matches!(
- byte,
- b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'.' | b'-' | b'_' | b':'
- )
- })
+ if value.is_empty() || value.len() > 255 {
+ return false;
+ }
+ let Some((host, port)) = value.rsplit_once(':') else {
+ return false;
+ };
+ !host.is_empty()
+ && !port.is_empty()
+ && host.bytes().all(|byte| {
+ matches!(byte, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'.' | b'-' | b'_')
+ })
+ && port.bytes().all(|byte| matches!(byte, b'0'..=b'9'))
+ && port.parse::<u16>().is_ok()
}Also applies to: 107-115
🤖 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 `@crates/android-connection/src/lib.rs` around lines 95 - 105, The
is_safe_adb_endpoint function currently allows invalid endpoint formats like
":", "host:", and "host:abc". Refactor the validation to enforce strict
host:port format by splitting the input string on the colon character, ensuring
exactly two parts exist, verifying both the host and port parts are non-empty,
validating that the port part contains only digits, and checking that the
numeric port value falls within the valid port range of 1 to 65535.
| fn read_next_message<R: BufRead>(reader: &mut R) -> io::Result<Option<String>> { | ||
| loop { | ||
| let mut line = String::new(); | ||
| let bytes_read = reader.read_line(&mut line)?; | ||
| if bytes_read == 0 { | ||
| return Ok(None); | ||
| } | ||
|
|
||
| let first_line = line.trim_end_matches(['\r', '\n']); | ||
| if first_line.is_empty() { | ||
| continue; | ||
| } | ||
|
|
||
| if let Some(length) = parse_content_length(first_line)? { | ||
| read_headers(reader)?; | ||
| let mut payload = vec![0_u8; length]; | ||
| reader.read_exact(&mut payload)?; | ||
| return String::from_utf8(payload) | ||
| .map(Some) | ||
| .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error)); | ||
| } | ||
|
|
||
| return Ok(Some(first_line.to_string())); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Парсер framed-stdio принимает только случай, когда Content-Length — первая строка заголовков.
На Line 68-91 при первом непустом заголовке, отличном от Content-Length, код трактует строку как JSON payload и ломает обработку. Это делает сервер хрупким к допустимым вариациям порядка заголовков.
Надёжнее: читать заголовки до пустой строки, извлекать Content-Length независимо от порядка, и только потом читать тело.
🤖 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 `@crates/android-connection/src/mcp.rs` around lines 68 - 91, The
read_next_message function incorrectly assumes Content-Length is always the
first header and treats any other first non-empty header as the JSON payload,
making the parser fragile to header order variations. Refactor the function to
read all headers in a loop until an empty line is encountered, extract the
Content-Length value from any header line that contains it (regardless of
order), then only after collecting all headers and obtaining the length value,
read the payload. This requires separating the header parsing logic from the
payload reading logic so headers can be processed in any order.
| fn workspace_path(workspace: &Path, value: &str) -> Result<PathBuf, McpToolError> { | ||
| let candidate = PathBuf::from(value); | ||
| if value.is_empty() | ||
| || candidate.is_absolute() | ||
| || candidate | ||
| .components() | ||
| .any(|component| component == Component::ParentDir) | ||
| { | ||
| return Err(McpToolError::InvalidArgument( | ||
| "path must be relative, non-empty, and must not contain '..'".to_string(), | ||
| )); | ||
| } | ||
|
|
||
| Ok(workspace.join(candidate)) | ||
| } |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
workspace_path не блокирует обход через symlink-компоненты.
На Line 533-547 фильтруются только абсолютные пути и .., но это не защищает от пути вида screenshots/link/out.png, где link — symlink наружу workspace. Тогда запись на Line 415-419 может уйти за пределы рабочей директории.
Добавьте проверку каждого существующего промежуточного компонента через symlink_metadata и отклоняйте symlink; отдельно нужен регрессионный тест с symlink-кейсом (должен падать до фикса и проходить после).
As per coding guidelines, "Fail if changed files introduce path traversal or writes outside intended project/container state directories."
🤖 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 `@crates/android-connection/src/mcp.rs` around lines 533 - 547, The
workspace_path function currently only validates against absolute paths and
parent directory traversal (..) but does not prevent symlink-based path
traversal attacks. To fix this, after validating the initial path conditions,
iterate through each component of the candidate path and use symlink_metadata to
check if any intermediate component is a symlink, rejecting the path if symlinks
are detected. This ensures that even if the path appears valid, it cannot escape
the workspace through symbolic links. Additionally, add a regression test that
attempts to use a path containing a symlink component (which should fail before
the fix and pass after implementation).
Source: Coding guidelines
| Match.when( | ||
| "mcpAndroid", | ||
| () => `Enable Android MCP (nested Android emulator)? [${renderExplicitBooleanChoice(defaults.enableMcpAndroid)}]` | ||
| ), |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
Функциональная корректность подтверждена.
Логика соответствует паттерну других boolean-шагов wizard (mcpPlaywright). Использование Match.exhaustive и renderExplicitBooleanChoice обеспечивает типовую безопасность и консистентность отображения.
Опциональное улучшение терминологии: В usage.ts строка 31 использует "Android MCP (android-connection)", но в wizard метке (строка 28) упоминается только "Android MCP (nested Android emulator)" без идентификатора сервера. Для полной согласованности с документацией можно рассмотреть упоминание "(android-connection)" и в wizard, либо принять текущий паттерн (где wizard использует более краткие пользовательские формулировки, а usage.ts — технические детали).
Also applies to: 64-69
🤖 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-create-labels.ts` around lines 26 - 29, For
consistency with the technical terminology used in usage.ts (which references
"android-connection"), update the prompt label in the Match.when case for
"mcpAndroid" to include the server identifier alongside the user-friendly
description. Specifically, modify the string template to include
"(android-connection)" in addition to "(nested Android emulator)" to align the
wizard terminology with the technical details referenced in usage.ts at line 31,
ensuring consistent naming across the codebase.
| const shouldSkipAndroidConnectionEntry = (entry: string): boolean => entry === "target" || entry === ".git" | ||
|
|
||
| const copyTextFile = ( | ||
| fs: FileSystem.FileSystem, | ||
| path: Path.Path, | ||
| sourcePath: string, | ||
| targetPath: string | ||
| ): Effect.Effect<void, PlatformError> => | ||
| Effect.gen(function*(_) { | ||
| const contents = yield* _(fs.readFileString(sourcePath)) | ||
| yield* _(ensureParentDir(path, fs, targetPath)) | ||
| yield* _(fs.writeFileString(targetPath, contents)) | ||
| }) | ||
|
|
||
| const copyTextDirectoryEntry = ( | ||
| fs: FileSystem.FileSystem, | ||
| path: Path.Path, | ||
| sourcePath: string, | ||
| targetPath: string | ||
| ): Effect.Effect<void, PlatformError> => | ||
| Effect.gen(function*(_) { | ||
| const info = yield* _(fs.stat(sourcePath)) | ||
| if (info.type === "Directory") { | ||
| yield* _(copyTextDirectory(fs, path, sourcePath, targetPath)) | ||
| return | ||
| } | ||
| if (info.type === "File") { | ||
| yield* _(copyTextFile(fs, path, sourcePath, targetPath)) | ||
| } | ||
| }) | ||
|
|
||
| const copyTextDirectory = ( | ||
| fs: FileSystem.FileSystem, | ||
| path: Path.Path, | ||
| sourcePath: string, | ||
| targetPath: string | ||
| ): Effect.Effect<void, PlatformError> => | ||
| Effect.gen(function*(_) { | ||
| yield* _(fs.makeDirectory(targetPath, { recursive: true })) | ||
| const entries = yield* _(fs.readDirectory(sourcePath)) | ||
| for (const entry of entries) { | ||
| if (shouldSkipAndroidConnectionEntry(entry)) { | ||
| continue | ||
| } | ||
| yield* _( | ||
| copyTextDirectoryEntry( | ||
| fs, | ||
| path, | ||
| path.join(sourcePath, entry), | ||
| path.join(targetPath, entry) | ||
| ) | ||
| ) | ||
| } | ||
| }) | ||
|
|
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Копирование всего дерева crate в build-context слишком широкое и может утянуть чувствительные файлы.
На Line 21-75 фильтрация исключает только target и .git, поэтому в .docker-git-tools/android-connection попадут любые локальные артефакты (включая потенциально секретные файлы/symlink-цели), что повышает риск утечки и ломает воспроизводимость сборки.
Лучше перейти на allowlist (например Cargo.toml, Cargo.lock, src/**, README.md) и явно исключать symlink/скрытые локальные артефакты.
As per coding guidelines, "Fail if changed files expose credentials, tokens, private-keys, or PII in source, generated config, logs, or CI output."
🤖 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/shell/android-connection-source.ts` around lines 21 - 75,
The shouldSkipAndroidConnectionEntry function uses a blocklist approach that
only excludes "target" and ".git", which is too permissive and risks exposing
sensitive files like credentials or local artifacts. Replace the blocklist logic
with an allowlist approach that only permits necessary files (such as
Cargo.toml, Cargo.lock, src directory, and README.md) to be copied into the
build context. Modify the shouldSkipAndroidConnectionEntry function to return
true (skip) for anything not explicitly allowed, and also reject hidden files
(starting with dot) and symlinks to prevent accidental inclusion of sensitive
local artifacts.
Source: Coding guidelines
| baseDir: string | ||
| ): Effect.Effect<void, PlatformError, FileSystem.FileSystem | Path.Path> => | ||
| Effect.gen(function*(_) { | ||
| const workspaceRoot = yield* _(resolveWorkspaceRoot(process.cwd())) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Проверка, есть ли уже абстракция cwd/env в shell-слое
rg -n 'process\.cwd\(' packages/lib/src
rg -n 'CurrentWorkingDirectory|cwd|Env|WorkspaceRoot|resolveWorkspaceRoot' packages/lib/srcRepository: ProverCoderAI/docker-git
Length of output: 50380
🏁 Script executed:
# Check the actual content of android-connection-source.ts around line 125
cat -n packages/lib/src/shell/android-connection-source.ts | head -150 | tail -30Repository: ProverCoderAI/docker-git
Length of output: 1156
🏁 Script executed:
# Check resolveWorkspaceRoot definition and its usage pattern
ast-grep outline packages/lib/src/shell/ --match resolveWorkspaceRoot --view expandedRepository: ProverCoderAI/docker-git
Length of output: 176
🏁 Script executed:
# Check if there's a pattern for context-based cwd abstraction (e.g., withFsPathContext usage)
rg -B3 -A3 'withFsPathContext|FsPathContext|cwd.*=' packages/lib/src/shell/ | head -60Repository: ProverCoderAI/docker-git
Length of output: 2435
🏁 Script executed:
# Find resolveWorkspaceRoot definition
rg -n 'resolveWorkspaceRoot' packages/lib/src --type ts -B2 -A5 | head -40Repository: ProverCoderAI/docker-git
Length of output: 3078
🏁 Script executed:
# Get the full function signature containing line 125
sed -n '110,135p' packages/lib/src/shell/android-connection-source.tsRepository: ProverCoderAI/docker-git
Length of output: 1339
🏁 Script executed:
# Check if there's a pattern like withFsPathContext or similar abstraction in shell/
rg -n 'export.*with.*Context|Context\.Tag' packages/lib/src/shell/ --type ts | head -20Repository: ProverCoderAI/docker-git
Length of output: 162
🏁 Script executed:
# Look at how other files in shell/ handle cwd injection/abstraction
rg -n 'cwd.*:.*string' packages/lib/src/shell/*.ts | head -15Repository: ProverCoderAI/docker-git
Length of output: 1052
Передайте cwd параметром вместо прямого вызова process.cwd().
На Line 125 функция вызывает process.cwd() напрямую вместо того, чтобы принять его как параметр. Согласно guidelines: "No process direct calls... in product code; all such operations must be abstracted through Layer-based services in SHELL." Добавьте cwd: string в сигнатуру функции (как это сделано в соседних функциях docker-compose.ts, docker-volume.ts и др.) и передавайте его в resolveWorkspaceRoot(cwd). Это повысит тестируемость и консистентность с кодовой базой.
🤖 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/shell/android-connection-source.ts` at line 125, The
function in android-connection-source.ts is calling process.cwd() directly in
the resolveWorkspaceRoot invocation, which violates the guideline that process
operations must be abstracted through Layer-based services. Refactor the
function to accept a cwd parameter of type string in its signature, then pass
that cwd parameter to resolveWorkspaceRoot(cwd) instead of calling process.cwd()
directly. This approach aligns with the pattern already established in related
files and improves testability.
Source: Coding guidelines
| // REF: issue-176 | ||
| yield* _(provisionDockerGitScripts(fs, path, baseDir)) | ||
| yield* _(provisionDockerGitSessionSyncTool(fs, path, baseDir)) | ||
| yield* _(provisionDockerGitBuildContext(fs, path, baseDir, normalizedConfig)) |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Сделайте provisioning build context fail-fast до записи шаблонов.
Сейчас provisioning выполняется после записи specs; если Android source недоступен, падение произойдёт уже после частичной генерации файлов, что оставляет проект в несогласованном состоянии.
Минимальный безопасный рефакторинг
Effect.gen(function*(_) {
const { fs, path, resolved: baseDir } = yield* _(resolveBaseDir(outDir))
yield* _(fs.makeDirectory(baseDir, { recursive: true }))
const normalizedConfig = withDefaultResourceLimitIntent(config)
+ yield* _(provisionDockerGitBuildContext(fs, path, baseDir, normalizedConfig))
+
const hostResources = yield* _(loadHostResources())
const composeResourceLimits = {
main: resolveComposeResourceLimits(normalizedConfig, hostResources),
playwright: resolvePlaywrightComposeResourceLimits(normalizedConfig, hostResources)
}
@@
- yield* _(provisionDockerGitBuildContext(fs, path, baseDir, normalizedConfig))
-
return created
})🤖 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/shell/files.ts` at line 285, The
provisionDockerGitBuildContext call should be executed earlier in the process
before any template or spec files are written, to implement fail-fast behavior.
Move the yield* _(provisionDockerGitBuildContext(fs, path, baseDir,
normalizedConfig)) statement to the beginning of the generator function, before
any other yield statements that write files or specs, ensuring that if the
Docker Git build context provisioning fails (e.g., due to unavailable Android
source), the failure occurs before the project reaches an inconsistent state
from partial file generation.
| yield* _(ensureDockerDaemonAccess(command.projectDir)) | ||
| return yield* _(runDockerComposeUpWithPortCheck(command.projectDir)) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Проверка: есть ли регрессионный тест, который явно покрывает mcpAndroidUp + projectDir.
# Ожидание: найден тест, где mcpAndroidUp запускается с projectDir, отличным от process.cwd(),
# и мок/стаб CommandExecutor проверяет cwd команд Docker.
rg -n -C 4 'mcpAndroidUp|ensureDockerDaemonAccess|process\.cwd|projectDir' packages/lib/testsRepository: ProverCoderAI/docker-git
Length of output: 33973
🏁 Script executed:
# First, find the mcp-android.ts file and check its implementation around lines 88-89
fd -type f -name "mcp-android.ts" packages/lib/src
# Then search for mcpAndroidUp specifically in tests
rg -n "mcpAndroidUp" packages/lib/testsRepository: ProverCoderAI/docker-git
Length of output: 333
🏁 Script executed:
# Correct fd syntax - use -t f instead of -type f, and search more broadly
fd "mcp-android" packages/lib/src
# Also search for mcpAndroidUp in the entire packages/lib directory
rg -n "mcpAndroidUp" packages/libRepository: ProverCoderAI/docker-git
Length of output: 277
🏁 Script executed:
# Read the mcp-android.ts file to understand the mcpAndroidUp function
cat -n packages/lib/src/usecases/mcp-android.ts | head -120Repository: ProverCoderAI/docker-git
Length of output: 4471
🏁 Script executed:
# Search for tests of mcpAndroidUp
rg -n "mcpAndroidUp" packages/lib/tests -A 10 -B 2
# Also check if there's a mcp-android.test.ts file
fd "mcp-android" packages/lib/testsRepository: ProverCoderAI/docker-git
Length of output: 210
🏁 Script executed:
# Read the mcp-android.test.ts file to see what tests exist
cat -n packages/lib/tests/usecases/mcp-android.test.tsRepository: ProverCoderAI/docker-git
Length of output: 6620
🏁 Script executed:
# Check the ensureDockerDaemonAccess implementation to understand what cwd it uses
rg -n "ensureDockerDaemonAccess" packages/lib/src/shell/docker.js -A 15Repository: ProverCoderAI/docker-git
Length of output: 235
🏁 Script executed:
# Find the docker file with ensureDockerDaemonAccess
fd "docker" packages/lib/src/shell
# Then read the correct file
rg -n "ensureDockerDaemonAccess" packages/lib/src -A 15Repository: ProverCoderAI/docker-git
Length of output: 15799
🏁 Script executed:
# Compare the mcp-playwright.ts implementation to see if it has the same issue
cat -n packages/lib/src/usecases/mcp-playwright.ts | head -95Repository: ProverCoderAI/docker-git
Length of output: 4559
Закрепите исправление projectDir регрессионным тестом для mcpAndroidUp.
Line 88 исправляет корневую ошибку, используя command.projectDir вместо process.cwd(), как в mcp-playwright.ts (которая ошибочно остаётся на process.cwd()). Однако mcp-android.test.ts не содержит теста функции mcpAndroidUp — нужен тест, где:
command.projectDirотличается отprocess.cwd()- Мок
CommandExecutorпроверяет, чтоdocker info(черезensureDockerDaemonAccess) запускается с правильнымcwd docker compose upзапускается также изcommand.projectDir
Без такого теста регрессия остаётся незадокументированной и может повториться при будущих рефакторингах.
🤖 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/mcp-android.ts` around lines 88 - 89, Add a
regression test for the mcpAndroidUp function in mcp-android.test.ts that
validates the projectDir fix by setting up a test scenario where
command.projectDir differs from process.cwd(). The test should mock the
CommandExecutor to verify that both ensureDockerDaemonAccess (which calls docker
info) and runDockerComposeUpWithPortCheck (which calls docker compose up) are
invoked with the correct working directory from command.projectDir rather than
the current process working directory. This ensures the fix on line 88 using
command.projectDir is properly tested and prevents regression in future
refactorings.
Sources: Coding guidelines, Path instructions
|
|
||
| - `--force` пересоздаёт окружение и удаляет volumes проекта. | ||
| - `--mcp-playwright` включает Playwright MCP и Chromium sidecar для браузерной автоматизации. | ||
| - `--mcp-android` включает first-party Android MCP (`android-connection`) и вложенный sidecar с Android-эмулятором (`docker-android`) для мобильной автоматизации. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
Упростите формулировку для параллельности со строкой --mcp-playwright.
Текущая формулировка:
- `--mcp-android` включает first-party Android MCP (`android-connection`) и вложенный sidecar с Android-эмулятором (`docker-android`) для мобильной автоматизации.
содержит больше деталей реализации, чем описание Playwright выше (line 73). Для лучшей параллельности и читаемости рекомендуется:
- `--mcp-android` включает Android MCP и Android-эмулятор sidecar для мобильной автоматизации.
Либо, если детали важны, добавьте аналогичную детализацию для Playwright:
- `--mcp-playwright` включает Playwright MCP (chromium-connection) и Chromium sidecar для браузерной автоматизации.
- `--mcp-android` включает Android MCP (android-connection) и Android-эмулятор sidecar для мобильной автоматизации.
🤖 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 `@README.md` at line 74, The documentation line describing the --mcp-android
flag contains excessive implementation details (mentioning first-party
designation, specific component names like android-connection and
docker-android) compared to the --mcp-playwright line above it, breaking
parallel structure. Simplify the --mcp-android description by removing the
implementation-specific terminology and details to match the conciseness of the
--mcp-playwright description, keeping only the essential information about what
capabilities are enabled for mobile automation.
Source: Path instructions
✅ Ready to mergeThis pull request is now ready to be merged:
Monitored by hive-mind with --auto-restart-until-mergeable flag |
Android MCP integration with a first-party module
Fixes #436: «Подключить mcp-android так же как работает MCP PLAYRIGHT».
This updates the Android MCP implementation after review feedback that the module itself must be implemented and proven separately before wiring it into the container.
What changed
crates/android-connection, a first-party Rust crate with:android-connection: MCP stdio server exposing Android tools over ADB.docker-git-android-connection: deterministic lifecycle CLI for Android runtime spec/start/status/stop.npx @mobilenext/mobile-mcp@latestwiring with directandroid-connectioncommands for Codex, Claude, Gemini, and Grok..docker-git-tools/android-connectioninto the build context and install the crate withcargo install --path ... --locked --bins.enableMcpAndroid, compose sidecar env, templates, apply path, CLI/docs, and changeset.cargo fmt --check,cargo test --locked, andcargo clippy --locked --all-targets -- -D warnings.Mathematical guarantees
[A-Za-z0-9._:-]...paths before writing screenshots or installing APKs.crates/android-connectionsource covered by local tests and CI.Proof of fix
npxcommand and did not provide a separately testable module.Verification
This PR was updated automatically by the AI issue solver.