Commit Graph

13853 Commits

Author SHA1 Message Date
Mathias Fredriksson 623e72d72d chore: add no-emdash/endash rule to agent instructions and CI lint (#24375)
Add a lint check that prevents introduction of Unicode emdash (U+2014)
and endash (U+2013) characters. These are almost exclusively introduced
by AI agents and conflict with the project writing style.

The lint script (scripts/check_emdash.sh) checks only added lines in
the current diff by default, so existing violations do not block CI.
Pass --all to scan the entire repo for auditing.

Agent instructions in AGENTS.md, site/AGENTS.md, and the docs style
guide now explicitly ban emdash, endash, and " -- " as punctuation,
with guidance to use commas, semicolons, or periods instead.
2026-04-21 13:55:24 +03:00
Michael Suchacz 9d0469fc4c feat: allow approved external MCP tools in root plan mode (#24509)
## Summary

Allow root plan-mode chats to use MCP tools from external servers that
an admin has explicitly approved for plan mode. Workspace MCP and
plan-mode subagents remain blocked.

## Problem

`chatd.go` excluded every MCP tool when `isPlanModeTurn` was true, so
planning had no access to tools like docs search, ticketing, etc.
Lifting that guard wholesale was unsafe: `mcp_server_configs` already
has centralized admin governance, but workspace-local MCP (discovered
from agent `.mcp.json`) does not, and subagents use a narrower trust
boundary.

## Fix

Add an admin-controlled per-server `allow_in_plan_mode` flag (default
`false`) and gate plan-mode MCP access on it.

### Backend / schema
- New migration `000472_mcp_server_allow_in_plan_mode.{up,down}.sql` and
matching fixture update.
- `mcpserverconfigs.sql` + generated code: persist and read the new
column.
- `codersdk/mcp.go`: thread the field through `MCPServerConfig`,
`Create*`, and `Update*` request types.
- `coderd/mcp.go`: validate, persist, and return the flag in
get/list/create/update handlers.

### chatd
- `coderd/x/chatd/chatd.go`: pre-filter selected external MCP configs by
`AllowInPlanMode` before calling `mcpclient.ConnectAll` on plan-mode
root turns. Workspace MCP discovery is skipped entirely on plan-mode
turns.
- Single helper decides whether a tool is available in plan mode, used
both at construction and for active-tool filtering (defense in depth).
Plan-mode subagents, dynamic tools, provider-native tools, computer-use,
and workspace MCP stay unchanged.
- `coderd/x/chatd/prompt.go`: update the root plan-mode overlay text to
match the new boundary.

### UI
- `MCPServerAdminPanel.tsx`: add an explicit toggle ("Allow all tools
from this MCP server in root plan mode") next to the existing governance
controls.
- Regenerated `site/src/api/typesGenerated.ts`.

### Docs
- `docs/ai-coder/agents/architecture.md`: replace the blanket "MCP is
unavailable in plan mode" note with the new root-only, external-only,
admin-approved policy. Explicitly call out that workspace MCP and
plan-mode subagents are still excluded.

### Tests
- Plan-mode visibility (approved vs non-approved external server).
- Plan-mode invocation of an approved external MCP tool.
- End-to-end plan-mode workflow that uses an approved MCP tool and then
reaches `propose_plan`.
- Regressions: workspace MCP still excluded in plan mode; plan-mode
subagents still on the restricted tool boundary; existing tool
allow/deny list filtering still applies.

## Policy precedence

`allow_in_plan_mode` is an **additional** requirement on top of existing
`enabled`, availability, chat-selected / forced server IDs, and tool
allow/deny lists. It approves **all tools on that server** for root plan
mode; a per-tool plan allowlist is deliberately deferred.

## Follow-ups (explicitly out of scope)

- Whether plan-mode subagents should inherit approved external MCP
tools.
- Workspace-local MCP safety model (agent-side `.mcp.json` schema vs. a
coderd-managed workspace MCP config).

## Validation

- `go vet ./coderd/x/chatd/...`
- `go test ./coderd/x/chatd -run 'TestPlan.*|TestMCP.*' -count=1`
- `go test ./coderd/x/chatd -count=1 -timeout 5m` (full chatd suite)
- `make fmt` (no diff)

> Mux opened this PR on Mike's behalf.
2026-04-21 12:26:12 +02:00
Cian Johnston c968a1f3a3 feat: make database.Chat auditable (#24485)
Wire database.Chat into the audit system so chat lifecycle events
(creation, patches, etc.) produce audit log entries.

Part of CODAGT-200.

> 🤖
2026-04-21 11:11:56 +01:00
Cian Johnston 5f3effd839 fix(coderd/x/chatd): add chattest.OpenAI() default fake server (#24540)
- Add `chattest.OpenAI(t)` convenience wrapper around `NewOpenAI` with
sensible defaults (JSON title response for non-streaming, text chunk for
streaming)
- Update `seedChatDependencies` to use it instead of an empty base URL,
preventing title generation from hitting real `api.openai.com` with a
fake key:

```
    t.go:111: 2026-04-20 19:23:31.885 [debu]  coderd.chatd.processor: title model candidate failed  chat_id=edb43454-f23d-4163-9974-d101b8091de6  chat_id=edb43454-f23d-4163-9974-d101b8091de6 ...
        error= generate structured title:
                   github.com/coder/coder/v2/coderd/x/chatd.generateStructuredTitleWithUsage
                       /home/coder/src/coder/coder/coderd/x/chatd/quickgen.go:443
                 - unauthorized: Incorrect API key provided: test-api-key. You can find your API key at https://platform.openai.com/account/api-keys.
```

> 🤖
2026-04-21 10:26:20 +01:00
Ethan bd3ed18fb1 chore: bump hashicorp/hc-install to v0.9.4 and drop coder fork replace (#24547)
Upstream `github.com/hashicorp/hc-install` v0.9.4 ships the refreshed
HashiCorp release-signing key (hashicorp/hc-install#355 +
hashicorp/hc-install#372), so the `coder/hc-install` fork replace
directive added in #24516 is no longer needed.

Relates to https://github.com/coder/internal/issues/1476

Closes ENG-2496
2026-04-21 15:21:12 +10:00
Jake Howell 3466806a66 fix(site): implement agent logs improvements (#24455)
Polishes the agent logs panel in the workspace resources UI: consistent
padding, clearer behavior when switching log source tabs, and a more
usable download menu for long source lists.

- Use symmetric vertical padding on the logs container (`py-4` instead
of top-only padding).
- Add optional `showSourceIcons` on `AgentLogs` (defaults on);
`AgentRow` turns it off unless the **All** tab is active so filtered
tabs are not cluttered with redundant source icons.
- Anchor the download-logs dropdown below the trigger and cap menu
height to 6 items with scrolling so many sources do not overflow the
viewport.
2026-04-21 03:49:50 +00:00
Jake Howell ac6c9452c0 chore(site): decss the <WorkspaceBuild* /> pages (#24530)
This removes the CSS props of various components found in our workspaces
pages. Eventually, we'd like to remove the MUI-specific components in
here, but its a good start!
2026-04-21 03:48:36 +00:00
Jake Howell 67c57abb63 chore: tighten .vscode IDE and typescript configuration (#24537)
This branch tightens import hygiene and editor guidance to reduce
accidental use of legacy or discouraged patterns.
It also updates consumers too, by propagating the new `lucide-react`
import convention across the existing UI surfaces that reference those
icons.

- Updated `.vscode/settings.json` to prefer non-relative imports and
improve TypeScript auto-import behavior.
- Re-enabled and expanded Biome restricted-import enforcement in
`biome.jsonc` for migration guardrails.
- Added/used `lucide-react` `-Icon` naming conventions for clarity and
consistency.
- Updated consumers too across components, modules, and pages so the new
import rules are applied end-to-end.
2026-04-21 13:45:08 +10:00
Jake Howell e186dc3222 chore(site): replace inline add member form with dialog on <OrganizationMembersPage /> (#24429)
> 🤖 This PR was written by Coder Agent on behalf of Jake Howell

Replace the single-select inline UserAutocomplete form with a
multi-select Dialog (matching the GroupMembersPage pattern from #24287).

Changes:
- Replace AddOrganizationMember inline form with AddUsersDialog using
MultiUserSelect for multi-user selection in a modal
- Batch-add multiple users via Promise.all in the page callback
- Remove isAddingMember prop (dialog manages its own loading state)
- Update stories to match new interface
2026-04-21 13:43:20 +10:00
Jake Howell 9324c16c97 chore(site): demui <CodeExample /> (#24528)
This pull-request takes our `<CodeExample />` component and removes the
MUI specific styles.

---------

Co-authored-by: Jeremy Ruppel <jeremyruppel@users.noreply.github.com>
2026-04-21 13:40:37 +10:00
Ethan 181e103201 fix: reuse shared tailnet for coderd-hosted MCP workspace tools (#24460)
## Problem

Coderd can expose an MCP server at `/api/experimental/mcp/http` (we have
this enabled on dogfood). Its workspace tools dialed agents through a
per-call client-side tailnet stack. Every tool call re-created a
WireGuard device, netstack, magicsock + UDP sockets, DERP connection,
coordinator websocket, and their goroutines — in a process that already
runs a long-lived shared tailnet. The duplicate stacks drove up resource
usage under load.

## Fix

Route this server's tool calls through the existing shared tailnet, so
none of those transports are reconstructed per call. Closing an
`AgentConn` now releases a tunnel reference instead of tearing down a
transport.

## Potential follow-up

`coder exp mcp server` still builds a fresh tailnet per call. It pays
per-call latency and causes coordinator/DERP churn. A shared CLI tailnet
is more involved — unlike coderd, the CLI has no existing shared tailnet
to reuse, so it would need a new long-lived client-side tailnet with
reconnect, sleep/wake, and idle-destination handling. There's less
motivation to optimize this, given the client-side MCP does not compete
for resources with coderd.

Closes CODAGT-199

> Generated by mux, but reviewed by a human
2026-04-21 11:37:10 +10:00
Ethan 1203f625b7 feat(coderd): accept parameters in start_workspace tool (#24434)
When the chat `start_workspace` tool triggers an active-version upgrade
that introduces new required parameters, the build fails with a
parameter validation error. Previously this returned a message telling
the user to update from the UI — a dead end for the model.

This PR lets the model recover inside the chat by:

1. Accepting an optional `parameters` map on `start_workspace` (same
schema as `create_workspace`), forwarded as `RichParameterValues`.
2. Returning structured JSON error responses that preserve validation
details and the workspace's `template_id`, so the model can call
`read_template` to discover what changed.
3. Replacing the UI-only guidance in `exp_chats.go` with
model-actionable retry instructions.

The expected model flow on an active-version parameter failure is now:

```
start_workspace → fails (structured error with template_id + validations)
read_template   → discovers new required parameters
start_workspace → retries with parameters map → workspace starts
```
<img width="846" height="511" alt="image"
src="https://github.com/user-attachments/assets/d18b6864-5970-4225-8da0-0f2ab134ccb4"
/>
2026-04-21 11:36:20 +10:00
TJ 3b0cd5bb12 fix(site): polish table alignment for workspace proxies (#24538)
Fixes alignment issues in the workspace proxies table.

## Changes

- **Status column alignment**: Removed `text-right` from the Status
column header and the `justify-end` flex wrapper from status cells.
Status indicator dots now align consistently across rows regardless of
text width ("Healthy" vs "Not reachable").
- **Error/warning text alignment**: Changed padding from `px-12` (48px)
to `px-14` (56px) so error/warning messages align with proxy name text,
which starts after cell padding (12px) + avatar (32px) + gap (12px) =
56px.
- **colSpan fix**: Corrected `colSpan={4}` to `colSpan={3}` to match the
actual number of table columns.

Relates to DES-22000

> 🤖 Generated by Coder Agents
2026-04-20 13:05:53 -07:00
Danielle Maywood bf885ccc71 fix(site/src): replace misused useEffectEvent with correct patterns (#24525) 2026-04-20 19:52:21 +01:00
Jake Howell 7f1b9cb648 chore(site): demui <Avatar /> and <AvatarCard /> (#24527)
This pull-request takes our `<Avatar />` and `<AvatarCard />` component
and removes the bespoke styles to them. As an added bonus I took care of
the `getExternalImageStylesFromUrl` helper util and cleaned out the
MUI-specific code to it.

There are some remnants of `@emotion/react` in
`getExternalImageStylesFromUrl` however we don't have a theme switcher
that could appropriately handle it yet.
2026-04-21 02:22:16 +10:00
Jake Howell 3b561dcea9 fix(site): simplify prerelease css (#24514)
> 🤖 This PR was modified by Coder Agent on behalf of Jake Howell

Removes the bottom-line navbar effect in `<NavbarView />` and cleans up
prerelease CSS.

- Remove `relative` from `<NavbarView />` as it was redundant with the
`sticky` class.
- Refactor `getPrereleaseFlag` to simplify version classification.
- Clean up unused prerelease CSS from `index.css`.

<img width="920" height="83" alt="image"
src="https://github.com/user-attachments/assets/84e351e6-d7a2-4fe2-a331-27c651266256"
/>
2026-04-21 02:11:25 +10:00
Cian Johnston 2f0d715e9f fix(site): stabilize agent form stories (#24532)
- replace the timer-driven permitted-orgs story wrapper with
deterministic API stubs
- keep the empty/subset story assertions focused on org picker
visibility and submitted organization IDs
- clean up the stale story comment and simplify the shared story setup

> 🤖
2026-04-20 15:27:10 +01:00
Jeremy Ruppel 4b755e514a fix(site): stabilize app.spec.ts e2e test (#24400)
The `app` e2e test flakes in CI with `waitForEvent("page")` or
`isVisible()` timeouts when opening a workspace app in a new tab.

The test had several timing hazards: the HTTP server address was read
before the socket finished binding, the popup event listener was
registered after the click, and content visibility used a point-in-time
check with the default 5s timeout.

Rewritten to wait for the server to listen, register the popup promise
before clicking, use `getByRole("link")` for a precise locator, and
replace `isVisible()` with a retrying `toBeVisible({ timeout: 30_000 })`
assertion that tolerates the intermediate `about:blank` page and
app-proxy startup delay. The test body is wrapped in `try/finally` to
ensure the HTTP server is always closed.

Fixes coder/internal#577

> Generated by Coder Agents

---

someone wise once said

> and I really don't know what we could do to make it more reliable
other than maybe trying to just rewrite it from scratch.
2026-04-20 10:21:36 -04:00
Cian Johnston d99949df43 feat(scripts/develop): add --prometheus-server flag to run Prometheus UI (#24408)
Builds on #24389. Adds `--prometheus-server` flag that starts a
`prom/prometheus:v3.11.2` container alongside the dev environment.

> 🤖
2026-04-20 14:08:13 +00:00
Atif Ali 81bd78d1c0 chore: add devcontainers icon (#24478)
Adds the devcontainers icon sourced from [Microsoft Fluent UI
`ic_fluent_cube_32_filled`](https://github.com/microsoft/fluentui-system-icons/blob/78c9587b995299d5bfc007a0077773556ecb0994/assets/Cube/SVG/ic_fluent_cube_32_filled.svg).
The registry module `devcontainers-cli` already references
`/icon/devcontainers.svg` — this adds the missing icon.

## Changes
- `site/static/icon/devcontainers.svg` — new icon
- `site/src/theme/icons.json` — auto-generated entry
- `site/src/theme/externalImages.ts` — registers icon as `monochrome` so
it renders correctly on both dark and light themes

> 🤖 This PR was created with the help of Coder Agents, and needs a human
review. 🧑💻

---------

Co-authored-by: Jake Howell <jake@hwll.me>
2026-04-20 18:54:22 +05:00
Jakub Domeracki 411ed21059 fix(coderd): omit frame-ancestors CSP for embed routes (#24529) 2026-04-20 15:38:52 +02:00
Jaayden Halko 410f9a5e19 feat: allow renaming of agent chat title (#24489)
Co-authored-by: Coder Agents <noreply@coder.com>
2026-04-20 14:00:46 +01:00
Thomas Kosiewski 18a30a7a10 feat: add chat debug HTTP handlers and API docs (#23918) 2026-04-20 13:34:41 +02:00
Dean Sheather ea00d2d396 fix(coderd): enforce workspace authz on watchChatGit (#24477)
`watchChatGit` proxies a live websocket to the workspace agent's git
watcher (`/api/v0/git/watch`), streaming repository diffs back through
the chat stream. Before this change it only enforced `chat:read` (via
`ExtractChatParam`) plus an implicit `workspace:read` from the dbauthz
wrapper on `GetWorkspaceAgentsInLatestBuildByWorkspaceID`. The sibling
`watchChatDesktop` handler already fetches the workspace and requires
`policy.ActionApplicationConnect` or `policy.ActionSSH` before dialing.

Built-in roles like **Template Admin** and **Org Admin** grant
`workspace:read` without SSH/ApplicationConnect, and **Owner** also
loses both under `DisableOwnerWorkspaceExec`. A chat owner whose
exec-level workspace access was revoked *after* the chat was bound could
therefore keep streaming repository content from the workspace agent
through the chat's git-watch endpoint.

Mirror `watchChatDesktop`: fetch the workspace and require
`ApplicationConnect || SSH` before any agent-tunnel activity. Adds one
real-coderdtest regression test (`TestWatchChatGitAuthz`) that demotes
the chat's owner to template-admin after binding and asserts the
git-watch endpoint returns 403; the mock-based `TestWatchChatGit` in
`coderd/workspaceagents_internal_test.go` continues to cover the
no-workspace / disconnected-agent / websocket-proxy paths.

Fixes CODAGT-184.
2026-04-20 21:33:35 +10:00
Jakub Domeracki 615be176b8 fix(coderd): add frame-ancestors CSP directive to prevent clickjacking (#24474) 2026-04-20 13:01:46 +02:00
Mathias Fredriksson 467430d8fa fix: sort child chats newest-first and prepend on creation (#24524)
GetChildChatsByParentIDs sorted created_at ASC, but the cache
helper appended new children to the end. On refetch the API and
cache agreed on oldest-first, putting the just-created child at
the bottom. Users expect newest first, matching the root-chat
sidebar convention.

- SQL: change child sort to created_at DESC, id DESC.
- Cache: prepend instead of append in addChildToParentInCache
  (renamed from appendChildToParentInCache to avoid leaking
  position semantics).
- Test: update ordering assertion to expect newest-first.

Refs #24404
2026-04-20 10:43:31 +00:00
Thomas Kosiewski df7e838c21 feat(coderd): wire debug logging into chat lifecycle (#23917) 2026-04-20 12:27:16 +02:00
Mathias Fredriksson fc2493780f fix: exclude subagent chats from sidebar pagination (#24404)
GetChats now returns only root chats (parent_chat_id IS NULL).
A new GetChildChatsByParentIDs query fetches children for visible
roots and embeds them in each parent's Children field. The
singular getChat endpoint does the same.

Archive invariant is one-way: parent archived implies child
archived. Parent archive/unarchive cascades via root_chat_id.
Individual child archive is permitted; child unarchive while the
parent is archived is rejected atomically (row lock on child,
re-read parent inside the transaction). Embedded children are
filtered by the caller's archive state so individually-archived
children stay hidden from active-parent views.

Gitsync MarkStale uses GetChatsByWorkspaceIDs directly;
MarkStaleParams.OwnerID removed (dead after the switch).

Frontend: buildChatTree reads from the embedded children field,
WebSocket handlers route child events into the parent's children
array, and archiving a child strips it from the parent cache.
2026-04-20 13:19:59 +03:00
Cian Johnston df429b7f60 fix: classify HTTP/2 transport failures as retryable timeouts (#24502)
Modifies chatloop error classification behaviour to treat the following as retryable:
* HTTP/2 `force closed`
* GOAWAY 
* use of closed network connection

* Modfies user-facing retry banner to show "<provider> is temporarily
unavailable."

Relates to CODAGT-212.

> 🤖
2026-04-20 11:09:47 +01:00
Danielle Maywood f688e85898 fix(site): prevent workspace icon from shrinking in chat pill (#24521)
The workspace pill in the chat box was shrinking smaller than the size
of its fixed content (icon, chevron, padding), causing the workspace
icon and chevron to become distorted or overflow.
2026-04-20 10:37:22 +01:00
Susana Ferreira 522118ab20 feat: support AWS SDK default credential chain for Bedrock authentication (#24346)
## Description

Makes AWS Bedrock credentials optional. When `AccessKey` and
`AccessKeySecret` are not set, AI Bridge falls back to the AWS SDK
default credential chain, which supports IAM Roles (instance profiles,
IRSA, ECS task roles), SSO, shared credentials files, and environment
variables.

This allows AI Bridge to authenticate with AWS Bedrock using:
- Permanent credentials (access key + secret) as before
- IAM Roles, shared config files, environment variables, SSO, etc, via
the SDK default credential chain

Depends on: https://github.com/coder/aibridge/pull/265
Related to: https://github.com/coder/aibridge/issues/144 
Related to: https://linear.app/codercom/issue/AIGOV-67

_Disclaimer: initially produced by Claude Opus 4.6, modified and
reviewed by @ssncferreira ._
2026-04-20 10:00:05 +01:00
Cian Johnston 12e49c18a5 fix(enterprise/coderd/x/chatd): reduce relay reconnect spam (#24495)
- Replaces the hard-coded 500ms reconnect timer for dialing chat relays with exponential backoff via `coder/retry`.
- `dialRelay` drops the `codersdk.ExperimentalClient.StreamChat` wrapper
and calls `websocket.Dial` directly so we can capture
`*http.Response.StatusCode` without parsing error strings.
- Adds `RelayDialError` that exposes the HTTP status from `websocket.Dial`
- Modifies retry logic: 401/403 tear the stream down immediately, 5xx/network/timeouts retry
then tear down on cap. Outer stream closes cleanly so the browser SDK
reconnects with a fresh cookie.
- Retry state resets on successful dial and on target-worker change, not
on every `closeRelay()`.

> 🤖 Generated by Coder Agents.
2026-04-20 09:19:17 +01:00
Ethan ef6969dd70 feat(coderd/x/chatd): agent-created file attachments in chat (#24280)
Agents can already see workspace files and take screenshots, but users could not download those artifacts from chat. This PR adds durable chat attachments to chatd. `attach_file`, explicit `computer` screenshot actions (not the automatic post-action screenshots), and `propose_plan` now fetch bytes over the agent connection, store them in `chat_files`, link them to the chat, and carry attachment metadata in tool responses so `buildAssistantPartsForPersist` can materialize ordinary `type:"file"` assistant parts that the chat file APIs serve.

The same storage helpers are reused for other artifact-producing paths. `wait_agent` recordings and thumbnails are stored as chat files and linked back to the parent chat, with best-effort relinking so parent chats retain those artifacts without leaving orphaned rows when chat-file caps reject links. `storeChatAttachment` wraps insert + link in one transaction, files are capped at 10 MB each and 20 per chat, and serving defaults to `Content-Disposition: attachment` with an explicit inline-safe allowlist.

This PR also consolidates chat-file media policy in `coderd/chatfiles`. Uploads and tool-generated attachments share byte-based MIME detection, SVG blocking, inline-safety rules, and compatible `text/plain` refinement for JSON, CSV, and Markdown. Prompt construction still only inlines synthetic pasted text for model consumption; assistant-created attachments are persisted for the user and intentionally not replayed into later LLM turns.

UI follow-up lives in #24281.

Relates to CODAGT-91
2026-04-20 18:04:35 +10:00
Ethan 596e55b136 test: pin DateRangePicker calendar today to caller-supplied clock (#24517)
The `DateRangePicker` accepts a `now` prop that stories and tests use to
pin preset ranges and future-date disabling to a deterministic clock,
but it never forwarded that value to the underlying `Calendar`.
`react-day-picker` then computed its own `today` from wall-clock time,
which drives both the "today" highlight modifier and the initial visible
month — causing stories like `TemplateInsightsControls:Day` to _flake_
as real time advanced.

Thread `currentTime` into `react-day-picker`'s `today` prop. When `now`
is omitted (production usage), `currentTime` falls back to `new Date()`,
which matches `react-day-picker`'s existing default, so there is no
runtime behavior change.
2026-04-20 16:36:13 +10:00
Ethan 7e89534d32 chore: use coder/hc-install fork to fix expired PGP key verification (#24516)
hc-install's bundled HashiCorp release-signing pubkey contains both the
original armored block and a refreshed one, but
`openpgp.ReadArmoredKeyRing` only decodes the first, so the verifier
sees the expired key and terraform installs (and `TestInstall`) fail
with `openpgp: key expired`.

Point `github.com/hashicorp/hc-install` at our fork, which parses every
armored block and merges entities by fingerprint so the refreshed
self-signature wins. We can drop the go mod replace once
https://github.com/hashicorp/hc-install/pull/371 (or an equivalent
upstream fix) ships.

Relates to https://github.com/coder/internal/issues/1476
2026-04-20 13:26:28 +10:00
Jake Howell 5f6c74adfa fix: resolve <ChatTopBar /> fmt issue (#24515)
Noticed in #24514, this was throwing an error in CI.

```
$ biome lint --error-on-warnings .
src/pages/AgentsPage/components/ChatTopBar.tsx:194:9 lint/complexity/noUselessFragments  FIXABLE  ━━━━━━━━━━

  ℹ This fragment is unnecessary.
  
    192 │                                             >
    193 │                                             {!isArchived && (
  > 194 │                                             <>
        │                                             ^^
  > 195 │                                             {onRegenerateTitle && (
         ...
  > 206 │                                             )}
  > 207 │                                             </>
        │                                             ^^^
    208 │                                             )}
    209 │                                             {isArchived ? (
  
  ℹ A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
  
  ℹ Unsafe fix: Remove the Fragment
  
    192 192 │               >
    193 193 │                 {!isArchived && (
    194     │ - → → → → → → → → <>
    195     │ - → → → → → → → → → {onRegenerateTitle·&&·(
        194 │ + → → → → → → → → onRegenerateTitle·&&·(
    196 195 │                       <>
    197 196 │                         <DropdownMenuItem
    ······· │ 
    204 203 │                         <DropdownMenuSeparator />
    205 204 │                       </>
    206     │ - → → → → → → → → → )}
    207     │ - → → → → → → → → </>
        205 │ + → → → → → → → → → )
    208 206 │                 )}
    209 207 │                 {isArchived ? (
  

```
2026-04-20 00:23:42 +00:00
Mathias Fredriksson 6b0bb02e5d fix: server-side diffs and stricter fuzzy splicing for edit_files (#24454)
Fixes three classes of edit_files bugs and adds structured per-file
diff output for tool callers:

- New IncludeDiff flag on FileEditRequest; when set, the agent
  returns FileEditResponse.Files[]{Path, Diff} with unified diffs
  computed via go-udiff v0.4.1 Lines + ToUnified (not Unified,
  which calls log.Fatalf on internal error).
- Fuzzy match comparators split each line into leading whitespace,
  body, trailing whitespace, and ending. The splice substitutes at
  each position: on agreement between search and replace the file's
  bytes win; on disagreement the replacement's bytes are spliced
  verbatim. Carve-outs for empty-body lines, multi-line EOF splices,
  and level-aware indent translation for inserted lines.
- Indent-unit detection (GCD for spaces, tab-priority) lets a 4sp
  LLM search insert correctly into tab or 2sp files. Falls back to
  the previous cLead-inheritance path when units can't be detected
  cleanly.
- Empty search is rejected with "search string must not be empty".
- Duplicate file paths in one request are rejected; symlink aliases
  resolved via api.resolvePath before the dedup check.
- Frontend EditFilesRenderer consumes the structured files array by
  explicit path (no label munging) with per-file synthetic fallback
  for older agents or mismatched paths. On error, no diff is
  rendered so the synthetic fallback doesn't misrepresent a
  rejected edit as applied.

Breaking change: AgentConn.EditFiles changes from (ctx, req) error
to (ctx, req) (FileEditResponse, error) in codersdk/workspacesdk.
Source-breaking for external Go consumers; no compat shim per plan
owner.

Out of scope (tracked in CODAGT-214): level-aware indent for
middle-substituted splice lines. Locked in
TestEditFiles_FuzzyIndent_InsertionLevelAware's Lock_* cases plus
TestEditFiles_ReplaceAll_FuzzyIndentGap.
2026-04-18 16:39:34 +03:00
christin 23f9e26796 refactor(site): replace shadcn color aliases with semantic design tokens (#24284)
The shadcn-compatible CSS aliases (`--background`, `--foreground`,
`--muted`,
`--muted-foreground`, `--primary`, `--primary-foreground`) were added as
part
of the Coder agents work with hardcoded HSL values that duplicated
existing
semantic design tokens. These non-standard color classes (`bg-muted`,
`text-muted-foreground`, `text-foreground`) had started spreading
through
components like Table, MultiUserSelect, and WorkspacesTable.

This PR makes two changes:

1. **CSS aliases now derive from canonical tokens via `var()`
references**
instead of duplicating HSL values. The aliases remain for `streamdown`
   and other external consumers, but `--background` now resolves to
   `--surface-primary` (`#FFFFFF` in light, was `#FAFAFA`), and the rest
   map to their semantic equivalents (`--content-primary`,
   `--surface-secondary`, `--content-secondary`, `--content-link`).

2. **Component classes replaced with semantic equivalents:**
   - `bg-muted` → `bg-surface-secondary`
   - `text-muted-foreground` → `text-content-secondary`
   - `text-foreground` → `text-content-primary`
   - `text-amber-400` → `text-content-warning`
   - `hsl(var(--background))` → `hsl(var(--surface-primary))`
   - `hsl(var(--muted-foreground))` → `hsl(var(--content-secondary))`

> This PR was initially created by Claude Opus 4.

Co-authored-by: Jaayden Halko <jaayden@coder.com>
Co-authored-by: Jaayden Halko <jaayden.halko@gmail.com>
2026-04-18 13:39:55 +01:00
Mathias Fredriksson 2a1984f0e8 fix(coderd/externalauth): save refreshed token before validation (#24332)
GitHub rotates refresh tokens on use, invalidating the old token
immediately. If post-refresh validation fails (e.g. rate-limited
403 from /user), the new token was silently discarded because the
DB save only happened after successful validation. The next refresh
attempt would use the stale refresh token, fail permanently, and
destroy the token.

Move the UpdateExternalAuthLink call to immediately after
TokenSource.Token() succeeds. The post-validation save block is
removed (dead code after the early save). The DB write uses a
detached context (context.WithoutCancel) so a canceled request
cannot prevent persistence of the already-consumed refresh token.
2026-04-18 14:28:29 +03:00
Spike Curtis 2ea27e897b chore: split Pubsub interface into Publisher and Subscriber (#24442)
<!--

If you have used AI to produce some or all of this PR, please ensure you have read our [AI Contribution guidelines](https://coder.com/docs/about/contributing/AI_CONTRIBUTING) before submitting.

-->

Splits the Pubsub into Publisher and Subscriber interfaces. Allows components to scope down their needs if they only publish or only subscribe. This allows smaller fakes/mocks and generally better encapsulation.
2026-04-17 22:58:33 -04:00
Spike Curtis e19b21b7d5 chore: add GetLatestWorkspaceBuildWithStatusByWorkspaceID query (#24441)
<!--

If you have used AI to produce some or all of this PR, please ensure you have read our [AI Contribution guidelines](https://coder.com/docs/about/contributing/AI_CONTRIBUTING) before submitting.

-->

relates to GRU-18  
  
Adds new database query supporting the Agent Connection Watch we will add.
2026-04-17 22:47:08 -04:00
Zach 72f35e1cd3 feat: runtime user secrets injection into workspaces (#24313)
Injects user secrets into workspace agents at runtime via the agent
manifest. Secrets with an environment variable name are set as
environment variables in every agent session and startup script. Secrets
with a file path are written to disk before startup scripts run.

- Fetch user secrets in GetManifest and convert to proto
- Defensively strip secrets from manifests received by the agent to
   avoid accidental leakage
- Add WorkspaceSecret type and proto conversion helpers to agentsdk
- Write secret files eagerly on manifest fetch (0600 perms, 0700 dirs)
- Inject secret env vars per-session in updateCommandEnv
- Expand ~/paths using caller-resolved home directory
- Log file write errors without blocking workspace startup
2026-04-17 16:55:24 -06:00
dependabot[bot] 8e2343f59c chore: bump github.com/go-git/go-git/v5 from 5.17.1 to 5.18.0 (#24504)
Bumps [github.com/go-git/go-git/v5](https://github.com/go-git/go-git)
from 5.17.1 to 5.18.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/go-git/go-git/releases">github.com/go-git/go-git/v5's
releases</a>.</em></p>
<blockquote>
<h2>v5.18.0</h2>
<h2>What's Changed</h2>
<ul>
<li>plumbing: transport/http, Add support for followRedirects policy by
<a href="https://github.com/pjbgf"><code>@​pjbgf</code></a> in <a
href="https://redirect.github.com/go-git/go-git/pull/2004">go-git/go-git#2004</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/go-git/go-git/compare/v5.17.2...v5.18.0">https://github.com/go-git/go-git/compare/v5.17.2...v5.18.0</a></p>
<h2>v5.17.2</h2>
<h2>What's Changed</h2>
<ul>
<li>build: Update module github.com/go-git/go-git/v5 to v5.17.1
[SECURITY] (releases/v5.x) by <a
href="https://github.com/go-git-renovate"><code>@​go-git-renovate</code></a>[bot]
in <a
href="https://redirect.github.com/go-git/go-git/pull/1941">go-git/go-git#1941</a></li>
<li>dotgit: skip writing pack files that already exist on disk by <a
href="https://github.com/pjbgf"><code>@​pjbgf</code></a> in <a
href="https://redirect.github.com/go-git/go-git/pull/1944">go-git/go-git#1944</a></li>
</ul>
<p>⚠️ This release fixes a bug (<a
href="https://redirect.github.com/go-git/go-git/issues/1942">go-git/go-git#1942</a>)
that blocked some users from upgrading to <code>v5.17.1</code>. Thanks
<a href="https://github.com/pskrbasu"><code>@​pskrbasu</code></a> for
reporting it. 🙇</p>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/go-git/go-git/compare/v5.17.1...v5.17.2">https://github.com/go-git/go-git/compare/v5.17.1...v5.17.2</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/go-git/go-git/commit/ea3e7ec9dfc54f577a01afb4dd601c0284604264"><code>ea3e7ec</code></a>
Merge pull request <a
href="https://redirect.github.com/go-git/go-git/issues/2004">#2004</a>
from go-git/v5-http-hardening</li>
<li><a
href="https://github.com/go-git/go-git/commit/bcd20a9c525826081262a06a9ed9c3167abfcd53"><code>bcd20a9</code></a>
plumbing: transport/http, Add support for followRedirects policy</li>
<li><a
href="https://github.com/go-git/go-git/commit/45ae193b3a60aa8ec8a3e373f7265a7819473d5f"><code>45ae193</code></a>
Merge pull request <a
href="https://redirect.github.com/go-git/go-git/issues/1944">#1944</a>
from go-git/fix-perms</li>
<li><a
href="https://github.com/go-git/go-git/commit/fda4f7464b597ff33d2dea1c026482a5e900037c"><code>fda4f74</code></a>
storage: filesystem/dotgit, Skip writing pack files that already exist
on disk</li>
<li><a
href="https://github.com/go-git/go-git/commit/2212dc7caeb2a389fe2129923811ef63f75a557a"><code>2212dc7</code></a>
Merge pull request <a
href="https://redirect.github.com/go-git/go-git/issues/1941">#1941</a>
from go-git/renovate/releases/v5.x-go-github.com-go-...</li>
<li><a
href="https://github.com/go-git/go-git/commit/ebb2d7da7f5d5aebeaa0b5e13276d72d602c1ae3"><code>ebb2d7d</code></a>
build: Update module github.com/go-git/go-git/v5 to v5.17.1
[SECURITY]</li>
<li>See full diff in <a
href="https://github.com/go-git/go-git/compare/v5.17.1...v5.18.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/go-git/go-git/v5&package-manager=go_modules&previous-version=5.17.1&new-version=5.18.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts page](https://github.com/coder/coder/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-17 22:53:10 +00:00
Danielle Maywood a53f52ee38 fix(site): fix flaky CreateWorkspacePage tests (#24480) 2026-04-17 22:04:14 +01:00
Jeremy Ruppel a2b9b74f4a fix(site): use hard reload after login to reload metadata (#24239)
After password login, `navigate('/')` performed a client-side SPA
navigation, leaving the pre-authentication `<meta>` tags (including
`userAppearance`) empty in the DOM. The `ThemeProvider` read empty
metadata and fell through to `DEFAULT_THEME` until the API query
resolved, causing a visible flash of the wrong theme. A page refresh
fixed it because the server re-rendered HTML with the session cookie
present.

Replace `navigate('/')` with `window.location.href` so the server
re-renders HTML with all metadata tags populated (`userAppearance`,
`user`, `permissions`, etc.) via the new session cookie. This matches
the pattern already used for API route redirects on the same page. Also
uses `redirectTo` instead of hardcoded "/" so the redirect query
parameter is respected for password login.

Fixes https://github.com/coder/coder/issues/20050

> [!NOTE]
> Generated by Coder Agents

<details><summary>Decision log</summary>

- Chose `window.location.href` over invalidating React Query caches
because a hard reload is the only way to get fresh server-rendered meta
tags. The API query approach still has a flash between mount and
response.
- Sanitized redirect URL with `redirectUrl.pathname` (same as existing
`<Navigate>` path) to prevent open redirects via absolute URLs.
- Removed unused `useNavigate` import.

</details>

---------

Co-authored-by: Kayla はな <kayla@tree.camp>
2026-04-17 16:28:03 -04:00
david-fraley 1feb183a87 docs: remove unused paused and completed chat statuses, add requires_action (#24264) 2026-04-17 15:17:37 -05:00
david-fraley c40f45b986 fix(site/src/pages/AgentsPage/components): insert newline on mobile Enter (#24498) 2026-04-17 14:55:18 -05:00
Kayla はな 72c3563257 refactor: replace @mui/x-tree-view with simple tree components (#24266) 2026-04-17 13:01:34 -06:00
Cian Johnston 3f6b40a833 fix: reap idle chatd stream states on a timer (#24476)
* Adds `streamJanitorLoop` to clean up stale streams every 30s
* zeroes dropped slots to aid in gc-eligibliity
* Adds regression tests in coderd/x/chatd and enterprise/coderd/x/chatd

> 🤖
2026-04-17 19:22:00 +01:00
Ehab Younes ee563636ed fix(dogfood): update display name and add README (#24487)
Update the `vscode-coder` dogfood template with better naming,
documentation, and agent testing instructions.
2026-04-17 19:06:44 +03:00