diff --git a/.cursor/Dockerfile b/.cursor/Dockerfile new file mode 100644 index 00000000000..3f32669c7df --- /dev/null +++ b/.cursor/Dockerfile @@ -0,0 +1,166 @@ +FROM ubuntu:24.04 + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +ARG GO_VERSION=1.25.9 +ARG NODE_VERSION=24.11.1 +ARG NVM_VERSION=0.40.3 +ARG AGENT_BROWSER_VERSION=0.27.0 +ARG DOCKER_VERSION=5:28.5.2-1~ubuntu.24.04~noble +ARG CONTAINERD_VERSION=2.2.3-1~ubuntu.24.04~noble +ARG DOCKER_BUILDX_VERSION=0.33.0-1~ubuntu.24.04~noble +ARG DOCKER_COMPOSE_VERSION=5.1.3-1~ubuntu.24.04~noble + +ENV DEBIAN_FRONTEND=noninteractive +ENV NVM_DIR=/home/ubuntu/.nvm +ENV GOPATH=/home/ubuntu/go +ENV PATH=/home/ubuntu/.nvm/versions/node/v${NODE_VERSION}/bin:/usr/local/go/bin:/home/ubuntu/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + apt-transport-https \ + acl \ + bash \ + build-essential \ + ca-certificates \ + curl \ + dnsutils \ + file \ + fuse-overlayfs \ + git \ + git-lfs \ + gnupg \ + iproute2 \ + iptables \ + jq \ + less \ + libasound2t64 \ + libatk-bridge2.0-0 \ + libatk1.0-0 \ + libatspi2.0-0 \ + libcairo2 \ + libcups2 \ + libdrm2 \ + libgbm1 \ + libgtk-3-0 \ + libnspr4 \ + libnss3 \ + libpango-1.0-0 \ + libsecret-1-0 \ + libx11-xcb1 \ + libxcomposite1 \ + libxdamage1 \ + libxfixes3 \ + libxkbcommon0 \ + libxrandr2 \ + libxshmfence1 \ + locales \ + lsof \ + make \ + nano \ + netcat-openbsd \ + openssh-server \ + pgloader \ + pkg-config \ + procps \ + python3 \ + python3-pip \ + python3-venv \ + rsync \ + sudo \ + tar \ + tmux \ + unzip \ + vim \ + xmlsec1 \ + xz-utils \ + zip && \ + locale-gen en_US.UTF-8 && \ + git lfs install --system && \ + rm -rf /var/lib/apt/lists/* + +RUN install -m 0755 -d /etc/apt/keyrings && \ + curl --retry 3 --retry-delay 5 -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg && \ + chmod a+r /etc/apt/keyrings/docker.gpg && \ + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" > /etc/apt/sources.list.d/docker.list && \ + apt-get update && \ + apt-get install -y --no-install-recommends \ + docker-ce=${DOCKER_VERSION} \ + docker-ce-cli=${DOCKER_VERSION} \ + containerd.io=${CONTAINERD_VERSION} \ + docker-buildx-plugin=${DOCKER_BUILDX_VERSION} \ + docker-compose-plugin=${DOCKER_COMPOSE_VERSION} && \ + rm -rf /var/lib/apt/lists/* + +RUN mkdir -p /etc/docker && \ + printf '%s\n' \ + '{' \ + ' "storage-driver": "fuse-overlayfs",' \ + ' "features": {' \ + ' "buildkit": true' \ + ' }' \ + '}' > /etc/docker/daemon.json && \ + update-alternatives --set iptables /usr/sbin/iptables-legacy && \ + update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy + +RUN install -m 0755 -d /etc/apt/keyrings && \ + curl --retry 3 --retry-delay 5 -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg -o /etc/apt/keyrings/githubcli-archive-keyring.gpg && \ + chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg && \ + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list && \ + apt-get update && \ + apt-get install -y --no-install-recommends gh && \ + rm -rf /var/lib/apt/lists/* + +RUN case "$(dpkg --print-architecture)" in \ + amd64) go_arch=amd64 ;; \ + arm64) go_arch=arm64 ;; \ + *) echo "Unsupported Go architecture: $(dpkg --print-architecture)" >&2; exit 1 ;; \ + esac && \ + curl --retry 3 --retry-delay 5 -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${go_arch}.tar.gz" -o /tmp/go.tgz && \ + rm -rf /usr/local/go && \ + tar -C /usr/local -xzf /tmp/go.tgz && \ + ln -sfnT /usr/local/go/bin/go /usr/local/bin/go && \ + ln -sfnT /usr/local/go/bin/gofmt /usr/local/bin/gofmt && \ + rm -f /tmp/go.tgz + +RUN case "$(dpkg --print-architecture)" in \ + amd64) aws_arch=x86_64 ;; \ + arm64) aws_arch=aarch64 ;; \ + *) echo "Unsupported AWS CLI architecture: $(dpkg --print-architecture)" >&2; exit 1 ;; \ + esac && \ + curl --retry 3 --retry-delay 5 -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-${aws_arch}.zip" -o /tmp/awscliv2.zip && \ + unzip -q /tmp/awscliv2.zip -d /tmp && \ + /tmp/aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli && \ + rm -rf /tmp/aws /tmp/awscliv2.zip + +RUN install -m 0755 -d /var/run/sshd && \ + printf '%s\n' 'PasswordAuthentication no' 'ChallengeResponseAuthentication no' 'UsePAM no' > /etc/ssh/sshd_config.d/disable_password_auth.conf && \ + if ! id -u ubuntu >/dev/null 2>&1; then useradd -m -s /bin/bash ubuntu; fi && \ + groupadd -f docker && \ + usermod -aG docker,sudo ubuntu && \ + echo "ubuntu ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/ubuntu && \ + chmod 0440 /etc/sudoers.d/ubuntu && \ + echo "ubuntu:ubuntu" | chpasswd && \ + install -d -o ubuntu -g ubuntu "${NVM_DIR}" "${GOPATH}" + +RUN git clone --depth 1 --branch "v${NVM_VERSION}" https://github.com/nvm-sh/nvm.git "${NVM_DIR}" && \ + chown -R ubuntu:ubuntu "${NVM_DIR}" "${GOPATH}" && \ + su ubuntu -c "bash -lc 'set -e; source ${NVM_DIR}/nvm.sh; nvm install ${NODE_VERSION}; nvm alias default ${NODE_VERSION}; nvm use default; npm install -g agent-browser@${AGENT_BROWSER_VERSION}; agent-browser install || true'" && \ + ln -sfn "${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/node" /usr/local/bin/node && \ + ln -sfn "${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/npm" /usr/local/bin/npm && \ + ln -sfn "${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/npx" /usr/local/bin/npx && \ + ln -sfn "${NVM_DIR}/versions/node/v${NODE_VERSION}/bin/agent-browser" /usr/local/bin/agent-browser + +RUN { \ + echo 'export NVM_DIR="$HOME/.nvm"'; \ + echo '[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"'; \ + echo 'export GOPATH="$HOME/go"'; \ + echo 'export PATH="$NVM_DIR/versions/node/v24.11.1/bin:/usr/local/go/bin:$GOPATH/bin:$PATH"'; \ + } >> /home/ubuntu/.bashrc && \ + chown ubuntu:ubuntu /home/ubuntu/.bashrc + +ENV LANG=en_US.UTF-8 +ENV LC_ALL=en_US.UTF-8 + +WORKDIR /home/ubuntu +USER ubuntu diff --git a/.cursor/README.md b/.cursor/README.md new file mode 100644 index 00000000000..93596cb5686 --- /dev/null +++ b/.cursor/README.md @@ -0,0 +1,36 @@ +# Cursor Cloud Agent Environment + +This directory defines the checked-in Cloud Agent environment for this repository. Cursor resolves `.cursor/environment.json` before personal or team saved environments, so this replaces the snapshot-dependent `/onboard` flow for agents started from this repo. + +The Docker build context is `.cursor/` only. The Dockerfile intentionally does not copy the repository; Cursor checks out the requested commit at runtime. + +## What Is Baked Into The Image + +- Ubuntu 24.04. +- Docker CE 28.5.2 with `fuse-overlayfs` and `iptables-legacy`, matching Cursor's Docker-in-Cloud guidance for complex compose setups. +- Go 1.25.9 from `server/.go-version`. +- Node 24.11.1/npm 11 via nvm, matching `.nvmrc` and `webapp/package.json`. +- `agent-browser@0.27.0` and browser dependencies for screenshot workflows. +- AWS CLI v2 for S3 uploads. +- Common Mattermost build/test tools: `make`, `jq`, `xmlsec1`, `pgloader`, Git LFS, GitHub CLI, Python 3, and build essentials. + +## Runtime Hooks + +- `cloud-agent-install.sh` runs after Cursor checks out the repo. It refreshes nvm, installs agent-browser browsers, verifies Cursor's multi-repo `mattermost/enterprise` checkout, runs `server` Go dependency hydration, installs webapp dependencies, and runs Playwright `npm ci`. +- `cloud-agent-start.sh` materializes `.cursor/cursor.md` as `.cursor/AGENTS.md`, fixes current-session Docker socket access, then starts Docker and waits until `docker info` and `docker compose version` succeed. + +The environment declares `github.com/mattermost/enterprise` in `repositoryDependencies` so Cursor can provide it as part of the multi-repo workspace. Cursor currently clones the repositories as siblings, such as `/agent/repos/mattermost` and `/agent/repos/enterprise`, which matches `server/Makefile`'s default `../../enterprise` path. The install hook does not clone, pull, or symlink enterprise. + +## Useful Skips + +Set these environment variables to `true` to shorten startup for narrow tasks: + +- `CLOUD_AGENT_SKIP_ENTERPRISE` +- `CLOUD_AGENT_SKIP_GO_DEPS` +- `CLOUD_AGENT_SKIP_WEBAPP_DEPS` +- `CLOUD_AGENT_SKIP_PLAYWRIGHT_DEPS` +- `CLOUD_AGENT_SKIP_AGENT_BROWSER_INSTALL` + +## Expected Secrets + +- AWS uploads use the standard AWS CLI environment variables provided to the Cloud Agent: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_S3_BUCKET_NAME`. The image only supplies the `aws` binary. diff --git a/.cursor/cursor.md b/.cursor/cursor.md new file mode 100644 index 00000000000..895f1f0db19 --- /dev/null +++ b/.cursor/cursor.md @@ -0,0 +1,106 @@ +# Cursor Cloud Agent Instructions + +These instructions apply to Cursor Cloud Agents after `.cursor/scripts/cloud-agent-start.sh` materializes this file as `.cursor/AGENTS.md`. + +## Environment + +- Docker must be available. If `docker info` fails, inspect `/tmp/docker-service-start.log` and `/tmp/dockerd.log`; do not assume a snapshot will provide Docker. +- The image includes Go, Node/npm, Docker Compose, AWS CLI v2, and `agent-browser`. +- Cursor should provide `mattermost/enterprise` through the multi-repo environment. The expected layout is sibling repositories, such as `/agent/repos/mattermost` and `/agent/repos/enterprise`; this matches `server/Makefile`'s default `../../enterprise` path. + +## Running Mattermost + +1. Start dependencies: + + ```bash + cd server + make start-docker + ``` + +2. Start the server: + + ```bash + cd server + make run-server + ``` + +3. Start the web app in another terminal when UI work needs live verification: + + ```bash + cd webapp + make run + ``` + +The Mattermost server is expected at `http://localhost:8065`. The webapp dev server commonly uses `http://localhost:9005`. + +### Known-good Cloud flow + +- In this multi-repo Cloud environment, `mattermost` and `enterprise` are expected to start from `master`, so sibling checkout skew should not need extra handling. +- `server/Makefile`'s `run` target only reaches `run-client` if the server is backgrounded. In Cloud, the reliable combined startup is: + + ```bash + cd server + ENABLED_DOCKER_SERVICES='postgres redis' RUN_SERVER_IN_BACKGROUND=true make run + ``` + +- If you want split terminals instead, use: + + ```bash + cd server + ENABLED_DOCKER_SERVICES='postgres redis' make run-server + ``` + + and then: + + ```bash + cd webapp + make run + ``` + +- When the server starts and `MM_LICENSE` is present in the environment, the server applies that license automatically. If `MM_LICENSE` is not set, starting the server automatically applies an Entry license, which provides nearly all functionality needed for development. +- `ENABLED_DOCKER_SERVICES='postgres redis'` avoids optional local-dev services such as Prometheus, Grafana, Loki, Minio, Azurite, and OpenLDAP. This is useful in Cloud when Docker Hub rate limits block the default `make start-docker` dependency set. +- If the first-user signup UI is flaky but the server is already healthy, seed local state with `mmctl` and then log in through the browser: + + ```bash + cd server + ./bin/mmctl --local user create --email cursor@example.com --username cursoradmin --password Password123! --system-admin --email-verified --disable-welcome-email + ./bin/mmctl --local team create --name cursorteam --display-name "Cursor Team" --email cursor@example.com + ``` + +- A healthy server responds at: + + ```bash + curl http://127.0.0.1:8065/api/v4/system/ping + ``` + +## Tests And Setup + +- Backend workspace setup is handled by `cd server && make setup-go-work`; never run `go mod tidy` directly. +- Webapp dependencies are installed with `cd webapp && make node_modules`. +- Playwright dependencies are installed with `cd e2e-tests/playwright && npm ci`. +- For full Playwright compose flows, use the existing `e2e-tests` Makefile and scripts. Docker Compose is available in the Cloud Agent image. + +## Browser Screenshots + +Use `agent-browser` for browser automation and screenshots. If the CLI is missing or browsers are unavailable, run: + +```bash +npm install -g agent-browser@0.27.0 +agent-browser install +``` + +- Chrome is available in the Cloud image, and `agent-browser skills get core --full` is a quick check that the CLI and bundled skills are working. +Prefer verifying UI changes against the running local Mattermost instance before opening or updating a PR. + +## AWS And PR Artifacts + +AWS CLI v2 is installed for uploading screenshots or reports. Cloud Agents should receive `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_S3_BUCKET_NAME` as environment variables. + +Before uploading, verify credentials with: + +```bash +aws sts get-caller-identity +``` + +- If the configured S3 bucket is public, upload with `aws s3 cp` and share the plain object URL `https://$AWS_S3_BUCKET_NAME.s3.amazonaws.com/` instead of generating a presigned URL. +Do not hardcode AWS credentials or bucket secrets in the repository. diff --git a/.cursor/environment.json b/.cursor/environment.json new file mode 100644 index 00000000000..745e0d0fd79 --- /dev/null +++ b/.cursor/environment.json @@ -0,0 +1,23 @@ +{ + "name": "Mattermost Cloud Agent", + "user": "ubuntu", + "build": { + "dockerfile": "Dockerfile", + "context": "." + }, + "repositoryDependencies": [ + "github.com/mattermost/enterprise" + ], + "install": "bash .cursor/scripts/cloud-agent-install.sh", + "start": "bash .cursor/scripts/cloud-agent-start.sh", + "ports": [ + { + "name": "Mattermost server", + "port": 8065 + }, + { + "name": "Webapp dev server", + "port": 9005 + } + ] +} diff --git a/.cursor/scripts/cloud-agent-install.sh b/.cursor/scripts/cloud-agent-install.sh new file mode 100755 index 00000000000..911a5c974c8 --- /dev/null +++ b/.cursor/scripts/cloud-agent-install.sh @@ -0,0 +1,179 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +log() { + printf '[cloud-agent-install] %s\n' "$*" >&2 +} + +is_true() { + case "${1:-}" in + 1 | true | TRUE | yes | YES) return 0 ;; + *) return 1 ;; + esac +} + +ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" +cd "$ROOT" + +NODE_VERSION="${CLOUD_AGENT_NODE_VERSION:-24.11.1}" +AGENT_BROWSER_VERSION="${CLOUD_AGENT_BROWSER_VERSION:-0.27.0}" + +export GOPATH="${GOPATH:-$HOME/go}" +export PATH="/usr/local/go/bin:$GOPATH/bin:/usr/local/bin:$PATH" + +ensure_go() { + if ! command -v go >/dev/null 2>&1; then + log "Go is not available on PATH. PATH=$PATH" + return 1 + fi + + log "Using $(go version)" +} + +source_node() { + export NVM_DIR="${NVM_DIR:-$HOME/.nvm}" + if [ -s "$NVM_DIR/nvm.sh" ]; then + # shellcheck source=/dev/null + . "$NVM_DIR/nvm.sh" + fi +} + +ensure_node() { + source_node + + if command -v nvm >/dev/null 2>&1; then + nvm install "$NODE_VERSION" >/dev/null + nvm alias default "$NODE_VERSION" >/dev/null + nvm use "$NODE_VERSION" >/dev/null + fi + + if ! command -v node >/dev/null 2>&1 || ! command -v npm >/dev/null 2>&1; then + log "Node.js/npm are not available; check the Cloud Agent Dockerfile build." + return 1 + fi + + log "Using node $(node --version) and npm $(npm --version)" + + if ! command -v agent-browser >/dev/null 2>&1; then + npm install -g "agent-browser@${AGENT_BROWSER_VERSION}" + fi + + if ! is_true "${CLOUD_AGENT_SKIP_AGENT_BROWSER_INSTALL:-false}"; then + agent-browser install || log "agent-browser install failed; continuing so code tasks are not blocked." + fi +} + +enterprise_build_dir() { + case "$BUILD_ENTERPRISE_DIR" in + /*) realpath -m "$BUILD_ENTERPRISE_DIR" ;; + *) realpath -m "$ROOT/server/$BUILD_ENTERPRISE_DIR" ;; + esac +} + +find_enterprise_checkout() { + local candidates=() + if [ -n "${ENTERPRISE_CHECKOUT_DIR:-}" ]; then + candidates+=("$ENTERPRISE_CHECKOUT_DIR") + fi + if [ -n "${ENTERPRISE_DIR:-}" ]; then + candidates+=("$ENTERPRISE_DIR") + fi + + candidates+=( + "$ROOT/../enterprise" + "$ROOT/../../enterprise" + "$HOME/enterprise" + ) + + local candidate + for candidate in "${candidates[@]}"; do + if git -C "$candidate" rev-parse --is-inside-work-tree >/dev/null 2>&1; then + realpath -m "$candidate" + return 0 + fi + done + + return 1 +} + +verify_enterprise_checkout() { + if is_true "${CLOUD_AGENT_SKIP_ENTERPRISE:-false}"; then + log "Skipping enterprise verification because CLOUD_AGENT_SKIP_ENTERPRISE is set." + return 0 + fi + + local target + if ! target="$(find_enterprise_checkout)"; then + log "Enterprise checkout not found. Ensure the Cursor multi-repo environment includes github.com/mattermost/enterprise." + return 1 + fi + + log "Enterprise checkout ready at $target." +} + +hydrate_go_dependencies() { + if is_true "${CLOUD_AGENT_SKIP_GO_DEPS:-false}"; then + log "Skipping Go dependency hydration." + return 0 + fi + + if [ -d server ]; then + if [ -n "${BUILD_ENTERPRISE_DIR:-}" ]; then + local enterprise_dir + enterprise_dir="$(enterprise_build_dir)" + log "Hydrating Go workspace with BUILD_ENTERPRISE_DIR=$enterprise_dir" + ( + cd server + BUILD_ENTERPRISE_DIR="$enterprise_dir" make setup-go-work + go mod download + if [ -f public/go.mod ]; then + (cd public && go mod download) + fi + ) + else + log "Hydrating Go workspace with server/Makefile default enterprise path." + ( + cd server + make setup-go-work + go mod download + if [ -f public/go.mod ]; then + (cd public && go mod download) + fi + ) + fi + fi +} + +hydrate_webapp_dependencies() { + if is_true "${CLOUD_AGENT_SKIP_WEBAPP_DEPS:-false}"; then + log "Skipping webapp dependency hydration." + return 0 + fi + + if [ -f webapp/package.json ]; then + log "Hydrating webapp dependencies." + (cd webapp && make node_modules) + fi +} + +hydrate_playwright_dependencies() { + if is_true "${CLOUD_AGENT_SKIP_PLAYWRIGHT_DEPS:-false}"; then + log "Skipping Playwright dependency hydration." + return 0 + fi + + if [ -f e2e-tests/playwright/package-lock.json ]; then + log "Hydrating Playwright dependencies." + (cd e2e-tests/playwright && npm ci) + fi +} + +ensure_go +ensure_node +verify_enterprise_checkout +hydrate_go_dependencies +hydrate_webapp_dependencies +hydrate_playwright_dependencies + +log "AWS CLI: $(aws --version 2>&1 || printf 'not available')" +log "Install hook complete." diff --git a/.cursor/scripts/cloud-agent-start.sh b/.cursor/scripts/cloud-agent-start.sh new file mode 100755 index 00000000000..268888e5d85 --- /dev/null +++ b/.cursor/scripts/cloud-agent-start.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +log() { + printf '[cloud-agent-start] %s\n' "$*" >&2 +} + +materialize_cloud_agent_instructions() { + if [ -f .cursor/cursor.md ]; then + cp .cursor/cursor.md .cursor/AGENTS.md + log "Materialized Cloud Agent instructions at .cursor/AGENTS.md." + fi +} + +materialize_cloud_agent_instructions + +if ! command -v docker >/dev/null 2>&1; then + log "Docker CLI is missing. The Cloud Agent image did not build from .cursor/Dockerfile." + exit 1 +fi + +ensure_docker_socket_access() { + if [ ! -S /var/run/docker.sock ]; then + return 0 + fi + + sudo groupadd -f docker + sudo usermod -aG docker "$(id -un)" + sudo chgrp docker /var/run/docker.sock >/dev/null 2>&1 || true + sudo chmod g+rw /var/run/docker.sock >/dev/null 2>&1 || true + + if command -v setfacl >/dev/null 2>&1; then + sudo setfacl -m "u:$(id -un):rw" /var/run/docker.sock >/dev/null 2>&1 || true + fi +} + +if [ -f /proc/sys/kernel/apparmor_restrict_unprivileged_userns ]; then + sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 >/dev/null 2>&1 || \ + log "Could not relax AppArmor user namespace restriction; openldap-based tests may need a larger host profile." +fi + +ensure_docker_socket_access + +if docker info >/dev/null 2>&1; then + log "Docker is already running." + docker compose version + exit 0 +fi + +log "Starting Docker daemon." +if command -v service >/dev/null 2>&1; then + sudo sh -c 'service docker start >/tmp/docker-service-start.log 2>&1' || \ + log "service docker start failed; falling back to direct dockerd startup." +fi + +if ! pgrep -x dockerd >/dev/null 2>&1; then + sudo sh -c 'nohup dockerd --host=unix:///var/run/docker.sock >/tmp/dockerd.log 2>&1 &' +fi + +for _ in {1..60}; do + ensure_docker_socket_access + + if docker info >/dev/null 2>&1; then + log "Docker is ready." + docker version + docker compose version + exit 0 + fi + + sleep 1 +done + +log "Docker did not become ready within 60 seconds." +if [ -f /tmp/docker-service-start.log ]; then + log "docker service output:" + tail -n 80 /tmp/docker-service-start.log >&2 || true +fi +if [ -f /tmp/dockerd.log ]; then + log "dockerd output:" + tail -n 120 /tmp/dockerd.log >&2 || true +fi + +exit 1 diff --git a/.gitignore b/.gitignore index a395e6988fa..7871bfe276b 100644 --- a/.gitignore +++ b/.gitignore @@ -166,7 +166,15 @@ docker-compose.override.yaml **/CLAUDE.md .claude .cursorrules -.cursor/ +.cursor/* +!.cursor/README.md +!.cursor/cursor.md +!.cursor/Dockerfile +!.cursor/environment.json +!.cursor/scripts/ +.cursor/scripts/* +!.cursor/scripts/cloud-agent-install.sh +!.cursor/scripts/cloud-agent-start.sh server/prev-report.xml server/prev-gotestsum.json server/shard-*.txt diff --git a/AGENTS.md b/AGENTS.md index 05f3506941d..b325b8ff4fe 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,3 +10,9 @@ When creating a pull request, follow `.github/PULL_REQUEST_TEMPLATE.md` exactly: - Remove all `` comments. - Omit sections that are not applicable (Ticket Link, Screenshots) — do not write N/A, just remove the header. - The `#### Release Note` header and its "```release-note" fenced code block **must always be present** (WITHOUT escaping the ``` characters). Write `NONE` if the change has no API, schema, UI, or breaking changes. + +## Cursor Cloud Agents + +This repository has a checked-in Cloud Agent environment under `.cursor/`. Docker is started by `.cursor/scripts/cloud-agent-start.sh`; if Docker is unavailable in Cloud, treat that as an environment failure rather than falling back to snapshot assumptions. + +The environment declares `mattermost/enterprise` as a Cursor multi-repo dependency. Cursor clones the repositories as siblings, so `server/Makefile` can use its default `../../enterprise` path; the install hook does not clone or symlink enterprise.