Commit Graph
14905 Commits
Author SHA1 Message Date
Ruben FiszelandClaude Opus 5.5 65cba2dbb7 perf: advance a flow step with one v2_job_status update (#11357)
* perf: advance a flow step with one v2_job_status update

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

* docs: state what advance_flow_status returning None means

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

* fix: keep the merged flow advance identical for rows without a status row or with a malformed status

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FbA4shbpCnRsUxir1GEfm

* docs: note the JSON null invariant behind the empty-path no-op

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FbA4shbpCnRsUxir1GEfm

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 00:18:59 +02:00
bebd762194 perf: complete a job in one statement on the common path (#11355)
* perf: complete a job in one statement on the common path

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

* fix: take completion locks in one order on every path

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

* fix: keep a losing zombie completion from touching its wac parent

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

* fix: leave a flow's ping alone when a step completes during its cancel

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

* test: probe only this test's completion for the lock wait

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

* fix: stamp a wac child's kept duration when its completed row exists

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJMJSJ2bDhYh7Shoh78Yyb

* perf: leave the parent ping out of completions with no flow to ping

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJMJSJ2bDhYh7Shoh78Yyb

* docs: note that the two completion statements must stay in step

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJMJSJ2bDhYh7Shoh78Yyb

* chore: update ee-repo-ref to 7a256cf353db7cf64a60a09fa0de7f3a8b27f626

This commit updates the EE repository reference after PR #830 was merged in windmill-ee-private.

Previous ee-repo-ref: 497137acb65e521568d46f3cbe1d66359f7f87ec

New ee-repo-ref: 7a256cf353db7cf64a60a09fa0de7f3a8b27f626

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-09-26 00:18:38 +02:00
Ruben FiszelandClaude Opus 5.5 e2be584ca5 fix: let custom workspace error handlers send email with the instance SMTP (#11365)
* fix: let custom workspace error handlers send email with the instance SMTP

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

* fix: state what the error handler email allowlist guarantees

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 22:18:40 +02:00
Ruben Fiszelandrubenfiszel 3974bbeac6 chore(main): release 1.818.0 (#11294)
* chore(main): release 1.818.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.818.0
2026-09-25 18:42:49 +00:00
hugocasaandClaude Opus 5.5 ca8a04a869 fix: allow results access inside nested functions in input transforms (#11358)
* fix: allow results access inside nested functions in input transforms

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: decode escaped bracket step ids and test deferred fetch errors

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: let quickjs decode bracket step ids and match quoted forms

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: prefetch results read through spread syntax

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: keep prefetched bracket literals on a single line

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: decode prefetch step literals as data and skip unparsable ones

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: run the results prefetch outside the expression scope

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: keep the transform expression a zero-arg iife after prefetch

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 18:41:52 +00:00
Ruben FiszelandClaude Opus 5.5 da866c5eff feat: alert on and optionally cancel jobs stuck on unserved tags (#11354)
* feat: alert on and optionally cancel jobs stuck on unserved tags

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

* fix: group stranded jobs in sql and recheck each job before canceling

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

* fix: guard stranded-job alerts and cancels against outages and pickups

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

* fix: count priority tags as served and retry lost stranded-job cancels

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

* feat: send one daily stranded-jobs alert that can be muted

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

* fix: cover native retries and finish lost stranded-job cancels unconditionally

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 17:48:21 +00:00
Ruben FiszelandClaude Opus 5.5 30bb62cd25 fix(cli): stub the API client over its real exports in tests (#11363)
* fix(cli): stub the API client over its real exports in tests

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

* fix(cli): mock the API client once and dispatch to per-suite stubs

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 17:43:08 +00:00
9a1c6e5081 feat: let a workspace withdraw operator schedule and trigger writes (#11226)
* feat: let a workspace withdraw operator schedule and trigger writes

Operators can create, edit and delete schedules and triggers today through the
API, CLI and MCP, while the operator_settings flags beside them only hide those
pages. An admin who wants operators to see what is scheduled without letting
them change it cannot express that. Add manage_schedules and manage_triggers as
enforced settings, gated at the schedule handlers and at the generic TriggerCrud
routes so every trigger kind is covered by one check.

They name capabilities operators already hold, so they are granted unless
withdrawn, and absence has to mean "never configured" rather than a value. The
read coalesces to true; the update endpoint merges into the stored jsonb with
the two fields as Option<bool>, so an omitted key keeps what is stored.
operator_settings is git-synced as a whole object, so a settings file written
before these keys existed reaches the endpoint on every pull, and a serde or SQL
default of either polarity would turn that pull into a silent withdrawal or
restoration.

The rights are read through a per-process cache, so withdrawing one publishes a
notify_event that drops the entry on every replica.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dsf6VC4MVLisiEoeQkgbr4

* feat: enforce operator write rights on the router and in the UI

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

* fix: close the capture gap and gate the trigger editors' write actions

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

* fix: gate acl writes and the native trigger drawer behind manage rights

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

* fix: refuse operator writes with 403 and gate sharing at the drawer

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

* perf: resolve identity in the operator write gate only for writes

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

* fix: gate the suspended-jobs actions and stop the route check refusing reads

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

* fix: explain the empty-state create button when operator writes are withdrawn

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

* fix: audit operator settings changes and fold path writes into native rows

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

* fix: open locked editors read-only and group the operator settings

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

* fix: skip email and azure lookups on editor open while triggers are locked

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

* docs: state each operator-rights rationale once in comments

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

* fix: address CI review findings on operator write rights

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

* fix: keep capture move gated and skip it in the builders while locked

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

* fix: keep admin and operator exclusive when setting a workspace role

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

* refactor: use the shared section component for operator settings groups

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

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2026-09-25 17:34:58 +00:00
Ruben FiszelandClaude Opus 5.5 a1abb36d9f fix: relock importers on their own tag, not the bare dependency tag (#11359)
* fix: relock importers on their own tag, not the bare dependency tag

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

* test: pin the tag of relocks triggered by a changed import

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 17:32:25 +00:00
Ruben FiszelandClaude Opus 5.5 53a5cfd17a perf: skip job-start pings and checkpoint read for short non-WAC jobs (#11356)
* perf: skip job-start pings and checkpoint read for short non-WAC jobs

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

* test: pin the wac language gate alongside is_wac_v2

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

* fix: keep the start memory sample for jobs shorter than one poll tick

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 18:39:08 +02:00
e14da5c6bc feat(bedrock): add OIDC role assumption as a fourth auth mode (#10936)
* feat(bedrock): add OIDC role assumption as a fourth auth mode

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YCVb91fZp3dqM14KRPzoEn

* fix(bedrock): gate the OIDC cache correctly and assume the role once per job

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YCVb91fZp3dqM14KRPzoEn

* refactor(bedrock): check the OIDC region before minting a token

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YCVb91fZp3dqM14KRPzoEn

* fix(bedrock): keep OIDC session names collision-resistant, gate the copy on EE

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YCVb91fZp3dqM14KRPzoEn

* fix(bedrock): check the OIDC region before reusing cached credentials

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YCVb91fZp3dqM14KRPzoEn

* fix(bedrock): clear assumed-role sessions when AI settings change

invalidate_ai_request_cache_for_workspace cleared AI_REQUEST_CACHE only, so a
workspace's AI settings edit reset one cache and left the assumed-role sessions
keyed on the old config in place until STS expired them.

Also name the region requirement in the credentials-check hint, so following it
does not land on the OIDC path's region guard.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YCVb91fZp3dqM14KRPzoEn

* chore: update ee-repo-ref to de73db2bacfdc3eaa2e63b1827178bc198d54e5c

This commit updates the EE repository reference after PR #770 was merged in windmill-ee-private.

Previous ee-repo-ref: c43dab1e69b1cb3f685e6df07bff634dc2a0b734

New ee-repo-ref: de73db2bacfdc3eaa2e63b1827178bc198d54e5c

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>
2026-09-25 18:19:38 +02:00
hugocasaandClaude Opus 5 94e4fb1c84 fix: carry labels when deploying variables, resources and folders (#11222)
* fix: carry labels when deploying variables, resources and folders across workspaces

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: clear a folder's labels in the target when the source has none

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test: pin that the frontend deploy adapter carries variable labels

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-25 18:15:08 +02:00
hugocasaandClaude Opus 5 d3d5392917 feat: add an options field to the postgresql resource (#11223)
* feat: add an options field to the postgresql resource

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: keep a literal plus in postgres connection string parameters

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: pass postgres options to trigger connections

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: read DATABASE_URL options the way sqlx does

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* feat: include postgres options in databaseUrlFromResource

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-25 17:40:13 +02:00
Alexander PetricandClaude Opus 5.5 f183bd43fb chore: retire the standalone lsp and multiplayer images from examples, drop lsp/Dockerfile (#11341)
* chore: retire the standalone lsp and multiplayer images from examples, drop lsp/Dockerfile

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

* chore: drop the unbuilt DockerfileMultiplayer, document running the LSP from windmill-extra

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

* fix(examples): ecs terraform destroys cleanly and gives private instances no public ip

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

* fix(examples): give windmill-extra on ecs a WINDMILL_BASE_URL for multiplayer auth, address review

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

* fix(examples): make the ecs example upgrade cleanly from the standalone lsp/multiplayer stack

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

* fix(examples): name the extra target group by prefix so create_before_destroy can replace it

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

* docs(examples): note the brief editor-socket gap when upgrading the ecs example

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

* docs(examples): the debugger stays off after the ecs upgrade unless enabled

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 17:13:06 +02:00
hugocasaandClaude Opus 5 3bd89e92d8 feat: collapse the fork members setting and show its state in a badge (#11220)
* feat: collapse the fork members setting and show its state in a badge

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: show the fork members badge next to the title, only when on, like other section badges

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-25 17:12:51 +02:00
Alexander PetricandClaude Opus 5.5 8caf414301 fix(multiplayer): a malformed frame from one client no longer exits the server (#11353)
* fix(multiplayer): don't drop client messages during cold-start token verification

`wss.on('connection')` awaits `verifyToken()` before `setupWSConnection()`
attaches the 'message' listener. On a cold process that await includes the
first `/api/debug/jwks` fetch (~30ms on ECS). A y-websocket client sends sync
step 1 the instant the socket opens, and `ws` drops messages emitted with no
listener attached, so that step 1 was lost and never answered with step 2 —
the client's provider never became `synced`.

Buffer messages from the moment the connection is accepted and replay them, in
order, once `setupWSConnection()` has installed its handlers. Rejected
connections drop the buffer and close with the same 4401/4403 codes as before.

Also prefetch the public key at startup when WINDMILL_BASE_URL is set. That is
insurance, not the fix: a connection arriving before the prefetch resolves
still relies on the buffer.

Adds `npm test` in multiplayer/ (node:test, no docker or backend needed) with a
fake JWKS endpoint that answers with a delay, which holds the cold window open
and makes the race deterministic; wired into the existing test_extra CI job.

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

* fix(multiplayer): cap what an unauthenticated peer can buffer pre-auth

Review follow-up.

The pre-auth buffer was unbounded: `ws` sets no `maxPayload` here and the JWKS
fetch has no timeout, so a peer that never authenticates could stream frames
into memory for as long as `verifyToken` was stalled. Cap it at 32 frames /
1 MiB — a real client only has sync step 1 and its first awareness update in
flight there — and close 1009 past that, dropping what was buffered.

A socket closed during verification (by the peer, or by that cap) is no longer
handed to setupWSConnection: it would be added to `doc.conns` with a 'close'
listener that can never fire.

The startup prefetch's .catch was dead code — getPublicKey() logs its own
failures and resolves to null rather than rejecting.

Test helper: pin REQUIRE_SIGNED_MULTIPLAYER_REQUESTS and BASE_INTERNAL_URL so an
ambient value cannot turn the rejection tests into false passes; bind the JWKS
server on port 0 instead of a released probe port, and retry the spawned server
on EADDRINUSE; destroy still-delayed JWKS responses on teardown, since
server.close() waits for in-flight requests.

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

* test(multiplayer): gate the JWKS response instead of delaying it

Review follow-up.

The cold window was held open by a 1500 ms delay on the fake JWKS response, but
that timer started when the startup prefetch reached the fake server, not when
the client sent its first frame. A slow enough machine could load the key before
the client connected, and the race test would then pass without ever exercising
the buffer — a false pass.

The fake JWKS server now parks every response until the test calls release(), so
the server provably holds no key while the client is sending. The race test
releases only after both frames are written to the socket, and asserts the
server has not logged the key as loaded at that point; the flood test never
releases until after the cap has closed the connection.

What is left to wall-clock time is 250 ms for bytes already written to the socket
to cross loopback into an otherwise idle server, rather than a window that had to
cover process startup, connect and handshake.

Also drops the prefetch precondition from the forged-token and flood tests so
each test still maps to one behaviour. Suite runs in ~1.1s instead of ~5.3s.

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

* fix(multiplayer): survive a malformed frame instead of exiting the process

`setupWSConnection`'s message handler decoded whatever an authenticated peer
put on the wire with no guard: `decoding.readVarUint`,
`syncProtocol.readSyncMessage` and `awarenessProtocol.applyAwarenessUpdate` all
throw on input they cannot parse, `ws` re-emits a listener's exception on the
process, and server.mjs installs no `uncaughtException` handler. One bad frame
from one client therefore killed the whole multiplayer server, taking every
other document and every other client with it.

Catch decode/apply failures, log the document, the client address and the error
message (never the payload), and close only the offending connection with 1007
"invalid frame payload data". Frames that arrive once a connection is no longer
OPEN are ignored, so the replay of the pre-auth buffer stops at the first
refusal instead of applying the rest.

docker/entrypoint-extra.sh made that outage permanent: on a service exit it
logged a bare PID and then `wait`ed on the rest, so the container stayed up with
a dead service and the health checks in front of it — which probe the LSP — saw
nothing wrong. It now names the service that died, stops the others through the
same shutdown path SIGTERM uses, and exits non-zero so the orchestrator replaces
the container. The "no services enabled" branch still sleeps.

Tests: multiplayer/test/malformed_frame.test.mjs covers four malformed payloads
from an authenticated client and one replayed out of the pre-auth buffer,
asserting the 1007 close, a live server process, an undisturbed bystander and a
real edit still propagating. docker/test_entrypoint_extra.sh runs the real
entrypoint in a container with stub services.

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

* test(multiplayer): prove the replayed malformed frame really is buffered pre-auth

Assert the server has not yet logged the loaded key when the frame is written,
and give it the same in-flight margin as the cold-start tests before releasing
the JWKS response, so the frame provably goes through the replay path rather
than landing on an already-authenticated connection.

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

* ci(extra): run the entrypoint supervision tests in publish_extra

The multiplayer unit tests already run there; the entrypoint test needs only
docker and the checkout, so run it in the same job, before the image build.

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

* fix(multiplayer): handle WebSocket protocol errors and bound the shutdown

Two crash paths of the same class as the malformed-frame one, from review.

`ws` fails a frame it cannot parse at the protocol level — an unmasked frame
from a client, a reserved opcode, a bad RSV bit — inside its Receiver, before
the application 'message' handler ever sees it, and `receiverOnError` ends with
`websocket.emit('error', err)`. With no 'error' listener that is an unhandled
EventEmitter error, so it exited the process just as a malformed payload did.
(A raw socket error such as ECONNRESET does not: ws 8.21.3's `socketOnError`
swallows those.) Add the listener on the accepted socket, before authentication
so the pre-auth window is covered too, and one on the server.

Log messages now go through `describeError`, which collapses whitespace and
truncates, so nothing that reaches an error message can forge or flood a log
line.

`stop_services` ended in a bare `wait`. On the `docker stop` path dockerd
provides the deadline; the "a service died" path signals itself, so a service
that is wedged or slow to honour SIGTERM would hold the container open
indefinitely — the state that path exists to prevent. Bound it: SIGTERM, wait
SHUTDOWN_GRACE_SECS (10 by default), then SIGKILL the stragglers by name.

Tests: multiplayer/test/socket_error.test.mjs (authenticated and pre-auth
illegal frames, asserting a live process and continued service), a
SIGTERM-ignoring stub scenario in docker/test_entrypoint_extra.sh, and that
harness is now bounded throughout — `timeout -k` on foreground runs, a watchdog
around the backgrounded ones, and an optional outer timeout on `docker run`.
`--entrypoint bash` so the documented windmill-extra:test override runs the
harness instead of the image's real entrypoint. The stubs publish a readiness
marker and the dying one waits for them, removing a startup race in the harness.

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

* fix(multiplayer): never log peer bytes, and keep a fatal server error fatal

Two review findings on the previous commit, both mine to answer for.

`describeError` collapsed whitespace, which is not enough. An error message is
not always a fixed string: `applyAwarenessUpdate` runs `JSON.parse` on the
peer's bytes and V8 quotes ~30 bytes of the offending input back verbatim, ESC
included, so a peer could put terminal escapes and forged content into a log
line. Strip everything outside printable ASCII instead, and say so where the
comment previously claimed the messages were fixed strings.

`wss.on('error')` was worse than the crash it replaced for one case: `ws`
forwards the HTTP server's errors there, so a failed listen (EADDRINUSE) was
logged and the process then exited 0 — a clean shutdown as far as anything
upstream could tell. It now sets a non-zero exit code. Setting `process.exitCode`
rather than calling `process.exit()` keeps the log line from being truncated.

`openClient` in the test helpers now records the socket error it was already
swallowing, so a failed connection reports its cause instead of surfacing as a
bare `waitFor` timeout.

Tests: a malformed awareness frame whose state is `x\x1b[2J OWNED THE LOG` added
to the payload table, with every case now asserting exactly one refusal line and
no control characters in it (1 fail before, 0 after, 3 runs); and a server that
cannot listen must exit non-zero (1 fail before, 0 after, 3 runs). 14/14 on 5
consecutive runs.

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

* test(multiplayer): make the exit-status helper robust to spawn and stdio races

Review follow-ups on runMultiplayerServerUntilExit.

Wait for 'close', not 'exit': 'exit' fires when the child terminates, which can
be before its stdio pipes are drained, and the caller reads the output. On the
EADDRINUSE path the child writes one line and exits immediately after, which is
exactly the shape that loses it.

Listen for 'error' too. A child that fails to spawn emits neither 'exit' nor
'close', so the promise would never settle and the SIGKILL guard could not help.

Report whether the guard fired, rather than leaving the caller to infer it from
the exit signal: `signal` is null for every child exit on Windows, so a server
that hung after the listen error would have looked like one that exited on its
own. The test asserts on that flag instead.

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

* test(multiplayer): assert the refusal line itself, and name hasSyncType for what it takes

Two review nits on the test helpers.

The `doc="..."` assertion searched the whole server log, where CONNECT and
DISCONNECT also name the document, so it would have passed even if the refusal
stopped naming anything. Every assertion about the refusal is now made against
the refusal line, which the test already isolates, and it also checks the peer
is named.

`hasKind` took a sync sub-type but was named as if it took any message kind, and
the two families overlap numerically (`syncStep1 === messageSync === 0`), so a
caller passing the wrong one got a silently wrong answer. No runtime check can
tell aliased numbers apart, so the fix is the name: `hasSyncType`, with the
overlap spelled out where the constants are declared.

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

* test(multiplayer): make the pre-auth tests prove which path they took

The replay test could not establish that its frame went through the pre-auth
buffer: a frame delivered after setup, into the live handler, produces the same
close code and the same refusal line, so if the in-flight margin were ever
missed the test would quietly become a duplicate of the main-loop cases rather
than fail. server.mjs now logs REPLAY when, and only when, it replays a buffered
pre-auth message — worth having on its own, since that path only runs when a
client beat the JWKS fetch on a slow-starting instance — and the test asserts on
it. Removing that log line turns the test red, which is the point.

The socket-error pre-auth test gated on `jwks.requests >= 1`, which the startup
warm-up already satisfies, so it proved nothing about the offender. What makes
it the pre-auth case is that the JWKS response stays parked for the whole test;
it now asserts the server never logged CONNECT, which is exact.

`killedByTimeout` was set before the kill, so a child that exited on its own just
before the timeout — with 'close' still pending on the stdio drain, the very
window this helper waits for — would have been reported as killed. It now claims
the rescue only when there was a live process to signal.

14/14 on eight consecutive runs.

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

* test(multiplayer): document the frame-recording contract in openClient

ws hands every frame over as a Buffer under the default binaryType, text frames
included, so recording them as Uint8Array is lossless for both. Worth stating:
ws 7 delivered text frames as strings, where new Uint8Array(string) would have
been a silent zero-fill, and the difference is not visible at the call site.

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

* test(multiplayer): pin the close code for an illegal frame, and trim comments to the 4-line rule

Both socket-error tests waited for a close and never checked what it was, so an
abrupt 1006 teardown would have passed while the comment beside the payload
claimed 1002. `ws` sends 1002 for an unmasked frame in both the authenticated
and pre-auth cases, confirmed over repeated runs; that is now a named constant
asserted in each test, mirroring malformed_frame.test.mjs. Changing the expected
value turns both red.

The comments added by this branch also ran past the four lines AGENTS.md allows,
and several justified the change to a reader rather than stating the invariant.
Condensed to the invariant, at the site that would break it.

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 17:12:47 +02:00
hugocasaandClaude Opus 5 1d119e6b25 fix: correct the tool controls and name field of a nested AI agent (#11221)
* fix: hide tool controls a nested AI agent cannot use

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor: drop the tool navigation prop an agent tool now implies

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: ask for a tool name on every kind of agent tool

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: keep enabled_tools reachable on a linked nested agent tool

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: name the tool kinds the header's name field actually renders

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: state the tool-name rule without listing the kinds it covers

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-25 17:12:28 +02:00
Diego ImbertandClaude Opus 5.5 4fd7d62bd0 feat: rework the db manager: native grid, tabs, sql editor, joined columns (#11340)
* feat: replace ag-grid in the db manager table viewer with a native grid

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

* feat: add user-managed data, diagram and sql editor tabs to the db manager

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

* feat: add schema autocomplete to the db manager sql editor and polish its layout

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

* feat: add joined foreign key columns and draggable tabs to the db manager

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

* fix: move db manager tabs on drop instead of mid-drag

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

* feat: open followed foreign keys in a new db manager tab

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

* fix: scroll large tables, drop stale joins and return to the last tab on close

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

* fix: tolerate the db manager tabs going away while switching data table

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

* fix: keep saved joined columns while metadata loads, test joins in every dialect

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

* fix: put the db manager grid on the input surface in dark mode

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

* fix: address db manager review nits on joins, boolean keys and sql quoting

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

* fix: keep the dark border color on the left pinned column edge

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

* fix: tone down the db manager tree menu icons

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

* fix: write json and jsonb values from the db manager through a text cast

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

* fix: dim unrelated diagram tables less on hover

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

* fix: match json columns as text when deleting a db manager row

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

* fix: compare postgres json columns as text in exact db manager filters

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

* feat: pick the columns the db manager grid shows

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

* feat: toggle every db manager column from one checkbox

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

* feat: word joined columns as a view in the db manager

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

* feat: keep data table roles and access visible when unavailable, with the reason

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

* feat: keep data table and instance roles visible in settings when unavailable

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

* feat: hide a db manager column from its header menu

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

* feat: format db manager columns with a unit, significant digits and color rules

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

* fix: drop the before/after hints from the db manager unit picker

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

* fix: write the euro after the amount and keep units off non-numeric values

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

* feat: color rule presets, bold and italic, layered and reorderable rules in the db manager

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

* feat: decimals, thousands separator, compact notation and alignment in db manager column formats

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

* feat: compact db manager format controls, a notation toggle group and a reset button

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

* fix: db manager format and filter nits

Keep the value's scale when decimals are auto, read boolean color-rule conditions as
booleans, let a rule's text color reach foreign-key links, close the formatter when the
columns picker opens, and filter BigQuery complex columns through TO_JSON_STRING.

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 15:58:25 +02:00
Alexander PetricandClaude Opus 5.5 2e5f6d0e76 fix(frontend): keep the session when the persisted workspace is stale (#11344)
* fix(frontend): keep the session when the persisted workspace is stale

A single-use login link signs a different account in while `workspace` in
session/localStorage still names the previous account's workspace. `loadUser`
read that workspace, got no membership back, threw `Not logged in` and logged
the brand-new session out, landing on `/user/login?rd=...`.

A missing membership says nothing about the session, so forget the workspace
and continue down the no-workspace path, which logs out only when
`globalWhoami` shows the session itself is gone.

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

* fix(frontend): confirm the session before the workspace-picker redirect

`loadWithoutWorkspace` fired the `/user/workspaces?rd=…` navigation before
awaiting `globalWhoami`, so when the session turned out to be gone the logout
read whichever URL the race had left in `page.url` and carried the picker as
its `rd`. Ask first, then redirect.

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

* docs(frontend): stop the loadUser comments overclaiming what they know

Neither comment can promise what it stated: `getUserExt` collapses every
failure into `undefined`, so the branch cannot tell a real non-membership from
a transient one, and `loadWithoutWorkspace` throws on any `globalWhoami`
rejection rather than only on a dead session. Say what each call actually
answers about.

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 15:56:45 +02:00
Alexander PetricandClaude Opus 5.5 e8c3f9514e fix(multiplayer): don't drop client messages during cold-start token verification (#11343)
* fix(multiplayer): don't drop client messages during cold-start token verification

`wss.on('connection')` awaits `verifyToken()` before `setupWSConnection()`
attaches the 'message' listener. On a cold process that await includes the
first `/api/debug/jwks` fetch (~30ms on ECS). A y-websocket client sends sync
step 1 the instant the socket opens, and `ws` drops messages emitted with no
listener attached, so that step 1 was lost and never answered with step 2 —
the client's provider never became `synced`.

Buffer messages from the moment the connection is accepted and replay them, in
order, once `setupWSConnection()` has installed its handlers. Rejected
connections drop the buffer and close with the same 4401/4403 codes as before.

Also prefetch the public key at startup when WINDMILL_BASE_URL is set. That is
insurance, not the fix: a connection arriving before the prefetch resolves
still relies on the buffer.

Adds `npm test` in multiplayer/ (node:test, no docker or backend needed) with a
fake JWKS endpoint that answers with a delay, which holds the cold window open
and makes the race deterministic; wired into the existing test_extra CI job.

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

* fix(multiplayer): cap what an unauthenticated peer can buffer pre-auth

Review follow-up.

The pre-auth buffer was unbounded: `ws` sets no `maxPayload` here and the JWKS
fetch has no timeout, so a peer that never authenticates could stream frames
into memory for as long as `verifyToken` was stalled. Cap it at 32 frames /
1 MiB — a real client only has sync step 1 and its first awareness update in
flight there — and close 1009 past that, dropping what was buffered.

A socket closed during verification (by the peer, or by that cap) is no longer
handed to setupWSConnection: it would be added to `doc.conns` with a 'close'
listener that can never fire.

The startup prefetch's .catch was dead code — getPublicKey() logs its own
failures and resolves to null rather than rejecting.

Test helper: pin REQUIRE_SIGNED_MULTIPLAYER_REQUESTS and BASE_INTERNAL_URL so an
ambient value cannot turn the rejection tests into false passes; bind the JWKS
server on port 0 instead of a released probe port, and retry the spawned server
on EADDRINUSE; destroy still-delayed JWKS responses on teardown, since
server.close() waits for in-flight requests.

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

* test(multiplayer): gate the JWKS response instead of delaying it

Review follow-up.

The cold window was held open by a 1500 ms delay on the fake JWKS response, but
that timer started when the startup prefetch reached the fake server, not when
the client sent its first frame. A slow enough machine could load the key before
the client connected, and the race test would then pass without ever exercising
the buffer — a false pass.

The fake JWKS server now parks every response until the test calls release(), so
the server provably holds no key while the client is sending. The race test
releases only after both frames are written to the socket, and asserts the
server has not logged the key as loaded at that point; the flood test never
releases until after the cap has closed the connection.

What is left to wall-clock time is 250 ms for bytes already written to the socket
to cross loopback into an otherwise idle server, rather than a window that had to
cover process startup, connect and handshake.

Also drops the prefetch precondition from the forged-token and flood tests so
each test still maps to one behaviour. Suite runs in ~1.1s instead of ~5.3s.

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 15:54:11 +02:00
Ruben FiszelandClaude Opus 5.5 d931032706 perf: stop polling http trigger routes on workers and every minute (#11351)
* perf: read the http trigger version only as a 20 min safety net

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

* perf: check the http trigger version every 5 min instead of 20

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

* perf: load http trigger routers lazily on workers

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

* style: drop unrelated formatting from main.rs

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

* fix: force the periodic http router rebuild and retry a failed one

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

* fix: retry a failed http router refresh from every caller

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 12:01:28 +00:00
Alexander PetricandClaude Opus 5.5 16f3ee84f6 ci: file release Docker Scout results under main so the code scanning status and alerts stay current (#11338)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 11:41:19 +00:00
hugocasaandClaude Opus 5.5 733c119fd9 feat: schedule hub scripts (#11330)
* feat: schedule hub scripts

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

* test: pin hub script schedule push

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

* feat: retry scheduled hub scripts natively

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

* chore: address review nits on hub schedules

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

* feat: open the hub picker from the script select

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

* chore: use a subtle button for the hub row

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 11:40:01 +00:00
AlexRV12andClaude Opus 5.5 421fdab3d8 fix: always save slack/teams/email handlers as scripts (#11345)
* fix: always save slack/teams/email handlers as scripts

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

* fix: key the handler kind on the selected tab, not the hub/ prefix

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

* fix: recognise email recovery and success handlers when loading a schedule

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 11:38:54 +00:00
9100ab954a feat: seed SCIM usernames from nickName (#11346)
* [ee] feat: seed SCIM usernames from a login-name userName

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

* chore: bump ee ref

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

* chore: bump ee ref

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

* chore: bump ee ref

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

* chore: bump ee ref

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

* chore: update ee-repo-ref to c099af43bad922fd57ed0449ab717ffa047b5546

This commit updates the EE repository reference after PR #828 was merged in windmill-ee-private.

Previous ee-repo-ref: 1af1871fb702346d6a2a033f5af3210bbfd0ef72

New ee-repo-ref: c099af43bad922fd57ed0449ab717ffa047b5546

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-09-25 11:04:19 +00:00
Ruben FiszelandClaude Opus 5.5 4b09558e13 feat: start a deferred queued job now without changing its id (#11347)
* feat: start a deferred queued job now without changing its id

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

* fix: refuse starting a schedule's upcoming tick early

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

* fix: hide run now on upcoming schedule ticks and register its audit op

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 10:43:46 +00:00
Ruben FiszelandClaude Opus 5.5 245628210f perf: skip parent status write when a parallel loop iteration starts (#11348)
* perf: skip parent status write when a parallel loop iteration starts

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

* fix: keep the loop viewer off the parent job while a parallel loop runs

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

* docs: state what a parallel module's job would hold

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

* perf: test the parallel module with one containment check

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 10:41:27 +00:00
Ruben FiszelandClaude Opus 5.5 bc4f872f10 perf: skip the flow_env ancestor walk for sub-flows with nothing to inherit (#11349)
* perf: skip the flow_env ancestor walk for sub-flows with nothing to inherit

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

* fix: keep the flow_env mark out of sub-flow definitions replayed by restarts

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

* test: align the guest scopable-path test with app path validation

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 10:30:43 +00:00
Ruben FiszelandClaude Opus 5.5 d18d7043df feat: infer a script's schema when a deploy (e.g. MCP) sends none (#11339)
* feat: infer a script's schema from its code when a deploy sends none

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

* fix: merge an inferred schema into the previous one the way the editor does

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

* fix: parse non-JSON TS defaults natively and keep the schema on a failed inference

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

* fix: type untyped TS params from their literal shape when the default can't be evaluated

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

* fix: read literal TS defaults off the AST so the server types them like the editor

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

* docs: word the script schema description for both create and update

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

* docs: note that dbt scripts derive their schema from the descriptor

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 10:00:49 +00:00
Ruben FiszelandClaude Opus 5.5 0bac766756 feat: refresh MCP tools when scripts and flows change (#11337)
* feat: notify MCP clients when a workspace's scripts or flows change

Advertise tools.listChanged and implement subscriptions/listen, so a
2026-07-28 client refreshes its tool list when scripts or flows are
deployed, archived, renamed or deleted. Changes reach every replica via
new statement-level notify_event triggers; MCP-originated changes also
signal the serving replica inline.

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

* fix: signal each workspace once per notify-event poll batch

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

* fix: signal script/flow path moves, keep unrelated updates trigger-free

Row-level UPDATE OF archived/deleted/path triggers with a WHEN guard
replace the statement-level ones, which built transition tables for
every UPDATE on script and flow. Path moves from username changes and
offboarding are now signalled. subscriptions/listen is refused when the
client asks for nothing this server sends.

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

* fix: signal path moves only for unarchived versions

A username change or offboarding rewrites the path of every version,
archived ones included, which would queue one notify_event per version.

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

* refactor: detect MCP tool-list changes by polling a workspace fingerprint

Replace the notify_event triggers and poller hook with a per-process,
per-workspace poll of a hash over the live scripts and flows, run only
while a subscriptions/listen stream watches that workspace. Every write
path (UI, CLI, git sync, user renames, workspace moves) is covered with
no migration; an MCP-originated change polls at once.

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

* fix: announce the first fingerprint so a change before the baseline is not lost

Also poll immediately after a script/flow mutation through a
multi-workspace token, and pin the fingerprint test on a lock update,
which is the unrelated write that actually happens.

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

* fix: open every tool-list subscription with one notification

A subscriber joining an existing watcher missed a change the watcher
recorded before it subscribed. Also move the fingerprint query to a
runnables module, since it spans scripts and flows.

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 09:38:41 +00:00
Ruben FiszelandClaude Opus 5.5 1fd729ac1a feat: add an instance-wide accent color setting with sidebar tint (#11335)
* feat: add an instance-wide accent color setting with sidebar tint

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

* fix: paint the cached accent before the license resolves

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

* feat: serve the banner and accent color from one cached endpoint

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

* fix: invalidate the instance ui cache and bound it with a ttl

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

* fix: keep the instance ui ttl under the client poll period

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

* refactor: load the banner and accent color once per page load

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

* refactor: read the banner and accent color without a server cache

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

* fix: show a cleared accent color as off

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 11:23:30 +02:00
2f1953ea10 restore the operator alias in the offline seat-count query (#11336)
* fix: restore the operator alias in the offline seat-count query

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

* chore: update ee-repo-ref to bf64ca98472a57cbfd150f8876877d2d4d9c217e

This commit updates the EE repository reference after PR #827 was merged in windmill-ee-private.

Previous ee-repo-ref: 59ac4f6e051fa9b6656b5d34759c09a04c4d8b85

New ee-repo-ref: bf64ca98472a57cbfd150f8876877d2d4d9c217e

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-09-24 15:36:04 +02:00
Diego ImbertandRuben Fiszel ebb3048ca0 feat: mount session list pages in process instead of iframes (#11289)
* feat: mount session list pages in process instead of iframes

* fix: seed filter defaults from the query, not the cached search params

* fix: type trigger list rows from the generated trigger types

* fix: judge hosted lists by the operating workspace's rules and keep role-gated filters

* fix: keep the user folders filter key for every role, hidden where it does not apply

* fix: drop the user folders filter for users it is not offered to

* fix: wait for a known user before dropping the user folders filter

* style: tint trigger rows for every kind and align the schedules footer wording

* fix: stamp edited_at when a schedule is updated

---------

Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2026-09-24 15:14:59 +02:00
GuilhemandClaude Opus 5 d02ff9ac24 fix: centre the toggle knob inside its track (#11314)
* fix: centre the toggle knob inside its track

The knob was positioned against the toggle's wrapper rather than the track,
so its 2px inset resolved to a 1px gap inside the track's 1px border. On a 1x
screen a toggle that lands on a fractional x blurs its edges across a whole
pixel, which swallows that 1px gap and makes the knob look like it overflows
the track.

Position the knob inside the track's border with a 2px gap on every side,
size the toggle in whole px so the 18px root font of large screens cannot
make the track fractional, and give each size an explicit checked translate
now that the knob is no longer exactly one translate-x-full wide.

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

* refactor: hoist the toggle knob's shared inset out of the size branches

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

* chore(frontend): add a Toggles tab to the kitchen sink

Covers the four sizes, the three colors, the label and EE-badge variants, and
a grid of quarter-pixel offsets: the knob's gap against the track border only
misreads once the track lands between device pixels.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-24 15:12:09 +02:00
AlexRV12andClaude Opus 5.5 1b74939952 feat: support aiagent steps in test_run_step (#11321)
* fix: support aiagent steps in test_run_step

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

* fix: offer the agent's tools as a picker in the step run form

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

* fix: run a blank tool list as no tools when the step form is bypassed

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 15:11:26 +02:00
9375c93fd8 fix: trust the system CA store for SMTP TLS (#11328)
* fix: trust the system CA store for SMTP TLS

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

* ci: run the smtp-gated backend tests

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

* chore: depend on webpki-roots 1 directly

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

* chore: update ee-repo-ref to 48193da8cb30bc4ae82a50f944caef85d8a20b48

This commit updates the EE repository reference after PR #826 was merged in windmill-ee-private.

Previous ee-repo-ref: cd3447143b25d9f3301975feca4b202755f2508f

New ee-repo-ref: 48193da8cb30bc4ae82a50f944caef85d8a20b48

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-09-24 15:10:28 +02:00
hugocasaandClaude Opus 5.5 8525206361 fix: pass the schedule's custom tag when using run now (#11322)
* fix: pass the schedule's tag when using run now on a schedule

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: keep flow schedules on the flow's own tag for run now

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 15:01:21 +02:00
GuilhemandClaude Opus 5.5 98d3897b8c fix: hide answer actions until the chat turn ends (#11323)
* fix: hide answer actions until the chat turn ends

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

* fix: keep the last turn's answer actions during a manual compaction

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

* docs: note answer actions stay hidden while a turn waits on the user

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 15:00:23 +02:00
GuilhemandClaude Opus 5.5 2f2882adff fix: label chat job links with the end of the job id (#11324)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 14:56:24 +02:00
hugocasaandClaude Opus 5.5 9b46b21f51 feat(cli): include extra paths in codebase digest for monorepo imports (#11327)
* feat(cli): hash codebase extra_digest_paths and warn on uncovered bundle inputs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cli): cache codebase digest only once complete, skip entry in warning

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cli): accept string extra_digest_paths, always print uncovered-input warning

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cli): clarify extra_digest_paths resolution and missing-path error

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 14:54:13 +02:00
Guilhem c232ea43b4 fix: limit compare page guidance to fork deploys (#11300)
* fix: limit compare page guidance to fork deploys

* fix: make open_page compare fork-only and drop stale api catalog bullet

* fix: always open the compare page in fork mode from open_page

* fix: drop the ignored mode argument from open_page
2026-09-24 14:53:36 +02:00
Ruben FiszelandClaude Opus 5.5 80903c9a64 feat: per-folder AI chat instructions via ai_instruction resources (#11325)
* feat: give the AI chat per-folder instructions from ai_instruction resources

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

* fix: hold a change back until the model has read its folder instructions

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

* fix: find nested trigger paths and scope instruction deliveries by workspace

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

* fix: cap folder instructions per result and record holds as their own outcome

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

* fix: show a held call as its own row and cover group folders

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

* fix: state how folder instructions combine with workspace and user ones

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 12:58:59 +02:00
Diego ImbertandClaude Opus 5 504d01a563 feat: rework the git sync setup into a guided flow (#11308)
* feat: rework git sync settings into a flat repo list and setup modal

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

* feat: add the connect step for gitlab and github in git sync setup

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

* feat: open the github app install page from the git sync setup next step

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

* feat: let git sync setup set the repository folder

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

* feat: add the configure sync step to git sync setup

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

* style: even out the git sync filter settings columns

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

* style: pin the filter input to the bottom of the filter list

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

* style: frame the git sync path filters in a box with an empty hint

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

* refactor: use a multiselect for the git sync path filters

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

* feat: grey out the skipped connect step in git sync setup

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

* style: move the check job line to the bottom of the setup modal

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

* fix: hide the check job line once the repository check resolved

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

* style: center the repository check loader in the setup modal

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

* fix: stop the setup modal shifting when the check job id arrives

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

* style: move the existing resource hint to the setup modal footer

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

* feat: always show the existing resource option when one exists

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

* style: drop the card and collapse from the git sync filter settings

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

* style: use a success alert for the pull from git notice

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

* feat: make initializing the repository a step of the git sync setup

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

* style: hide the push job lines once they succeed

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

* style: reword the push step intro

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

* style: copy button on the cli snippet and a taller changes list

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

* style: match the push step loading to the check step

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

* fix: stop the push step shifting when a job id arrives

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

* style: let the changes list fill the push step

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

* feat: end the git sync setup on a done step instead of a modal

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

* feat: delete a git sync repository from a row menu with a confirmation

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

* style: lift the git sync done message off the notices

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

* feat: restore github app installation transfer between instances

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

* fix: address regressions from the git sync setup rework

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

* fix: keep the overlay z-index floor in step with the ai chat

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

* fix: hold the push state in the setup dialog, not in the step it destroys

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

* fix: block every dismissal while setup work is in flight and keep sync reachable

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

* fix: regenerate the resource path when the repository changes

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

* fix: configure the resource the connect step actually created

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

* fix: keep a modal open when a drawer above it takes the click

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

* fix: snapshot the topmost surface for keyboard clicks too

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

* style: size the add repository buttons and explain git promotion

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

* revert: drop the promotion-first action from the empty state

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

* style: shrink the test connection result line

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

* feat: offer the fork sync and fork pull request toggles during setup

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

* style: group promotion repositories under their own label

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

* feat: offer the deploy branch pull request toggle during setup

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

* fix: wait for the repository credential before saving the setup

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

* fix: ignore a superseded credential load and drop the bindable default

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

* fix: key setup readiness to the repository it was loaded for

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

* fix: tie setup readiness to the attempt that asked for it

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

* feat: link to where the access token is created

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

* style: say plainly how each provider connects

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

* feat: sync resources, variables, schedules and triggers by default

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

* style: use the accent colour for the token help link

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

* style: move the CI/CD deploy hint next to the pull toggle

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

* fix: keep setup gated when the connection could not be read

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

* fix: only explain pull-from-git where the workspace can turn it on

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

* fix: offer a save retry once the repository is initialized

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

* fix: say when pulling fell back to polling on the last setup step

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

* fix: clear the initialized flag when a new draft starts

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-24 11:54:25 +02:00
AlexRV12andClaude Opus 5 6cd70a8e08 feat: filter ai session tools to the user's workspace capabilities (#10719)
* feat: filter ai session tools to the user's workspace capabilities

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

* docs: correct and tighten comments on the session capability filter

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

* fix: gate session deploy tools on DisableDirectDeployment and the pipeline prompt

* fix: gate create_folder on the deploy capability

* refactor: assemble session prompt and tools through one seam

* docs: state the capability filter as best-effort, not a guarantee

* refactor: take the whole deploy gate from the shared preflight

`checkDeployPermission` now evaluates `DisableDirectDeployment` and folds superadmin
into the admin bypass itself, so the resolver's local composition of those two terms
is redundant. Delegate outright and drop the protection-rule fetch it needed, along
with the two tests that restated rule semantics the preflight's own suite now pins.

The preflight's per-kind narrowing stays unused: the filter runs on tool names, before
the model has named a kind, so a direct-deployment lock withholds the deploy tools for
schedules and triggers too.

* fix: address review findings on the session capability filter

Six findings from the Claude and Codex review rounds.

- `discard_local_draft` is ungated. The backend exempts discarding your OWN draft
  from `require_can_write_path` precisely so drafts stay cleanable after a role
  change; gating it stranded that cleanup.
- `deploy` splits into `deploy` and `deploy_gated_kinds`, mirroring
  `deployPermissionForKind`. A direct-deployment lock stops only the kinds that
  reach `check_deploy_rules`, so schedules and triggers stay deployable and the
  two kind-taking deploy tools survive the lock; `create_folder` does not, folder
  being a gated kind. The prompt now names the lock and what it leaves deployable,
  instead of implying nothing can be deployed.
- `COVERED_ENDPOINTS` keyed `createApp` / `updateApp`, which the MCP catalog does
  not expose; the app-authoring endpoints it does expose, `createAppRawSource` and
  `updateAppRawSource`, were uncovered and reachable through `call_api_endpoint`.
- The YOLO tooltip listed tools a restricted session never ships. Both it and the
  token estimate now read one `shippedTools`, and `sessionAccess` is reactive so
  the UI follows the resolution.

* fix: restore the covered API-catalog names for the raw-app endpoints

`COVERED_ENDPOINTS` is matched against `EndpointTool.name`, which openapi.yaml
overrides with `x-mcp-tool-name` for these two operations: `createAppRawSource`
and `updateAppRawSource` are served as `createApp` and `updateApp`
(`mcp/auto_generated_endpoints.rs`). Keying them by operationId left both raw-app
POST endpoints discoverable and callable through the API catalog tools. Restore
the exposed names and record why they differ from the operationIds.

* docs: state each capability invariant once, and document the draft discard

The asymmetric admin/operator precedence was restated three times in
sessionAccess.ts and again in its test, the fail-open rationale twice, and the
deploy split across four sites. Each now lives at the one place someone would
break it, within the four-line budget, with the other sites pointing at it.

Ungating discard_local_draft left it undocumented for the read-only profile,
which is the profile the backend exemption exists for: the only bullet naming it
sits under the draft-writing gate, beneath an opener saying no change is
possible. Add the one line that profile needs.

* docs: record why the session tool filter runs unconditionally

The filter would strip everything from a non-GLOBAL toolset, whose names carry no
policy entries. That cannot happen — `changeMode` refuses to move a session chat
out of GLOBAL, and `sessionAccess` is only ever set for session chats — but the
dependency was not visible at the filter itself.

* fix: match the server's deploy gate exactly, never exceed it

The filter must be as strict as the server and no stricter. Schedules and triggers
reach no deploy rule — `check_deploy_rules` runs only from the gated kinds' handlers
— so no workspace refuses `deploy_workspace_item` or `delete_workspace_item`
outright, whatever refusal `checkDeployPermission` reports. Gating them on a deploy
capability withheld operations the server performs.

Neither tool now requires a capability. Deploying still needs a draft to deploy, so
it keeps the authoring relevance; deleting a deployed item does not, so it is
ungated. `deploy` returns to one capability, covering the kinds the rules gate, and
`create_folder` — whose kind is one of them — is the only tool that names it. The
session-state note now states which kinds a refusing workspace still accepts.

* feat: gate the new app-runnable preview tool on run_preview

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* fix: fail open when whoami resolves without a role

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* fix: count plan-mode tools in the shipped toolset

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* docs: drop the dead capability assertion and the repeated deploy rationale

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* refactor: drop dead code and a duplicated invariant from the session filter

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* refactor: reduce SessionAccess to the capability set it is read for

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* refactor: gate session tools on permission alone, never on relevance

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* test: pin the filter to the outbound request and widen the description sweep

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* refactor: collapse SessionAccess to a capability set and merge adjacent gates

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* fix: gate get_db_schema on run_preview, it runs a query script

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* fix: reuse the cached workspace role and derive the exhaustiveness list from assembly

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* revert: keep tool names in descriptions that ship with them

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* fix: let an admin who is also an operator deploy, as the server does

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* fix: derive the deploy capability from the protection rules alone

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* fix: stop the datatable instructions naming a tool a session may not have

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* fix: keep the prompt and tool results honest for a profile that cannot draft

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* refactor: move tool policies onto the tools and gate kinds per handler

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* chore: tighten stale comments and name deploy in the operator prompt

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* fix: keep the assembled tool list raw so narrowing can clone its defs

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* fix: point an operator at a workspace admin for code the role refuses

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* fix: resolve session permissions when the assistant settings modal opens

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH

* refactor: return per-chat tool schemas instead of writing them to shared tools

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

* fix: forward this through the eval tool wrapper so tools see their sent def

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

* test: pin identity and contents in the session filter and schema tests

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

* docs: note why the overhead estimate skips per-chat tool schemas

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-23 18:59:54 +02:00
GuilhemandClaude Opus 5.5 0e53d53b07 fix: space chat rows evenly after thinking and answers (#11315)
* fix: space chat rows evenly after thinking and answers

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

* fix: keep a flow step's answer actions and space its step label

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

* fix: pick the answer that shows actions from later answers, not the next row

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

* fix: group answer actions by the step run's job, not its label

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

* docs: state the per-run action row rule in AssistantMessage comments

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 17:37:57 +02:00
GuilhemandClaude Opus 5.5 62d0088de5 feat: show restart from failed step in run page top bar (#11317)
* feat: show restart from failed step in run page top bar

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

* fix: keep failed-step restart button when selection is not restartable

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

* feat: add restart link to the failed run status line

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

* fix: use the input error color for the progress bar error state

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

* feat: mention restarting on a fixed flow version in the error line

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

* feat: show a chevron on the restart button when it opens a picker

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

* fix: shrink run page top bar buttons so the bar fits on one line

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

* fix: target the step that failed the run, not a tolerated failure

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

* fix: address review nits on the restart link

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

* fix: skip canceled runs and match the restart link label to its text

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 17:37:41 +02:00
Diego ImbertandClaude Opus 5.5 5b03c1732e fix: build ag grid link cells as DOM nodes with a vetted href (#11316)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 17:36:47 +02:00
ceb17223dc fix: bill from a single service account telemetry count (#11301)
* [ee] fix: bill from a single service account telemetry count

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* [ee] fix: count service accounts held in forks

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore: update ee-repo-ref to ed5a367b4def5280c3a5e1090e7abfa099a01042

This commit updates the EE repository reference after PR #824 was merged in windmill-ee-private.

Previous ee-repo-ref: bc1fe61364c2a731ec26186eb04596254886a74c

New ee-repo-ref: ed5a367b4def5280c3a5e1090e7abfa099a01042

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-09-23 14:36:23 +00:00
Ruben FiszelandClaude Opus 5.5 7593597617 fix: validate app and trigger paths, refuse traversal in workspace export (#11311)
* fix: enforce proper_id paths on apps and triggers, refuse traversal in export

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

* fix: skip proper_id on tables already holding non-conforming paths

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

* test: pin archive entry path traversal guard

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

* fix: refuse windows-normalized traversal in export, check raw app path early

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

* fix: only treat a colon in the first archive segment as a drive prefix

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

* test: accept a colon past the first archive segment

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

* revert: drop proper_id migration, keep path validation in the API

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

* fix: validate paths in bulk http trigger creation

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 15:50:32 +02:00
GuilhemandClaude Opus 5.5 1de54eeea4 feat(ai-chat): show native script edit diffs (#11278)
* feat(ai-chat): show native script edit diffs

* fix: render streamed edit diffs

* fix: render in-editor script edit diffs

* style: soften diff context separators

* fix: render full script update diffs

* fix: support empty script diffs

* fix: bound streamed tool diffs

* fix: preserve trailing diff context

* fix: defer collapsed tool diffs

* fix: retain full-code streaming previews

* fix: preserve created script diffs

* fix: disambiguate collapsed diff keys

* fix: render final newline diffs

* fix: preserve multiline diff highlighting

* fix: highlight diff sides as complete sources

* fix: bound completed tool diffs

* fix: diff large completed tool edits

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

* fix: bound tool diff rendering

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

* fix: bound tool diff highlighting and expand omitted rows

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

* fix: reveal omitted diff rows in chunks and bound long-line highlighting

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

* fix: collapse written scripts, skip empty diff bodies and fit line numbers

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

* fix: keep whole-file tool diffs collapsed while running

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

* fix: classify whole-file tool calls by argument shape

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

* fix: reopen failed diff cards and keep empty streamed replacements

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 15:44:40 +02:00