Commit Graph
543 Commits
Author SHA1 Message Date
Rohit Malhotraandopenhands f2d19c8923 Add GitHub bug report issue template (#813)
* Add GitHub bug report issue template

- Bug report form with install method dropdown (npm, Docker, source, other)
  and version dropdown listing all pre-release versions (alpha.2–alpha.6)
- Includes optional agent-server version, environment, logs/screenshots fields

Co-authored-by: openhands <openhands@all-hands.dev>

* Remove agent server version field from bug report template

Co-authored-by: openhands <openhands@all-hands.dev>

* Remove environment field from bug report template

Co-authored-by: openhands <openhands@all-hands.dev>

* Add OS dropdown to bug report template

Co-authored-by: openhands <openhands@all-hands.dev>

* Address review feedback on bug report template

- Convert version dropdown to free-text input to avoid maintenance burden
- Fix docker inspect description to include image reference
- Add Actual Behavior field between Steps to Reproduce and Expected Behavior
- Split Logs/Screenshots into separate fields so render:shell doesn't break images

Co-authored-by: openhands <openhands@all-hands.dev>

* Add --version flag to CLI and version label to Docker image

- bin/agent-canvas.mjs: add -v/--version flag that reads version from package.json
- docker/Dockerfile: add AGENT_CANVAS_VERSION build arg and org.opencontainers.image.version label
- .github/workflows/docker.yml: extract version from package.json, pass as build arg
- bug_report.yml: update version field description with the actual commands users can run

Co-authored-by: openhands <openhands@all-hands.dev>

* Update version description: use image tag for Docker (label not yet released)

Co-authored-by: openhands <openhands@all-hands.dev>

---------

Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-27 12:17:35 -04:00
Xingyao Wangandopenhands 4655f7a119 chore: remove PR review GitHub Actions workflow (#814)
Remove `pr-review-by-openhands.yml`, `pr-review-evaluation.yml` — PR review is now handled
via OpenHands Cloud automation.

Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-27 11:47:46 -04:00
Rohit Malhotraandopenhands 489070029d fix(ci): publish directly with --tag latest to avoid OIDC dist-tag failure (#778)
* fix(ci): publish directly with --tag latest to avoid OIDC dist-tag failure

The previous workflow published with --tag alpha then ran a separate
npm dist-tag add to set latest. The second call failed with E401
because OIDC trusted publishing tokens don't cover post-publish
registry mutations like dist-tag.

Simplify to a single npm publish --tag latest, which is all we need
until the first stable release (#395).

* docs(ci): note that named prerelease dist-tags are removed under current policy

Add a comment block explaining that alpha/beta/rc dist-tags are intentionally
not published while issue #395's 'everything is latest' policy is active, so
consumers pinning to named prerelease tags are not silently broken without
notice.

Co-authored-by: openhands <openhands@all-hands.dev>

* docs(ci): add OIDC root cause to publish comment per review

Co-authored-by: openhands <openhands@all-hands.dev>

---------

Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-26 18:16:14 +00:00
Rohit Malhotraandopenhands 5d7f539303 fix(docker): ensure latest tag always points to latest stable release (#780)
Previously, the merge-manifests job unconditionally aliased main→latest
on every push to the main branch. This meant any commit to main after a
release would overwrite the `latest` multi-arch manifest with unreleased
main-branch code instead of the most recent stable tagged version.

The per-arch build already adds `latest-{arch}` tags exclusively for
stable (non-pre-release) version tags (e.g. v1.2.3), and the manifest
merge loop correctly creates the `latest` multi-arch manifest from
those arch-suffixed images. The extra main→latest alias was redundant
for tag pushes and incorrect for plain main pushes.

Remove the main→latest alias so `latest` is only produced by stable
version tag pushes, ensuring `docker pull …:latest` always gets the
highest stable release.

Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-26 18:05:00 +00:00
cc63f48a07 refactor(acp): source ACP model lists from typescript-client (closes #740) (#775)
* refactor(acp): source model lists from typescript-client registry

Replace the hand-mined CLAUDE_MODELS / CODEX_MODELS / GEMINI_MODELS lists (and
the duplicated provider metadata) with the @openhands/typescript-client ACP
registry, which mirrors the Python SDK source of truth
(openhands.sdk.settings.acp_providers). acp-providers.ts becomes a thin
adapter: it enriches each upstream record with Canvas-only UI fields (brand
icon + onboarding description) and keeps the helper functions + public export
surface unchanged, so no consumers change.

- Bump the @openhands/typescript-client pin to the #187 merge commit
  (082d4d46), which adds available_models / default_model to the registry.
- Delete the three hardcoded model lists; build ACP_PROVIDERS from
  getAcpProvider() + a small ACP_PROVIDER_UI map.
- Incidentally corrects the Gemini default to auto-gemini-2.5 (the CLI's
  auto-router default), matching the merged SDK/client.

Closes #740.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(acp): pin typescript-client to v1.23.2 tag (was SHA)

Now that typescript-client v1.23.2 is tagged/released (includes #187's ACP
registry, mirroring SDK #3389), pin to the tag instead of the raw #187 merge
SHA. v1.23.2 tracks the SDK's v1.23.2 patch line. Resolves to the same commit
as the prior SHA, so no resolved-content change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ci(acp): remove obsolete ACP providers sync check

The acp-providers-sync workflow + scripts/check-acp-providers-sync.mjs existed
to keep Canvas's hand-kept ACP registry mirror in sync with the SDK source
(agent-canvas#587). That mirror is gone — acp-providers.ts now sources its
model data from @openhands/typescript-client, which carries its own
SDK-drift check (check-acp-drift.py). So this canvas-side check is redundant
and was failing on the refactored ACP_PROVIDERS (no longer a literal array).

- Delete .github/workflows/acp-providers-sync.yml + the script.
- Drop the docs-version-sync test case that asserted the script's example.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Debug Agent <debug@example.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 19:25:08 +02:00
Graham Neubigandneubig 8cab54e0b1 Show agent-server version errors for workspaces (#742)
* Show workspace version errors in canvas

* Use current agent server version in mocks

* Pin merged typescript client dependency

* Use typescript client v1.23 release

* Clarify typescript client release pinning guidance

---------

Co-authored-by: neubig <398875+neubig@users.noreply.github.com>
2026-05-23 12:53:53 +00:00
dependabot[bot]andEngel Nyst 22f1783ca9 ci(deps): bump the actions group across 1 directory with 2 updates (#590)
Bumps the actions group with 2 updates in the / directory: [actions/upload-artifact](https://github.com/actions/upload-artifact) and [actions/download-artifact](https://github.com/actions/download-artifact).


Updates `actions/upload-artifact` from 4 to 7
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v7)

Updates `actions/download-artifact` from 4 to 8
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v8)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Engel Nyst <engel.nyst@gmail.com>
2026-05-20 22:09:52 +00:00
Rohit Malhotraandopenhands db976f2e66 fix: use PostHog prod creds only for tagged Docker releases (#666)
* fix: set VITE_APP_ENV=production in Docker build for PostHog prod creds

The Docker frontend build stage was not setting VITE_APP_ENV, so all
Docker images (including tagged releases) used the PostHog staging key.
This adds ENV VITE_APP_ENV=production to the frontend-build stage,
matching the build:lib npm path behavior.

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: use PostHog prod creds only for tagged Docker releases

Make VITE_APP_ENV a Dockerfile build arg (default empty = staging key).
The CI workflow passes VITE_APP_ENV=production only when building from
a tagged release (refs/tags/v*), so PR and main-branch images keep the
staging key while release images get the production key.

Co-authored-by: openhands <openhands@all-hands.dev>

---------

Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-20 14:55:56 +00:00
Rohit Malhotraandopenhands 979e64fe19 feat: add Docker CI to build all-in-one image with agent-server + automation + frontend (#634)
* feat: add Docker CI to build all-in-one image with agent-server + automation + frontend

Adds a GitHub Actions workflow (.github/workflows/docker.yml) that builds and
publishes ghcr.io/openhands/agent-canvas — a single Docker image combining:

  1. Agent Server (ghcr.io/openhands/agent-server base image from SDK repo)
  2. Automation server (pip-installed from openhands-automation)
  3. agent-canvas frontend (static build from this repo)

The automation server is pip-installed rather than copied from its Docker image
because both services share openhands-sdk, fastapi, uvicorn, pydantic, httpx
etc. — installing into the agent-server's Python 3.13 deduplicates all shared
packages. Only automation-specific deps (asyncpg, sqlalchemy, boto3, …) are
added on top.

An entrypoint script starts all three services and a static-server proxy that
unifies them behind a single port (default 8000):
  /api/automation/* → automation backend (:18001)
  /api/*            → agent-server (:18000)
  /*                → static frontend + SPA fallback

Workflow triggers:
  - Push to main: builds and pushes with branch + SHA tags
  - v* tags (releases): also pushes semver tags (1.2.3, 1.2, 1, latest)
  - PRs: builds, pushes SHA-tagged image, updates PR description with
    pull/run instructions (same pattern as the SDK repo)
  - workflow_dispatch: supports overriding base image and automation version

Files added:
  - docker/Dockerfile (multi-stage: frontend build + agent-server base)
  - docker/entrypoint.sh (process manager for all three services)
  - .dockerignore
  - .github/workflows/docker.yml

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: build multi-arch Docker images (amd64 + arm64)

Adds QEMU setup for cross-compilation and defaults the platform matrix
to linux/amd64,linux/arm64 so the image works on both Intel and Apple
Silicon machines.

Co-authored-by: openhands <openhands@all-hands.dev>

* refactor: rewrite Docker workflow to match SDK repo structure

Replace the single-job QEMU approach with the same architecture-matrix
pattern used by the SDK repo's server.yml:

  1. build-and-push-image — matrix over {amd64, arm64} with native runners
     (ubuntu-24.04 for amd64, ubuntu-24.04-arm for arm64). Each job pushes
     arch-suffixed tags (e.g. sha-abc1234-amd64) and uploads build-info
     artifacts.

  2. merge-manifests — downloads both arch build-infos, strips the -amd64
     suffix from amd64 tags to derive manifest tags, and creates multi-arch
     manifests via `docker buildx imagetools create`.

  3. consolidate-build-info — aggregates all build-info and manifest-info
     artifacts into a single JSON summary (PR-only).

  4. update-pr-description — renders the summary into the PR body between
     AGENT_CANVAS_DOCKER_START/END markers.

Native runners avoid the 3-5× slowdown of QEMU emulation for arm64
builds.

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: sanitize branch names in Docker tags (/ is not allowed)

Branch names like 'feat/docker-ci' produce invalid Docker tags because
'/' is forbidden in tag names. Replace '/' with '-' so the tag becomes
'feat-docker-ci-amd64'.

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: default automation to SQLite and fix wait blocking proxy startup

Two bugs:

1. The automation server defaults to PostgreSQL on localhost, which
   doesn't exist in the all-in-one container. Default AUTOMATION_DB_URL
   to sqlite+aiosqlite:// so it works out of the box. Users can override
   with a real Postgres URL for production.

2. The bare 'wait' command waited for ALL background children — including
   the long-running agent-server and automation processes — so the
   static-server/proxy on port 8000 never started. Fix by waiting only
   for the wait_for_port subshell PIDs.

Verified locally: all three services start, endpoints respond correctly,
no more scheduler ConnectionRefusedError.

Co-authored-by: openhands <openhands@all-hands.dev>

* feat: add VOLUME directives for persistence and project mounts

Declare /home/openhands/.openhands (settings, secrets, conversations,
automation SQLite DB) and /projects (user code) as Docker volumes so
data survives container restarts by default. Users should bind-mount
these for durable persistence:

  docker run -v ~/.openhands:/home/openhands/.openhands \
             -v ~/projects:/projects \
             -p 8000:8000 ghcr.io/openhands/agent-canvas

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: set OH_SECRET_KEY default and pre-create persistence dirs

Three issues fixed:

1. OH_SECRET_KEY was not set → agent-server refused to return encrypted
   secrets → conversation creation failed with 503. Set the same static
   default used by dev-safe.mjs / dev-docker.mjs.

2. Persistence dirs (conversations, bash_events, automation DB) were not
   pre-created → the openhands user got PermissionError when the VOLUME
   directive created them as root. Pre-create with correct ownership
   before the USER switch in the Dockerfile.

3. Set OH_PERSISTENCE_DIR, OH_CONVERSATIONS_PATH, OH_BASH_EVENTS_DIR
   defaults in the entrypoint (matching dev-docker.mjs) so data lands
   under the well-known ~/.openhands tree.

Verified locally: all three services start clean, no warnings about
OH_SECRET_KEY, SQLite migrations apply successfully.

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: merge main and remove stale dev-docker.mjs references

Main removed scripts/dev-docker.mjs (Docker is no longer a dependency of
the npm package flow). Update comments in docker.yml, entrypoint.sh, and
AGENTS.md that referenced the deleted file.

Co-authored-by: openhands <openhands@all-hands.dev>

* feat: centralize config into config/defaults.json (single source of truth)

All version pins, port defaults, persistence paths, package names, and
the dev secret key now live in config/defaults.json. Consumers read from
it instead of hardcoding values:

- scripts/dev-safe.mjs: reads via JSON.parse(readFileSync(...))
- scripts/dev-with-automation.mjs: same
- scripts/check-sdk-version-sync.mjs: same (no longer regex-parses JS)
- docker/Dockerfile: config-gen build stage converts JSON to
  /opt/agent-canvas/defaults.env (shell-sourceable)
- docker/entrypoint.sh: sources defaults.env at startup; also adds
  session API key auto-generation so the image doesn't run wide-open
- .github/workflows/docker.yml: reads versions from JSON in a setup
  step (no more hardcoded env vars)

To bump a version, edit config/defaults.json only.

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: address PR review feedback (#634)

- Fix PID tracking bug: move PIDS+=($!) inside if/elif branches so the
  else (automation-not-found) path doesn't add a stale PID
- chmod 600 session API key file to prevent credential leak
- Warn when using insecure default OH_SECRET_KEY in Docker entrypoint
- Add try/catch + field validation for config/defaults.json loading in
  check-sdk-version-sync.mjs
- Fix semver tag parsing: strip pre-release/build metadata, only create
  abbreviated tags (major.minor, major, latest) for stable releases
- Sanitize branch names for Docker tags (tr invalid chars, strip leading
  dot/dash) to handle branches with #, @, spaces, etc.
- Add arch validation before manifest merge (assert both amd64.json and
  arm64.json exist)
- Remove $schema reference to non-existent defaults.schema.json

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: remove hardcoded version defaults from Dockerfile

Replace hardcoded ARG defaults (AGENT_SERVER_IMAGE, AUTOMATION_VERSION)
with empty ARGs. Values are always derived from config/defaults.json:
- CI: reads JSON in the workflow config step, passes --build-arg
- Local: new scripts/docker-build.mjs helper reads JSON and invokes
  docker build with the correct --build-arg values

Added npm run build:docker convenience script.

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: stabilize snapshot tests and auto-generate Docker secret key

Two fixes:

1. **Flaky snapshot tests**: The 'Local pagination fixture' mock conversation
   used a fixed absolute timestamp (PAGINATION_BASE_TIME = May 13, 2026) for
   its created_at/updated_at, while 'Errored Project' used a relative
   timestamp (now - 7d). As real time progressed past the crossover point,
   their sort order in the sidebar flipped, causing 30/73 snapshot diffs on
   every PR. Fix: use relative timestamps (now - 6d) for the pagination
   fixture's conversation listing fields. The internal event timestamps
   (used by pagination tests) still use PAGINATION_BASE_TIME — only the
   sidebar ordering is affected.

2. **Docker OH_SECRET_KEY**: The entrypoint used a static insecure default
   for OH_SECRET_KEY and warned about it. Now mirrors the session API key
   pattern: auto-generate a cryptographic random key on first run, persist
   it to ~/.openhands/agent-canvas/secret-key.txt, and reuse on restart.
   Users can still override via the OH_SECRET_KEY env var. Removed the
   now-unused CONFIG_SECRET_KEY from the Docker defaults.env generation.
   Also deduped STATE_DIR computation (was repeated for session key path).

Co-authored-by: openhands <openhands@all-hands.dev>

* docs: update AGENTS.md with mock timestamp and Docker secret key notes

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: include canvas_ui tool in Docker image

The Docker image was missing the tools/ directory and OH_EXTRA_PYTHON_PATH,
so the agent-server couldn't import canvas_ui_tool.py when the frontend
sent canvas_ui in the conversation tools list. This caused:

  HTTP 500: ToolDefinition 'canvas_ui' is not registered

Fix: COPY tools/ into the image and set OH_EXTRA_PYTHON_PATH in the
entrypoint, matching what scripts/dev-safe.mjs already does for local dev.

Co-authored-by: openhands <openhands@all-hands.dev>

---------

Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-20 04:24:45 +00:00
Robert Brennanandopenhands b26e85ecba ci(snapshot-tests): support pull_request events from forks (#633)
The Snapshot Tests workflow assumed every PR's head branch lives on the
upstream repo. Two places break for cross-repo (fork) PRs:

1. The "Check out repository" step uses
   `ref: ${{ github.head_ref }}` without `repository:`, so
   actions/checkout defaults to `github.repository` (the upstream repo)
   and errors out with
       A branch or tag with the name '<head-branch>' could not be found
   The subsequent "Post snapshot report to PR" step has `if: always()`,
   runs against an empty working directory, and fails with
       Cannot find module 'tests/e2e/snapshots/scripts/post-snapshot-comment.mjs'
   - which is what surfaces in the failing run's logs.

2. Once the checkout is fixed, `post-snapshot-comment.mjs` still tries
   to POST a PR comment via the REST API. `pull_request` workflows
   triggered from a fork get a `GITHUB_TOKEN` that is downgraded to
   read-only regardless of the `permissions:` block, so the POST 403s
   and the whole script exits 1 (taking the workflow with it). The
   sibling code path (`publishImages` pushing snapshot artifacts) is
   already wrapped in try/catch and degrades to a warning — the comment
   post should do the same.

Fixes:

* Set `repository: ${{ github.event.pull_request.head.repo.full_name
  || github.repository }}` and
  `ref: ${{ github.event.pull_request.head.sha || github.ref_name }}`
  on the checkout, so fork PRs check out the head commit from the fork
  while `push` / `workflow_dispatch` events keep their previous
  behavior. Switching the PR-event ref from a branch name to the exact
  head SHA also pins each run to the commit that triggered it, which
  is more robust against branch updates while the job is queued.
* Wrap `postFreshComment` in try/catch in
  `post-snapshot-comment.mjs`. On a 403 from a fork PR's token the
  script now logs a warning and continues, so it still writes
  `has_changes` to `$GITHUB_OUTPUT` and the downstream
  "Fail if snapshot comparison found differences" step keeps working.

Out of scope: making the workflow able to actually post comments /
push artifact images from fork PRs. That would require migrating to
`pull_request_target` (or a dedicated post-run workflow), with the
attendant supply-chain review. This PR's only goal is to stop the job
from failing because of where the branch is hosted.

Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-19 16:05:52 +00:00
56fc790076 ci: detect drift between TS ACP_PROVIDERS mirror and SDK source (#630)
Closes #587.

PR #416 introduced src/constants/acp-providers.ts as a hand-kept
TypeScript mirror of the Python registry in
openhands-sdk/openhands/sdk/settings/acp_providers.py
(OpenHands/software-agent-sdk). Drift between the two is hazardous:
during PR #416's E2E we briefly shipped
["npx","-y","@openai/codex","acp"], which is not a valid ACP server,
and the agent-server deadlocked on the handshake instead of failing
loudly.

This commit adds the minimum infrastructure to catch that class of
drift before it lands:

- scripts/check-acp-providers-sync.mjs fetches the SDK file (from a
  configurable ref, default `main`), parses both registries with a
  string-aware brace matcher, and diffs them on the three fields
  canvas mirrors: key, display_name, default_command. The richer SDK
  record (api_key_env_var, session mode, agent_name_patterns, etc.)
  is intentionally not compared because canvas does not mirror it.
  --sdk-file lets the script run offline against a local SDK
  checkout for development.
- .github/workflows/acp-providers-sync.yml runs the check on PRs
  touching the mirror or the script, on push to main, on a daily
  cron (to catch SDK-side drift that did not ping us), via
  workflow_dispatch, and via repository_dispatch (so the SDK repo
  can trigger us when it changes acp_providers.py — payload key
  `sdk_ref`).

Co-authored-by: Debug Agent <debug@example.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 15:46:01 +02:00
4f46598460 Clarify OpenHands backend login host (#423)
* Add backend modal visual snapshot

Co-authored-by: openhands <openhands@all-hands.dev>

* Clarify OpenHands backend login host

Co-authored-by: openhands <openhands@all-hands.dev>

* Clarify OpenHands Cloud login copy

Co-authored-by: openhands <openhands@all-hands.dev>

* Add missing i18n translations and move host into connection box

- Translate BACKEND$HOST_HELPER, BACKEND$HOST_DOCS_LINK, and
  BACKEND$AUTH_METHOD_HELPER into all 14 non-English locales.
- Move the Host input inside the bordered connection card for cloud-add
  mode so host, login, and API key are visually grouped.
- Keep the host input in a stable DOM position (never unmounted when
  kind flips mid-keystroke) by conditionally styling the wrapper
  rather than rendering two separate input trees.

Co-authored-by: openhands <openhands@all-hands.dev>

* Update add-backend-modal snapshot

Co-authored-by: openhands <openhands@all-hands.dev>

* Reorder: Host + API Key first, then OR Login with OpenHands Cloud

The connection box now shows:
1. Host input + helper text
2. API Key input + docs link
3. ── OR ──
4. Login with OpenHands Cloud button

This groups the manual credentials together and presents the
OAuth device flow as the alternative, which is a clearer mental
model.

Also removes the now-unused BACKEND$AUTH_METHOD_HELPER translation
key.

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: update baseline snapshots [skip ci]

* Remove prefilled default host; Login with Cloud always uses app.openhands.dev

- Host field starts empty — no confusing 'use the default' guidance.
- 'Login with OpenHands Cloud' always targets app.openhands.dev
  regardless of what's in the host field, and fills both host and
  API key on success.
- Updated helper text to simply say 'Enter the URL of your OpenHands
  Cloud or self-hosted Agent Server.'
- Removed now-unused BACKEND$AUTH_METHOD_HELPER translation key.
- Updated tests to reflect no-prefill behavior.

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: update baseline snapshots [skip ci]

* Remove redundant helper text; form layout is self-explanatory

The Login with OpenHands Cloud button already handles the cloud
case, so the helper text about entering a Cloud URL was confusing.
Removed HOST_HELPER, HOST_DOCS_LINK translation keys and the
OPENHANDS_CLOUD_DOCS_URL constant.

The form now reads cleanly:
  Host  +  API Key  →  OR  →  Login with OpenHands Cloud

Co-authored-by: openhands <openhands@all-hands.dev>

* Add host helper: 'Enter the URL of your agent server or self-hosted OpenHands Cloud'

Links 'self-hosted OpenHands Cloud' to
https://github.com/All-Hands-AI/OpenHands-Cloud

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: update baseline snapshots [skip ci]

* Login button uses host field; prefill cloud default; add OAuth hint

- Host prefilled with https://app.openhands.dev (self-hosted users
  can change it to their own deployment).
- Login button now uses the host from the field (not hardcoded),
  so self-hosted OpenHands Cloud deployments can also use OAuth.
- Added hint below login button: 'Works with OpenHands Cloud or
  your self-hosted OpenHands Cloud deployment.'

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: update baseline snapshots [skip ci]

* Two-column Add Backend modal with i18n translations

Redesign the Add Backend modal as a two-column layout:
- Left column: manual connection (Name, Host, API Key + Connect button)
- Right column: OpenHands Cloud OAuth login with Advanced host override
- Vertical OR divider separating the two approaches

Add 5 new i18n translation keys with all 15 language translations:
- BACKEND$CLOUD_TITLE, BACKEND$CLOUD_DESCRIPTION, BACKEND$CONNECT,
  BACKEND$ADVANCED, BACKEND$NAME_HELPER

Update tests for the new layout (add-backend-modal, backend-selector).

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: lint and prettier formatting in backend-form-modal

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: stabilize add-backend snapshot test with server_info mock and networkidle wait

The e2e test was timing out on the dropdown trigger click because the
backend health check was making real requests to the dev server. Mock
the /server_info endpoint and wait for networkidle before interacting.

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: replace networkidle with targeted element wait in snapshot test

The networkidle wait was consuming most of the 60s test timeout due to
periodic health check polls. Wait for the specific dropdown trigger
element instead.

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: use hover instead of click to open backend dropdown in snapshot test

The BackendSelector uses openOnHover=true. Playwright's click first
hovers (opening the menu), then clicks the toggle (closing it).
Using hover() keeps the menu open for the subsequent menu item click.

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: update baseline snapshots [skip ci]

* ci: trigger CI after snapshot baseline update

Co-authored-by: openhands <openhands@all-hands.dev>

* Render backend host helper text

Co-authored-by: openhands <openhands@all-hands.dev>

* Update self-hosted cloud repository link

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: use current cloud login host

---------

Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-16 16:55:44 -04:00
14d2e9454b test(snapshot): changes tab diff viewer + backend management UI (6 tests) (#450)
* test(snapshot): changes tab diff viewer + backend management UI (6 tests)

Pre-seed MOCK_GIT_CHANGES with M/A/D entries (using AgentServerGitChangeStatus
values: UPDATED/ADDED/DELETED) so changes-tab tests can exercise the file list,
Monaco diff viewer, and deleted-file placeholder without per-test MSW manipulation.

Expose window.__setMockGitChanges__ so the empty-state test can clear the list
after boot and trigger a React Query refetch via __TEST_INVALIDATE_QUERIES__,
avoiding a full page reload that would reinitialise module state.

Backend management tests exercise the selector dropdown, add-backend modal, and
manage-backends modal — all driven by localStorage seeding via addInitScript.

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: update baseline snapshots [skip ci]

* ci: trigger re-run against CI-generated baselines

* fix(snapshot-tests): mask Monaco editor for stable CI screenshots; fix unit test

- changes-tab spec: mask data-testid=editor-container so Monaco's sub-pixel
  font hinting (which varies per OS) doesn't cause false pixel-diff failures
- mock-conversation-handlers test: update assertion to match the new pre-seeded
  MOCK_GIT_CHANGES (3 M/A/D entries) instead of the previous empty array

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: update baseline snapshots [skip ci]

* ci: trigger re-run against CI-regenerated baselines (Monaco mask + unit test fix)

* fix(snapshot-tests): normalize RandomTip height via addStyleTag for stable empty-state screenshot

RandomTip renders a randomly-chosen tip whose line-count varies, causing the
flex-1 container above it to have different heights across runs. Fix by injecting
a CSS rule via page.addStyleTag() that pins .text-m.bg-tertiary.p-4 to 80px
(visibility:hidden so the variable text is invisible) — layout is now deterministic.
Switch back to screenshotting the full files-tab panel since dimensions are stable.

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: update baseline snapshots [skip ci]

* ci: trigger re-run against baselines (empty-state RandomTip height fix)

* fix(snapshot-tests): use inner content div for empty-state screenshot to avoid left-strip artefact

Screenshot files-tab's last direct div child (the flex-1 content wrapper)
instead of the outer main element.  During CI baseline generation the outer
main's bounding box occasionally captured a ~30px left-panel overlay artefact
that made the baseline permanently diverge from subsequent verification runs.
Targeting the inner wrapper excludes the outer-element overflow while still
showing the full empty-state (icon + 'no changes yet' text + hidden tip area).

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: update baseline snapshots [skip ci]

* ci: validate against fresh inner-div empty-state baseline

* test(snapshot): extended backend UI flows — 12 tests, 19 screenshots

Add backends-extended.snapshot.spec.ts covering 8 behaviour flows
with iterative screenshot captures at each state transition:

Flow 1a  Blank add form — Save disabled until name+host filled
Flow 1b  Local backend — Save enabled with name+host, no API key needed
Flow 1c  Cloud backend — Save disabled without API key, enabled with it
Flow 2a  Host auto-infers Local kind; OAuth section disappears
Flow 2b  Cloud-domain URL keeps Cloud kind; OAuth section shows
Flow 2c  Manual kind selection locks type (touchedKind=true) even when
         a cloud URL is later typed into the Host field
Flow 3   OAuth Login button disabled while host is empty; enabled once filled
Flow 4   Remove backend: shows ConfirmationModal → Cancel keeps row →
         Confirm removes it from the list (4 screenshots)
Flow 5   Edit modal pre-populates name/host/key from stored backend
Flow 6   Switch active backend: environment-switch overlay captured via
         page-level screenshot + animation override so the card is
         opaque at frame-0; after-switch state verified via selector label
Flow 7   Whitespace-only host keeps Save disabled; syntactically invalid
         URL is accepted by the frontend (no URL-format validation)
Flow 8   Cancel add form: dismisses modal, Manage Backends confirms no
         phantom entry was saved

Notable decisions:
- Uses body[data-environment-switching="true"] as the early DOM signal
  before React paints the portal div for the switch overlay
- Adds inline style-tag override before the overlay screenshot because
  .environment-switch-overlay > div has opacity:0 at animation frame 0;
  Playwright's animations:"disabled" pauses there, making the card
  invisible without the override
- Backends seeded via page.addInitScript localStorage injection so
  tests are fully self-contained with no MSW state dependency

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: update baseline snapshots [skip ci]

* ci: validate extended backend snapshot tests against CI baselines

* ci: always post snapshot PR comment even when test generation step fails

The 'Post snapshot report to PR' step was skipped whenever 'Generate
current PR snapshots' exited non-zero (e.g. a test crash like a hidden
element, not just a snapshot diff). GitHub Actions skips steps without
an always() guard when a prior step fails.

Add always() so the comment is posted regardless — showing diffs or
the test failure output — which was the intended behaviour.

Co-authored-by: openhands <openhands@all-hands.dev>

* ci: fix snapshot comment - remove tracked screenshots, add crash reporting

Three fixes:

1. Remove 28 git-tracked snapshot PNGs from this branch.
   These were committed by the old baseline-in-git workflow before #482
   migrated to artifact storage. Because they stayed tracked (gitignore
   doesn't untrack already-indexed files), every CI checkout put them in
   tests/e2e/__snapshots__/ BEFORE the baseline artifact was downloaded.
   The Save step then copied them into /tmp/main-baselines, making the
   new tests appear as 'Unchanged' instead of 'New' in the PR comment.

2. Add 'Clear snapshot directory before downloading baselines' step.
   Wipes tests/e2e/__snapshots__/ before the artifact download so any
   future accidentally-tracked files can never contaminate the baseline.

3. Surface test crashes in the PR comment.
   - Generate step gets continue-on-error + an id so subsequent steps
     can read its outcome.
   - GENERATE_OUTCOME is passed to the comment script.
   - If outcome == 'failure', a GitHub-flavoured WARNING callout is
     prepended to the comment with a direct link to the CI run logs.
   - A dedicated 'Fail if snapshot generation had test crashes' step
     restores the job failure that continue-on-error absorbed.

Co-authored-by: openhands <openhands@all-hands.dev>

* ci: use PR number in snapshot concurrency group for cleaner cancellation

The previous group used github.ref which resolves to refs/pull/{N}/merge
for PR events — correct but opaque. Using github.event.pull_request.number
makes the grouping explicit and human-readable (snapshot-tests-450), and
falls back to github.ref for main pushes and workflow_dispatch.

cancel-in-progress: true was already set, so new commits already cancelled
prior runs. This just makes the intent clearer.

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: syntax error in post-snapshot-comment.mjs (] vs ) in lines.push)

lines.push(...) was accidentally closed with ]; instead of ); after
splitting the original lines = [...] array literal into a push call.
Caused a SyntaxError at startup, preventing any comment from being posted.

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: snapshot test disabled states, changes-tab crash, and CI false-failures

Three fixes:

1. BrandButton disabled visual styling (brand-button.tsx)
   disabled:opacity-30 pseudo-class was not applying in Vite dev mode
   (Tailwind v4 + postcss-prefix-selector interaction), making disabled
   and enabled buttons visually identical in snapshot screenshots.
   Fix: add isDisabled conditional class directly ('opacity-30
   cursor-not-allowed pointer-events-none') so the disabled appearance
   is applied regardless of whether :disabled pseudo-class works.

2. changes-tab test crash (changes-tab.snapshot.spec.ts)
   Test waited for data-testid='files-tab' but the right panel always
   starts CLOSED (isRightPanelShown = false is session-only Zustand
   state; sanitizeStoredState strips any persisted rightPanelShown key).
   Fix: click data-testid='right-panel-toggle' after navigation to open
   the panel before waiting for files-tab. Also remove the no-op
   rightPanelShown: true from the localStorage seed.

3. CI false-failures for new snapshot tests (snapshot-tests.yml +
   post-snapshot-comment.mjs)
   The 'Fail if comparison found differences' step fired on
   'missing baseline' failures (expected for new tests in a PR) as
   well as actual pixel-diff failures.
   Fix:
   - post-snapshot-comment.mjs outputs has_changes=true/false to
     GITHUB_OUTPUT (true only when changed.length > 0, i.e. real diffs)
   - 'Fail if' step now checks steps.post-comment.outputs.has_changes
     == 'true' instead of compare.outcome == 'failure', so PRs that
     only add new snapshot tests pass CI cleanly.

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: reject invalid host URLs in backend form; use http for local addresses

Two related fixes to backend host validation / normalisation:

1. isValidHostUrl() — reject invalid host strings
   canSubmit previously only checked host.trim().length > 0, so
   garbage like 'not://:::a valid url!!!' passed through and enabled
   the Save button. isValidHostUrl() adds two checks before the URL
   constructor: (a) the trimmed value must be non-empty, (b) it must
   contain no whitespace. This catches the test-case input whose spaces
   are the tell-tale sign of a malformed value.

2. normalizeHost() — http:// for local addresses
   Bare hostnames (no explicit scheme) were unconditionally prepended
   with https://, but local servers almost never have TLS certificates.
   The new isLocalAddress() helper detects localhost, 127.x, RFC-1918
   private ranges (10.x, 192.168.x, 172.16-31.x), .local / mDNS names,
   and single-label hostnames — all get http:// instead of https://.
   Hostnames with dots that are not in those ranges (e.g. app.all-hands.dev)
   still default to https://. Explicit http:// or https:// prefixes are
   always preserved as-is.

Test update: the 'backend-add-invalid-url-accepted' snapshot is renamed
to 'backend-add-invalid-url-disabled' and the assertion flips from
not.toBeDisabled() → toBeDisabled(), reflecting the new behaviour.

Co-authored-by: openhands <openhands@all-hands.dev>

* feat: inline error feedback on Name and Host fields in BackendForm

Three parts:

1. SettingsInput gains error / showRequiredTag / onBlur props
   - error?: string — red border on the input plus a small red alert
     paragraph below it (role=alert, data-testid=${testId}-error, linked
     via aria-describedby).
   - showRequiredTag?: boolean — renders a red * after the label to
     signal that the field is mandatory, consistent with OptionalTag.
   - onBlur?: () => void — forwarded directly to the <input>.
   - aria-invalid is set automatically when error is truthy.

2. BackendForm wires touched state → errors → inputs
   - nameTouched / hostTouched (both false on open, set on blur)
   - nameError: 'Name is required' when touched + empty
   - hostError: 'Host is required' when touched + blank/whitespace;
                'Enter a valid URL (e.g. http://localhost:8080)' when
                touched + non-empty but fails isValidHostUrl()
   - Both name and host SettingsInputs get showRequiredTag, the
     computed error, and onBlur={() => setXTouched(true)}.
   Errors are intentionally suppressed until blur so the form does not
   scold the user before they have had a chance to type anything.

3. Three snapshot tests call .blur() after .fill() to reveal errors
   - backend-add-name-only-disabled: focus+blur empty host → 'Host is
     required' appears below the Host field.
   - backend-add-whitespace-host-disabled: blur after fill('   ') →
     same 'Host is required' (whitespace counts as empty).
   - backend-add-invalid-url-disabled: blur after invalid URL fill →
     'Enter a valid URL...' appears below the Host field.
   The backend-add-blank-disabled snapshot is unchanged (neither field
   touched, no errors yet — correct for the fresh-open state).

New i18n keys: BACKEND$NAME_REQUIRED, BACKEND$HOST_REQUIRED,
BACKEND$HOST_INVALID (English only; other locales fall back to en).

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: prettier formatting on nameError / hostError ternaries

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: disable OAuth Login button until name and host are both valid

Previously the 'Login with OpenHands' button was enabled as soon as
a non-empty host was typed, even when the Name field was still blank.
This let users go through the full OAuth device-flow only to find they
still couldn't save because the name was missing.

Gate isDisabled on !name.trim() || !isValidHostUrl(host) so the button
stays disabled until the form is actually ready to save (modulo the
API key that OAuth itself will provide).

Update Flow 3 snapshot test to fill the name before asserting the
button becomes enabled, and update the test description accordingly.

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: address PR review feedback (#450)

IPv6 parsing fixes (normalizeHost / isLocalAddress):
- normalizeHost: handle bracket notation [::1]:8080 (extract ::1),
  bare IPv6 addresses with multiple colons (use whole string as
  hostname), and regular host:port as before — prevents split(':')[0]
  from grabbing only the first segment of a multi-colon IPv6 address
- isLocalAddress: strip brackets before comparison; add :: (any-addr),
  ::ffff:127.x.x.x (IPv4-mapped loopback), fe80::/10 (link-local),
  fc00::/7 (unique local); tighten single-label check to exclude
  addresses that contain colons (bare IPv6 non-local addresses)

Mark fields touched on submit attempt:
- handleSubmit sets nameTouched + hostTouched when !canSubmit so
  inline errors appear for keyboard users who press Enter on an
  incomplete form

Snapshot workflow comparison-crash detection:
- Pass COMPARE_OUTCOME=${{ steps.compare.outcome }} to post-comment
- post-snapshot-comment.mjs reads COMPARE_OUTCOME and prepends a
  '[!WARNING]' block when the comparison step itself crashed
  (timeout/OOM) so the comment accurately reflects the run state
  instead of silently showing an incomplete/empty diff table

Remove unnecessary serial mode from backends-extended snapshot suite:
- Each test calls setupPage() with fresh state on its own Playwright
  page; no shared mutable state exists between tests, so serial is
  unnecessary and slows the suite

Co-authored-by: openhands <openhands@all-hands.dev>

---------

Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-15 23:14:30 -04:00
Rohit Malhotraandopenhands 63704f65e5 test: rename sidebar nav label "New" → "Chats" to verify snapshot CI diff comment (#497)
* test: rename sidebar nav label New → Chats to trigger snapshot diff

Intentional one-line change to verify that the snapshot CI workflow
correctly posts a PR comment showing the expected/actual/diff images.

Co-authored-by: openhands <openhands@all-hands.dev>

* fix(snapshot-ci): save comparison test-results before update step clears them

Root cause: Playwright wipes its output directory (test-results/) at the
start of each new run.  The workflow runs the tests twice:
  1. npm run test:e2e:snapshots        → comparison, writes *-diff.png files
  2. npm run test:e2e:snapshots:update → regenerates baselines, clears
                                         test-results/ first, no diffs written

By the time post-snapshot-comment.mjs runs, all diff files are gone.
diffBySnapshotName is always empty, so every snapshot is classified as
"unchanged" even when Playwright reported 16 failures.

Fix:
- Add a "Save comparison test-results" step immediately after the
  comparison run that copies test-results/ to /tmp/comparison-results
  before the update pass can delete them.
- Pass COMPARISON_RESULTS_DIR=/tmp/comparison-results to the comment script.
- In post-snapshot-comment.mjs, read TEST_RESULTS_DIR from
  COMPARISON_RESULTS_DIR env var (falls back to "test-results" for local use).

Co-authored-by: openhands <openhands@all-hands.dev>

* docs: document snapshot CI comparison-results ordering in AGENTS.md

Co-authored-by: openhands <openhands@all-hands.dev>

* revert: restore sidebar nav label to New

Co-authored-by: openhands <openhands@all-hands.dev>

---------

Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-15 18:34:00 -04:00
Rohit Malhotraandopenhands 77b7012993 ci: add resolution guidance to failing snapshot PR comment (#489)
* ci: add resolution guidance to failing snapshot PR comment

When snapshots differ from the main baseline, the comment now includes
a short blockquote explaining both resolution paths:
- merge the latest main (in case upstream baselines have moved)
- add the update-snapshots label to acknowledge intentional changes

* ci: wait for main baseline workflow before downloading artifact

Before downloading the snapshot-baselines artifact on PR runs, resolve
main's current HEAD SHA and check if the snapshot-tests.yml run for
that exact commit is still in-progress or queued. If so, poll every
10 s (up to 10 min) until it completes, then proceed.

This eliminates the race condition where a PR job starts while main's
baseline upload is still in-flight, causing it to pull the previous
(stale) artifact and produce false snapshot failures.

The wait targets only the run for the current HEAD SHA — not an older
in-progress run from a different commit — so two rapid commits to main
can't trick the check into waiting for the wrong run.

Also bumps job timeout-minutes from 20 → 30 to accommodate the wait.

---------

Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-15 19:03:57 +00:00
e9b5e07293 ci: store snapshot baselines as GitHub Actions artifacts instead of git (#482)
* ci: store snapshot baselines as GitHub Actions artifacts, not in git

Move baseline PNG storage from git to a 90-day GitHub Actions artifact
named 'snapshot-baselines', uploaded on every push to main.

- PRs download the latest main-branch artifact and run Playwright
  comparison against it; no more checked-in PNGs causing merge conflicts.
- New 'post-snapshot-comment.mjs' script classifies each snapshot as
  Changed/New/Unchanged, commits images to .pr/snapshots/<run_id>/ and
  posts a PR comment with collapsed <details> sections showing
  side-by-side expected/actual/diff images via raw.githubusercontent.com.
- For fork PRs or if push fails, falls back to a workflow run link for
  downloading the 'snapshot-test-results' artifact.
- Force-refresh baselines any time via workflow_dispatch force_update=true
  (replaces the old update_snapshots=true flow that committed PNGs to git).
- Remove 44 baseline PNGs from git; gitignore tests/e2e/__snapshots__/.
- Update AGENTS.md with the new workflow model.

Co-authored-by: openhands <openhands@all-hands.dev>

* ci: fix bootstrap case — pass CI when no baseline artifact exists yet

When no main-branch 'snapshot-baselines' artifact has been uploaded yet
(e.g. this very first run after merging from an old baseline-in-git flow),
the comparison step fails because Playwright has nothing to compare against.
Gate the 'Fail if differences' step on has_baselines==true so the bootstrap
PR passes with all snapshots shown as new. Once it merges to main the
artifact is created and subsequent PRs compare normally.

Also derive the PR comment status from the classification (changed.length > 0)
rather than from TEST_OUTCOME, which is 'failure' in the bootstrap case
despite zero actual regressions.

Co-authored-by: openhands <openhands@all-hands.dev>

* ci: delete stale comment and re-post on each push; always embed new snapshot images

- Replace PATCH-in-place with DELETE + POST so every push posts a fresh
  comment whose image URLs reference the current run's .pr/snapshots/<run_id>/.
  Editing in-place would leave raw.githubusercontent.com URLs pointing at
  the previous run's images once new images are committed under a new run_id.
- Embed new snapshot images inside the collapsed <details> section when
  commitSha is available; add a fallback artifact-download link when the
  push fails (e.g. fork PRs).
- Handle 204 No Content returned by DELETE in githubFetch.

Co-authored-by: openhands <openhands@all-hands.dev>

* ci: fix find-run to query artifacts API by name, not workflow runs by status

The previous approach (find latest successful run of snapshot-tests.yml on
main) would match old runs that predate the artifact upload step, causing
actions/download-artifact to hard-fail with 'Artifact not found' before the
comparison or comment steps could run.

Fix: query the artifacts REST API directly for name=snapshot-baselines,
filtering to non-expired artifacts from the main branch. This guarantees
we only match runs that actually uploaded the baseline artifact.

Also add continue-on-error: true to the download step as a safety net
against the artifact expiring between the API lookup and the download.

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: snapshot images for run 25929925639 [skip ci]

* ci: replace .pr/snapshots on each run instead of accumulating per-run dirs

Previously each CI run committed images under .pr/snapshots/<run_id>/, so
reruns would accumulate multiple directories on the PR branch. The PR comment
always pointed to the current run's images (via SHA in the raw.githubusercontent
URL), but old directories silently piled up.

Fix: use a fixed .pr/snapshots/ path and git rm -rf --ignore-unmatch it before
staging new images. Each run completely replaces the previous images rather than
appending alongside them. Raw URLs still use the commit SHA so they remain stable
per push.

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: snapshot images for run 25930435218 [skip ci]

* ci: allow review_requested on draft same-repo PRs to trigger pr-review

GitHub does not fire pull_request events for review_requested on draft PRs —
only pull_request_target fires. The existing if condition rejected
pull_request_target for same-repo PRs via the fork check, so requesting
all-hands-bot or openhands-agent on a draft PR was always silently skipped.

Add a carve-out: pull_request_target is also accepted for same-repo PRs
when draft==true AND action==review_requested. Non-draft same-repo PRs are
unaffected — they continue to be handled by the pull_request event, and the
draft==true guard prevents pull_request_target from also running (no duplicate).

Co-authored-by: openhands <openhands@all-hands.dev>

* ci: add update-snapshots label bypass for intentional snapshot changes

When snapshot diffs are expected (UI redesign, intentional change, etc.) the
author now adds the 'update-snapshots' label to the PR to acknowledge them:

- Fail step gains a !contains(labels, 'update-snapshots') guard so CI passes
  even when Playwright reports differences.
- The PR comment status adjusts: ❌ 'N snapshots differ — add label to
  acknowledge' when unapproved, ✅ 'N snapshots changed — acknowledged via
  label' when approved.
- The snapshot workflow now triggers on labeled/unlabeled events so that adding
  or removing the label immediately re-runs CI with the current label state in
  scope (no manual re-run or empty commit needed).
- New baselines are uploaded automatically when the PR merges to main, so no
  separate 'regenerate on main' step is needed.

Co-authored-by: openhands <openhands@all-hands.dev>

* docs: update snapshot testing section in AGENTS.md

Add details on: artifact lookup by name, delete-then-post comment behavior,
fixed .pr/snapshots/ path (no accumulation), update-snapshots label bypass
for intentional changes, labeled/unlabeled triggers, bootstrap behavior.

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: git rm must run before copyFile, not after

On the second CI run the branch already has .pr/snapshots/ tracked from the
previous run. The old order was: copyFile → git rm → git add. git rm removes
tracked files from disk, which deleted the freshly written images, leaving the
directory empty and causing 'fatal: pathspec did not match any files'.

Fix: run git rm --ignore-unmatch before copyFile so the tracked files are
cleared from disk first; then copyFile writes clean new files with nothing
to conflict; then git add finds them as expected.

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: snapshot images for run 25931876588 [skip ci]

* fix: push snapshot images to orphan branch, not PR branch

Pushing to the PR branch with [skip ci] caused required checks to never
run on the HEAD commit, permanently blocking the PR.

New approach:
- publishImages() creates a fresh git repo in a temp directory, adds the
  images, and force-pushes to snapshot-artifacts/pr-<N> — a dedicated
  ephemeral branch that no CI workflow watches.
- The PR branch is never touched by CI, so required checks always run on
  the actual code commits.
- [skip ci] is removed; no loop prevention is needed because nothing
  triggers snapshot CI on the artifacts branch.
- Images in the orphan commit live at changed/<relPath>-{actual,expected,diff}.png
  and new/<relPath>.png (no .pr/snapshots/ prefix).
- raw.githubusercontent.com/<owner>/<repo>/<sha>/changed/... URLs are
  stable because they pin the orphan commit SHA.
- pr-artifacts.yml gains a closed trigger + cleanup-snapshot-artifacts job
  that deletes snapshot-artifacts/pr-<N> when the PR merges or is abandoned.
- Stale .pr/snapshots/ files from previous CI runs removed from this branch.

Co-authored-by: openhands <openhands@all-hands.dev>

* docs: update AGENTS.md — orphan branch image storage, branch cleanup

* docs: tighten AGENTS.md snapshot section and pr-artifacts description

- Remove duplicate gitignore mention (already stated in baseline-storage line)
- Update pr-artifacts.yml description to cover both cleanup responsibilities:
  .pr/live-e2e/ (on approval) and snapshot-artifacts/pr-<N> (on close)

Co-authored-by: openhands <openhands@all-hands.dev>

---------

Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-15 14:12:53 -04:00
Graham Neubig 5b05321483 Fix Windows static asset serving (#456) 2026-05-15 01:24:11 -04:00
4ed58e2379 fix: restore data-testid="chat-interface" removed by #340 (#437)
* fix: restore data-testid="chat-interface" removed by #340

PR #340 added left padding to the ChatInterface wrapper div but
accidentally dropped the data-testid attribute in the same edit.
This broke both the collapsible-thinking snapshot tests and the live
e2e test, which both use getByTestId('chat-interface') as the load
signal and screenshot target.

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: update baseline snapshots [skip ci]

* ci: trigger re-run after snapshot baseline update

---------

Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-14 16:02:33 +00:00
dd18f8aee0 feat: add Playwright visual snapshot testing infrastructure (#392)
* feat: add Playwright visual snapshot testing infrastructure

- Add snapshot test file for home and settings pages
- Configure playwright.config.ts with snapshot settings
- Add npm scripts: test:e2e:snapshots and test:e2e:snapshots:update
- Create CI workflow (.github/workflows/snapshot-tests.yml)
- Include baseline snapshots for chromium

Closes #390

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: properly mock analytics consent in snapshot tests

- Add setupMocks helper with showConsentModal parameter
- Set user_consents_to_analytics: false to hide modal by default
- Add dedicated test for analytics consent modal appearance
- Document snapshot testing patterns in AGENTS.md

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: add explicit modal absence assertions in snapshot tests

- All non-modal tests now assert consent modal has count 0
- Use rootLayout consistently for all snapshots
- Tests will fail fast if modal incorrectly appears

Note: Snapshots need regeneration - CI will fail until baselines updated

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: dismiss consent modal before taking snapshots

- Add dismissConsentModal helper to click 'Confirm preferences'
- Call dismissConsentModal after page load in all non-modal tests
- Regenerate all baseline snapshots without modal overlay

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: make snapshot tests work in mock mode CI

- Add file API mock to prevent proxy errors
- Make consent modal test skip if modal doesn't appear in mock mode
- Tests now pass in both local and CI environments

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: generate snapshots in CI environment

- Add workflow_dispatch with update_snapshots option
- Remove local snapshots (will be generated in CI)
- CI can now update and commit snapshots automatically
- Update AGENTS.md with snapshot testing details

To generate snapshots: Run workflow manually with 'Update baseline snapshots' checked

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: update baseline snapshots [skip ci]

* docs: add CI snapshot update instructions to AGENTS.md

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: address review comments

- Use setupMocks(page, true) for consent modal test instead of try-catch
- Align global threshold to 0.01 (1%) matching documented standard

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: update baseline snapshots [skip ci]

* fix: stabilize flaky consent modal test

- Wait for root-layout to be visible before checking modal
- Add networkidle wait for settings query to resolve
- Increase modal visibility timeout to 10s for lazy-load

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: wait for settings API response to stabilize consent modal test

- Use Promise.all to wait for settings response during navigation
- Increase root-layout visibility timeout to 10s
- Ensures settings data is loaded before checking for modal

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: increase timeouts for consent modal test

- Set test timeout to 60s
- Use networkidle for goto
- Increase element visibility timeouts to 15s

Co-authored-by: openhands <openhands@all-hands.dev>

---------

Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-12 19:07:42 -04:00
Rohit Malhotraandopenhands 9bcfbb6a0f fix: also tag prerelease versions as latest on npm (#394)
* fix: also tag prerelease versions as latest on npm

Since we don't have stable releases yet, prerelease versions (alpha, beta, rc)
should also be tagged as 'latest' so users running 'npm install @openhands/agent-canvas'
get the most recent version rather than needing to specify @alpha explicitly.

The workflow now:
1. Publishes with the prerelease tag (e.g., 'alpha')
2. Also adds the 'latest' tag to that version

Co-authored-by: openhands <openhands@all-hands.dev>

* docs: note npm dist-tag cleanup issue

Co-authored-by: openhands <openhands@all-hands.dev>

* docs: warn about prerelease npm latest tag

Co-authored-by: openhands <openhands@all-hands.dev>

---------

Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-12 18:38:44 -04:00
bad60ed8de Add live Agent Server E2E framework (#195)
* Add demo flow E2E coverage

* Add live Agent Server E2E

* Stabilize live E2E CI

* Stabilize live Agent Server E2E

* Use default pull request workflow triggers

* Organize Playwright E2E tests

* Comment live E2E results on PR

* Fix live E2E comment permissions

* Stabilize live E2E PR reporting

* Add collapsible live E2E evidence

* Embed live E2E media in PR report

* Use release assets for live E2E media

* Stabilize live E2E media and auth

* Use raw URLs for live E2E media

* Update tests for SDK workspace API

* Use PR artifacts for live E2E media

* Move live E2E scripts under tests

* chore: Update PR QA artifacts

* Clarify live E2E test layout

* Document and simplify live E2E local runs

* Remove unrelated non-test diffs

* Preserve HEAD git ref in workspace client

* Strengthen live Agent Server E2E

* chore: Update PR QA artifacts

* Remove workspace session URL normalization

* Remove obsolete mock E2E regressions

* Disable live E2E trace capture

* Harden live E2E workflow

* Harden live E2E review fixes

* Fix live E2E manual checkout

* chore: Update PR QA artifacts

* Address live E2E re-review feedback

* Address live E2E security review feedback

* Address live E2E approval suggestions

* chore: address PR review feedback (#195)

* chore: address live e2e review followups (#195)

* chore: Remove PR-only artifacts

* chore: address latest live e2e review

* fix(ci): drop --ignore-scripts so typescript-client git dep builds

After merging main (PR #278), source files import directly from
@openhands/typescript-client subpath exports (e.g. /clients,
/workspace/remote-workspace). These resolve to dist/ files that are
generated by the package's prepare script. The --ignore-scripts flag
on npm ci prevented that script from running, so CI's typecheck
failed with TS2307 'Cannot find module' for every subpath import.

Main's CI uses plain 'npm ci' (no --ignore-scripts) and passes.
Align this branch to match.

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: restore avatar-menu and css-isolation regression tests

These were moved from tests/ to tests/e2e/regressions/ in 08b8e12
but then mistakenly deleted in 5c5a39b. The live E2E framework is
additive — it should not remove existing browser regression coverage.

The placeholder.spec.ts is not restored since it was a no-op stub.

Co-authored-by: openhands <openhands@all-hands.dev>

---------

Co-authored-by: allhands-bot <allhands-bot@users.noreply.github.com>
Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-12 14:19:24 -04:00
Rohit Malhotraandopenhands 4738f5b7c6 Add npm publish workflow and release infrastructure (#330)
* Add npm publish workflow and release infrastructure

- Add .github/workflows/npm-publish.yml for automated npm publishing on GitHub releases
- Update CI to verify library build (npm run build:lib) and package contents
- Add CHANGELOG.md for version history tracking
- Update README.md with npm installation and usage documentation

Closes #197

Co-authored-by: openhands <openhands@all-hands.dev>

* correct package version

* chore: update npm-publish workflow for trusted publishing

- Remove NODE_AUTH_TOKEN secret dependency
- Keep id-token: write permission for OIDC
- Add provenance flag for npm attestations
- Add comment explaining trusted publisher setup on npmjs.com

Co-authored-by: openhands <openhands@all-hands.dev>

* feat: add CLI entry point for npx execution

- Add bin/agent-canvas.mjs as executable CLI
- Add bin field to package.json for npm bin linking
- Include bin/ and build/ directories in published files
- CLI serves the built application with SPA routing support
- Supports --port, --host, and --help options

Co-authored-by: openhands <openhands@all-hands.dev>

* refactor: consolidate npm executable to use dev-docker infrastructure

- bin/agent-canvas.mjs now uses dev-with-automation.mjs main() with
  dev-docker.mjs's Docker-specific agent-server starter
- Added --static and --static-dir support to dev-with-automation.mjs
  so the npm executable serves pre-built static assets instead of Vite
- Added startStaticFrontend() function that uses static-server.mjs
- npm executable runs full stack: Docker agent-server + uvx automation
  backend + static frontend + ingress proxy

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: include scripts/ in npm package files

The bin/agent-canvas.mjs executable imports from scripts/dev-with-automation.mjs
and scripts/dev-docker.mjs, so the scripts directory must be included in the
published package.

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: address review comments

- Fix CHANGELOG.md version mismatch: 1.6.0 -> 1.0.0-alpha.1 to match package.json
- Add NODE_AUTH_TOKEN env var to npm-publish workflow for authentication
- Add CLI entry point mention to CHANGELOG

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: use OIDC trusted publishing (no NPM_TOKEN needed)

npm trusted publishing with OIDC doesn't require NODE_AUTH_TOKEN.
Instead it uses short-lived OIDC tokens generated by GitHub Actions.

Requirements:
- id-token: write permission (already set)
- npm CLI 11.5.1+ (added npm install -g npm@latest step)
- Trusted publisher configured on npmjs.com

See: https://docs.npmjs.com/trusted-publishers/

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: bump version to 1.0.0-alpha.2

Co-authored-by: openhands <openhands@all-hands.dev>

* Build app assets before npm publish

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: use Node 24 for npm trusted publishing

Trusted publishing requires Node 22.14.0+ and npm 11.5.1+.
Node 24 ships with npm 11.x which meets the requirement.
Node 22.12.0 (previous) ships with npm 10.x which doesn't support OIDC.

Also removed the manual npm upgrade step since Node 24 includes
a compatible npm version by default.

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: align all workflows to Node 24 and regenerate lockfile

- Update ci.yml to use Node 24
- Update sdk-version-sync.yml to use Node 24
- Regenerate package-lock.json with npm 11.12.1

All workflows now use Node 24 which ships with npm 11.x,
required for OIDC trusted publishing (npm 11.5.1+).

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: remove incorrect LLM env vars from CLI help

LLM_MODEL and LLM_API_KEY were listed in the help text but aren't
actually used by the scripts. LLM settings are configured through
the web UI settings page instead.

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: address PR review feedback

Critical fixes:
- Guard prepare script to only run in dev context (check for ../.git)
- Add missing existsSync import in dev-with-automation.mjs

Workflow improvements:
- Update checkout/setup-node actions to v6 for consistency
- Add npm version validation (must be 11.5.1+ for trusted publishing)
- Add package version validation (must match release tag)

CLI improvements:
- Add try-catch for dynamic imports with helpful error message
- Use console.error directly instead of imported logError/c

Documentation:
- Fix README export names: ChatInterface→ChatPanel, Terminal→TerminalPanel
- Add dist/ to .gitignore

Co-authored-by: openhands <openhands@all-hands.dev>

* ci: trigger npm publish on tag push instead of release

Simpler workflow - just push a tag like v1.0.0-alpha.2 to publish.

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: remove tarball and add *.tgz to gitignore

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: npm publish errors

1. Fix bin path - remove './' prefix (npm pkg fix)
2. Add --tag for prerelease versions (alpha/beta/rc)

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: add repository field for npm provenance verification

npm provenance requires repository.url to match the GitHub Actions
source. Also added description, homepage, and bugs fields.

Co-authored-by: openhands <openhands@all-hands.dev>

---------

Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-12 01:52:32 -04:00
Rohit Malhotraandopenhands 773cc72324 feat: update SDK to 1.22.0 and add CI version sync check (#333)
* feat: update SDK to 1.22.0 and add CI version sync check

- Update DEFAULT_AGENT_SERVER_VERSION from 1.21.1 to 1.22.0 in dev-safe.mjs
- Update SDK version references in AGENTS.md
- Add scripts/check-sdk-version-sync.mjs to verify automation project uses
  matching SDK versions for openhands-sdk, openhands-tools, openhands-workspace,
  and openhands-agent-server
- Add .github/workflows/sdk-version-sync.yml CI workflow with:
  - Path-filtered PR/push triggers for version-related file changes
  - repository_dispatch triggers (sdk-version-check, sdk-release) for
    external repos to notify when SDK deps change
  - workflow_dispatch with optional version override
  - Scheduled runs every 6 hours to catch upstream changes
  - PyPI version checking support (--check-pypi flag)

The check script supports:
- EXPECTED_SDK_VERSION env var override for CI triggers
- --check-pypi flag to also display latest PyPI versions
- --help for usage documentation

To trigger from external repos (e.g., OpenHands/automation or SDK repo):
  curl -X POST -H "Authorization: token \$GITHUB_TOKEN" \\
    https://api.github.com/repos/OpenHands/agent-canvas/dispatches \\
    -d '{"event_type": "sdk-version-check"}'

* fix: check released PyPI version instead of GitHub main branch

The SDK version sync check now fetches dependencies from the released
openhands-automation package on PyPI (version specified by
DEFAULT_AUTOMATION_VERSION in dev-with-automation.mjs) rather than
fetching pyproject.toml from the GitHub main branch.

This ensures we're checking the actual released version that users
would install, not the development version on main.

* fix: address review feedback for SDK version sync check

- Add env var overrides for automation package name and version
- Add retry logic with exponential backoff for PyPI API failures
- Add semantic version normalization for comparing versions
- Fix repository_dispatch to use client_payload.version
- Improve regex to handle parenthesized dependency formats
- Add comprehensive test coverage for helper functions

* fix: add type casts for dynamic module import in tests

* chore: update automation version to 1.0.0a2

- Update DEFAULT_AUTOMATION_VERSION in dev-with-automation.mjs
- Update AGENTS.md documentation
- Update test expectation

---------

Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-11 15:39:17 -04:00
Robert Brennanandopenhands 30a8810f16 Remove Windows from CI test matrix (#250)
Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-09 16:43:36 -07:00
Hiep Le b2961fd39f chore: add GitHub pull request template (#221) 2026-05-09 19:47:39 +07:00
Graham Neubigandopenhands 00f1d99b1c Fix lint failures and enforce linting in CI (#209)
* Fix lint errors and run lint in CI

Closes #208

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: enforce LF line endings in CI

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: address PR review feedback (#209)

Co-authored-by: openhands <openhands@all-hands.dev>

* chore: use stop hook for OpenHands quality gate

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: resolve main merge typecheck failure

Co-authored-by: openhands <openhands@all-hands.dev>

* fix: keep settings retry helper iterative

Co-authored-by: openhands <openhands@all-hands.dev>

---------

Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-09 07:35:39 -04:00
Graham Neubig ffd19e977f Fix Windows dev script startup (#199)
* Fix Windows dev script startup

* Run CI on Windows

* Disable npm cache on Windows CI
2026-05-08 21:36:20 -04:00
Xingyao Wangandopenhands c38422fa43 ci: enable sub-agent delegation for PR reviews (#158)
This repo typically has large PRs spanning multiple files, so enabling
sub-agent delegation lets the review bot fan out file-level reviews to
dedicated sub-agents for better coverage.

Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-07 15:32:41 -04:00
dependabot[bot] 1e2646a26a ci(deps): bump dawidd6/action-download-artifact in the actions group (#147)
Bumps the actions group with 1 update: [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact).


Updates `dawidd6/action-download-artifact` from 20 to 21
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](https://github.com/dawidd6/action-download-artifact/compare/v20...v21)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-version: '21'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-07 13:05:23 -04:00
Graham Neubigandopenhands dbcbe506fc deps(deps): group related dependabot updates (#144)
Group npm packages by feature area so related libraries land in a
single PR rather than as separate, racing updates. This avoids the
package-lock.json conflicts we saw when sequential PRs all touched
the same lockfile entries (e.g. tailwindcss + @tailwindcss/vite),
and reduces churn for users that watch the dependencies label.

Groups:
- tailwind, tanstack, i18next, react, react-router, testing,
  eslint, monaco, xterm, types

High-impact packages that are not assigned to a group (vite,
framer-motion, axios, posthog-js, lucide-react, etc.) still get
their own PR so each can be reviewed and tested independently.

GitHub Actions updates are now also grouped into a single weekly PR.

Co-authored-by: openhands <openhands@all-hands.dev>
2026-05-07 12:32:33 -04:00
Graham Neubigandopenhands fb03842d1b Align PR review workflows with OpenHands repos (#51)
Co-authored-by: openhands <openhands@all-hands.dev>
2026-04-29 12:21:29 -04:00
Graham Neubigandopenhands 299d6f630e Add OpenHands PR review workflow (#49)
Co-authored-by: openhands <openhands@all-hands.dev>
2026-04-28 23:30:29 -04:00
dependabot[bot]andopenhands 42d4d6ea62 ci(deps): bump actions/setup-node from 4 to 6 (#27)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: openhands <openhands@all-hands.dev>
2026-04-26 13:48:22 -04:00
dependabot[bot] 79ac8220ea ci(deps): bump actions/checkout from 4 to 6 (#26)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-26 12:53:39 -04:00
Graham Neubigandopenhands 9cdc64ac00 Add CI workflows and exact dependency pinning (#25)
* Add CI workflows and Dependabot updates

Co-authored-by: openhands <openhands@all-hands.dev>

* Exact-pin direct npm dependencies

Co-authored-by: openhands <openhands@all-hands.dev>

* Fix CI Vite config test portability

Co-authored-by: openhands <openhands@all-hands.dev>

---------

Co-authored-by: openhands <openhands@all-hands.dev>
2026-04-26 11:33:46 -04:00
Graham Neubigandopenhands 72eef808f0 Add OpenHands repository setup files (#23)
Co-authored-by: openhands <openhands@all-hands.dev>
2026-04-25 18:22:43 -04:00
Graham Neubigandneubig cb9138caf6 chore: clear repository for Agent Canvas migration (#15397)
Co-authored-by: neubig <neubig@users.noreply.github.com>
2026-07-27 09:09:20 -04:00
Joe Laverty d3b43ff34c ci: wait for the docker build before retagging images (#15213) 2026-07-10 20:16:13 +00:00
aivong-openhands f6a3d4f32e ci: PLTF-2960 sync chart appVersion with cloud image tag (#15219) 2026-07-10 11:49:38 -05:00
aivong-openhands 808eb06bb2 ci: PLTF-2960 open a chart image-tag bump PR on cloud release (#15166) 2026-07-07 14:09:51 -05:00
Engel Nystandopenhands ae5b8a995d ci: add release ready gate (#14987)
Co-authored-by: openhands <openhands@all-hands.dev>
2026-07-02 02:56:19 +02:00
4d9e7af514 chore(security): add Python dependency freshness guardrails (#13754)
Co-authored-by: aivong-openhands <ai.vong@openhands.dev>
Co-authored-by: enyst <engel.nyst@gmail.com>
Co-authored-by: openhands <openhands@all-hands.dev>
2026-06-26 03:46:26 +02:00
Engel Nystandopenhands faf0e08f23 fix: Pin duplicate checker action to extensions release (#14771)
Co-authored-by: openhands <openhands@all-hands.dev>
2026-06-12 02:47:14 +02:00
Engel Nystandopenhands d8b3f3302e Use reusable issue duplicate checker action (#14609)
Co-authored-by: openhands <openhands@all-hands.dev>
2026-06-12 02:09:59 +02:00
Joe Laverty e092b0b2b1 ci: adopt release-please for app and cloud releases (#14718) 2026-06-10 14:14:20 -04:00
aivong-openhandsandopenhands 5399cb13c1 PLTF-2895: add enterprise migration integrity check (#14689)
Co-authored-by: openhands <openhands@all-hands.dev>
2026-06-10 13:09:26 -05:00
Engel Nystandopenhands 4b9fa526b8 ci: add label-triggered OpenHands QA workflow (#14730)
Co-authored-by: openhands <openhands@all-hands.dev>
2026-06-09 20:08:14 +02:00
Engel Nystandopenhands 41eaaf44c0 Harden workflow GitHub context handling (#14537)
Co-authored-by: openhands <openhands@all-hands.dev>
2026-06-09 19:48:31 +02:00
aivong-openhands ded85cd217 PLTF-2875: Add promote-to-development sender (#14635) 2026-06-05 13:06:43 -05:00
aivong-openhandsandopenhands 568beb1196 PLTF-2895: Enterprise Apply Migrations on Test DB (#14652)
Co-authored-by: openhands <openhands@all-hands.dev>
2026-06-05 10:38:09 -05:00