Commit Graph
5611 Commits
Author SHA1 Message Date
dylanhuff-at-coder d5a3963167 feat: add bulk user secret import endpoint and SDK client (PLAT-240) (#26724)
Adds `POST /api/v2/users/{user}/secrets/batch` and
`codersdk.Client.ImportUserSecrets` to import env, JSON, or YAML secrets
atomically. The endpoint validates each entry, rolls back the full batch
on conflicts or limits, omits secret values from responses and audit
logs, and imports keys that cannot be injected as environment variables
with an empty `env_name`.

Part of the [PLAT-240 bulk secret import
stack](https://linear.app/codercom/issue/PLAT-240). Reviewed and updated
by Coder Agents on behalf of @dylanhuff-at-coder.
2026-07-23 14:55:34 -07:00
Ehab Younes 10624122c5 feat(site/src): show spend for unlimited and zero AI budgets (#27458)
The group members table hid a member's spend behind a bare "Unlimited"
label when their budget resolves to a group with no limit, and rendered
a $0 budget as a special "None" label. Spend now always shows: as
"$X / Unlimited USD" for unlimited budgets, and as a normal limit row
("Group limit $0", exceeded color once spend is above zero) for $0
budgets.

The Everyone badge drops "(not allocated)" when the Everyone group's
own budget or a user override applies, showing "Everyone" or
"Everyone (individual)" instead. The not-attributed tooltip now states
that the amount is the user's spend in the viewed group and that their
AI budget is managed by another group, replacing the misleading
"Not attributed to this group" wording.
2026-07-23 17:38:05 +00:00
Jaayden HalkoandCursor 3c7a1d33e3 feat: add persisted whole-chat summary with background generation (#26657)
Adds a persisted whole-chat summary that backs the chat summary popover.
A new nullable `chats.summary` column is populated in the background
after a successful root-chat turn and pushed to clients via a new
`chat_summary_change` watch event (distinct from `summary_change`, which
is bound to `last_turn_summary`), so the popover reads `chat.summary`
straight off the loaded `Chat` with no extra query.

This is the data source for the popover and per-chat cost UI built in
#26649; the popover can consume `chat.summary` once this lands (the
field is nullable, so merge order does not matter).

## How it works

- **Generation** runs in the existing successful-turn finalize hook,
detached from the request so the user's turn is never blocked. A cadence
gate generates the first summary after one completed turn, then
regenerates every three turns, using the `chats.summary_generated_at`
freshness marker. Generation reads compaction-aware history, renders it
to a bounded plain-text transcript (short transcripts are skipped), and
asks for a 1-3 sentence summary via structured output. Failures never
clear an existing summary.
- **Staleness** is guarded by `history_version` (mirroring
`last_turn_summary`), so a background write racing a newer turn loses
while worker lifecycle transitions cannot reject a fresh write.
- **Model selection** uses the chat's configured model.

## Deferred to follow-ups

- **Cost accounting**: the `chat_messages.cost_source` discriminator and
summary/title usage recording were removed from this PR so summary
persistence is not blocked by hidden accounting rows advancing
`history_version`. Title usage recording stays on main's
`InsertChatMessages` path.
- **Model override**: deployment-wide summary generation model selection
is split into #26803; the base feature always uses the chat model.

## Notes

- Migration `000540` adds `chats.summary` and
`chats.summary_generated_at`, and recreates `chats_expanded` to expose
the new columns.
- Root chats only; shared viewers pick up the summary on their next
refetch (live watch events are owner-only).

Refs #26649

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-23 16:36:23 +01:00
Danielle Maywood 9ce366414e fix(site): remember reasoning effort per model on new chat (#27457) 2026-07-23 13:37:50 +01:00
Susana Ferreira c23f2c0223 feat: fall back to the Everyone group for AI spend attribution (#27364)
## Description

Previously, a user with no per-user override and no membership in a budgeted group had no effective group, so their AI spend was attributed nowhere and was, therefore, untracked. This change falls back to the organization's Everyone group when no override or group budget applies.

Since every user in an organization is implicitly a member of that org's Everyone group, spend is now attributed and tracked for any user with organization membership. A user with no organization membership resolves to no group, so their daily spend is not incremented and a warning is logged.

The fallback is unlimited, so enforcement is unaffected: only override and group budgets can block requests. For users in multiple organizations, an existing budget on any Everyone group is still chosen by the "highest" policy; when none is budgeted, the fallback prefers the default org, then orders by organization name.

## Changes

- Add `ResolveUserEffectiveGroup` and the `GetUserEveryoneFallbackGroup` query: resolve override → group budget → Everyone group fallback.
- Attribute token-usage spend and the user AI spend endpoint via the fallback, so unbudgeted users resolve to their Everyone group instead of null.
- Update `GetGroupMembersAISpend` to surface the Everyone fallback as the effective group.
- Update `GetHighestGroupAIBudgetByUser` to break ties by organization name then group name, keeping multi-org resolution deterministic and consistent with the fallback.
- For multi-org users with no budget anywhere, the fallback picks the Everyone group deterministically: prefer the default org, then order by organization name.

Closes https://linear.app/codercom/issue/AIGOV-509/fall-back-to-the-everyone-group-for-spend-attribution

> [!NOTE]
> Initially generated by Claude Opus 4.7, modified and reviewed by @ssncferreira
2026-07-23 09:26:25 +01:00
Michael Suchacz 52a687902f docs: add frontend-review skill for pre-PR FE rule audits (#27408)
## What

Adds `.claude/skills/frontend-review`, a diff-scoped self-review skill
that audits changes under `site/src/` against the FE1 to FE10 rule
contract before a PR is created or updated. Each rule has a concrete
"what to look for in a diff" checklist, and the output format is a terse
per-rule PASS/FAIL table with `file:line` findings.

Wiring:

- `site/AGENTS.md` Pre-PR Checklist gains step 6: run the audit when the
diff touches `site/src/`.
- `.claude/skills/code-review` now cites FE rule IDs for frontend
findings.
- The deep-review `frontend-reviewer` role audits against the same
contract.

## Why

Most frontend review findings are semantic (missing interaction
coverage, clobbered form state, near-duplicate components) and cannot be
linted. Today they are caught post-hoc by reviewers and the review bot,
which is exactly the "PRs get complaints" experience. Running the same
rubric before the PR exists converts review rounds into pre-push fixes.

Stacked on #27407 (the rule contract). The deterministic-checks
follow-up (#27409) was closed; that subset will be enforced through
proper linting instead.

> This PR was written by Mux, an AI coding agent, on behalf of Mike.
2026-07-23 07:22:10 +02:00
Michael Suchacz 5565fcd03b docs: add frontend pattern rule contract (FE1-FE10) (#27407)
## What

Adds `.claude/docs/FRONTEND_PATTERNS.md`, a canonical frontend rule
contract for `site/src/` with ten stable rule IDs (FE1 to FE10), each
with short incorrect/correct examples using real repo idioms. Adds a
compact non-negotiables index at the top of `site/AGENTS.md` and links
the contract from the root `AGENTS.md` frontend routing line.

## Why

Frontend PRs keep drawing the same review findings. Mining the last 18
months of `site/` PR review data (330 closed/merged PRs, 1,105 inline
comments, 358 actionable pattern findings across 57 PRs) shows the
recurring themes, in order of frequency: missing Storybook interaction
coverage, loose TypeScript, component duplication and PR scope,
redundant comments, unhandled UI states, accessibility, react-query
misuse, and effect misuse. The guidance largely existed in
`site/AGENTS.md` already, but as unprioritized prose with no shared
vocabulary.

Stable rule IDs give reviewers, agents, and tooling one shared language
("FE7: re-typed query key"), and the rules are ordered by how often
reviewers actually flagged them.

This is the first PR of a stack of two:

1. This PR: the rule contract.
2. A `frontend-review` skill that audits diffs against these rules
pre-PR (#27408).

A third PR with a deterministic ratchet script (#27409) was closed; the
machine-checkable subset will be enforced through proper linting
instead.

## Notes for reviewers

The rule content is derived from your own review comments (for example,
the re-typed query key example in FE7 mirrors feedback on #27385). If a
rule does not match how you want the frontend built, the contract file
is the place to change it.

> This PR was written by Mux, an AI coding agent, on behalf of Mike.
2026-07-23 07:21:27 +02:00
McKayla はな 1c2bb07b81 chore(site): upgrade to pixel 0.2 (#27353) 2026-07-22 22:27:05 +00:00
Jeremy Ruppel 6b22383823 fix(site/src/pages/TemplateBuilder): show all step content without inner scroll (#27437)
## Summary

The Template Builder steps clipped their content to an inner scrollbar
via
`max-h-[calc(...)]` + `overflow-y-auto`, so the base picker showed fewer
than
three rows before requiring scroll. This removes those wrappers from all
four
steps so every base/module renders and the page scrolls naturally.

Resolves DEVEX-585.

## Changes

- `BaseInfraSelectStep.tsx` — base picker grid (3-col grid retained)
- `ModuleSelectStep.tsx` — module picker grid
- `ModuleSettingsStep.tsx` — module variables list
- `BaseTemplateParametersStep.tsx` — base config; unwrapped the
now-styleless
  wrapper `div` into the fragment

The sticky sidebar summary (`SelectionSummary.tsx`) is intentionally
left as-is;
it is not a wizard step.

### Tradeoff

With the inner scroll removed, the Back/Continue controls sit below the
full
grid, so reaching them requires page scroll when a list is long. This
matches
the requested "just show all of em" behavior.


https://github.com/user-attachments/assets/7e371850-7b97-42c7-b92c-5ac00a3e7979

<details>
<summary>Implementation plan</summary>

# DEVEX-585: Show more base templates before requiring scroll

## Problem
The base template picker on the Template Builder feels too narrow: it
clips to
fewer than three rows before an inner scrollbar appears.

## Root cause
The step grids were wrapped in `max-h-[calc(100vh-420px)]
overflow-y-auto`
(and `340px` variants), constraining height so only a couple of rows
showed
before an inner scrollbar clipped the rest.

## Approach (chosen: remove inner scroll)
Show all content and let the page scroll naturally by removing the
height/scroll utilities (and stale comments) from each step's container.
Applied to the base picker, base parameters, module picker, and module
settings steps.

## Testing / verification
- Biome check passes on all edited files; LSP reports no diagnostics.
- Visual: each step renders all content with no inner scrollbar; the
page
  scrolls if the list is long.

## Out of scope
- The sidebar summary scroll (`SelectionSummary.tsx`) is not a wizard
step.
- Auto-filling customization fields (separate work, PR #27272).

</details>

---

This PR was generated by Coder Agents on behalf of @jeremyruppel.
2026-07-22 16:05:29 -05:00
Jeremy Ruppel c309f4d5ff feat(site/src/pages/TemplateBuilder): auto-fill customization fields from base template (#27272)
Closes
[DEVEX-586](https://linear.app/codercom/issue/DEVEX-586/auto-fill-customization-fields-from-selected-base-template).

The Template Builder wizard's final **Customizations** step rendered
empty inputs for ID, Display name, Description, and Icon. This seeds
those fields with sensible defaults derived from the selected base
template, while keeping every field editable.

## Changes

All frontend, in `site/src/pages/TemplateBuilder/wizardState.ts`:

- `SelectedBaseMeta` now carries `description`, mapped in
`toSelectedBaseMeta`.
- New pure helper `baseCustomizationDefaults(base)` maps the base to `{
name: base.id, displayName: base.name, description, icon }`.
- `SET_BASE` seeds the four customization fields when the base changes
(still clearing base variable values). Re-selecting the same base
preserves user edits.
- `initWizardState` seeds the same defaults for the `?base=` deeplink
entry path.
- `RESET_CUSTOMIZATIONS` (fired on back-navigation) now resets only
organization/provisioner state, so auto-filled values survive stepping
back and forth.

No change was needed in `TemplateCustomizationsStep.tsx`; it already
binds to these state fields, so seeded values render and stay editable.
Existing placeholders remain as the fallback when a base value is empty
(e.g. `scratch`).

### Default mapping

| Form field   | State key     | Source             |
| ------------ | ------------- | ------------------ |
| ID           | `name`        | `base.id`          |
| Display name | `displayName` | `base.name`        |
| Description  | `description` | `base.description` |
| Icon         | `icon`        | `base.icon`        |

`base.id` is used for the ID field because base ids are already valid
template slugs (`docker`, `aws-linux`, ...). Icon values are already
served asset paths (`/icon/*`, `/emojis/*`), so no lookup map is needed.

## Testing

- `wizardState.test.ts`: 27 passing, including new coverage for seeding,
base-change re-seed, same-base edit preservation,
`RESET_CUSTOMIZATIONS`, `initWizardState`, `toSelectedBaseMeta`, and
`baseCustomizationDefaults`.
- `biome check` clean; `tsc --noEmit` clean.

<img width="1043" height="593" alt="Screenshot 2026-07-15 at 2 17 19 PM"
src="https://github.com/user-attachments/assets/25620df4-b020-4430-b5f3-9ce8b7b9f379"
/>

<details>
<summary>Implementation plan</summary>

# DEVEX-586: Auto-fill customization fields from selected base template

## Goal

In the Template Builder wizard, the final **Customizations** step
currently renders empty inputs for Display name, Description, ID, and
Icon. Pre-populate these with sensible defaults derived from the
selected base template, while keeping every field editable. Organization
is already auto-selected when a single org is available, so it is out of
scope beyond leaving it untouched.

Source: Linear DEVEX-586 (Ben Potter): "Would love if all these options
... were auto-filled and generated and can be edited versus the user
manually filling it out." Fields called out: display name, description,
ID, and icon.

## Current behavior (findings)

Frontend lives in `site/src/pages/TemplateBuilder/`.

- `TemplateCustomizationsStep.tsx` renders the four fields bound to
`state.displayName`, `state.description`, `state.name` (the "ID" field),
and `state.icon`. All start empty (`initialWizardState`).
- `wizardState.ts` holds the state, the `wizardReducer`, and the
`SelectedBaseMeta` UI type.
  - `SelectedBaseMeta` did not carry `description`.
- `toSelectedBaseMeta(base)` maps the API `TemplateBuilderBase` into
`SelectedBaseMeta`.
- `SET_BASE` set the base and cleared `baseVariableValues` only when the
base id changed; customization fields were left empty.
- `RESET_CUSTOMIZATIONS` (dispatched by `handleBack`) blanked
org/provisioner plus `name`, `displayName`, `description`, `icon`.
- `initWizardState(preselectedBase)` seeded `baseTemplateId` and
`selectedBase` for deeplinks but left customization fields empty.
- API type `TemplateBuilderBase` exposes `id`, `name`, `description`,
`icon`, `os`, `variables`, `prerequisites`.
- Backend (`coderd/templatebuilder_handler.go`) builds each base from
the built-in `TemplateExample`: `id = ex.ID`, `name = ex.Name`,
`description = ex.Description`, `icon = ex.Icon`.
- Base IDs are valid template names (lowercase, hyphen-separated):
`docker`, `kubernetes`, `aws-linux`, `aws-windows`, `gcp-linux`,
`gcp-windows`, `azure-linux`, `digitalocean-linux`, `scratch`.

## Default mapping

| Form field | State key | Default source |
| --- | --- | --- |
| ID (required) | `name` | `base.id` |
| Display name | `displayName` | `base.name` |
| Description | `description` | `base.description` |
| Icon | `icon` | `base.iconUrl` (`base.icon`) |
| Organization | `organizationId` | unchanged (already auto-selected) |

Rationale for `name = base.id`: base ids are guaranteed valid template
slugs, whereas slugifying the human display name is lossy and can
collide. The field stays editable.

## Icon default: confirmed, no map needed

The API already returns normalized, served asset paths in `base.icon`
(e.g. `/icon/docker.png`, `/icon/aws.svg`, `/emojis/1f4e6.png` for
`scratch`), the same values `CreateTemplatePage` assigns when creating
from a built-in example. `IconField` accepts any URL/path, so every base
renders correctly. A base-id-to-icon map is unnecessary.

## Implementation

Frontend-only, in `wizardState.ts`:

1. Add `description?: string` to `SelectedBaseMeta`; map it in
`toSelectedBaseMeta`.
2. Add pure helper `baseCustomizationDefaults(base)` returning `{ name,
displayName, description, icon }`.
3. `SET_BASE`: on base change, spread the defaults alongside the
`baseVariableValues: {}` reset; on same-base re-selection, preserve
existing values.
4. `initWizardState(preselectedBase)`: spread defaults into the returned
state.
5. Narrow `RESET_CUSTOMIZATIONS` to reset only `organizationId` and
`hasProvisioners`.
6. `toCreateTemplateRequest` already sends the fields, so no payload
change.

## Tests

Reducer unit tests in `wizardState.test.ts` for seeding, base-change
re-seed, same-base edit preservation, `RESET_CUSTOMIZATIONS`,
`initWizardState`, `toSelectedBaseMeta` (description carried), and
`baseCustomizationDefaults`.

## Scope / non-goals

- No backend changes; the API already returns all needed fields.
- Organization auto-selection is unchanged.
- No slug transformation of display names (base id is used directly).
- No base-id-to-icon map.

</details>

---
*Opened by Coder Agents on behalf of @jeremyruppel.*
2026-07-22 15:09:37 -05:00
Michael Suchacz 02fd1cc691 feat: allow spawn_agent model and reasoning effort override (#27385) 2026-07-22 18:43:22 +02:00
dylanhuff-at-coder 99e740bdb7 feat: add user secrets file parser and shared validator (PLAT-240) (#26723)
Part of the **PLAT-240** bulk secret import stack: this PR adds the
`codersdk` parser and shared create-secret validator used by the
follow-up batch endpoint and UI PRs.

`ParseSecretsFile` parses `.env`, `.json`, and `.yaml` files into
`CreateUserSecretRequest` entries in source order, with size, count,
duplicate-key, structure, and malformed-input checks.
`ValidateCreateUserSecretRequest` now backs the single-create handler
too, so create validation has one SDK-level implementation.

Part of https://linear.app/codercom/issue/PLAT-240

> This PR was generated by Coder Agents on behalf of
@dylanhuff-at-coder.
2026-07-22 06:23:38 -07:00
Danielle Maywood ff71bb3850 fix(site): align AI Settings model provider dropdowns (#27391) 2026-07-22 14:13:31 +01:00
Sas SwartandClaude Opus 4.8 f17d488479 feat: add network call badges to AI sessions table (#27341)
Surface the total and blocked Agent Firewall network calls on the AI
sessions list. Sessions that did not pass through Agent Firewall show as
"Disabled".

<img width="2842" height="1366" alt="image"
src="https://github.com/user-attachments/assets/2a68b4a9-4d93-454d-a06e-5f0d0b734a33"
/>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 14:16:31 +02:00
Danielle Maywood 507ce504f8 refactor(site): align AgentsPage layout naming with codebase conventions (#27378) 2026-07-22 13:16:14 +01:00
Ehab Younes 6ec45f75c6 chore(site): replace handrolled AI spend types with generated types (#27342)
The groups and group members pages consumed AI spend through local ai_cost_control wrapper types with TODOs to adopt the generated contract. Both spend endpoints are now live, so this switches to the generated types and hardens the fetch path.

- Use OrganizationGroupsAISpend and GroupMembersAISpend from typesGenerated for the org groups and group members spend endpoints
- Fetch identity and spend separately, joining by group_id/user_id at the container so each row gets one enriched object
- Batch spend requests at the backend cap of 100 IDs in the API client and merge the responses, with table-driven tests covering both endpoints
- Treat a null effective_group_id as a budget managed by a group in another org: render an em-dash with an info tooltip and skip the group name lookup instead of firing an empty-ID request

Closes AIGOV-509
2026-07-22 12:17:22 +03:00
Michael Suchacz 608c2ee46f fix(site/src/pages/AgentsPage/components/ChatMessageInput): scroll skills menu selection into view (#27345)
When navigating the slash skills menu with arrow keys, moving the
highlight past the visible area did not scroll the list, so the selected
skill went out of view.

The menu drives cmdk in controlled mode while arrow keys are consumed by
the Lexical trigger plugin, so cmdk's internal scroll-into-view never
runs for keyboard navigation. This adds a layout effect in
`SkillsTriggerMenu` that scrolls the highlighted item (and its group
heading when it is the first item in a group) into view on
keyboard-driven index changes, while skipping pointer-driven highlights
to avoid hover/scroll loops, matching cmdk's own behavior.

Covered by two new interaction stories that fail without the fix:
`ScrollsSelectionIntoView` (menu in isolation) and
`ArrowKeysScrollMenuList` (end-to-end arrow-key wrap in
`ChatMessageInput`).

> Opened by Mux, an AI coding agent, on Mike's behalf.
2026-07-21 19:23:42 +02:00
Michael Suchacz dcf3cce51c fix(site/src/pages/AgentsPage): clarify empty context usage popover state (#27389)
## Summary

The context usage badge popover showed "Context usage unavailable"
before any assistant message reported token usage, which read like an
error. This changes the empty-state copy to "Context usage will appear
after sending a message." and fixes a spacing bug that state exposed:
the pinned context list's top margin was conditional on a usage
percentage being present, so without usage data the list sat flush
against the message.

## Changes

- `ContextUsageIndicator`: new empty-state copy; unconditional `mt-2` on
the context list.
- Stories: `NoUsage` (message only) and `NoUsageWithContext` (message
plus pinned resource list), both asserting the new copy via hover
interactions.

## Testing

- Storybook interaction stories cover both empty states.
- `biome check` and `tsc --noEmit` pass; verified visually in Storybook.

> This PR was authored by Mux, an AI coding agent, acting on Mike's
behalf.
2026-07-21 16:24:35 +00:00
Sas SwartandClaude Opus 4.8 a9a1dcc65d feat: add network calls column to AI sessions table (#27269)
Add a "Total/blocked network calls" column to the AIBridge sessions
table.

Update `ListAIBridgeSessions` query to calculate network called made and
blocked per session. See query plan
[here](https://explain.dalibo.com/plan/54355c90b165ggb4).

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 14:34:23 +02:00
Danielle Maywood 6014a44c85 fix(site): keep mobile model picker effort row and last model visible (#27336) 2026-07-21 12:37:55 +01:00
Michael Suchacz 3227cac217 feat: add manual chat compaction via /compact (#27081)
Adds a user-triggered `/compact` action for Coder Agents chats: typing
`/compact` in the composer (or picking it from the `/` trigger menu)
summarizes the conversation so far to free up context window space.

## How it works

- New `POST /api/experimental/chats/{chat}/compact` endpoint
(owner-only, RBAC `ActionUpdate`, excluded from the public API reference
via `x-apidocgen skip`). It marks the chat with a durable one-shot
`chats.compaction_requested_at` signal and moves it `waiting -> running`
via a new `RequestCompaction` state transition; no message row is
inserted. AI Gateway attribution needs no per-request key: generation
preparation resolves the owner's synthetic API key (#27170) like any
other turn.
- `RequestCompaction` hands off chat ownership (clears
`worker_id`/`runner_id`) so a worker acquisition hint is published;
since the transition changes no history, the previous runner could
otherwise miss the request under reordered pubsub delivery.
- The background chat worker picks the chat up like any other turn. A
pending manual request takes precedence over turn completion in the
generation decision, and forces compaction even below the automatic
threshold (and when compaction is disabled via threshold=100). The
commit step consumes the request marker in the same transaction; any
transition that ends the turn clears stale markers.
- The summary triplet reuses the automatic-compaction path, now tagged
with a `source` (`automatic` | `manual`) that is plumbed through
streamed progress parts, persisted tool JSON, and the UI label
("Summarized (manual)").
- Validation order: busy chats reject with 409 (state-machine conflict),
empty/already-compacted chats with 409 "nothing to compact", archived
chats with 400; the owner usage-limit check runs last so no-op requests
surface the specific conflict instead of a limit error.
- Web UI: the `/` trigger menu now has a built-in "Commands" group
listing `/compact`; submit intercepts exactly `/compact` and calls the
endpoint instead of sending a message. A personal or workspace skill
named `compact` takes precedence over the built-in command; while skill
collisions are still resolving, an exact `/compact` submission is
blocked with a retryable hint instead of leaking as message text.
History and queued-message edits are never intercepted. After
compaction, the context usage indicator resets to its unknown state
until the next assistant response reports fresh usage, instead of
showing the stale pre-compaction number.
- codersdk: `ExperimentalClient.CompactChat`.

Worker-path execution (rather than compacting synchronously in the
handler) reuses the existing lock fencing, live "Summarizing..."
streaming, retry accounting, restart resilience, and debug-run
observability. Rationale documented in `coderd/x/chatd/ARCHITECTURE.md`.

## Testing

- State machine: transition-matrix coverage for `RequestCompaction`,
marker lifecycle tests (carried by lease renewals/queue appends, cleared
by terminal transitions, consumed by commit), ownership handoff +
acquisition hint assertions.
- Worker: decision-ordering and forced-compaction unit tests;
active-server end-to-end test (manual compact below threshold produces a
`source=manual` summary, returns to `waiting`, no assistant follow-up;
busy chat rejected).
- API: success, archived, non-owner, RBAC-denied, empty-chat, no-daemon
cases; usage-limit ordering (at-limit owners still get
state/nothing-to-compact conflicts for no-op requests, with marker
rollback).
- Frontend: Storybook play tests for the Commands menu group, submit
intercept, skill-name collision, queued-edit passthrough, and
manual/automatic tool rendering; unit tests for command availability
resolution and the post-compaction context usage reset.

> This PR was created by Mux, an AI coding agent, working on Mike's
behalf.
2026-07-21 10:58:08 +02:00
dependabot[bot] 69a045f944 chore: bump axios from 1.16.1 to 1.18.0 in /site (#27350)
Bumps [axios](https://github.com/axios/axios) from 1.16.1 to 1.18.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/axios/axios/releases">axios's
releases</a>.</em></p>
<blockquote>
<h2>v1.18.0 — June 13, 2026</h2>
<p>This release hardens redirect and URL handling, improves the
validateStatus configuration semantics, and includes updates to
documentation, dependencies, and release metadata.</p>
<h2>🔒 Security Fixes</h2>
<ul>
<li>
<p><strong>Redirect Header Safety:</strong> Added Node HTTP adapter
support for stripping caller-specified sensitive headers on cross-origin
redirects, helping prevent custom auth headers such as API keys from
leaking to another origin. (<strong><a
href="https://redirect.github.com/axios/axios/issues/10892">#10892</a></strong>)</p>
</li>
<li>
<p><strong>URL And Request Hardening:</strong> Rejects malformed
<code>http:</code> and <code>https:</code> URLs that omit
<code>//</code> with <code>ERR_INVALID_URL</code>, while tightening
prototype-pollution-safe config reads, stream size limits, FormData
depth handling, data URL sizing, and local <code>NO_PROXY</code>
matching. (<strong><a
href="https://redirect.github.com/axios/axios/issues/11000">#11000</a></strong>)</p>
</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li><strong>Status Validation:</strong> Added
<code>transitional.validateStatusUndefinedResolves</code> so
applications can opt in to treating <code>validateStatus:
undefined</code> like the option was omitted, while
<code>validateStatus: null</code> remains the explicit way to accept
every status. (<strong><a
href="https://redirect.github.com/axios/axios/issues/10899">#10899</a></strong>)</li>
</ul>
<h2>🔧 Maintenance &amp; Chores</h2>
<ul>
<li>
<p><strong>Documentation:</strong> Published the v1.17.0 release notes,
fixed a changelog typo, clarified the package update PR policy, and
marked the <code>proxy</code> request config as Node.js-only in the
advanced docs. (<strong><a
href="https://redirect.github.com/axios/axios/issues/10984">#10984</a></strong>,
<strong><a
href="https://redirect.github.com/axios/axios/issues/10988">#10988</a></strong>,
<strong><a
href="https://redirect.github.com/axios/axios/issues/10992">#10992</a></strong>,
<strong><a
href="https://redirect.github.com/axios/axios/issues/10995">#10995</a></strong>)</p>
</li>
<li>
<p><strong>Dependencies:</strong> Bumped <code>@babel/core</code>,
<code>@babel/preset-env</code>, <code>@commitlint/cli</code>,
<code>@commitlint/config-conventional</code>,
<code>@rollup/plugin-babel</code>, <code>@rollup/plugin-commonjs</code>,
<code>@vitest/browser</code>, <code>@vitest/browser-playwright</code>,
<code>eslint</code>, <code>lint-staged</code>, <code>rollup</code>,
<code>vitest</code>, and <code>actions/checkout</code>. (<strong><a
href="https://redirect.github.com/axios/axios/issues/10989">#10989</a></strong>,
<strong><a
href="https://redirect.github.com/axios/axios/issues/10996">#10996</a></strong>,
<strong><a
href="https://redirect.github.com/axios/axios/issues/10997">#10997</a></strong>)</p>
</li>
<li>
<p><strong>Release Metadata:</strong> Prepared the 1.18.0 release by
updating package metadata and the runtime <code>VERSION</code> value.
(<strong><a
href="https://redirect.github.com/axios/axios/issues/11003">#11003</a></strong>)</p>
</li>
</ul>
<h2>🌟 New Contributors</h2>
<p>We are thrilled to welcome our new contributors. Thank you for
helping improve axios:</p>
<ul>
<li><strong><a
href="https://github.com/drori12"><code>@​drori12</code></a></strong>
(<strong><a
href="https://redirect.github.com/axios/axios/issues/10984">#10984</a></strong>)</li>
<li><strong><a
href="https://github.com/eyupcanakman"><code>@​eyupcanakman</code></a></strong>
(<strong><a
href="https://redirect.github.com/axios/axios/issues/10899">#10899</a></strong>)</li>
<li><strong><a
href="https://github.com/Adi-Beker"><code>@​Adi-Beker</code></a></strong>
(<strong><a
href="https://redirect.github.com/axios/axios/issues/10995">#10995</a></strong>)</li>
</ul>
<p><a
href="https://github.com/axios/axios/compare/v1.17.0...v1.18.0">Full
Changelog</a></p>
<h2>v1.17.0 — June 1, 2026</h2>
<p>This release adds Node HTTP zstd decompression, hardens config and
release workflows, and fixes authentication, header, proxy, and
type-handling regressions.</p>
<h2>🔒 Security Fixes</h2>
<ul>
<li><strong>Config Hardening:</strong> Guarded <code>socketPath</code>,
<code>params</code>, and <code>paramsSerializer</code> reads with
own-property checks to prevent inherited prototype values from affecting
request behavior, including SSRF-sensitive paths. (<strong><a
href="https://redirect.github.com/axios/axios/issues/10901">#10901</a></strong>,
<strong><a
href="https://redirect.github.com/axios/axios/issues/10922">#10922</a></strong>)</li>
<li><strong>Release Publishing:</strong> Switched the publish workflow
to npm staged publishing for safer, auditable package releases with
provenance. (<strong><a
href="https://redirect.github.com/axios/axios/issues/10926">#10926</a></strong>)</li>
</ul>
<h2>🚀 New Features</h2>
<ul>
<li><strong>HTTP Compression:</strong> Added Node HTTP adapter support
for zstd response decompression, with
<code>transitional.advertiseZstdAcceptEncoding</code> controlling
whether <code>zstd</code> is advertised in <code>Accept-Encoding</code>.
(<strong><a
href="https://redirect.github.com/axios/axios/issues/6792">#6792</a></strong>,
<strong><a
href="https://redirect.github.com/axios/axios/issues/10920">#10920</a></strong>)</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li><strong>Authentication Handling:</strong> Restored Basic auth on
same-origin Node redirects while continuing to strip credentials
cross-origin, and aligned the fetch adapter with HTTP adapter behavior
for URL-embedded Basic auth. (<strong><a
href="https://redirect.github.com/axios/axios/issues/10929">#10929</a></strong>,
<strong><a
href="https://redirect.github.com/axios/axios/issues/10896">#10896</a></strong>)</li>
<li><strong>Proxy TLS:</strong> Preserved user <code>httpsAgent</code>
TLS options when tunneling HTTPS requests through HTTP CONNECT proxies.
(<strong><a
href="https://redirect.github.com/axios/axios/issues/10957">#10957</a></strong>)</li>
<li><strong>React Native FormData:</strong> Cleared default
<code>Content-Type</code> for React Native <code>FormData</code> so
multipart boundaries can be generated correctly. (<strong><a
href="https://redirect.github.com/axios/axios/issues/10898">#10898</a></strong>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/axios/axios/blob/v1.x/CHANGELOG.md">axios's
changelog</a>.</em></p>
<blockquote>
<h2>v1.18.0 — June 13, 2026</h2>
<p>This release hardens redirect and URL handling, improves the
validateStatus configuration semantics, and includes updates to
documentation, dependencies, and release metadata.</p>
<h2>🔒 Security Fixes</h2>
<ul>
<li>
<p><strong>Redirect Header Safety:</strong> Added Node HTTP adapter
support for stripping caller-specified sensitive headers on cross-origin
redirects, helping prevent custom auth headers such as API keys from
leaking to another origin. (<strong><a
href="https://redirect.github.com/axios/axios/issues/10892">#10892</a></strong>)</p>
</li>
<li>
<p><strong>URL And Request Hardening:</strong> Rejects malformed
<code>http:</code> and <code>https:</code> URLs that omit
<code>//</code> with <code>ERR_INVALID_URL</code>, while tightening
prototype-pollution-safe config reads, stream size limits, FormData
depth handling, data URL sizing, and local <code>NO_PROXY</code>
matching. (<strong><a
href="https://redirect.github.com/axios/axios/issues/11000">#11000</a></strong>)</p>
</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li><strong>Status Validation:</strong> Added
<code>transitional.validateStatusUndefinedResolves</code> so
applications can opt in to treating <code>validateStatus:
undefined</code> like the option was omitted, while
<code>validateStatus: null</code> remains the explicit way to accept
every status. (<strong><a
href="https://redirect.github.com/axios/axios/issues/10899">#10899</a></strong>)</li>
</ul>
<h2>🔧 Maintenance &amp; Chores</h2>
<ul>
<li>
<p><strong>Documentation:</strong> Published the v1.17.0 release notes,
fixed a changelog typo, clarified the package update PR policy, and
marked the <code>proxy</code> request config as Node.js-only in the
advanced docs. (<strong><a
href="https://redirect.github.com/axios/axios/issues/10984">#10984</a></strong>,
<strong><a
href="https://redirect.github.com/axios/axios/issues/10988">#10988</a></strong>,
<strong><a
href="https://redirect.github.com/axios/axios/issues/10992">#10992</a></strong>,
<strong><a
href="https://redirect.github.com/axios/axios/issues/10995">#10995</a></strong>)</p>
</li>
<li>
<p><strong>Dependencies:</strong> Bumped <code>@babel/core</code>,
<code>@babel/preset-env</code>, <code>@commitlint/cli</code>,
<code>@commitlint/config-conventional</code>,
<code>@rollup/plugin-babel</code>, <code>@rollup/plugin-commonjs</code>,
<code>@vitest/browser</code>, <code>@vitest/browser-playwright</code>,
<code>eslint</code>, <code>lint-staged</code>, <code>rollup</code>,
<code>vitest</code>, and <code>actions/checkout</code>. (<strong><a
href="https://redirect.github.com/axios/axios/issues/10989">#10989</a></strong>,
<strong><a
href="https://redirect.github.com/axios/axios/issues/10996">#10996</a></strong>,
<strong><a
href="https://redirect.github.com/axios/axios/issues/10997">#10997</a></strong>)</p>
</li>
<li>
<p><strong>Release Metadata:</strong> Prepared the 1.18.0 release by
updating package metadata and the runtime <code>VERSION</code> value.
(<strong><a
href="https://redirect.github.com/axios/axios/issues/11003">#11003</a></strong>)</p>
</li>
</ul>
<h2>🌟 New Contributors</h2>
<p>We are thrilled to welcome our new contributors. Thank you for
helping improve axios:</p>
<ul>
<li><strong><a
href="https://github.com/drori12"><code>@​drori12</code></a></strong>
(<strong><a
href="https://redirect.github.com/axios/axios/issues/10984">#10984</a></strong>)</li>
<li><strong><a
href="https://github.com/eyupcanakman"><code>@​eyupcanakman</code></a></strong>
(<strong><a
href="https://redirect.github.com/axios/axios/issues/10899">#10899</a></strong>)</li>
<li><strong><a
href="https://github.com/Adi-Beker"><code>@​Adi-Beker</code></a></strong>
(<strong><a
href="https://redirect.github.com/axios/axios/issues/10995">#10995</a></strong>)</li>
</ul>
<p><a
href="https://github.com/axios/axios/compare/v1.17.0...v1.18.0">Full
Changelog</a></p>
<h2>v1.17.0 — June 1, 2026</h2>
<p>This release adds Node HTTP zstd decompression, hardens config and
release workflows, and fixes authentication, header, proxy, and
type-handling regressions.</p>
<h2>🔒 Security Fixes</h2>
<ul>
<li><strong>Config Hardening:</strong> Guarded <code>socketPath</code>,
<code>params</code>, and <code>paramsSerializer</code> reads with
own-property checks to prevent inherited prototype values from affecting
request behavior, including SSRF-sensitive paths. (<strong><a
href="https://redirect.github.com/axios/axios/issues/10901">#10901</a></strong>,
<strong><a
href="https://redirect.github.com/axios/axios/issues/10922">#10922</a></strong>)</li>
<li><strong>Release Publishing:</strong> Switched the publish workflow
to npm staged publishing for safer, auditable package releases with
provenance. (<strong><a
href="https://redirect.github.com/axios/axios/issues/10926">#10926</a></strong>)</li>
</ul>
<h2>🚀 New Features</h2>
<ul>
<li><strong>HTTP Compression:</strong> Added Node HTTP adapter support
for zstd response decompression, with
<code>transitional.advertiseZstdAcceptEncoding</code> controlling
whether <code>zstd</code> is advertised in <code>Accept-Encoding</code>.
(<strong><a
href="https://redirect.github.com/axios/axios/issues/6792">#6792</a></strong>,
<strong><a
href="https://redirect.github.com/axios/axios/issues/10920">#10920</a></strong>)</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li><strong>Authentication Handling:</strong> Restored Basic auth on
same-origin Node redirects while continuing to strip credentials
cross-origin, and aligned the fetch adapter with HTTP adapter behavior
for URL-embedded Basic auth. (<strong><a
href="https://redirect.github.com/axios/axios/issues/10929">#10929</a></strong>,
<strong><a
href="https://redirect.github.com/axios/axios/issues/10896">#10896</a></strong>)</li>
<li><strong>Proxy TLS:</strong> Preserved user <code>httpsAgent</code>
TLS options when tunneling HTTPS requests through HTTP CONNECT proxies.
(<strong><a
href="https://redirect.github.com/axios/axios/issues/10957">#10957</a></strong>)</li>
<li><strong>React Native FormData:</strong> Cleared default
<code>Content-Type</code> for React Native <code>FormData</code> so
multipart boundaries can be generated correctly. (<strong><a
href="https://redirect.github.com/axios/axios/issues/10898">#10898</a></strong>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/axios/axios/commit/2d06f96e8602c2db13b65a26340ee4a1bbc0b61f"><code>2d06f96</code></a>
chore(release): prepare release 1.18.0 (<a
href="https://redirect.github.com/axios/axios/issues/11003">#11003</a>)</li>
<li><a
href="https://github.com/axios/axios/commit/32fc489632377d214db55bfa4e2c48486a7d7ce2"><code>32fc489</code></a>
fix: malformed http urls (<a
href="https://redirect.github.com/axios/axios/issues/11000">#11000</a>)</li>
<li><a
href="https://github.com/axios/axios/commit/b40ce498abfa10d90b873b4fd08f520afa5d2545"><code>b40ce49</code></a>
chore(deps-dev): bump the development_dependencies group with 10 updates
(<a
href="https://redirect.github.com/axios/axios/issues/10">#10</a>...</li>
<li><a
href="https://github.com/axios/axios/commit/fe964f960ecb52c3e1155b0daf7be77541956b01"><code>fe964f9</code></a>
docs: mark proxy config as Node.js only (<a
href="https://redirect.github.com/axios/axios/issues/10995">#10995</a>)</li>
<li><a
href="https://github.com/axios/axios/commit/5f229d2d1f018d1db3dab6bbe034dbf3f9041b99"><code>5f229d2</code></a>
chore(deps): bump actions/checkout from 6.0.2 to 6.0.3 in the
github-actions ...</li>
<li><a
href="https://github.com/axios/axios/commit/fae9d4e7db6a858c407c75e607a071c533c5c4f6"><code>fae9d4e</code></a>
docs: clarify package update PR policy (<a
href="https://redirect.github.com/axios/axios/issues/10992">#10992</a>)</li>
<li><a
href="https://github.com/axios/axios/commit/28ab2ced820e55192806c53472ab3eb0cbb68dc2"><code>28ab2ce</code></a>
chore(deps-dev): bump the development_dependencies group with 2 updates
(<a
href="https://redirect.github.com/axios/axios/issues/10989">#10989</a>)</li>
<li><a
href="https://github.com/axios/axios/commit/a8e4f13aeecc45a3b8fab3ecfd9ddb5d70fb772b"><code>a8e4f13</code></a>
fix(core): keep default validateStatus when request passes undefined (<a
href="https://redirect.github.com/axios/axios/issues/10899">#10899</a>)</li>
<li><a
href="https://github.com/axios/axios/commit/614f4552a17de757d4171ad7c3bd38c9c1025fd8"><code>614f455</code></a>
docs: publish v1.17.0 release notes (<a
href="https://redirect.github.com/axios/axios/issues/10988">#10988</a>)</li>
<li><a
href="https://github.com/axios/axios/commit/6bb12c191f5380fad321322fb90216ae0dc36985"><code>6bb12c1</code></a>
fix: custom auth headers not stripped on cross-origin redirects (<a
href="https://redirect.github.com/axios/axios/issues/10892">#10892</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/axios/axios/compare/v1.16.1...v1.18.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=axios&package-manager=npm_and_yarn&previous-version=1.16.1&new-version=1.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-07-20 19:06:59 +00:00
Michael Suchacz f18c664be2 fix(site): stack settings layouts on mobile (#27334)
## Problem

On mobile viewports every settings shell renders a fixed 240px sidebar
next to the content in a non-responsive flex row, leaving the content
almost no width. The MCP Servers page is worst: its fixed-layout table
cannot shrink, so the whole page collapses into a single cramped column.

## Changes

- `Sidebar` component: full width below the `lg` breakpoint, `w-60` at
`lg`+.
- Six settings layouts (AI, Deployment, Organization, User, Workspace,
Template) stack the nav above the content below `lg` and keep the
previous side-by-side spacing at `lg`+. Content wrappers get `min-w-0`
so flex children cannot force overflow, and horizontal padding tightens
on small screens.
- MCP servers table gets `min-w-[640px]` so the existing `overflow-auto`
wrapper provides horizontal scrolling instead of colliding column
headers.

Tailwind class changes only; no component or behavior changes.

## Testing

- `pnpm check` and `pnpm run lint:types` pass.
- Dogfood UAT on a dev deployment: at 390x844 the MCP Servers,
Deployment, Account, and Template settings pages stack nav-above-content
with no horizontal body overflow and a scrollable MCP table; boundary
verified stacked at 1023px and side-by-side at 1024px; at 1440x900 the
layouts are pixel-identical to before (240px sidebar, 112px gap, 40px
padding).

Closes CODAGT-828.

> Created by Mux, an AI agent, on Mike's behalf.
2026-07-20 19:35:23 +02:00
Susana Ferreira a9fdf87a2f feat: add GET /groups/{group}/members/ai/spend (#27130)
## Description

Adds `GET /api/v2/groups/{group}/members/ai/spend?user_ids=...` (also available org-scoped at `/api/v2/organizations/{org}/groups/{groupName}/members/ai/spend`) to return per-member AI spend attributed to a group, along with each member's effective budget group and the applied spend limit when the queried group is their effective budget source.

In the UI, this endpoint is used alongside the existing `/api/v2/groups/{group}/members` endpoint. AI spend data is kept separate from that endpoint so that:

- Different concepts stay on different endpoints: identity (group members) vs. cost control (spend). Cost control is an additional feature layered on top of groups/orgs.
- Callers that don't need spend information don't pay for its computation.

UI flow:

1. Request `/api/v2/groups/{group}/members` → returns the group's members.
2. Request `/api/v2/groups/{group}/members/ai/spend?user_ids=...` with the IDs from step 1.

**Note:** Only current members of the queried group are returned. `spend_limit_micros` and `limit_source` are populated only when the queried group is the member's effective budget source (its own limit or a user override). `effective_group_id` is null when the member's budget resolves to a group in another organization, since an organization is treated as a tenant boundary.

<img width="2880" height="1904" alt="image" src="https://github.com/user-attachments/assets/33ed395d-d1a3-4b46-bb04-c8d3f41c8886" />

## Changes

- Add `codersdk.GroupMembersAISpend` and `GroupMemberAISpend` types, reusing the shared `AISpendPeriodWindow`.
- Add `GetGroupMembersAISpend` SQL query with a dbauthz per-row filter that mirrors `GET /api/v2/groups/{group}/members`.
- Add handler and routes under `/groups/{group}/members/ai/spend` (and the org-scoped alias) with a required `user_ids` query param (cap 100). Callers with more than 100 members are expected to batch across multiple requests.
- Add codersdk client method.
- Tests: dbauthz, raw SQL, endpoint, and role-access.

Closes https://linear.app/codercom/issue/AIGOV-471/backend-group-members-endpoint-with-members-spend

> [!NOTE]
> Initially generated by Claude Opus 4.7, modified and reviewed by @ssncferreira
2026-07-20 13:04:37 +01:00
Susana Ferreira 2adc8f5272 feat: add GET /organizations/{org}/groups/ai/spend (#27123)
## Description

Adds `GET /api/v2/organizations/{org}/groups/ai/spend?group_ids=...` to return per-group AI spend and configured limits for a set of groups in an organization.

In the UI, this endpoint is used alongside the existing `/api/v2/organizations/{org}/groups` endpoint. AI spend data is kept separate from that endpoint so that:

- Different concepts stay on different endpoints: identity (groups) vs. cost control (spend). Cost control is an additional feature layered on top of groups/orgs.
- Callers that don't need spend information don't pay for its computation.

UI flow:

1. Request `/api/v2/organizations/{org}/groups` → returns the organization's groups.
2. Request `/api/v2/organizations/{org}/groups/ai/spend?group_ids=...` with the IDs from step 1.

The groups endpoint from 1) is currently not paginated, but if pagination is added later, this design keeps the two responses in sync. This spend endpoint intentionally takes `group_ids` rather than paginating on its own, since it depends on the group set from step 1. Pagination could be added in the future, especially for Cost Control-focused pages.

<img width="2880" height="1460" alt="image" src="https://github.com/user-attachments/assets/ea83b74d-6a4f-45a6-af2f-1024e019da07" />

## Changes

- Add `codersdk.OrganizationGroupsAISpend` and `OrganizationGroupAISpend` types, plus a shared `AISpendPeriodWindow` embedded in the spend response.
- Add `GetOrganizationGroupsAISpend` SQL query with a dbauthz per-row filter that mirrors `GET /organizations/{org}/groups`.
- Add handler and route under `/organizations/{organization}/groups/ai/spend` with a required `group_ids` query param (cap 100). Callers with more than 100 groups are expected to batch across multiple requests.
- Add codersdk client method.
- Tests: dbauthz, raw SQL, endpoint, and role-access.

Closes https://linear.app/codercom/issue/AIGOV-466/backend-organization-groups-endpoint-with-groups-spend

> [!NOTE]
> Initially generated by Claude Opus 4.7, modified and reviewed by @ssncferreira
2026-07-20 12:54:52 +01:00
Michael Suchacz 9f4ddea571 feat: revoke MCP server OAuth grants at the provider on disconnect (#27300)
Closes
[CODAGT-805](https://linear.app/codercom/issue/CODAGT-805/revoke-oauth-grants-at-the-source-for-mcp-servers).

The experimental MCP server OAuth2 disconnect endpoint previously
deleted only the stored token row, leaving the grant active at the OAuth
provider. This PR adds provider-side token revocation while keeping
local disconnect independent of provider availability.

## Changes

- Add `mcp_server_configs.oauth2_revocation_url` in migration `000547`.
The value can be configured manually, discovered from RFC 8414 metadata,
and managed through the MCP server settings UI. Non-admin responses
redact it with the other OAuth2 fields.
- Revoke the refresh token first through the RFC 7009 endpoint, then
fall back to the access token only for `unsupported_token_type`. Public
clients send `client_id`; confidential clients use
`client_secret_basic`.
- Delete the local token transactionally before best-effort provider
revocation. Callers without a token receive the same response for hidden
and nonexistent config IDs, and provider failures return a generic
warning without exposing provider response bodies.
- Require HTTPS revocation endpoints except for HTTP loopback URLs.
Redirects must preserve the POST and remain on the configured origin.
Redirect errors omit provider-controlled paths and query strings so
reflected token material cannot enter logs.
- Treat `200 OK` and `204 No Content` as completed revocations. `202
Accepted` remains a failure because it does not confirm completion.
- Prevent an in-flight refresh from recreating a token deleted by
disconnect. Refresh persistence now uses an optimistic update keyed by
token ID and `updated_at`; only the OAuth callback can create a token
row. Refresh conflicts reload the current row or clear in-memory auth
when disconnect deleted it.
- Return `{token_revoked, token_revocation_error}` from disconnect,
while retaining SDK compatibility with the legacy `204` response. The UI
surfaces provider revocation failures as warning toasts.
- Document revocation endpoint discovery, HTTPS requirements, and
best-effort disconnect behavior.

No token or no configured revocation URL returns `token_revoked: false`
without an error, so disconnect remains idempotent.

> Updated by Mux, an AI coding agent, on Mike's behalf.
2026-07-20 00:14:03 +02:00
Michael Suchacz 9b3af629cd fix: hide and reject chat models from disabled AI providers (#27070) 2026-07-19 08:33:40 +02:00
Michael Suchacz 34ed124478 fix(site): align React Compiler check scope with vite.config.mts (#27216)
## Stack Context

First PR of a 6-PR stack that thins the agent instruction corpus (~4,800
lines down to ~2,800) by removing startup bloat, assigning each
procedure one canonical owner, and fixing rules that drifted from
reality. Split from #27203 for reviewability.

## Why?

`site/vite.config.mts` compiles `src/pages/AIBridgePage/` with the React
Compiler, but `site/scripts/check-compiler.mjs` did not include that
directory. Compiler regressions in AIBridgePage were invisible to CI:
code could silently bail out of compilation with no signal. The two
lists had already drifted once, which is exactly how this class of bug
recurs.

## What?

- Add `src/pages/AIBridgePage/` to the check-compiler scope. Verified
all 381 functions in scope compile cleanly.
- Cross-reference the two lists with comments so the next person who
edits one finds the other.

This is the only behavioral (non-docs) change in the stack, which is why
it sits at the bottom.

> This PR was prepared by Mux (AI agent) on Mike's behalf.
2026-07-19 07:29:53 +02:00
Michael Suchacz 1ea61b976b fix(site): prevent slash menu from flashing at top-left corner when closed (#27326)
Typing `/` in the agent chat input opens the skills slash menu. Pressing
Backspace to erase the `/` made the menu flash at the top-left corner of
the app for a split second before disappearing.

Radix keeps the popover content mounted through its exit animation, but
the caret-positioned `PopoverAnchor` was unmounted in the same render
that closed the menu. Without an anchor, the popper repositioned the
still-visible closing content to the viewport origin. The anchor now
stays rendered at the last known caret rect, so the menu holds its
position while it animates out.

Verified with a frame-by-frame position recorder in the browser: before
the fix the closing menu jumped from the caret position to `(0, 4)`;
after the fix it stays in place until unmount. Added a
`BackspaceClosesMenuWithoutRepositioning` story that fails without the
fix.

> This PR was created by Mux, an AI coding agent, on Mike's behalf.
2026-07-18 22:43:34 +02:00
Michael Suchacz 46d1823c0a feat: add workspace skills to agent chat slash menu (#25600)
> This Pull Request was updated by Mux working on behalf of Mike.

Adds workspace skills to the agent chat slash menu, sourced entirely
from the chat's pinned context resources (the single-chat GET response
the page already fetches), the same inventory `read_skill` resolves
from. No new API endpoint is introduced.

Personal entries insert `/name`, or `/personal/name` when the name
collides with a workspace skill or the chat's pinned context has not
resolved yet; workspace entries insert `/workspace/name`. Qualified
aliases stay searchable even when the displayed trigger is bare. Before
a chat binds a workspace (new chat form, or a selected but unbound
workspace), the menu lists personal skills only.

Sending a message invalidates the chat detail query, and chatd
broadcasts a context watch event when a first-turn bind pins the chat,
so the menu picks up newly pinned context without a reload.

Makes `UpdateChatWorkspaceBinding` a no-op when the requested
workspace/build/agent binding is unchanged, preserving `updated_at` so
chat list ordering and watch events stay stable.

Includes regression coverage for the no-op binding guard, pinned-context
skill mapping, collision qualification, and skills menu behavior.

Refs
[CODAGT-474](https://linear.app/codercom/issue/CODAGT-474/ux-improvements-for-coder-agents)
(skills autocompleting in the editor).
2026-07-18 21:52:02 +02:00
Michael Suchacz 36e36e2048 fix(site): wrap workspace topbar controls on narrow viewports (#27313)
On mobile-width viewports the workspace page grew to ~1080px wide (390px
viewport), pushing the schedule controls, status indicator, and action
buttons off-screen. Users had to zoom out or scroll horizontally to
reach Stop/Restart/Favorite/Share.

The topbar header and the right-side controls group used non-wrapping
flex rows, and every child is a `whitespace-nowrap` button, so the row's
minimum width (~725px for the controls alone) forced the document wider
than the viewport.

## Changes

- `WorkspaceTopbar`: allow the topbar header and the right controls
group to wrap; right controls stay right-aligned when they wrap onto
their own row.
- `WorkspaceActions`: allow the button row to wrap.
- `TopbarData`: merge a caller-provided `className` (no existing caller
passed one); the workspace breadcrumbs use it to wrap on very narrow
screens.

## Verification

Compared before/after with agent-browser on Storybook stories
(`Workspace: Running`, `WorkspaceTopbar: Outdated / WithQuotaWithOrgs /
Dormant / ConnectedWithMaxDeadline`):

| Viewport | Before `scrollWidth` | After `scrollWidth` |
|---|---|---|
| 320 | 1080 (overflow) | 305 (fits) |
| 390 | 1080 (overflow) | 375 (fits) |
| 768 | 1080 (overflow) | 753 (fits) |
| 1024 | 1080 (overflow) | 1009 (fits) |
| 1440 | 1425 (fits) | 1425, pixel-identical (0% diff) |

At widths >= 1280 the layout is unchanged (0% pixel diff at 1440 across
the stories above). Between ~1080-1230px the controls now wrap onto a
second right-aligned row instead of squeezing label text onto two lines
inside a single row.

Validation: `biome check`, `tsc --noEmit`, and `pnpm test:storybook` for
`Workspace.stories.tsx` + `WorkspaceTopbar.stories.tsx` (36 passed).

> This PR was prepared by Mux, an AI coding agent, on Mike's behalf.
2026-07-17 18:12:25 +02:00
Michael Suchacz 1ac106255b feat: add Anthropic 1M context window toggle for Agents model configs (#27257) 2026-07-17 13:04:13 +02:00
Asher 2ac2295b1e fix: do not send or use stale init dynamic parameter state (#27283)
In summary, we use the init message if we have no autofill params. If we
do, then we ignore the init message, send another message with the
autofilled values, and then when we get *that* response, finally we
render the form since we know we have good state. This eliminates the
possibility of temporarily rendering with stale state.

This is the same fix that was applied to the edit page, but on the
create page this time. The only difference is that the create page does
not need to wait on a build parameters query, instead it has to wait on
the first message from the socket (to get defaults).

This also makes one change where we would send the defaults in the init
message. The server already knows the defaults so there is no need to
send them. The advantage here is that we no longer need to wait for the
first message, and it also fixes an issue where fields with blank values
were getting validation errors because they were not filled out, before
the user had a chance to actually fill them out.
2026-07-16 12:55:43 -08:00
Yevhenii Shcherbina 1453b4b1fc docs: document Bedrock mantle protocol (#27296)
Implements:
https://linear.app/codercom/issue/AIGOV-518/add-docs-for-bedrock-mantle
Follow-up to: https://github.com/coder/coder/pull/26745
2026-07-16 14:58:09 -04:00
Michael Suchacz 3dd9265fa6 feat: add UI option to disconnect OAuth2 MCP credentials (#27299)
Closes
[CODAGT-804](https://linear.app/codercom/issue/CODAGT-804/add-ui-option-to-revoke-oauth-mcp-credentials).

Users could authenticate with an OAuth2 MCP server from the chat input,
but there was no UI to disconnect those per-user credentials. The
backend endpoint (`DELETE
/api/experimental/mcp/servers/{id}/oauth2/disconnect`) already existed.

## Changes

- Connected OAuth2 MCP rows in the chat input plus menu now show a
disconnect icon button next to the enable switch. It opens a
confirmation dialog; confirming calls the disconnect endpoint, shows a
toast, and refetches MCP configs so the row reverts to the `Auth` button
without a reload.
- New `disconnectMCPServerOAuth2` API client method and react-query
mutation that invalidates `mcp-server-configs`.
- Storybook interaction tests: control visibility per auth state, cancel
makes no API call, confirm calls the endpoint once, failed disconnect
keeps the dialog open.
- Hardened `TestMCPServerConfigsOAuth2Disconnect`: seeded tokens flip
`auth_connected`, disconnect only removes the calling user's token, and
repeat disconnect stays idempotent.

The endpoint removes the token stored in Coder; it does not revoke the
upstream OAuth grant, so the UI copy says "disconnect" rather than
"revoke".

Validated with the targeted Go test, Storybook tests (51 passed), tsc,
biome, the react-compiler check, and a manual dogfood run (seeded token,
disconnect/cancel/reconnect flows verified in the UI).

> This PR was authored by Mux, an AI coding agent, on Mike's behalf.
2026-07-16 18:26:35 +02:00
Yevhenii ShcherbinaandJake Howell 9862f10484 feat(site): add Bedrock mantle protocol selector to provider form (#27156)
Implements:
https://linear.app/codercom/issue/AIGOV-517/add-ui-for-bedrock-mantle

Follow-up to https://github.com/coder/coder/pull/26745, which added AWS
Bedrock **mantle** support to the backend and modeled it as a `protocol`
field on the Bedrock provider settings.
## What changed

- Adds a **Protocol** selector to the Bedrock provider form: InvokeModel
(default) or Mantle.
- The form is now protocol-aware:
- **Model** / **Small-fast model** fields are shown only for
InvokeModel. Mantle is a passthrough (the client sends the model at
request time), so the fields are hidden and omitted from the saved
settings.
- **Endpoint** validation, placeholder, and hint switch per protocol.
Mantle requires a `https://bedrock-mantle.{region}.api.aws/anthropic`
URL; InvokeModel keeps the
`https://bedrock-runtime.{region}.amazonaws.com` shape. The `/anthropic`
suffix is required for mantle because the SDK appends `/v1/messages` to
the base URL.

## Manual Testing

Tested the following scenarios:

1. Creating a new Mantle provider — works.
2. Creating a new InvokeModel provider — works.
3. Verifying that an existing InvokeModel provider continues to work.
4. Upgrading an existing InvokeModel provider to Mantle — works.

## Screenshots

### InvokeModel

<img width="1085" height="474" alt="image"
src="https://github.com/user-attachments/assets/4c36b9b0-0eb8-4b17-80b7-e2112325f8d1"
/>


### Mantle

<img width="1082" height="357" alt="image"
src="https://github.com/user-attachments/assets/e8caef26-83d1-4b7e-8f96-79079949e8f1"
/>

---------

Co-authored-by: Jake Howell <jake@hwll.me>
2026-07-16 09:37:48 -04:00
Jeremy Ruppel b3ff4baeb9 fix: smooth compose loader to files page transition (#27277)
## Summary

During the template builder compose flow, the transition into the
template
files page briefly flashed the wizard form again before the files page
settled.

Root cause: the loader was gated on `createMutation.isPending`. When the
compose
POST resolved, `isPending` flipped to `false` in the same commit that
`onSuccess` navigated to the files page, so `TemplateBuilderPageView`
repainted
the wizard form for a frame before the route change committed and
unmounted it.

Fix: keep the loader mounted while the mutation is pending **or**
succeeded
(`createMutation.isPending || createMutation.isSuccess`). Since
`onSuccess`
always navigates away, the loader stays until the component unmounts, so
the
form never reflashes. The error path is unaffected (`isSuccess` stays
false).

Resolves DEVEX-561.


https://github.com/user-attachments/assets/6d5ec04e-9f97-4864-bd18-e1e75055f079

## Scope

Targets the wizard form reflash only. Two adjacent items were identified
during
investigation and intentionally left out:

- The destination files page briefly shows its own `<Loader />` while it
fetches
template files. Smoothing that requires prefetching before navigation
and is a
  larger change.
- The `justCreated` "Awesome, you just created a template!" alert is
cleared by a
mount effect, so it renders one frame then disappears. Arguably its own
bug.

Happy to follow up on either if wanted.

## Testing

- Biome clean on the changed file.
- Manual: build a template through the wizard and confirm the loader
holds
  straight through to the files page with no form flash.

## Stack

Stacked on top of #27276 (DEVEX-593).

---

Generated by Coder Agents.
2026-07-16 09:15:11 -04:00
Jeremy Ruppel 3ddf7d3baa fix: stop the template builder build progress bar from looping (#27276)
## Summary

The template builder's "Building your template" loader had a progress
bar that
animated 0→100% every 5s with an infinite repeat, so it visibly
restarted over
and over while a template built. It looked broken and was frustrating to
watch.

This replaces the looping fill with a single ease-out fill that
decelerates
toward 90% and holds until the request resolves and the loader unmounts.

Since the loader is intentionally indeterminate and no progress is
streamed to
the browser, this also removes the now-dead `onUpdate` callback plumbing
from
the backend `waitForProvisionerJob` (its only caller passed `nil`).

Resolves DEVEX-593.


https://github.com/user-attachments/assets/6d5ec04e-9f97-4864-bd18-e1e75055f079

## Commits

- `refactor(coderd): drop unused onUpdate callback from
waitForProvisionerJob`
- `fix(site/src/pages/TemplateBuilder): stop build progress bar from
looping`

## Testing

- `go build ./coderd/` passes with the reduced `waitForProvisionerJob`
signature.
- Biome clean on the changed frontend file.
- Storybook: `pages/TemplateBuilder/BuildingTemplateLoader` shows the
bar fill
  once and hold, with no restart.

<details>
<summary>Implementation plan</summary>

# DEVEX-593: Stop the build progress bar from looping repeatedly

## Problem

While the template builder composes and imports a template, the FE shows
`BuildingTemplateLoader`. Its progress bar animates from 0% to 100% over
5s
with `repeat: Number.POSITIVE_INFINITY`, so it visibly restarts over and
over.
Users report this looks broken and is frustrating to watch while
waiting.

## Decision (scope)

Minimal fix only: **stop the loop**, plus remove the now-dead `onUpdate`
plumbing from the backend. Since the UI is intentionally indeterminate
and no
progress signal is streamed, the callback serves no purpose and should
be
deleted rather than left as dead code.

### Why not "real sync" now

- `POST /api/v2/templatebuilder/compose/template` is a single blocking
request.
  It composes, bundles, inserts the provisioner job, then calls
`waitForProvisionerJob(jobCtx, provisionerJob.ID, nil)` and only
responds once
  the job completes.
- The `onUpdate` callback runs server-side only. Nothing is streamed to
the
  browser during the wait, so the FE has no progress signal to bind to.
- A provisioner job exposes no numeric percentage. Only status
transitions
  (`pending -> running -> succeeded`) and coarse log stages
(`init/plan/graph/apply`) exist. Real sync would require converting the
endpoint to a streaming protocol (SSE/WebSocket) plus FE rework, which
is
  disproportionate for this 1-point ticket.

### Keep polling (do not switch to pubsub-block)

The wait could technically block instead of poll: on completion
`CompleteJob`
publishes `ProvisionerJobLogsNotifyMessage{EndOfLogs: true}` on the job
logs
notify channel, so we could subscribe and wait for that message with the
context timeout as a fallback. We deliberately do not do that here:
correctness
would require subscribe-before-completion plus an initial DB completion
check to
avoid a race, and Postgres LISTEN/NOTIFY is at-most-once (can drop under
load),
so a poll fallback would still be needed. The existing backoff poll
(100ms -> 200ms -> 500ms -> 1s) is simple and robust for a short-lived
synchronous request.

## Approach

Replace the looping fill with a single, non-repeating ease-out fill that
decelerates and approaches (but never reaches) ~90%, holding there until
the
request resolves and the loader unmounts. This reads as continuous
forward
progress for an unknown-duration operation and never restarts. The
floating-icon
animation is intentional ambient motion and is not in scope.

## Out of scope

- Any behavioral change to how the endpoint waits (it still blocks on
the job).
- Streaming real job progress to the browser.
- Changes to the floating-icon animation.

</details>

---

Generated by Coder Agents.
2026-07-16 09:14:07 -04:00
TJandCoder Agents 529b2ead78 feat(site/src/pages/AgentsPage): show "Archived chats" sidebar heading when viewing archived chats (#26926)
In the agents sidebar, show "Archived chats" instead of "Chats" when the
archive filter is set to `archived`. The heading reads the existing
`sidebarFilters.archiveStatus` state, the same condition already used
for the archived empty-state message.

---

_This PR was opened by [Coder Agents](https://coder.com/) on behalf of
@tracyjohnsonux._

---------

Co-authored-by: Coder Agents <noreply@coder.com>
2026-07-16 06:04:52 -07:00
Danielle Maywood 213f5ce606 fix(site): redesign provider tri-state controls (#27288) 2026-07-16 12:12:38 +01:00
Danielle Maywood 457fa5afa3 fix(site): move thinking settings to provider configuration (#27287) 2026-07-16 12:12:24 +01:00
Danielle Maywood 9d1e881093 refactor(site/src/pages/AgentsPage): use model selector for personal overrides (#27229) 2026-07-16 11:22:48 +01:00
Andrew Aquino baf4dfae4d fix(site/src/pages/TemplateBuilder): display TemplateCard/ModuleCard's official badge inline (#27036)
closes DEVEX-575

There are some screen widths / base template names where the official
badge will break lines by itself as an orphan (see Google Compute Engine
(Linux) in screenshot below). However, I personally prefer this over the
current flex layout (compare with the screenshot in original issue)

<img width="1840" height="1191" alt="image"
src="https://github.com/user-attachments/assets/d5bee310-0202-4d45-aef7-767e457be051"
/>

Unfortunately `&nbsp;` only works if the entities on either side are
both text--not text on the left + image on the right, which is what we
have here.

^One alternative to prevent orphan badges is to split the base template
name by words, then wrap the last word + the official badge in a span
with `white-space: nowrap;`. But that feels a little overwrought to me;
I like the clarity of continuing to just show `{name}` in the JSX. What
do you guys think?
2026-07-15 15:27:07 -07:00
Faur Ioan-Aurel 0caaac5d27 fix: prebuild coderd before Playwright startup for e2e tests (#27136)
The test-e2e job could flake while Playwright waited for its webServer
to become ready. CI already built site/e2e/bin/coder, but that binary
was built before pnpm build and without the embed tag, so Playwright
ignored it and started coderd with go run -tags embed instead. That put
Go compilation, including frontend asset embedding, inside Playwright's
webServer timeout.

Local runs had a similar ordering trap. pnpm playwright:test invoked
Playwright directly, and Playwright starts webServer before globalSetup,
so the existing preflight build could not guarantee a binary existed
before webServer startup.

Build the E2E coder binary with the embed tag and make it depend on
site/out/index.html. In CI, build the frontend first, then build the E2E
binary, then run Playwright. For local runs, have pnpm playwright:test
and pnpm playwright:test-ui run make site/e2e/bin/coder before invoking
Playwright.

Playwright now starts the prebuilt site/e2e/bin/coder binary and waits
on the public /healthz endpoint instead of an authenticated API
endpoint. This keeps compilation outside the webServer readiness timeout
and makes the readiness probe quieter and more direct. I moved to
/healtz because the existing endpoint was returning 401, which still
means “server is up,” but it is a strange readiness signal. /healthz is
explicitly public and returns 200 OK once the HTTP server is accepting
requests.

Caveat: running pnpm exec playwright test
--config=e2e/playwright.config.ts directly bypasses the package script
and therefore bypasses the prebuild. Use pnpm playwright:test or make
test-e2e for the supported local flow.

Because the site package scripts now call make, add make to knip's
ignored
system binaries.

Tests:
- pnpm lint:types
- pnpm exec playwright test --config=e2e/playwright.config.ts --list
-
PATH="/opt/homebrew/opt/make/libexec/gnubin:/opt/homebrew/opt/gnu-getopt/bin:$PATH"
make gen/mark-fresh
-
PATH="/opt/homebrew/opt/make/libexec/gnubin:/opt/homebrew/opt/gnu-getopt/bin:$PATH"
pnpm playwright:test --list

<!--

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.

-->
2026-07-15 21:21:59 +03:00
Ethan cc11c8a536 feat: surface model content-filter refusals as a blocked chat error (#27118)
Blocked turns from a provider's content filter (Anthropic's `refusal`
stop reason with empty content) previously ended silently on the
"Thinking" spinner. They now end as a terminal `content_filter` error
that renders as a "Response blocked" message with the provider's
category and explanation.

<img width="888" height="335" alt="image"
src="https://github.com/user-attachments/assets/cef85a59-4091-4e62-9d45-1eb06748db48"
/>


Closes CODAGT-611

Follow-ups will involve implementing fallbacks, but this alone is pretty
important
2026-07-15 16:36:31 +10:00
Cian JohnstonandCopilot Autofix powered by AI 8eaf4f507b feat: generate the known-models catalog and aigateway prices (#27146)
- Regenerates `prices.json` from models.dev. The seeder only upserts, so
existing deployments keep delisted models.
- Generate the frontend known-models catalog instead of hand-writing it.
`make gen/aibridge-prices` fetches models.dev once
- Moved patches to model definitions to separate `overrides.jq` which 
  handles both `claude-sonnet-4-5` 200k context and 'aliasing' Fable 5
  as Mythos 5.
- Editorial choices of selection, order, aliases, and reasoning defaults 
  live in `curation.json`.
- Adds golden join tests with one error case per validation, a
no-network drift test comparing curation to the checked-in artifact, and
pinned invariants for the Anthropic thinking-mode split (the wrong side
returns HTTP 400) and the sonnet-4-5 context pin.

Adding a model is now one `curation.json` entry plus `make
gen/aibridge-prices`, assuming it is present on models.dev.

> This PR was authored by Coder Agents on Cian's behalf.

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-14 19:36:27 +00:00
McKayla はな b377bec5f4 fix(site): replace ansi-to-html in the log viewer (#27206) 2026-07-14 12:54:16 -06:00
Nick Vigilante 61e52532c0 docs: wrap placeholder syntax in backticks in CLI help and swagger annotations (#27194)
## Problem

Generated reference docs (`docs/reference/cli/*`,
`docs/reference/api/*`) contained raw placeholder and JSON syntax that
came straight from Go CLI help strings and swagger annotations. HTML
renderers treat the angle-bracket tokens (`<team-slug>`, `<uuid>`,
`<KEY>`, etc.) as unknown tags and drop them, so readers see
broken/half-missing text today. The same strings also break MDX parsing.

## Fix

Wrap the placeholder/JSON syntax in backticks **at the source** (Go help
strings and swagger annotation comments), then `make gen`. Rendered docs
now show the placeholders as inline code instead of dropping them.

### Source changes

| File | Placeholder wrapped | Surfaces in |
|------|--------------------|-------------|
| `codersdk/deployment.go` | `` `<organization-name>/<team-slug>` `` |
`cli/server.md`, `coder --help`, settings UI |
| `codersdk/deployment.go` | `` `CODER_AI_GATEWAY_PROVIDER_<N>_*` ``, ``
`CODER_AI_GATEWAY_PROVIDER_<N>_<KEY>` `` | `api/schemas.md` |
| `cli/tokens.go` | `` `<type>:<uuid>` `` | `cli/tokens_create.md`,
`coder --help` |
| `coderd/aitasks.go` | `` `owner:<…>` ``, `` `organization:<…>` ``, ``
`status:<status>` `` | `api/tasks.md` |
| `coderd/exp_chats.go` | `` `pr_status:<…>` `` and sibling filter
tokens | `api/chats.md` |
| `coderd/provisionerdaemons.go`, `coderd/provisionerjobs.go` | ``
`{'tag1':'value1','tag2':'value2'}` `` | `api/organizations.md`,
`api/provisioning.md` |

Everything else in the diff (`coderd/apidoc/*`, `docs/reference/**`,
`*.golden`, `site/src/api/typesGenerated.ts`) is `make gen` output.

## Reviewer notes (the "considered pass" from the ticket)

- **Product-visible:** this changes `coder server --help` and `coder
tokens create --help` output, and the `server-config.yaml` reference
comment. Backticks in terminal help are literal but read fine as
placeholder markers.
- **Settings UI:** the `deployment.go` `Description` also renders in the
deployment settings page. If that field is not Markdown-rendered,
literal backticks will show there. Happy to drop the `deployment.go`
change if you'd rather keep the UI text clean and fix `server.md`
another way.
- **Out of scope here:** `docs/reference/cli/agent-firewall.md`
(`<host>`/`<glob>`) is generated from the external
`github.com/coder/boundary` module, not this repo. It needs an upstream
fix + module bump; not included in this PR.

<details>
<summary>Implementation notes / decision log</summary>

- Scope taken from DOCS-551: source-level backtick pass for generated
reference docs only. Hand-written Markdown fixes are tracked separately
(companion ticket).
- Swagger `@Param` descriptions are Go comments, so the existing `\|`
pipe-escaping in the chats `q` filter is preserved inside the new
backticks (still required for the Markdown table cell to render `|`).
- Verified after `make gen`: generated docs render placeholders as code
spans, table pipes intact; `gofmt` clean; changed Go packages build; no
emdash/endash introduced.
- Deliberately left the `AIProviderConfig` type-level doc comment
untouched because it does not surface in any generated doc (kept the
diff to doc-feeding comments).

</details>

Linear: DOCS-551

---

_Opened by Coder Agents on behalf of @nickvigilante._



---

## Evidence: placeholders dropped on the live docs site

Verified **2026-07-14** against the live site (`coder.com/docs`, i.e.
`main`, pre-merge) by loading each affected page in headless Chrome and
reading the post-hydration DOM (confirmed identical in the raw page
payload). Each simple `<token>` placeholder is parsed as an **empty
custom HTML element**, so the browser renders nothing for it and the
placeholder text disappears from the page.

### What readers see today (before this PR)

| Page (live) | Source Markdown | Rendered on the live site |
|-------------|-----------------|---------------------------|
| [`cli/server`](https://coder.com/docs/reference/cli/server) — OAuth2
GitHub Allowed Teams | `Structured as: <organization-name>/<team-slug>.`
| `Structured as: /.` |
|
[`cli/tokens_create`](https://coder.com/docs/reference/cli/tokens_create)
— `--allow` | `Repeatable allow-list entry (<type>:<uuid>, e.g.
workspace:1234-...).` | `Repeatable allow-list entry (:, e.g.
workspace:1234-...).` |
| [`api/tasks`](https://coder.com/docs/reference/api/tasks) — `q` | `...
status:<status>` | `... status:` (nothing after the colon) |
| [`api/schemas`](https://coder.com/docs/reference/api/schemas) —
AIBridgeConfig (`anthropic`/`bedrock`/`openai`) |
`CODER_AI_GATEWAY_PROVIDER_<N>_*` | `CODER_AI_GATEWAY_PROVIDER__*` |
| [`api/schemas`](https://coder.com/docs/reference/api/schemas) —
AIBridgeConfig (`providers`) | `CODER_AI_GATEWAY_PROVIDER_<N>_<KEY>` |
`CODER_AI_GATEWAY_PROVIDER__` |

[`api/chats`](https://coder.com/docs/reference/api/chats) (`q`) drops
five tokens the same way — `title:<substring>`, `diff_url:<url>`,
`pr:<number>`, `pr_title:<text>`, and the trailing `title:<value>`. The
live parameter description reads (note the dangling `title:`,
`diff_url:`, `pr:`, `pr_title:`):

```text
Search query. Supports title: (case-insensitive, quote multi-word values), archived:bool, has_unread:bool, pr_status:<draft|open|merged|closed> as repeated or comma-separated values, source:<created_by_me|shared_with_me>, diff_url: (quote values containing colons), pr: (exact PR number match), repo:<owner/repo> (case-insensitive substring match against git remote origin or URL), pr_title: (case-insensitive PR title substring). Bare terms are not supported; use title: for title filtering.
```

<details>
<summary>Raw rendered DOM from the live site (headless Chrome,
post-hydration)</summary>

```html
<!-- reference/cli/server -->
Structured as: <organization-name>/<team-slug>.</team-slug></organization-name>

<!-- reference/cli/tokens_create -->
Repeatable allow-list entry (<type>:<uuid>, e.g. workspace:1234-...).</uuid></type>

<!-- reference/api/tasks : only status:<status> drops; the /-containing tokens are escaped and survive -->
Search query for filtering tasks. Supports: owner:&lt;username/uuid/me&gt;, organization:&lt;org-name/uuid&gt;, status:<status></status>

<!-- reference/api/schemas : anthropic / bedrock / openai rows -->
Deprecated: Use Providers with indexed CODER_AI_GATEWAY_PROVIDER_<n>_* env vars instead.</n>

<!-- reference/api/schemas : providers row -->
Providers holds provider instances populated from CODER_AI_GATEWAY_PROVIDER_<n>_<key> env vars and/or the deprecated LegacyOpenAI/LegacyAnthropic/LegacyBedrock fields above.</key></n>
```

The parser auto-inserts closing tags
(`</team-slug></organization-name>`) and lowercases the tag name (`<N>`
becomes `<n>`), leaving `__` where `<N>_` used to be. Every wrapped
placeholder renders correctly as inline code on the [docs preview for
this
branch](https://coder.com/docs/@vigilante%2Fdocs-551-backtick-placeholder-syntax-in-generated-reference-docs-cli/reference/cli/server).

</details>

### Accuracy note — cases that do *not* drop on live

These render fine today, so they are **not** evidence of dropping (the
PR still wraps them for consistency / MDX-safety):

-
[`api/organizations`](https://coder.com/docs/reference/api/organizations)
and
[`api/provisioning`](https://coder.com/docs/reference/api/provisioning):
`{'tag1':'value1','tag2':'value2'}` renders verbatim — curly braces are
not an HTML tag.
- Tokens containing `/` or `|` are escaped by the renderer and stay
visible (as literal `<...>`): `<username/uuid/me>`, `<org-name/uuid>`,
`<owner/repo>`, `<draft|open|merged|closed>`,
`<created_by_me|shared_with_me>`. Backticks still improve their
readability, but they were never dropped.
2026-07-14 13:39:58 -04:00
Paweł Banaszewski 3126306598 feat: add --aigateway-proxy-target flag (#27122)
Adds `--aigateway-proxy-target` option to
`deploymentGroupAIGatewayProxy` that defines URL to which intercepted
requests should be forwarded to.
Forward URL used to be hardcoded to `coderAPI.AccessURL` pointing to
embedded Gateway. With addition of standalone AI Gateway this needs to
be configurable.

Renamed `aibridgeproxyd.Server.coderAccessURL` and `coderAccessPort` ->
`gatewayURL` and `gatewayPort` + option to better reflect reality.
2026-07-14 16:40:22 +00:00
Michael Suchacz a567f6a89f feat: allow admins to override the chat compaction model (#27151) 2026-07-14 16:57:04 +02:00