chore: Initial GHA workflow - #1
Conversation
kylecarbs
left a comment
There was a problem hiding this comment.
Few minor things! Once fixed, feel free to merge!
| ############################################################################### | ||
| .cache | ||
| vendor | ||
| product/coder/cmd/coderd/config.toml |
There was a problem hiding this comment.
We should be able to cleanup a few of these.
There was a problem hiding this comment.
Ooh, ya, good point - I'll clear these out to just the ones we actually need (right now, just node_modules).
| "name": "coder-v2", | ||
| "version": "0.0.1", | ||
| "description": "Coder V2 (Workspaces V2)", | ||
| "main": "index.js", |
There was a problem hiding this comment.
Probably should remove the main for now, since it seems unlikely we'll have one.
There was a problem hiding this comment.
Totally, thanks for catching this! Removed in db32104
| @@ -0,0 +1,15 @@ | |||
| { | |||
| "name": "coder-v2", | |||
| "version": "0.0.1", | |||
There was a problem hiding this comment.
Feels like this version will get outdated really fast.
There was a problem hiding this comment.
Good point, I realized we don't have a version in coder/m's root package.json, so I'll leave out here too. We can always add back later, but better to simplify as you suggested 👍
Also removed this in db32104
|
Thanks for the review and suggestions, @kylecarbs ! |
…24867) Bumps [sanitize-html](https://github.com/apostrophecms/apostrophe/tree/HEAD/packages/sanitize-html) and [@types/sanitize-html](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/sanitize-html). These dependencies needed to be updated together. Updates `sanitize-html` from 2.17.0 to 2.17.3 <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/apostrophecms/apostrophe/blob/main/packages/sanitize-html/CHANGELOG.md">sanitize-html's changelog</a>.</em></p> <blockquote> <h2>2.17.3 (2026-04-15)</h2> <h3>Security</h3> <ul> <li>Fix vulnerability introduced in version 2.17.2 that allowed XSS attacks if the developer chose to permit <code>option</code> tags. There was no vulnerability when not explicitly allowing <code>option</code> tags.</li> </ul> <h2>2.17.2 (2026-03-19)</h2> <h3>Changes</h3> <ul> <li>Upgrade <code>htmlparser2</code> from 8.x to 10.1.0. This improves security by correctly decoding zero-padded numeric character references (e.g., <code>&[#1](https://github.com/apostrophecms/apostrophe/tree/HEAD/packages/sanitize-html/issues/0000001)</code>) that previously bypassed <code>javascript:</code> URL detection. Also fixes double-encoding of entities inside raw text elements like <code>textarea</code> and <code>option</code>.</li> </ul> <h2>2.17.1 (2026-02-18)</h2> <h3>Fixes</h3> <ul> <li>Fix unclosed tags (e.g., <code><hello</code>) returning empty string in <code>escape</code> and <code>recursiveEscape</code> modes. Fixes <a href="https://redirect.github.com/apostrophecms/sanitize-html/issues/706">#706</a>. Thanks to <a href="https://github.com/choi2601">Byeong Hyeon</a> for the fix.</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/apostrophecms/apostrophe/commit/96cf174486e1387948e189786c2d574cf7c3f3d0"><code>96cf174</code></a> For release only (<a href="https://github.com/apostrophecms/apostrophe/tree/HEAD/packages/sanitize-html/issues/5381">#5381</a>)</li> <li><a href="https://github.com/apostrophecms/apostrophe/commit/7ca2d16237c72718ef7e5c7ae0458e6027ac4f64"><code>7ca2d16</code></a> Merge commit from fork</li> <li><a href="https://github.com/apostrophecms/apostrophe/commit/297a4227f30243c25c172ae69a9435884d496e73"><code>297a422</code></a> Bump dependencies (<a href="https://github.com/apostrophecms/apostrophe/tree/HEAD/packages/sanitize-html/issues/5376">#5376</a>)</li> <li><a href="https://github.com/apostrophecms/apostrophe/commit/7e607c9fe1605764144bdc9f529961d5738e7ea2"><code>7e607c9</code></a> Changelog reconciliation for release (<a href="https://github.com/apostrophecms/apostrophe/tree/HEAD/packages/sanitize-html/issues/5359">#5359</a>)</li> <li><a href="https://github.com/apostrophecms/apostrophe/commit/49d0bb775161ce5ccf572752979ff727a31e51a5"><code>49d0bb7</code></a> Port/sanitize html community contrib (<a href="https://github.com/apostrophecms/apostrophe/tree/HEAD/packages/sanitize-html/issues/5337">#5337</a>)</li> <li><a href="https://github.com/apostrophecms/apostrophe/commit/a9ca4ef04f77a8e73add90e96254f3358cf4cbaa"><code>a9ca4ef</code></a> For release only (<a href="https://github.com/apostrophecms/apostrophe/tree/HEAD/packages/sanitize-html/issues/5328">#5328</a>)</li> <li><a href="https://github.com/apostrophecms/apostrophe/commit/bbf3359314c1bff667f11716e3cb55d3d42f0150"><code>bbf3359</code></a> Port sanitize html standalone pr (<a href="https://github.com/apostrophecms/apostrophe/tree/HEAD/packages/sanitize-html/issues/5323">#5323</a>)</li> <li><a href="https://github.com/apostrophecms/apostrophe/commit/f5f266c2caff45df376aba68d06f4bb67cbde5d7"><code>f5f266c</code></a> Adds changeset (<a href="https://github.com/apostrophecms/apostrophe/tree/HEAD/packages/sanitize-html/issues/5209">#5209</a>)</li> <li><a href="https://github.com/apostrophecms/apostrophe/commit/c9aba85f33b958278fdb9ccff52ce79e299e3913"><code>c9aba85</code></a> PRO-8756: monorepo workflows (<a href="https://github.com/apostrophecms/apostrophe/tree/HEAD/packages/sanitize-html/issues/5179">#5179</a>)</li> <li><a href="https://github.com/apostrophecms/apostrophe/commit/107bcd2427a4e6e8e41e5a48847cdc8548fcb242"><code>107bcd2</code></a> Pro 8756 monorepo switch (<a href="https://github.com/apostrophecms/apostrophe/tree/HEAD/packages/sanitize-html/issues/5177">#5177</a>)</li> <li>See full diff in <a href="https://github.com/apostrophecms/apostrophe/commits/sanitize-html@2.17.3/packages/sanitize-html">compare view</a></li> </ul> </details> <br /> Updates `@types/sanitize-html` from 2.16.0 to 2.16.1 <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/sanitize-html">compare view</a></li> </ul> </details> <br /> 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) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
… history Replaces the previous draft of this PR (a backend workspaces.claimed_at column plus migration plus SDK plumbing) with a frontend-only heuristic per Cian's review. The /agents archive-and-delete molly-guard previously compared workspace.created_at against chat.created_at to decide whether to require typing the workspace name. ClaimPrebuiltWorkspace never updates workspace.created_at, so claimed prebuilds always looked pre-existing and the dialog misfired. Build history already records the truth: build #1's initiator is the prebuilds system user iff the workspace was a prebuild, and build #2 is the claim. Compute that in the resolver and compare its created_at against the chat. From-scratch workspaces fall through to workspace.created_at as before. The prebuilds system user UUID is hardcoded on the frontend; it lives in coderd/database/constants.go on the backend and has not changed since the prebuild feature shipped. If it ever moves, both sides have to move together. 🤖 Generated with the help of Coder Agents.
… dialog (#25057) Closes [CODAGT-317](https://linear.app/codercom/issue/CODAGT-317/pr-workspaces-sometimes-require-name-confirmation-to-delete). ## Problem The `/agents` archive-and-delete molly-guard (typing the workspace name) was firing for chats that had clearly created their own workspace. The heuristic in `resolveArchiveAndDeleteAction` decides whether confirmation is needed by comparing the workspace's `created_at` against the chat's `created_at`: ```ts return new Date(workspaceCreatedAt) >= new Date(chatCreatedAt); ``` That assumption breaks for **prebuilt workspaces**. `ClaimPrebuiltWorkspace` rewrites `owner_id`, `name`, `updated_at`, `last_used_at`, etc., but **never touches `created_at`**, which still reflects when the prebuild was provisioned by the reconciler, often hours before the chat exists. Result: every prebuild-claimed workspace looks pre-existing, so the molly-guard fires. Concrete example from a real chat: | Field | Value | |---|---| | `chat.created_at` | `2026-05-07T15:12:23Z` | | `workspace.created_at` (provision) | `2026-05-07T14:22:24Z` | | `latest_build.created_at` (claim) | `2026-05-07T15:19:09Z` | `14:22:24 < 15:12:23` so `isWorkspaceAutoCreated` returned false even though the chat issued the claim. ## Fix (frontend-only) Derive the moment a workspace was acquired from existing build history rather than relying on `workspace.created_at`: - Build #1 initiator = prebuilds system user → workspace was a prebuild → use `build_2.created_at` (the claim build) as the acquisition time. - Build #1 initiator = real user → workspace was created from scratch → use `workspace.created_at` (unchanged behavior). - Unclaimed prebuild or no build history → return `null` (force confirmation; safe degradation for a destructive flow). The resolver fetches the build list via the existing `getWorkspaceBuilds` endpoint when the dialog might fire. No new column, no migration, no schema change. Works retroactively for all existing claimed prebuilds; no backfill needed. The prebuilds system user UUID is exposed via `codersdk.PrebuildsSystemUserID` and typegen'd to `typesGenerated.ts`. `coderd/database.PrebuildsSystemUserID` parses that constant via `uuid.MustParse` so the two cannot drift; if the codersdk literal ever changes, package init fails fast. ## History The first draft of this PR added a `workspaces.claimed_at` column populated by `ClaimPrebuiltWorkspace`. After review feedback from @johnstcn pointing out that the same fact is already implicit in build history, I pivoted to the frontend-only approach. Subsequent review notes consolidated the prebuilds system user UUID into a single typegen'd constant. ## Why not the other open PRs - **#25055** (`chatKey` cache fallback) only fixes a different cache-miss path; it explicitly notes it does not address `created_at < chat.created_at`. - **#25053** (`chats.workspace_auto_created` boolean) puts the truth on the wrong side of the schema: "this workspace was claimed at time T" is a property of the workspace, not the chat. The MCP plumbing it adds is also unnecessary now that the same answer is available from build history. ## Test plan - `pnpm vitest run --project=unit src/pages/AgentsPage/utils/agentWorkspaceUtils.test.ts` — 40/40 pass; new cases cover prebuild claim before/after chat, unclaimed prebuild, missing-build-history fallback, and the fetch-skip when the chat is not in cache. - `pnpm lint:types`, `pnpm check`, `make pre-commit`. <details> <summary>Disclosure</summary> Opened on behalf of @kylecarbs by [Coder Agents](https://coder.com/coder-agents). </details>
…orkspaceBuild CreateWorkspaceBuild goes through wsbuilder which now calls SoftDeletePriorWorkspaceAgents, soft-deleting the agent from build #1. The GetWorkspaceAgentLogs test was using that agent's ID, so it got a 404 after the stop build ran. Move it before CreateWorkspaceBuild so the agent is still visible.
…orkspaceBuild CreateWorkspaceBuild goes through wsbuilder which now calls SoftDeletePriorWorkspaceAgents, soft-deleting the agent from build #1. The GetWorkspaceAgentLogs test was using that agent's ID, so it got a 404 after the stop build ran. Move it before CreateWorkspaceBuild so the agent is still visible.
Prior sub-tests call CreateWorkspaceBuild through the API, which triggers SoftDeletePriorWorkspaceAgents and soft-deletes the agent from build #1. Re-fetch the workspace to get the current (non-deleted) agent ID instead of using the stale one captured at setup time.
Prior sub-tests call CreateWorkspaceBuild through the API, which triggers SoftDeletePriorWorkspaceAgents and soft-deletes the agent from build #1. Re-fetch the workspace to get the current (non-deleted) agent ID instead of using the stale one captured at setup time.
Prior sub-tests call CreateWorkspaceBuild through the API, which triggers SoftDeletePriorWorkspaceAgents and soft-deletes the agent from build #1. Re-fetch the workspace to get the current (non-deleted) agent ID instead of using the stale one captured at setup time.
…nges (#27059) Closes CODAGT-592. ## Problem The advisor tool sometimes fails with the opaque error `advisor produced no text output`. Live reproduction against `claude-sonnet-4-6` showed the cause: `BuildAdvisorMessages` forwards the parent conversation's raw `tool_use`/`tool_result` blocks into the nested advisor call, which defines no tools. The nested model imitates the forwarded pattern and spends its turn committing to a tool call it cannot make (captured reasoning from a failing run: "The user wants me to make another tool call to the advisor about writing a poem about cucumbers."), so the step ends with reasoning-only or empty content and no advice. Because each chat step currently rebuilds the advisor runtime and snapshot (CODAGT-593), the second advisor call in a run reliably sees the first call's exchange, which is why the first call succeeds and later ones fail. ## Fix - `BuildAdvisorMessages` rewrites tool activity as plain-text notes: assistant tool-call parts are removed and folded, together with their matching result, into a single user-role note of the form `[The parent agent ran the X tool with input {...}. Result: ...]`. No raw tool blocks and no bare call lines reach the tool-less nested request. This also removes the provider requirement that `tool_result` blocks pair with a `tool_use`, so results orphaned by window truncation are kept as notes instead of dropped. - The `advisor produced no text output` error now appends the finish reason and content-part kinds, e.g. `advisor produced no text output (finish_reason=stop; parts: reasoning=1)`, so field reports distinguish tool-call mimicry, reasoning-only turns, and truncation. Validated live by driving the production `RunAdvisor` path against `claude-sonnet-4-6` through the dev.coder.com AI gateway: the failing scenario went from 3/3 errors to 6/6 genuine advice (with and without extended thinking), with the control scenario unaffected. Related: CODAGT-593 (per-step advisor runtime recreation, addressed separately) and CODAGT-742 (advisor tool call design). <details> <summary>Investigation and validation details</summary> ### Reproduction A CLI prototype constructed the exact conversation snapshot the generation preparer hands the advisor tool and called the real `chatadvisor.NewRuntime` / `Runtime.RunAdvisor` / `BuildAdvisorMessages` / `chatloop.GenerateAssistant` chain against live `claude-sonnet-4-6`, with a stream-teeing model wrapper capturing what `runner.go` discards (finish reason, part kinds, reasoning text). | Scenario (snapshot contents) | Thinking | Before fix | After fix | |---|---|---|---| | control: call #1 state, no prior advisor exchange | on | 3/3 advice | 2/2 advice | | repro: call #2 state, prior advisor `tool_use`/`tool_result` pair forwarded | on | 3/3 `advisor produced no text output` | 3/3 genuine advice | | repro | off | 2/3 same error, 1/3 degenerate advice ("I'll ask the advisor...") | 3/3 genuine advice | Every failing response was a tiny thinking block, zero text, zero tool-call stream parts, finish reason `stop`; the model's own reasoning text showed it deciding to "make the second tool call" in a request with `tools=0`. The refunded `remaining_uses: 1200` in the failing tool-result JSON matches the original issue screenshot. ### Decision log - Tool exchanges are folded into a single user-role note per call/result pair. A first attempt rendered assistant-authored `[tool call: name(input)]` text lines plus separate result messages; live runs then returned the literal `[tool call: advisor(...)]` line as the advice 6/6 times. The bare assistant call line is itself an imitable pattern, so no assistant-authored tool artifact may survive the handoff. The folded user-role note produced 6/6 genuine advice. - An assistant message that carried only tool calls is dropped entirely; the folded notes preserve the information. - `dropOrphanToolMessages` was removed: without raw tool blocks there is no provider pairing constraint, and an orphaned result note retains context value. - A reasoning-budget-starvation hypothesis (thinking budget consuming `MaxOutputTokens`) did not reproduce on `claude-sonnet-4-6`; the model adapts thinking length to the cap. The enriched error would identify such cases on other models via `finish_reason=length`. - CODAGT-593 (persisting the advisor runtime across steps) is intentionally not addressed here; it shrinks the priming window but the handoff fix is what removes the failure mode. </details> --- *This PR was generated by Coder Agents on behalf of @ThomasK33 (Linear agent session for CODAGT-592).*
This implements an initial GitHub Actions workflow for us - to be run on PRs and on
maincommits.This just implements a really simple
style/fmtcheck - runningprettieron theREADME.md.I assumed we'll stick with using a top-level
Makefilefor commands like inmandlink- but open to alternatives, too!Since I was adding a
package.jsonandnode_modulesfor this, I realized we were missing.gitignores, so I added some a subset of the ignore files fromcoder/mTODO:
README.mdneeds formatting