* feat: let the merge UI target an arbitrary workspace
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep the target picker reachable when a comparison fails
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: address review findings on the arbitrary merge target
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: collapse app/raw-app conversions and offer a comparison retry
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: make a re-scan replace the candidate set and keep retry reachable
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: drop destructive rows from the selection when a recompute flips them
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep bulk selection and refreshes out of the removal opt-in
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: serialize a full scan against dev attachment on the same pair
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep the compare view reachable from drafts and prune stale selections
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: make the destination badge the target picker and reorder the settings
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: render the destination trigger as the same badge as the source
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(frontend): add missing resource type icons and show them in the picker
Anthropic, DeepSeek, OpenRouter, Google AI (Gemini) and Ultravox resource
types rendered as a blank grey circle. Add their marks and wire up two icons
that already existed in the repo but were never imported.
Unmapped resource types now fall back to the generic resource glyph instead
of the grey circle, and the resource picker shows the icon before the path —
both in the dropdown rows and inside the input — omitting it entirely, with
no reserved padding, when the type has no icon.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(frontend): correct gemini gradient units and reuse the icon resolver
The Gemini gradient omitted gradientUnits, so its 0..24 coordinates were read
as objectBoundingBox fractions and the whole mark collapsed onto a 4% slice of
the ramp — a flat purple. Pin it to userSpaceOnUse like every other gradient
icon in the directory.
Index the resource list by path once instead of scanning it per dropdown row,
fold the two remaining inline copies of the icon lookup into appIconComponent,
and drop the sendflake key — no resource type by that name exists.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* style(frontend): shrink the resource picker icon to 14px
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* style(frontend): drop the redundant frame around the ai providers list
SettingCard already supplies p-4, rounded-md and bg-surface-tertiary, so the
wrapper repeated all three and added a border, nesting a card inside a card.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(frontend): keep the unregistered snowflake mark, extend the card fix
SendflakeIcon is the Snowflake logo under a misleading filename, not a
different product; SnowflakeIcon is the same logo with a baked-in ® that
shrinks and off-centres the flake and turns to a smudge at 14-24px. Leave the
mapping where it was.
Apply the card-in-card removal to the two InstanceFallbackSettings cards that
stack directly above the AI providers one, so the frames stay consistent.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(frontend): make the ansible mark legible on dark surfaces
Mapping `ansible` renders this icon for the first time, and its near-black disc
disappears into the dark surface, leaving only the white "A" counter floating.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(cli): lint against the checkout's schema, not the published validator
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(cli): mirror the permissioned_as exclusion into agent guidance
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: version windmill-yaml-validator with the release, publish by hand
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: generate schemas with the validator's own yaml parser
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(cli): declare ajv, no longer reaching tests via the validator
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: fail schema generation on a spec YAML syntax error
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(git-sync): let GitHub webhooks register a dedicated base url
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): validate the webhook base url and apply it on change
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: pin ee ref for the git-sync webhook base url change
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): validate and reconcile the webhook base url on every write path
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): route every declarative settings writer through the same rules
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): let the reconciler own the webhook field write-back
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): make the webhook base url validators agree across UI and server
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): lock the workspace row across git_sync read-modify-writes
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test: pin the webhook base url validator to its server counterpart
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): retry a failed webhook move on every re-apply of the setting
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): retry pending webhook moves on every declarative re-apply
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): reject non-string webhook base urls and bound the sweep
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): reject credential-bearing webhook base urls
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): keep credentials out of webhook base url validation errors
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): redact through the last authority @ when reporting a bad url
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): stop echoing unparsed webhook base urls instead of scrubbing them
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): never echo a submitted webhook base url in validation errors
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): keep the submitted scheme out of validation errors
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* refactor(git-sync): drop the webhook sweep, surface stale receivers in settings
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): refresh the stale webhook list when settings are saved
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): mark registered_url nullable and drop the duplicated field error
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: pin ee ref after dropping the reconcile lock and CAS
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(git-sync): refresh the stale webhook list on category saves too
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to aa05ca8e97fc8265cd724753a80db37f83243254
This commit updates the EE repository reference after PR #695 was merged in windmill-ee-private.
Previous ee-repo-ref: 3e6cd9226b68707233ae2434511fe5131dce808b
New ee-repo-ref: aa05ca8e97fc8265cd724753a80db37f83243254
Automated by sync-ee-ref workflow.
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* fix(flows): mint fresh orchestration token so long steps don't expire the result-fetch JWT
A flow step's ephemeral JWT is minted at step pull time with a lifetime of
SCRIPT_TOKEN_EXPIRY (900s on cloud) and reused to drive post-completion flow
orchestration — including the next step's input-transform isolated-eval, which
fetches prior steps' results (e.g. `[...results.x]`). If the step whose
completion triggers that fetch ran longer than the token's lifetime minus the
60s JWT leeway (~16min on cloud), the reused token is already expired and the
fetch is rejected as anonymous:
Failed to fetch results for step 'x':
Bad request: As a non logged in user, you can only see jobs ran by anonymous users
This surfaces as an intermittent, hard-to-diagnose failure of long-running
flows (per-step duration, not total flow duration).
Mint a fresh token for flow-step completions so the orchestration client's
lifetime is independent of how long the finished step ran (falls back to the
step token on error).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* address review: derive end-user label, guard mint on step staleness, trim comment
- Derive the token label the same way as create_token
(ephemeral-script-end-user-{created_by} when permissioned_as differs from
created_by) so run-on-behalf-of flows keep the end-user override that
username_override_from_label relies on, instead of hardcoding "ephemeral-script".
- Only mint the fresh token when the finished step could actually have expired it
(duration >= SCRIPT_TOKEN_EXPIRY/2), so the common short-step path keeps the
pull-time token and avoids an extra get_job_perms query per completion.
- Add warn_after_seconds(5) on the mint, matching create_token.
- Trim the comment to the durable invariant and drop the internal ticket id
(comment + log line) per AGENTS.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat: make the fork lineage the only deploy relationship
`workspace_settings.deploy_to` (2023) and `workspace.parent_workspace_id` (2025)
both expressed "which workspace does this one deploy into". Fork creation and
dev-workspace attach seeded both, but nothing kept them in agreement, so every
reader picked one and they disagreed.
Drop `deploy_to`. A migration folds surviving pairs into the lineage: a sole
claimant on a target with no dev workspace becomes that target's dev workspace
and keeps its own job tags, while many-to-one pairs become plain forks. Pairs
that the lineage cannot express -- dangling target, self-reference, chain,
mutual -- are reported and left unlinked.
Job tags were never lineage-aware: `per_workspace_tag` mapped any parented
workspace to its parent while `$workspace` interpolated the raw id, so a fork
running a script tagged `<tag>-$workspace` produced a tag no worker serves and
the job queued forever. Both paths now resolve to the nearest ancestor whose id
an admin would provision workers for.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: preserve unconvertible deploy links and sweep tag caches on reparent
Review findings on the deploy_to unification:
- convert chains instead of discarding them, and keep whatever the lineage
cannot express in workspace_deploy_to_unmigrated so the down migration can
restore it
- ignore soft-deleted workspaces when choosing between a dev workspace and a
plain fork; an archived claimant was demoting live pairs
- mirror attach_dev_workspace's git-sync strip, which the migration skipped
- sweep the tag cache over whole subtrees on rename and delete: tag resolution
now walks ancestors, so a nested fork kept a tag nothing serves
- call a dev workspace a dev workspace in the settings copy
- redirect a root away from ?tab=deploy_to instead of rendering an empty target
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: detect lineage cycles and record archived links in the deploy_to migration
Second review round on the unification:
- detect cycles over the lineage as it would exist after conversion, not over
the deploy_to graph alone: a root whose target was one of its own forks
closed a loop that no deploy_to edge revealed
- record an archived source's link instead of filtering it out entirely, which
dropped it with the column
- treat a fork whose deploy_to merely repeats its parent as redundant rather
than reporting every pre-existing fork as unmigrated
- read the row count from the lineage update rather than the git-sync one
- sweep the tag cache when archiving a dev workspace, the last site that
mutates is_dev_workspace without one
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: resolve $workspace on preprocessed flow tags regardless of $args
Third review round on the unification:
- a flow tag containing only `$workspace` skipped interpolation entirely on the
preprocessed path, because the branch that ran it keys on `$args`. The raw
tag was written back and named a queue no worker serves. Resolve `$workspace`
before the branch and leave `$args` to it.
- record the new table's foreign key in the schema summary
- describe what the archive tag sweep actually does: the dev flag is cleared for
any archived workspace, which is why it is unconditional
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep the deploy_to leftovers table only when it holds something
* fix: sweep tag caches on archive only where the dev flag actually changes
* feat: broadcast lineage changes and walk ws_specific ancestors only
- propagate tag-cache invalidation across processes over notify_events: the
cache is per-process, so replicas kept resolving stale lineage for the TTL.
The listener clears the whole cache rather than tracking ids, since a single
mutation invalidates an unbounded set of descendants and lineage changes are
rare admin actions.
- narrow list_ws_specific_versions to ancestors: walking down as well made a
root fan out over its entire live fork subtree, and each member costs an
identity lookup plus an RLS switch and probe. Ancestors are bounded by the
fork depth limit.
- probe the leftovers table unqualified so rollback restores on a PG_SCHEMA
install, where search_path is not public
- drop the nativets client method for the removed edit_deploy_to endpoint
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: let a prod see its dev workspace in ws_specific, and stop the walk oscillating
Descending into plain forks made a root fan out over its whole live fork
subtree, but a dev workspace is the paired editable environment rather than a
throwaway copy, so a prod should still see it. There is at most one per parent
and attach rejects nested dev chains, so that edge stays bounded.
The edges run both ways, so the recursion never converged: it bounced
parent<->dev until the depth cap on every call, 33 rows for a two-member set.
A visited-path guard ends the walk when nothing new is reachable.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep dev pairings unnested, gate the delete broadcast, cover the ws_specific walk
Fifth review round:
- a root that already owns a dev workspace no longer converts: linking it under
its deploy target would leave that dev nested beneath a fork, the shape
attach_dev_workspace refuses to create. The link is preserved instead.
- broadcast a lineage change on delete only when descendants are orphaned.
Deleting a leaf, which ephemeral fork churn does constantly, changes nobody
else's resolution and was making every replica drop its whole tag cache.
- call list_ws_specific_versions in a test. plpgsql defers everything past a raw
parse to the first call, so replaying the migration only proved it parses.
- use unwrap_or_default for the descendant sweeps, which run after the
transaction has committed; a transient failure must not fail the request
- trim the traversal comment to the four-line limit
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: cache the renamed tally query and clear instance alerts on conversion
The integration test's query was never cached: `cargo sqlx prepare` without
--all-targets skips test targets entirely, and renaming its fixture workspace
changed the query text. Regenerated with --all-targets --features
all_sqlx_features,private, which is what lets the EE-gated otel test compile.
Also from review:
- clear error_handler_fallback_to_instance_alerts on converted workspaces.
Dispatch ignores it once a parent exists, but the settings page keeps
submitting the stored true, which the API rejects on a fork.
- restore the schema summary row to the file's name: columns format and put it
back in alphabetical order
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: never cache an unresolvable tag workspace, and unadvertise the removed endpoint
- lookup_tag_workspace cached a "no row" result as self-resolution. A rename
resolves the new id before its row lands, so a fork could be pinned to its own
wm-fork-* id -- which nothing serves -- for the whole TTL, and its schedules
kept re-pushing onto that dead tag. Fall back for the call without caching,
matching how the error path already behaved.
- change_workspace_id swept its children but never itself. Sweep the new and old
ids and broadcast unconditionally, since a rename always changes lineage.
- openapi-deref.{json,yaml} are served to clients via include_str!, so they were
advertising edit_deploy_to after it started 404ing. The audit-action enum
keeps the entry: historical rows still carry it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: align the served YAML spec with the JSON one and correct two comments
- the YAML deref lost the removed path but kept deploy_to on get_settings,
so the two served specs disagreed. Both are now identical.
- the rename-sweep comment blamed cached-unresolvable lookups, which the same
commit stopped caching. The real reason is that workspace ids are
reclaimable, so a new id can carry a previous occupant's resolution.
- the instance-alert comment claimed the settings page submits the stored true
and gets a 400. It hides the option on a fork and sends false; the hazard is
the value outliving the pairing and re-enabling alerts after a detach.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to 82da6cb2bafeda18acd6b70c599013a12117ecb0
This commit updates the EE repository reference after PR #694 was merged in windmill-ee-private.
Previous ee-repo-ref: f9ddf6a75aa13d1c13a3d7216a361a96f75ca435
New ee-repo-ref: 82da6cb2bafeda18acd6b70c599013a12117ecb0
Automated by sync-ee-ref workflow.
* fix: grant the deploy_to preservation table to the windmill roles
* test: drop the one-shot migration tests, keep the ws_specific execution guard
The two conversion tests replayed the migration against the fully-migrated
schema, which is not how it runs -- in production it runs mid-sequence against
the schema as of that point. A later migration touching workspace or
workspace_settings would break them without breaking anything real, and sqlx
checksums already freeze a released migration. They earned their keep finding
the archived-claimant and nested-dev cases during development; there is nothing
left for them to guard.
list_ws_specific_versions is different: it is live, no caller exercises it, and
plpgsql only parses a function body until first call.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: invalidate a reclaimed fork id cluster-wide without flushing every entry
Gating the delete broadcast on orphaned descendants stopped leaf churn flushing
every replica, but fork ids are reclaimable: the deleting process invalidated
locally while every other replica kept the old parent for the TTL, so a job
pushed in a recreated fork routed to the previous parent's tag.
The broadcast payload now carries meaning. A workspace id drops that one entry,
used for leaf deletion where exactly one id changed what it denotes. The `*`
sentinel drops everything, used for attach, detach, archive, rename and
deletions that orphan descendants -- reshaping a subtree no single id names.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs: name the right broadcast for each invalidation case
* docs: attach does invalidate the tag cache; the resolver walks the whole chain
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* fix: make /usr/bin/coursier self-contained so java jobs work air-gapped
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: smoke-test the coursier assembly at build time
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: run the init script before dedicated workers install dependencies
* chore: point ee-repo-ref at the init script gate companion
* fix: resolve the init script gate from the post-processed job outcome
* chore: update ee-repo-ref to 4f9a6edab8dc4b104388a3b3991b1c684523b653
This commit updates the EE repository reference after PR #696 was merged in windmill-ee-private.
Previous ee-repo-ref: a92307dc953100bad35d8e10791e5f4bb1537062
New ee-repo-ref: 4f9a6edab8dc4b104388a3b3991b1c684523b653
Automated by sync-ee-ref workflow.
---------
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* fix(ai): route Azure OpenAI agent steps through the Responses API
* docs: note why azure responses routing is per-provider
* fix(ai): fall back to chat/completions when an azure endpoint rejects responses
* refactor(ai): retry endpoint and stream_options rejections in one loop
* fix(ai): keep a rejected request shape dropped across agent iterations
* perf(ai): remember which deployments reject the responses route
* fix(ai): only remember a route rejection the fallback resolved
* fix(ai): keep web search on azure and require the deployment be named to reroute
* fix(ai): remember an unserved route only on a 404
* docs: correct the reroute-flag and fallback-hook comments
* fix(forks): tally fork changes when a deploy's lock job fails
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(forks): tally fork changes even when deploy_to is unset
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: bump ee-repo-ref to the fork tally companion commit
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(forks): never tally a dependency deploy twice
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(forks): pin the ahead tally for a fork with no deploy_to
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(forks): cover the dedup case and commit the offline query cache
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(forks): let the tally settle before asserting the dedup count
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(forks): key the ahead tally on the fork lineage, not deploy_to
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to caf6abc45afd910620ef66f7550c076c18ca4589
This commit updates the EE repository reference after PR #693 was merged in windmill-ee-private.
Previous ee-repo-ref: d5c6ee8b774993aa341196746d141107aa4567d1
New ee-repo-ref: caf6abc45afd910620ef66f7550c076c18ca4589
Automated by sync-ee-ref workflow.
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* feat: sidebar workspace toggle navigates home when already in workspace mode
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: fire the toggle home navigation on keyboard activation too
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: one activation per key press and no duplicate history entry from home
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Picks up the language-server fix in the in-editor builder
(windmill-labs/windmill-code-ui-builder#26), so .svelte files get
IntelliSense, diagnostics and go-to-definition again. The bundled
extension's language server was dying on startup with
Cannot read properties of undefined (reading 'useCaseSensitiveFileNames')
Builds and runtime were unaffected — this is editor language support
only, and it predates the rune-module and delegated-event fixes already
pinned here.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(cli): compile runes in .svelte.ts / .svelte.js modules
The svelte plugin only ran on `/\.svelte$/`, so a rune module like
`lib.svelte.ts` was bundled as plain TypeScript: the types were stripped
and `$state(0)` survived as a call to an undefined global, blowing up at
runtime with "ReferenceError: $state is not defined".
Route those files through `compileModule`. It parses with plain acorn and
chokes on TypeScript, so types come off first via esbuild's transform —
which is what vite-plugin-svelte gets for free by running after Vite's own
esbuild transform.
`wmill app dev` picks this up too; watch mode builds its plugin list with
the same `createFrameworkPlugins`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: pin ui_builder to 1ffb28e
Picks up the matching rune-module fix in the in-editor builder
(windmill-labs/windmill-code-ui-builder#24), so `.svelte.ts` modules
compile in the editor as well as through the CLI.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(cli): compile raw apps with the app's own svelte compiler
Svelte 5.52.0 moved delegated event handlers off `element.__click` onto a
Symbol-keyed map. A raw app supplies its own Svelte *runtime* via
package.json, but `import("svelte/compiler")` resolves against the CLI,
whose own svelte floats independently — so the two can land on opposite
sides of that change and the app builds, renders, and has every
onclick/oninput silently dead.
Resolve the compiler from the app's node_modules instead, so compiler and
runtime are the same install by construction, and raise the CLI's own
floor past the break for the fallback path.
Also pin ui_builder to 013bf67, which carries the matching fix for the
in-editor builder (windmill-labs/windmill-code-ui-builder#25), and move
the Svelte raw-app template onto the same range. Those two go together:
the new builder rejects a runtime that sits on the far side of the ABI
break from its compiler.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: surface the real reason git sync settings saves are rejected
* fix: redact credentials and cover the remaining api error sites
* chore: update ee-repo-ref to 85209cfccb07538ae4748d85b56e61c0bef4f606
This commit updates the EE repository reference after PR #691 was merged in windmill-ee-private.
Previous ee-repo-ref: 01ca990c6a02a745e16f13da972497add0ad7a6c
New ee-repo-ref: 85209cfccb07538ae4748d85b56e61c0bef4f606
Automated by sync-ee-ref workflow.
* fix: drop the unactionable branch advice and the last inline error copy
---------
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* feat: expand the active fork's family in the workspace menu
* fix: distinguish waiting-on-user from streaming in ai sessions
* fix: honor compact sizing in the waiting-for-input pill
* docs: condense waiting-state comments to the 4-line limit
* fix: detect a blocked tool card sitting behind queued ones
* fix: scan to the turn boundary for a blocked tool card
* fix(frontend): render the error handler as an inert run marker in the flow editor graph
* fix(frontend): dismiss nested error handler markers via a dedicated handler
* docs(frontend): note that error handler markers are keyed by failing step
* feat: add github dark mode variant switchable in user settings
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: boot the UI Builder iframe into the current theme
Seed the UI Builder iframe URL with the live dark/variant state
(`?dark=&variant=`) so the VS Code workbench boots straight into GitHub
Dark / Nord / Light instead of flashing the dark default until the host's
`setDarkMode` message lands. Read from the <html> classes rather than the
reactive state so the src is computed once at mount — a later theme toggle
still updates the workbench via postMessage and does not reload the iframe.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat: align github-dark surfaces to GitHub Primer's elevation scale
Snap the invented mid-greys to Primer's real dark canvas scale
(inset=neutral.0, default=neutral.1, muted=neutral.2). Recessed surfaces
now use true inset (#010409) instead of washed-out half-steps that sat in
no-man's-land between inset and the page; raised surfaces align to muted.
- surface-secondary #0b0e13 → #010409 (true inset)
- surface-input #0c0f14 → #010409 (true inset)
- surface-disabled #0b0e13 → #151b23 (muted)
- surface-tertiary #161b22 → #151b23 (Primer neutral.2)
- component-virtual-node #161b22 → #151b23
- surface-selected #21262d → #212830 (Primer neutral.3)
surface-sunken (#010409) and surface-primary (#0d1117) already matched
Primer inset/default exactly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix: keep github-dark inputs subtle instead of full inset
surface-input at true inset (#010409) made form fields read as recessed as
the sidebar rail — too much contrast against the canvas. Inputs aren't
sunken, so keep the subtle #0c0f14 (a hair below the page) while the
recessed panel surfaces stay at inset.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore: bump UI Builder pin to the github-dark build (76ee616)
windmill-code-ui-builder PR #16 is merged and published to R2, so pin the
artifact to that build. The embedded raw-app editor now renders GitHub Dark
(and honors the `variant` message) natively from the pinned build — no local
swap needed. Reword the variant comment now that the dependency is resolved.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix: address codex review nits on the github-dark theme
- UserSettings: re-read the dark variant when the settings drawer opens, so a
change made through one mounted instance (page-local drawer) isn't shown
stale by another (the always-mounted layout instance).
- PublicApp / OAuth login callback: restore the `github-dark` variant class,
not just the base `dark` class. These routes bypass the (root) layout, so
they previously fell back to the default dark palette despite the saved
preference.
- RawAppEditor: condense the two new theme comments to the durable constraints
per AGENTS.md (drop narration and the ephemeral artifact-pin history).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix: address CI review findings on the github-dark theme
- Move the hand-authored `github-dark` token set out of the Figma-generated
tokens.json into githubDark.json, merged back in at the two consumers
(tailwind.config.cjs before the rgb pass, utils.ts) so a Figma re-export of
tokens.json can no longer drop the set and crash the build.
- Restore the default-dark sidebar divider to #374151 — the PR must leave the
Default variant unchanged; only the github variant adapts it to border-light.
- Extract the `github-dark` DOM-class read into getAppliedDarkModeVariant() and
reuse it across RawAppEditor and vscode.ts; drop the redundant `void darkVariant`.
- Override the Monaco popup vars (suggest/hover widgets) in the github variant so
they match the GitHub palette instead of VS Code's greys.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
* feat: make hub resource type export explicit and validated
* fix: skip resource type validation when the workspace has no type catalog
* fix: snapshot the export opt-in and exclude s3_object unconditionally
* fix: capture the export opt-in at publish click, not after the draft request
* docs: correct the publish-snapshot rationale
* fix: truncate strings on char boundaries to avoid panics on multibyte input
* fix: add borrowed truncate_chars helper and pin ee ref for audit fix
* docs: clarify truncate_with_ellipsis length contract
* chore: update ee-repo-ref to bbfb0de0dc9fa06130a231eb10c64f60238d1bbd
This commit updates the EE repository reference after PR #690 was merged in windmill-ee-private.
Previous ee-repo-ref: de15aeff12daf457711f5b981de691418484535c
New ee-repo-ref: bbfb0de0dc9fa06130a231eb10c64f60238d1bbd
Automated by sync-ee-ref workflow.
---------
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* test(wac): pin the failure record with one corpus both SDKs read
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(wac): add the behaviour matrix that verified the failure record
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(wac): record how to exercise an unreleased SDK change
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): guard the whole extra pair, not just its value
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): never rehash an untrusted extra key
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): walk only a real __dict__ when collecting extra
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(wac): name the divergence the corpus cannot pin
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore(wac): state the extra-encoding constraints in four lines
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* ci: run the python and typescript SDK suites
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* ci: run the SDK suites on release tags only
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore(ci): state the constraint without the incident
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(sdk): claim only what functools.wraps actually restores
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(ci): note the interpreter the suite runs on is not the worker's
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(frontend): bulk discard selected drafts on the Compare & Deploy page
Add a destructive "Discard N drafts" button next to "Deploy N drafts" in
draft mode. A single confirmation modal lists draft-only items (permanent
deletions) by path before discarding sequentially with per-row status.
Split the selection gate into isDiscardable (own draft, not deployed this
session, not a data-pipeline bundle) and isDeployable (+ can_write): the
server lets you discard your own draft on a path you can no longer write
to, so each footer button counts its own eligible selection.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(frontend): address review findings on bulk draft discard
- invalidate the workspace-drafts resource once per batch instead of once
per discarded row (discardDraft gains an invalidate opt-out)
- write-gate legacy (ownerless) drafts in isDiscardable + tooltips,
mirroring the server's discard check
- explain diverging footer counts with a hint when selected drafts are
discardable but not deployable
- update selection-contract comments left over from the deploy-only gate
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(frontend): cover shared-draft outcome in bulk discard modal + comment reflow
A draft-only item someone else also drafted is neither reverted nor
deleted — only the current user's draft is removed. Say so in the modal.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(ai-chat): make hub script paths readable from the global chat
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(ai-evals): match hub fixtures on whole words, not substrings
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: source setQuery's query string from the address bar, not page.url
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: stop treating site-wide cross-origin isolation as leaving the editor
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: surface the real postgres error when data table migrations fail
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: address review nits on the data table migration error fix
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: name the exact grant a data table migration needs
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: quote both identifiers in the data table grant hint
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: add a data table connection and privilege check to workspace settings
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: report data table privileges from the capability fields, not the grant list
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: read grant targets from the server and drop the public schema guess
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: render the search_path suggestion server-side and pin the granted database
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: key the connection check on request identity, not the data table name
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: declare the data table check schema field nullable and required
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): hand a caught task and step failure the same shape in every round
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* refactor(wac): decide the failure record once, server-side
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): leave a legacy SDK's failure marker untouched, and ship wacError to jsr
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): carry a step's custom error fields, and bound the stack in bytes
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): keep a step's extra fields serializable and bounded
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): record a non-Error throw the way a task records it
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): guard the last unguarded throw site in the step marker
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): make failure reporting non-throwing on both clients
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): take the step traceback the way the executor takes it
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): contain the reads that happen before a failure is checkpointed
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): fall back to the checkpointed marker, not the live one
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): keep non-finite fields and hostile proxies out of the checkpoint path
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): keep the snapshot that passed the serialization probe
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore(wac): keep the failure-record module's surface to what is used
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(datatable): provision the replication user on managed postgres
* fix(datatable): serialize replication user provisioning and sync config schema
* fix(datatable): keep replication cleanup best-effort and self-heal a null password
* fix(wac): return the checkpointed value from step(), not the live object
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(wac): regenerate system prompts and narrow the round-trip claim
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* style(wac): condense the round-trip comments and fix the fallback note
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(sdk): type step() as the JSON round trip of its body's result
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(sdk): apply the JSON round trip to task() and the standalone paths
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(sdk): encode bigint, keep unknown as unknown, align dropped-key results
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): null out results whose key JSON.stringify would drop
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): normalize only the top-level result, keeping nested keys as they were
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(wac): normalize a child task's result so a deployed job cannot fail to parse
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(sdk): pin non-finite number behavior in Jsonified and its tests
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(sdk): admit undefined for keys whose value JSON.stringify may omit
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(sdk): make a key JSON.stringify may omit optional, not just nullable
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(sdk): treat a class-valued property as dropped, like any other function
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: show draft badge and disable toggle for draft-only triggers
* fix: align draft badge visibility with local draft hint
* fix: refine draft trigger rows (badge by label, off toggle, hover hints)
* fix: match draft pill size to standard badge size
* fix: show not-allowed cursor on disabled toggles
* fix: show the draft-only badge in place of the trigger toggle
Draft-only triggers have nothing deployed to enable, so the row renders
the "Draft only" badge in the toggle's slot instead of a disabled toggle.
Deployed triggers that also have a draft keep their toggle and show the
"Draft" badge next to the label.
Applies to schedules and every trigger list page, including amqp.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: place the draft badge left of the trigger toggle
Both badges now sit in the toggle's row: "Draft only" next to a disabled,
off toggle, and "Draft" next to the live toggle of a deployed trigger that
also has a draft. The label keeps only its `*` marker.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: show the draft badge hint as a tooltip when it has no actions
Without owner rows the popover renders a focus-ringed 256px card for a
single sentence. Route that case through Tooltip and keep the popover for
the owner list, whose View Diff / Load / Migrate buttons need click targets.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: drop the "edited by" label when there is no author
Draft-only rows are synthesized from the draft table and carry no author,
so the label rendered with nothing after it. Show it only when a name exists.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: render the draft badge on push-mode GCP and Azure triggers
Those rows have no mode toggle, and the badge slot was nested inside the
toggle's conditional, so they showed no badge at all.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: let the trigger control slot grow, and hint the suspended group too
The suspended three-state control is ~246px and overflowed the fixed 8rem
slot into the row's status and badges; the slot now treats 8rem as a
minimum so unsuspended rows still line up. Moving `title` onto the wrapper
also gives the suspended group the draft explanation the toggle already had.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: drop the date's "the"/"at" prefix on authorless rows
Without an author the prefix dangled ("the 7/15, 03:42 PM"); those rows now
show a bare timestamp.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: address PR review — draft-only row state, and DraftBadge visibility
- Derive each trigger row's status indicator from one effective mode, so a
synthesized draft-only row (mode 'enabled', no server_id) no longer claims
the trigger is starting up next to an off, disabled toggle.
- Fold draft_only into DraftBadge's own visibility rule so call sites pass
their state as-is instead of hard-coding is_draft={true} behind a guard
that duplicated the rule.
- Apply the same call to variables and resources, which still carried the
original is_draft={false} form and so rendered no badge at all.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: keep every mode control off draft-only rows
The row's overflow menu still offered "Suspend job execution" for draft-only
triggers, calling the mode API for a trigger with no deployment, and the
schedules enabled/disabled filter still read the raw `enabled` flag, so
draft-only schedules listed under Enabled while rendering an off toggle.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* perf: mount the draft diff drawer only where it can be opened
DraftBadge mounted a DiffDrawer on every instance, so unpaginated lists like
resources and variables carried a hidden drawer per row (measured: 4334 vs
3854 DOM nodes over 120 draft-less rows). The drawer is only reachable from
the popover's View Diff, which already requires `actionsEnabled`.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>