* fix: keep raw-app files within their app folder on sync pull
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix: validate raw-app file keys as stored, closing nul and duplicate-field bypasses
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix: guard raw-app runnable ids too and fail closed on unparseable value
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix: strip only a leading slash on raw-app file keys to match backend
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix: strip only a leading slash on raw-app file keys to match backend
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
* test: assert the unpacked repo symlink without following it
`unpack_keeps_a_link_that_stays_in_the_repo` read through the link it had just
unpacked. Windows stores a symlink's target verbatim and its object manager
rejects the `/` in a POSIX one, so `read_to_string` came back with
`ERROR_INVALID_NAME` and the release's `cargo_test_windows` job was red.
Pin what the function is responsible for on every platform — the link is kept
and materialized — and read through it only where a POSIX relative target
resolves.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P3WRtxdKNGdomWX9vaAYGx
* test: key the cli sync-map fixtures with the platform separator
A sync map is keyed with the platform separator on both sides — `FSFSElement`
walks the tree with `path.join`, and the remote `ZipFSElement` starts at
`"." + SEP` and joins from there — while an `!inline` reference is always
forward-slash. `lock_dedup.ts` follows that convention; the fixtures did not,
so on Windows they built a map shape the CLI never produces and 12 of them
failed. `getTypeStrFromPath` is the same story: it matches
`"dependencies" + SEP`, and the test handed it a forward-slashed path.
Build the fixture keys through the separator, leaving the `!inline` references
and the `present` map forward-slash, as `sync.ts` hands them over.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P3WRtxdKNGdomWX9vaAYGx
* ci: skip the discord comment relay when the thread lookup returns none
A rate-limited or unauthorized Discord response carries no thread list, and
under `bash -e` that aborted the step — jq cannot iterate null, nor parse the
HTML error page Cloudflare answers a 429 with — before it reached the "thread
not found, skipping" branch right below. Three comment relays failed that way
on the 1.794.0 head.
Keep the step green for both, but tell them apart: a response with no thread
list is a delivery that was dropped for a reason worth seeing, so it warns with
the body it got, while a PR that genuinely has no thread stays quiet.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P3WRtxdKNGdomWX9vaAYGx
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: support application default credentials for gcp pub/sub triggers
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: address review findings on gcp application default credentials
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: address review nits on gcp application default credentials
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: key the gcp credential-mode permission off the loaded mode
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: gate enabling an ADC gcp trigger on workspace admin
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: lock the gcp trigger row while authorizing a mode change
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix: skip admin-only gcp listing when the caller cannot use those credentials
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* chore: update ee-repo-ref to 54bf630681000c8ed87a7067e357118e015123b1
This commit updates the EE repository reference after PR #738 was merged in windmill-ee-private.
Previous ee-repo-ref: 91d0e228a0ad226625278b400c64f96a61404a10
New ee-repo-ref: 54bf630681000c8ed87a7067e357118e015123b1
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>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
* feat(cli): deduplicate identical script lockfiles into one per language
* test: pin shared lockfile path classification
* fix(cli): never delete a lockfile the dedup plan also writes
* fix(cli): plan lockfile dedup from the whole tree, not the sync scope
* fix(cli): keep dedup out of dry runs and stop hiding scripts from its scan
* test: pin which files the shared-lock scan counts as readers
* fix(cli): validate shared-lock refs and let the majority keep its file
* fix(cli): snapshot shared-lock ownership before regeneration moves it
* fix(cli): address dedup review nits (dry-run push, json shape, scan scope)
* refactor(cli): put shared lockfiles in a top-level locks/ directory
* fix(cli): claim only the shared lock names windmill writes, and only when on
* fix(cli): read the lock field itself, and count only scripts sync reads
* fix(cli): parse metadata by its real format and lint from the sync root
* fix(cli): never re-hash a script whose generation failed
* fix(cli): share sync's walk exclusions and fail closed on unreadable dirs
* fix(cli): keep a lockfile the metadata on disk still references
* fix(cli): decide a lock is unread from the metadata field sync reads
* refactor(cli): name shared lockfiles after the dependency file they resolve
* fix(cli): carry shared lockfiles a narrowed sync cannot speak for
* fix(cli): move a shared lockfile when its dependency file moved, not on a head count
* fix(cli): let the many correct a shared lockfile a lone variant planted
* fix(cli): read why a lock differs from the stamp the worker writes into it
* fix(cli): let an agreeing majority speak whatever the stamps say
* docs(cli): count the disjuncts the comment introduces
* fix(cli): keep a private lock for any script the worker locks differently
* fix(cli): match annotations by the worker's own names, not by shape
* fix(cli): recognize the py: interpreter pin the macro does not cover
* fix(cli): let the map speak for dependency-file deletions
* perf(cli): group lock entries without rebuilding the group per insert
* fix(cli): defer shared-lock deletions until the metadata has settled
* fix(cli): decide shared-lock readers by the lock field, failing closed
* fix(cli): read folded lock refs and keep locks read by unparseable metadata
* refactor(cli): one shared-lock reader scan, shared by the pull and push paths
* fix(cli): keep nested dependency set names out of shared lockfiles
* fix(cli): drop a shared-lock scan gate that no real repo took
* feat: teach the AI the raw-app job bindings and the draft/deployed split
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: scope the raw-app deploy advice to the referenced item, and stop kind-conversion from stranding fields
The draft/deployed guidance added in the previous commit was read as "deploy the
app too": the agent asked for both the flow and the app and routed a one-item
dependency through the review-and-deploy page. Only the referenced flow or
script has to exist deployed — the preview runs the app's draft — so the prompts,
the `write_app_runnable` warning and the testing rule now say to offer that one
deploy and leave the app a draft.
`buildPersistedRunnable` spread the existing runnable when rewriting it, so
converting a path runnable to inline left `runType`/`path` behind (and the
reverse left `inlineScript`). `isRunnableByName` matches the inline branch
first, so an app "wired to a flow" silently ran stale inline code.
`test_run_app_runnable` now fills ctx-bound inputs with `$ctx:<prop>` the way
RawAppBackgroundRunner does, so a ctx argument no longer arrives missing.
The SDK-reference rationale claimed WM_TOKEN may be unset, that a missing base
URL falls back to localhost, and that a job token is scoped enough to 403 a
hand-rolled REST call. None of the three is true, and it shipped to every
write-script prompt; the text now only says the client configures itself.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: address review round on the raw-app AI instructions
The eval case could pass on the exact answer it exists to reject. Every
`requiredMentionsAnyOf` alternative but one was flow-agnostic, so "the app must
be deployed" satisfied "must be deployed". All alternatives now name the flow,
and a unit test pins that the app-only phrasing fails.
`instanceLine` asserted "self-hosted Community Edition" outside the browser,
where `isCloudHosted()` reads false and the license store is unset — so every
global eval was told that regardless of what it pointed at. It is now emitted
only under BROWSER.
`assistantExpect.forbiddenMentions` defaulted a missing `assistantText` to "",
which passes every entry forever on a mode whose runner does not report it.
It now fails with that as the reason.
`buildPersistedRunnable` carried `schema` across a retarget, so a path runnable
pointed at a new flow kept the previous item's schema and `genWmillTs` typed
`backend.<key>(args)` from the wrong inputs. It survives only while kind and
path both match.
The SDK header claimed "a function that is not listed below does not exist".
`windmill-client` also exports the generated services, and the Python client
exposes `Windmill.get`/`.post`, so an endpoint without a helper had no legal
move. Each language now names its own escape hatch.
`getAppInstructions` said the attached reference carries the TypeScript SDK even
when `language: "python3"` had swapped in the Python one — on the very sentence
telling the model to make that call.
The kind-conversion comment claimed a hybrid runnable "silently runs stale
inline code". It does not: `isRunnableByName`, `isRunnableByPath`,
`convertPersistedToBackendRunnable` and `rawAppPolicy.processRunnable` all
dispatch on `type` alone. The leftovers contradict the runnable's kind rather
than override it, which is what the comment now says.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: address round-2 review nits on the raw-app AI instructions
`flow is deployed` was satisfied both by "once the flow is deployed, the button
works" and by a hallucinated "done — the flow is deployed", which eval mode makes
impossible and the drafts-only judge cannot see. Every alternative now states an
outstanding obligation, and two more real phrasings ("will need to be deployed")
are accepted so a correct answer is not failed on wording.
Condenses the three comment blocks that ran past the four-line limit in
AGENTS.md, and drops two claims inside them that no longer hold: the
`testRunAppRunnable` doc said it runs a runnable the way the app's own frontend
does (it is the editor preview, which a deployed app's stored policy does not
match), and `undeployedRunnableTargets` described its argument as the write
tool's raw input when the call site passes the persisted runnable.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: report the real cause when a test run fails, and label the app-runnable card
Driving `test_run_app_runnable` in a live session surfaced two defects the
API-level check could not see.
`executeTestRun` built its failure message from `error.message`, which the
generated client leaves as the bare status text while the server's message sits
in `body`. A path runnable aimed at an undeployed flow reported "Not Found"
instead of "Not found: flow not found at name u/admin/current_time" — dropping
the one diagnostic the run exists to produce. `formatToolError`, in the same
file and written for exactly this, now does it. This also applies to
test_run_script and test_run_flow, which had the same loss.
The completion card read "Flow test completed successfully" for an app runnable,
because `contextName` doubles as the jobs-tray kind and a path runnable pointing
at a flow really does queue a flow job. A `completionName` override now names
what ran without changing the kind.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test: pin the deploy expectation against wrong answers, not just correct ones
`deploying the flow` was satisfied by "done deploying the flow" — a deploy the
agent only claims to have made, which eval mode makes impossible and the
drafts-only judge cannot see. Replaced with the prospective forms, and dropped
the same reading from the workflow variant.
Three review rounds each found this same class of hole in the phrasing list, so
the list is now exercised against the wrong answers themselves rather than
eyeballed: naming the app as what needs deploying, claiming the deploy is
already done, claiming to have deployed the flow, and saying nothing about
deploying all have to fail, while four real correct phrasings have to pass. The
test reads the case out of global.yaml, so a future edit to the alternatives is
checked by it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test: drop the tense-neutral deploy alternatives and cover completed claims
A gerund after a preposition carries no tense, so `before`/`after`/`by deploying
the flow` all match a deploy the agent only claims to have made ("after
deploying the flow, I clicked the button and it returns the greeting") just as
the bare gerund did. All three are gone rather than swapped for whichever reads
least badly, and the two completed-deploy phrasings are now negative fixtures.
The remaining alternatives are imperative or obligational, which a claim of
having already deployed cannot satisfy.
Condenses the two comments this list carries: the YAML block to four lines, and
the test's rationale to the durable constraint about substring matching.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: encrypt sensitive inputs when test-running an app runnable
`test_run_app_runnable` sent `force_viewer_static_fields` but not
`force_viewer_sensitive_inputs`, which every other preview path derives from
the runnable's `sensitive` user fields. That list is the only thing driving the
encryption loop in apps.rs, so testing a runnable with a sensitive input wrote
the real value into the job's args in plaintext, readable by anyone with run
access to the workspace.
Verified against a running EE instance. With the list, `api_key` is stored as
`$encrypted:mvqtSRI9…` and the sentinel appears nowhere in the job record;
without it, the sentinel is readable in run details. A non-sensitive field is
left plaintext either way.
The tool claims parity with the editor preview, so it uses that same filter
(`type == 'user' && sensitive`) and omits the field entirely when empty.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
* fix: reject invalid AI agent tool names when the chat writes a flow
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: address review nits on agent tool name validation
Share one AI-agent walk between the providerless-agent and invalid-tool-name
collectors, drop the unused validateToolName, and list every reserved id in the
tool naming rules.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: describe an agent tool's summary as the name the agent calls it by
The OpenFlow schema described `AgentTool.summary` as a short description of
the tool, which is the same schema the flow write tools hand the model, so it
pulled against the naming rules. Narrow those rules to flowmodule tools, since
websearch and mcp tool names are never regex-checked, and let `kind` take
either vocabulary its callers resolve.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: name-check only the agent tools whose summary the agent calls
An mcp tool exposes the MCP server's own tool names and a websearch tool's
summary is a plain label, so neither reaches the worker's name check. Both
default to an empty summary in the editor, which the chat then refused to
write back.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(cli): keep script retention, debounce and cache settings on push
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(cli): surface the create response when the fixture fails
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(cli): drop debounce settings the CI build refuses to accept
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* repair the script push up-to-date comparison (#10743)
* test: settle the backlog before the capped audit-export drain (#10737)
* test: settle the backlog before the capped audit-export drain
* chore: update ee-repo-ref to bd4de74eb37b32a2b6c7c69f6dedac031ef8436b
This commit updates the EE repository reference after PR #730 was merged in windmill-ee-private.
Previous ee-repo-ref: b5a5f9114df26088cfe976d91f10e55ba8bfcaa6
New ee-repo-ref: bd4de74eb37b32a2b6c7c69f6dedac031ef8436b
Automated by sync-ee-ref workflow.
---------
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
* fix(cli): repair the script push up-to-date comparison
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(cli): drain dependency jobs and pin a non-1 priority skip
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(cli): describe the priority fixture without the old comparison
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>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* refactor(cli): read cache_ignore_s3_path off the typed response
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(cli): stop redeploying bunnative scripts on every push
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
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: default an omitted app policy execution_mode to publisher
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs: drop stale comments claiming execution_mode is required
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: derive a raw app's policy on deploy instead of trusting the caller's
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: pin the ee ref to the companion branch
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: vendor the raw-app policy derivation into the bundle job
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs: note the vendored raw-app policy bundle
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: derive the policy on a value-only raw-source update too
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: reject raw-app runnables whose shape yields an unusable grant
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: cache the new policy query and tighten raw-app runnable validation
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: let the policy bundle drift guard survive a CRLF checkout
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to 23431f5cf1d627051ded89111bbf2e301e9db456
This commit updates the EE repository reference after PR #729 was merged in windmill-ee-private.
Previous ee-repo-ref: 0bdf8818fa115ad6b0d14f3117a18e8a580cce4d
New ee-repo-ref: 23431f5cf1d627051ded89111bbf2e301e9db456
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: add trigger_history table with source tracking
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: gate trigger history reads on scopes and harden its writers
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: filter trigger history scopes in SQL and match the cleared-handler diff
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: record a trigger restore from the trashbin in its history
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: record bulk http trigger creates and document the recording boundary
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: lock the trigger row when capturing its history preimage
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: only record an auto-disable that actually flipped the schedule
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: state the auto-disable invariant once instead of at four call sites
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: render trigger history changes as a structured field diff
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: make a server-initiated disable atomic with its history row
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs: note that the auto-disable savepoint takes no pool connection
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs: note the flow fallback is the last chance to disable
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: never leave a trigger enabled because its history row failed
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: retry the disable history row instead of dropping it on first failure
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: use the design-system Button for the change-value expander
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: hold the trigger row lock across its disable history row
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: keep the history-loss alert out of the listener cancellation race
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: read the history workspace through the trigger-workspace seam
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test: wait for the app dependency job before pulling in repro_diffname
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test: reuse waitForDeploymentJobs and assert pulled lock files
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test: condense the dependency-job wait comment
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(cli): route fileset children to their parent resource on sync push
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(cli): scope fileset pointer validation to sync pushes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(cli): error on script push of file/fileset resource content files
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(cli): enforce server-canonical fileset pointers and fail fast before apply
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(cli): resolve ws-specific fileset metadata and validate pointers before dry-run
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(cli): prefer workspace-specific fileset metadata over base file
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(cli): make fileset metadata lookup assertions platform-separator safe
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(cli): stop dropping fileset children whose names look like typed metadata
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(cli): exempt fileset children from the current-workspace classifier too
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(parser-py): keep first param when def main( line has trailing comment
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore: bump windmill-parser-wasm-py to 1.782.0
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(triggers): nested any_of / all_of filter groups
A trigger filter entry can now be a group — `{"any_of": [...]}` or
`{"all_of": [...]}` — nesting further entries, so criteria like
`A AND B AND (C OR D)` are expressible. Existing flat `{key, value}` lists keep
their meaning, combined by the trigger's `filter_logic` as before.
Filters are compiled once per connection: the set of top-level keys the whole
tree references is collected up front, so a message is parsed in a single
streaming pass that captures only those keys, instead of one full pass per leaf
filter as before. Filters that fail to parse are now logged rather than dropped
silently, since a nested group is easier to mistype than a flat entry.
The editor gains "Add group", rendering groups recursively with their own
AND/OR selector; Kafka and WebSocket triggers share it.
Fixes WIN-2345
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(triggers): drop empty filter groups instead of evaluating them
A group with no criterion cannot evaluate to a constant: true makes an `or`
filter list accept every message, false mutes an `and` list. Two clicks in the
editor ("Add group", save) produced one. Drop it when compiling so its siblings
stay in force, and reject at save time the filters the listener would otherwise
drop silently.
Also restore the item shape of `$ref`-typed arrays in the generated agent
schemas: the extractor only resolved refs at the property level, so moving
`filters.items` to a shared schema flattened it to a bare object. Resolving them
inside `items` too also recovers the shapes `initial_messages` and the MQTT
`topics` had already lost.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(triggers): name the offending entry when a nested filter is invalid
Serde's untagged error only reports that the outermost entry matched no
variant, whatever depth is actually wrong, which defeats the point of
validating a group at save time. Walk the tree instead and report the path.
Normalize the WebSocket editor's filters to [] on load, as the Kafka editor
does, so the list component can rely on an array.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(triggers): key filter rows by node so deletion keeps values aligned
The value editor seeds itself from `code` once, so an index-keyed row reused
for a different filter kept showing the deleted row's value.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: bump ee-repo-ref after merging main
The merge pulled OSS code that needs EE symbols newer than the companion
branch's base, so the companion was merged with EE main too.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* perf(triggers): keep filter short-circuiting from materializing unread fields
The single-pass scan deserialized every referenced key before the boolean tree
ran, so an AND whose first leaf rejects the message still allocated the large
objects the later leaves name — the shape this feature exists for. Borrow the
wanted keys as raw slices during the scan and parse a field only when
evaluation actually reaches it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(triggers): none_of filter group
Negation of a nested group, so a trigger can exclude what it must not react to
without inverting every other criterion. A key the message does not carry
satisfies it: there is nothing there to match.
Only groups can negate — the root's operator is the trigger's filter_logic
column, which has no value for it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(triggers): address a nested field with a dotted path
`{path: "a.b.c", value: v}` alongside the existing `{key, value}`, so the common
case reads the way people write it instead of nesting the shape into the value.
A separate field rather than dots in `key`, which already means the top-level
field spelled that way — overloading it would resettle what existing triggers
over flattened payloads match.
Paths address objects only for now: a path through an array does not match
rather than guessing an element, and array containment stays on the value side.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(triggers): mention none_of in the filter_logic description
Plus a test for the empty-path-segment rejection, which had none.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to 78859aab0c6e78283ec8d2b37e8c410963afdc83
This commit updates the EE repository reference after PR #722 was merged in windmill-ee-private.
Previous ee-repo-ref: 0e42ba72ccc38a6b0a380f58afe0db36d284f4c9
New ee-repo-ref: 78859aab0c6e78283ec8d2b37e8c410963afdc83
Automated by sync-ee-ref workflow.
* fix(triggers): reject a criterion naming both key and path
The untagged enum takes such an entry as a `key` criterion and drops the
`path`, which is the silent-ignore the save-time validation exists to prevent.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* refactor(triggers): drop the label next to the key/path toggle
The toggle already shows which one is selected.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(triggers): reject an entry that combines a criterion with a group
Generalizes the key+path fix: the untagged enum settles a half-and-half entry
on the first variant that fits and ignores the rest, so a criterion carrying a
group key lost the whole subtree without a word.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
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(sdk): add cancelJob to the TypeScript client
The Python client has had cancel_job since forever; the TypeScript one had no
way to cancel a job at all. Wire the same jobs_u/queue/cancel endpoint, with a
default reason when none is given, and export it from both the named and
default exports of the npm package as well as the JSR one.
* chore: regenerate system prompts for cancelJob
check-system-prompts triggers on typescript-client/**, so the agent-facing SDK
reference has to carry the new function.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Tushar <tusharanshu18@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(cli): attach the right job path to preview runs
* fix(cli): keep a deliberately-absent file in the directory it was named in
* fix(cli): resolve links for a path naming a file that is not there
* fix(cli): sync package-lock.json with package.json
`npm ci` fails in cli/ because the lockfile predates two manifest changes:
windmill-parser-wasm-yaml was bumped to 1.770.0 and windmill-yaml-validator
1.1.1 was added, neither of which reached the lockfile.
Regenerated with `npm install --package-lock-only`; the only entries touched
are those two packages and windmill-yaml-validator's transitive deps.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(cli): drop the unread npm lockfile, bun.lock is the CLI's
Every install path in cli/ runs `bun install`: cli-tests.yml, git-sync-test.yml,
backend-test.yml, build.sh, and install_dev.sh (its --node branch installs the
generated npm/ bundle, which carries its own manifest). build-npm.ts synthesises
the published package.json from scratch, and change-versions.sh regenerates the
frontend and yaml-validator lockfiles but not this one.
So package-lock.json was read by nothing and verified by nothing, and drifted out
of sync with package.json unnoticed until `npm ci` refused to install. Deleting it
removes the second source of truth rather than hand-repairing it again on the next
bun-driven dependency change.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: allow custom dev workspace environment labels
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: reject dev labels that shadow a tracked branch's namespace
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: guard dev labels against a repo's assumed default branch
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore: state the badge-cap rationale once and drop unenforceable openapi constraints
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* refactor: offer a fixed list of environment labels instead of free text
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: match the accepted label set to the openapi enum exactly
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs: stop describing the label set as dev/staging only
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: deploy a raw app from its sources, bundling them on a worker
* refactor: bundle raw app sources with the wmill CLI instead of a second bundler
* fix: address review findings on the raw app source deploy
* fix: bound bundle decompression, drop the npm dependency on slim workers
* fix: stop minting jobs:run for the source deploy, share the decode budget
* feat: let an MCP token grant the scopes its selected tools require
* fix: carry a caller-held extra scope through the MCP proxy
* fix: confine the run scope to the proxied request instead of the token
* fix: mint the run scope only for a token that names the tool
* fix: require write access before compiling, and state the grant where it is granted
* fix: let the database decide write access instead of restating its policies
* fix: answer a write denial with 403, not 401