Commit Graph

13116 Commits

Author SHA1 Message Date
Guilhem Lemouel 85218dae5b feat(chat): add ask_user_question tool for structured disambiguation
A global-mode tool that pauses execution and lets the AI ask the user
a multiple-choice question (2–4 mutually-exclusive options). Pure
frontend, mirrors the existing tool-confirmation flow:

- shared.ts: ToolPendingQuestion type; pendingQuestion + answeredValue
  fields on ToolDisplayMessage; requestAnswer callback on ToolCallbacks.
- AIChatManager: answerCallback + requestAnswer / handleToolAnswer pair.
  Resolves with the picked option's value, or '' on cancel. Cancel sweep
  clears the callback alongside the existing confirmation cleanup.
- ToolExecutionDisplay: when pendingQuestion is set, the card auto-
  expands and replaces its body with the question text + one button per
  option. Clicking an option calls aiChatManager.handleToolAnswer.
- global/core.ts: askUserQuestionSchema and the tool entry in
  globalTools. Returns the picked option's value verbatim to the model,
  or '(user cancelled the question)' if the user cancelled.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 16:16:23 +02:00
Ruben Fiszel 33bf01b627 fix(python): preserve strings containing Infinity/NaN in result JSON (#9149)
* fix(python): preserve strings containing Infinity/NaN in result JSON

* test(python): add sanity checks for Infinity/NaN in results

* refactor(python): use string-aware regex callback for single-pass cleanup

* refactor(python): compact regex + handle backslash-escape parity

* perf(python): short-circuit cleanup when no Infinity/NaN/NUL in result
2026-05-13 15:49:36 +00:00
Ruben Fiszel d666e8431c feat: read-only flag on API tokens (#9144)
* feat: read-only flag on API tokens, orthogonal to scopes

Add a per-token `read_only` boolean set at creation time. When true, the
token can only call HTTP methods classified as Read (GET/HEAD/OPTIONS).
Mutating methods and job-run actions are rejected with 403, regardless of
which scopes are attached. Surfaced as a prominent toggle in the standard
token-creation flow and a discreet `2xs` toggle in MCP mode (where users
often want write access, so we don't bias them toward enabling it).

MCP enforcement: read-only tokens hide all script/flow/hub tools from
`list_tools` and only see endpoint tools whose method is GET, and the
runner rejects `call_tool` on anything mutating.

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

* fix: review fixes for read-only token flag

- Exempt /api/mcp/* and /mcp/* paths from the read-only middleware check.
  MCP transport runs over POST (streamable HTTP / SSE), so otherwise the
  middleware would 403 every MCP request before the runner could enforce
  read-only at the tool-call level.
- Tighten is_endpoint_read_only to GET only, matching the read_only_hint
  that create_endpoint_annotations actually emits.
- Add unit test for check_read_only_for_route covering GET/HEAD/OPTIONS,
  mutating methods, and run paths.

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

* chore: bump ee-repo-ref to read-only-trigger-toggle

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

* fix(frontend): make read-only toggle discreet in both modes

Match the MCP-mode treatment in standard mode: text-tertiary, 2xs, shared
"Read-only" label. The tooltip switches per mode so the explanation still
fits the context.

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

* fix(frontend): gate read-only toggle behind Limit token permissions

The read-only toggle now only shows when the user has limited the token's
scopes (standard mode) or in MCP mode (which always picks an MCP scope).
Turning the limit off also resets read-only so it doesn't silently stick.

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

* feat(frontend): hide incompatible MCP tools when read-only is on

When the read-only toggle is on in MCP mode:
- Endpoint badges and the custom-mode endpoint MultiSelect filter to GET.
- Already-selected non-GET endpoints are pruned from the scope.
- The scripts/flows preview is replaced with a note explaining they're
  hidden (the runner already rejects script/flow runs for read-only).

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

* fix(frontend): place read-only toggle at top of limited scope area

The previous gate required at least one scope to be picked before the
read-only toggle appeared, which made it look missing while the user was
still building their scope list. Move the toggle inside ScopesPicker:
- Standard mode: sits directly under the "Limit token permissions" toggle
  whenever Limit is on, before the scope selector.
- MCP mode: sits at the top of the MCP scope block.

readOnly is now $bindable on ScopesPicker so CreateToken still owns the
value. The auto-reset on un-limit moves into ScopesPicker too.

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

* fix(frontend): nest read-only toggle inside the scope list card

Place the read-only toggle at the top of the scope list (between the
Selected Scopes summary and the bordered domain list) via a new optional
topSlot snippet on ScopeSelector. Keeps ScopeSelector decoupled from
read-only specifics; ScopesPicker fills the slot.

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

* chore: update ee-repo-ref to 9bc8160be50b3e57a60daf4e1b71c389a6e02b8a

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

Previous ee-repo-ref: f53d26e6685dfd60bfa67686fbd7358169cfd130

New ee-repo-ref: 9bc8160be50b3e57a60daf4e1b71c389a6e02b8a

Automated by sync-ee-ref workflow.

* fix: address CI review for read-only token flag

- P1 (Codex): narrow the MCP middleware exemption from "any /api/mcp/*"
  to just the streamable HTTP transport endpoints
  (/api/mcp/gateway, /api/mcp/w/{ws}/{mcp,sse,list_tools}). Without this,
  a read-only token could POST /api/mcp/gateway/oauth/server/approve and
  mint a follow-on non-read-only MCP token via the OAuth code/token
  exchange.
- P2 (Claude/cubic): fix test comment/assertion mismatch — the run-path
  assertion now exercises GET (which is what the RUN_PATH_ACTIONS
  elevation comment describes) in addition to POST. Add a regression
  assertion for /api/mcp/gateway/oauth/server/approve.
- P2 (cubic): short-circuit script/flow/hub-script/resource fetches in
  MCP list_tools when read_only is on — they would only be discarded
  below, so skipping the DB and resource fan-out is pure win.
- P2 (cubic): when scopes are pre-supplied via the CreateToken prop, the
  ScopesPicker isn't rendered, which previously hid the read-only
  toggle entirely. Render it next to the pre-supplied scopes display.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-05-13 15:26:21 +00:00
windmill-internal-app[bot] 110bef0a6e fix: Allow devops role to use all_workspaces runs filter in admins workspace (#9153)
Co-authored-by: windmill-internal-app[bot] <1429786+windmill-internal-app[bot]@users.noreply.github.com>
2026-05-13 15:12:11 +00:00
Ruben Fiszel c5092069cb fix: align script path existence check with deploy logic; hide Delete for non-admin (#9152)
- exists_script_by_path now filters archived = false, matching the
  conflict check in create_script_internal. Previously the frontend
  blocked creating a new script at a path occupied only by archived
  scripts, even though renaming to that same path was allowed.
- Hide the Delete entry in the script details "..." menu unless the
  user is admin. The backend delete_script_by_hash already requires
  admin, so non-admins would always see an error after clicking.
2026-05-13 15:05:25 +00:00
Ruben Fiszel dd19e52a84 perf(dynselect): only retrigger when helper args actually change (#9148)
* perf(dynselect): only retrigger when helper-script args actually change

Parse the inline helper's signature with the existing WASM parser and
restrict the form-arg diff to keys the helper actually consumes. Typing
into unrelated fields no longer queues a dynselect job every second.
Falls back to the previous full-args comparison when the helper is
deployed or parsing fails.

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

* fix(dynselect): avoid double helper-script fetch on mount

usePromise defaults to loadInit=true, so refresh() ran before the
JobLoader child was bound (firing a no-op pending promise) and the
$effect then fired a second refresh once the bind:this resolved.
Disable loadInit so the effect owns the single first call.

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

* refactor(dynselect): use parser directly instead of inferArgs

inferArgs mutates a Schema object we never use and goes through a
shared cache; when fed an empty schema for non-main entrypoints the
caller cannot reliably read back the resulting properties. Add
parseEntrypointArgs that just runs the parser and returns the
parameter name Set (or undefined when unknown / unsupported / has
rest args / function not found). DynamicInput uses that and keeps
the previous params in flight while the next parse is computing.

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

* feat(dynselect): support deployed helpers in smart retrigger

Add getHelperEntrypointArgs which dispatches on HelperScript.source:
inline parses immediately; deployed fetches the script (or the flow's
inline dyn-select code) once and caches per (workspace, kind, path,
entrypoint). Without this the /scripts/get/* run view fell back to
the full-args comparison and still retriggered on unrelated fields.

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

* fix(dynselect): zero-arg helpers report empty deps, not unknown

Codex review flagged that a valid zero-parameter entrypoint was being
treated as "couldn't determine signature" and falling back to the
full-args comparison. Distinguish "function found with no params" from
"function not found" via the parser's auto_kind field — only the
latter sets it, so empty args + auto_kind=null means a real zero-arg
helper and we return an empty Set (no retrigger on unrelated fields).

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 14:58:35 +00:00
Ruben Fiszel 4d0f2c26a1 fix(bun): pass --preserve-symlinks on unbundled execution (#9147)
* fix(bun): pass --preserve-symlinks on unbundled execution

Bun 1.2/1.3 moved its global package cache to a content-addressed
layout and the installer now creates a single directory symlink from
node_modules/<pkg> to the cache entry. Without --preserve-symlinks,
Bun resolves modules from each file's realpath, so any require/import
inside an installed package walks up from cache_nomount/bun/... and
never finds the sibling deps living under <job_dir>/node_modules/.

This manifested as e.g.
  ENOENT while resolving package 'zod/v3' from
  '/tmp/windmill/cache_nomount/bun/@langchain/core@1.1.44@@@1/dist/...'
on //nobundling scripts that pull @langchain/core, even though zod is
correctly installed alongside it in node_modules.

The bundled execution path already had --preserve-symlinks since #4132
(needed because we symlink the cached bundle file into the job dir).
The unbundled path didn't, because at the time Bun installed via per-
file hardlinks and the realpath of node_modules entries was the job
dir itself. The Bun installer's layout change made the flag necessary
on the unbundled path as well.

Add the flag to all three unbundled `bun run` invocations:
- nsjail unbundled path
- non-nsjail unbundled path
- dedicated worker (always unbundled)

This also fixes a latent bug on the first run of any bun script that
imports a package whose internals reference siblings (the build_cache
path runs unbundled this round while it builds the bundle for next
time).

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

* test(bun): regression test for nobundling + transitive require resolution

Adds an integration test that mirrors the original failure: a //nobundling
script importing @langchain/core, which (in its CJS internals) does
require('zod/v3'). Before --preserve-symlinks was added to the unbundled
bun run invocations, this failed with:

  ENOENT while resolving package 'zod/v3' from
  '.../cache_nomount/bun/@langchain/core@<ver>@@@1/dist/runnables/base.js'

The test covers the non-nsjail unbundled path. Reproducibility of the
pre-fix failure depends on Bun's installer choosing the directory-symlink
layout for the node_modules entry (the default on Bun 1.2/1.3+ with the
new content-addressed global cache that produced the user's error).

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 13:04:31 +00:00
centdix d243e0cde8 align global flow tool arguments (#9146) 2026-05-13 12:38:49 +00:00
windmill-internal-app[bot] 818cb31fbc fix: send flow push-loop ping outside transaction so zombie monitor sees it (#9136)
* fix: send flow push-loop ping outside transaction so zombie monitor sees it

* fix: keep flow push-loop ping using now() with reusable sqlx cache

---------

Co-authored-by: windmill-internal-app[bot] <1429786+windmill-internal-app[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2026-05-13 12:32:35 +00:00
hugocasa 2ec1863340 fix: scope promotion-mode debounce key per repo (#9145)
* test(git-sync): regression tests for secondary promotion repos

Adds two integration tests that reproduce the bug where a second
promotion-mode repo's deployment callback was silently dropped via
debounce-key collision, plus the EE ref bump that includes the fix.

Updates the two existing promotion-mode debounce-key tests to expect
the new repo-namespaced key shape.

* test(git-sync): drop redundant distinct-debounce-keys test

The behavior test (`test_two_promotion_repos_both_enqueue_callback`)
already covers the same regression one layer up: if the debounce keys
collide, one callback gets marked skipped, which the behavior test
catches.

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

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

Previous ee-repo-ref: dbf26f5e4c01c0de536f606679be46eb316aaf31

New ee-repo-ref: 7a32388adaa37eb1dd1820b40e140ff1877110f2

Automated by sync-ee-ref workflow.

---------

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-05-13 11:35:30 +00:00
centdix 7a7d246a6e test: add global ai eval mode (#9129)
* feat: add global ai eval mode

* fix: improve global eval validation feedback
2026-05-13 08:20:30 +00:00
Ruben Fiszel b348119ab9 publish CLI skills + AGENTS.md to windmill-cli-docs for context7 (#9143)
* feat: publish CLI skills + AGENTS.md to windmill-cli-docs for context7

Auto-generates a public docs snapshot (AGENTS.md, full CLI reference,
all rendered skills) and pushes it to windmill-labs/windmill-cli-docs on
every release tag, so context7 can index Windmill CLI docs.

- generate.py: new --context7-dir flag rendering fully-resolved skills
  + AGENTS.md (extracted from cli/src/guidance/core.ts to avoid drift)
  + cli-commands.md + README.md + manifest.json into a docs-repo checkout.
  Preserves .git, .github, LICENSE, context7.json across regenerations.
- publish-cli-docs.yml: GitHub Action on v* tag and workflow_dispatch
  that regenerates the docs repo and pushes via the CLI_DOCS_DEPLOY_KEY
  SSH deploy key.

* fix: skip tag mirror on workflow_dispatch from non-tag ref

* docs: turn windmill-cli-docs README into a CLI quickstart

* fix: address PR review (target safety, regex anchor, concurrency, tag mirror)

- Refuse to wipe --context7-dir unless empty, has a context7 marker, or
  points at the windmill-cli-docs remote (P1, prevents typo blast).
- Anchor AGENTS.md template regex on `generateAgentsMdContent` so adding
  other template-returning functions to core.ts can't silently retarget it.
- Decode TS escapes in one pass to avoid order-sensitive mangling.
- Include Windmill version (from version.txt) in manifest.json so each
  snapshot is self-describing.
- Add concurrency group on the publish workflow.
- Always mirror version tag on tag pushes, even when content is unchanged,
  so the docs repo has a tag for every Windmill release.
- Expand preserve list with .gitignore, .gitattributes, CODEOWNERS.

* fix: validate manifest.json content, not just presence, before wipe
2026-05-13 07:11:24 +00:00
Ruben Fiszel 79c5b7b8b7 fix(cli): prevent !inline-corruption in flow push/pull (#9142)
* fix(cli): hard-fail flow push on missing inline files; guard extractor

* fix(cli): gate !inline extractor guard with opt-in flag

* test(cli): fix createFlowFixture !inline path to be relative to flow folder
2026-05-13 07:09:45 +00:00
Ruben Fiszel 7ebb08133c fix(operator): refresh IAM RDS / Entra ID tokens in operator process (#9141)
* fix(operator): refresh IAM RDS / Entra ID tokens in operator process

* fix: gate DEFAULT_MAX_CONNECTIONS_OPERATOR on operator feature
2026-05-13 06:38:57 +00:00
Guilhem d0f23cc523 feat(frontend): unified EditorHeader with file picker for flow/script/app editors (#9047)
* feat: add EditableInput component

* feat: add EditorHeader for flow editor with file picker entry point

* feat: WorkspaceItemPicker for editor header navigation

* feat: clickable breadcrumb in EditorHeader, scoped picker keyboard nav

* fix: reload flow on URL change and reset highlight in search mode

* feat: editor header layout polish and trigger removal

* feat: apply EditorHeader to script, app, and raw app editors

* fix: show generated initial path for new apps in EditorHeader

* fix: align EditorHeader new-app path with draft drawer's Path component

* fix: read page.params.path in loadApp to reload on URL change

* fix: remount AppEditor when navigating between apps

* fix: clear app/files on URL change so editor remounts with fresh data

* fix: route picker selections to /apps/edit or /apps_raw/edit based on raw_app

* fix: drop Save button from path popover; defer rename to deploy

* refactor: drop pathPopoverContent snippet, bind newEditedPath directly

* refactor: dedupe editor header plumbing (editPathFor, userPathPrefix, breadcrumb snippet)

* fix: freeze breadcrumb during path edit so popover doesn't drift

* fix: drop spinner from path dependency-check; render nothing when no usages

* fix: swallow 404 in checkFlowOnBehalfOf so renaming a flow doesn't toast

* Revert "fix: swallow 404 in checkFlowOnBehalfOf so renaming a flow doesn't toast"

This reverts commit 82dec462ae.

* refactor: drop moveRenameManager dep from EditorHeader; pass onBehalfOfEmail as prop

* refactor: replace breadcrumb-snapshot effect with open/close setter

* refactor: drop unused dirtyPath state from EditorHeader

* fix: surface Path validation error in pen popover

* fix: decouple Path validation error from hideFullPath toggle

* refactor: use InputError for path validation message (slide transition)

* fix: re-derive Path meta from external path changes (sibling sync)

* docs: note Path's meta could be replaced with function-form bindings

* fix: 'Exit & see details' uses deployed path, not live store

* fix: undo/redo shortcut uses shiftKey instead of fragile case-match

* fix: type errors and keep edit pen visible while popover is open

* chore: remove unused meltComponents/Accordion wrapper

* fix: focus search input on picker open via popover openFocus selector

* fix: refocus picker search input on every popover open

* fix: pre-seed picker loaded state from cache so accordion opens at the right place

* fix: breadcrumb and picker track savedPath, not draft-renamed live path

* fix: inject current draft item into picker so breadcrumb scope isn't empty

* docs: add component-level and prop-level docs to EditableInput

* feat: warn that a deploy is needed when path is edited on a saved item

* feat: show same path-change-needs-deploy message in flow/script settings

* fix(flows): persist draft-renamed path through reload and dirty check

* fix: include path in unsaved-changes diff so renames trigger the modal

* feat: nested folders in picker tree and breadcrumb

* fix: per-segment popover state so switching breadcrumbs closes the previous one

* refactor: replace accordion picker with drill-through picker

* refactor(picker): review fixes, drill polish, and breadcrumb collapse

* fix(picker): review fixes — banned bindable, drop sibling-sync, load races, mouse highlight

* fix(picker): smooth-scroll highlighted row into view on open

* fix(picker): second-pass review fixes — load races, cache invalidation, breadcrumb/picker a11y, raw_app routing

* fix(RowIcon): apply size prop to resource_type and fallback divs

* feat(picker): add cross-kind 'All' root; deeper breadcrumb segments open there

* fix(picker,editor): third-pass review — search loading state, pen autofocus, allow empty summary, a11y

* fix(picker,editor): fourth-pass review — own check, flowbuilder arrows, editableinput double-save, customui.path gate, invalidate races

* fix(editor,picker): codex review — fresh URL state per load, granular whitelabel topBar gates

* fix(flows): clear localStorage in auto-reload to break URL-state loop
2026-05-12 14:33:21 +00:00
centdix 17cf538a2d refactor: move ai providers to windmill-ai (#9120) 2026-05-12 14:09:31 +00:00
centdix a305a74e73 refactor: require ai evals proxy backend (#9119) 2026-05-12 13:44:00 +00:00
Ruben Fiszel c6346aabe0 chore(main): release 1.700.2 (#9117)
* chore(main): release 1.700.2

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.700.2
2026-05-12 12:32:07 +00:00
Ruben Fiszel cab0000f3a fix: preserve explicit nulls for typed fields in bulk instance config (#9123)
Setting a typed instance setting (e.g. `object_store_cache_config`) to
`null` via `PUT /api/settings/instance_config` was silently ignored:
`Json<InstanceConfig>` deserialized null to `None`, and `to_settings_map`
then dropped it via `skip_serializing_if = "Option::is_none"`, so
`diff_global_settings` (Merge mode) never saw the deletion.

Add `#[serde(remote = "Self")]` to `GlobalSettings` plus a manual
`Deserialize` impl that captures top-level explicit nulls into `extra`,
which already round-trips correctly via flatten. The handler stays
fully typed.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 12:07:45 +00:00
Ruben Fiszel 0bb77a9bd6 route result and args downloads through downloadViaClient (#9122)
* fix(frontend): route result and args downloads through downloadViaClient

* refactor(frontend): reuse argsApiPath in WINDMILL_TOO_BIG branch
2026-05-12 11:48:42 +00:00
Ruben Fiszel 07a4cb6872 branch download UI on shouldDownloadViaClient instead of onclick interception (#9118)
* fix(frontend): branch download UI on shouldDownloadViaClient instead of intercepting in onclick

When OpenAPI.TOKEN is set, several download links rendered an `<a href>`
to the API and relied on an `onclick` handler to call `e.preventDefault()`
and route the request through `downloadViaClient`. This is fragile in
embedded contexts (e.g. the whitelabel React SDK) where Svelte's hydrated
event listener may not intercept the click in time, so the browser
follows the unauthenticated `href` straight to the API.

Mirror the drawer pattern already used in `LogViewer` and
`FlowStatusViewerInner`: render a `<button>` calling `downloadViaClient`
when `shouldDownloadViaClient()` is true, and fall back to the plain
`<a href download>` otherwise. Affects the LogViewer top bar, the large-
result download in DisplayResult, the inline S3 link in ObjectViewer,
the CSV link in ParqetCsvTableRenderer, and FileDownload.

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

* fix(frontend): treat custom HEADERS / basic auth as token equivalents in shouldDownloadViaClient

Customers wiring the SDK with cookie-bypass auth via custom request
headers (e.g. `OpenAPI.HEADERS = getAuthHeaders()` returning a Bearer
header) had `shouldDownloadViaClient()` return false because it only
checked `OpenAPI.TOKEN`. The plain `<a href download>` branch then
followed the link without those headers, so authenticated downloads
silently degraded to the cookie path (or failed when there is no cookie).

Widen the check to any non-cookie auth: TOKEN, HEADERS, or USERNAME
(basic auth). Route `downloadViaClient` through the generated client's
`getHeaders` so all configured auth schemes are applied consistently
instead of hand-building an Authorization header for TOKEN only.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 10:42:05 +00:00
centdix 110384580e refactor: add global ai chat mode with workspace-item draft tools (#9056)
* docs: add global ai mode plan

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

* feat: add global ai draft mode

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

* fix: scope global ai mode to scripts and flows

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

* refactor: simplify global ai workspace item shape

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

* refactor: split global ai write tool into per-type tools

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

* feat: add global ai schedule and trigger workspace item tools

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

* feat: add dev-only /global_drafts route to inspect ai draft store

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

* feat: add edit_script and patch_flow_json global ai tools

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

* feat: add deploy_workspace_item global ai tool with confirmation

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

* feat: emit open-resource action card after deploy_workspace_item

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

* feat: add delete_workspace_item global ai tool with confirmation

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

* chore(system_prompts): emit RESOURCES_BASE and resource/variable zod schemas

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

* feat: add global ai resource and variable workspace item tools

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

* fix: search_resource_types uses listResourceType to avoid embedding feature dep

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

* Revert "fix: search_resource_types uses listResourceType to avoid embedding feature dep"

This reverts commit 6d1d19514a.

* feat: emit open-resource action card for variable and resource deploys

* feat: add global ai raw app workspace item tools

* feat: split raw-app prompt into chat-only authoring and cli prefix

* feat: add init_app global ai tool to scaffold raw apps from templates

* fix: pass write_flow value as JSON string for gemini compat

* refactor: hoist countExactMatches and applyExactReplace to chat/shared

* refactor: extract editableFlowJson module shared with global mode

* fix(global): preserve flow schema and groups across draft and deploy

* feat: extract inline scripts from flow reads and patches in global mode

* refactor: add findAndReplace helper for match-validated text patches

* refactor: extract getInlineRunnableContent helper for app file tools

* refactor: extract assertNotGeneratedAppFile guard for /wmill.d.ts

* feat: gate global ai mode behind localStorage flag for dev rollout

* chore: bump svelte to ^5.55.5 in raw app template (sync with main)

* fix: isolate global ai draft rollout

* fix: preserve global ai deploy metadata

* fix: harden global ai draft tools

* chore: remove global ai plan doc

* fix: align raw app prompt guidance

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-12 09:42:07 +00:00
Ruben Fiszel 01e21c7f91 fix: preserve negative integers in Bedrock tool schema conversion (#9116)
json_to_document cast any i64 to u64 via `as` and wrapped in PosInt.
Negative integers in a tool's JSON schema (e.g. "default": -1,
"minimum": -1) became huge unsigned values like 18446744073709551615,
which Bedrock rejected with `tools.N.custom.input_schema: int too big
to convert`.

Try as_u64 first to preserve full u64 range, fall back to as_i64 for
negatives via NegInt, then as_f64.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 07:00:58 +00:00
Ruben Fiszel 411ca47ffd chore(main): release 1.700.1 (#9114)
* chore(main): release 1.700.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.700.1
2026-05-11 23:23:08 +00:00
Ruben Fiszel cd65de4928 fix: CE build broken by enterprise-gated compute_instance_hash (#9113)
* [ee] fix(license): bump ee-repo-ref to fix CE build

#9089 introduced a call from `windmill-api-settings/src/ee.rs::validate_license_key`
(license-gated) to `windmill_common::ee::compute_instance_hash` (enterprise-gated).
CE builds compile the caller (private + license) but not the callee, breaking the
docker image build on main with E0425 since #9089 landed.

Companion EE PR drops the enterprise gate from `compute_instance_hash`. The
function only depends on common state (BASE_URL, get_instance_uid,
canonical_base_url) and the parent `ee` module is already gated by `private`.

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

* chore: update ee-repo-ref to f9494c6320bb5fd07c1e9e09734b7fd5fbe7aa38

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

Previous ee-repo-ref: 0f495da1ef984cad22342c90691c0dc8b0a20faa

New ee-repo-ref: f9494c6320bb5fd07c1e9e09734b7fd5fbe7aa38

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-05-11 23:14:20 +00:00
Ruben Fiszel b972fabab4 chore(main): release 1.700.0 (#9092)
* chore(main): release 1.700.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.700.0
2026-05-11 22:37:58 +00:00
Ruben Fiszel 9da13d0180 update prompts 2026-05-11 22:34:09 +00:00
Ruben Fiszel ac3c155541 fix: mask oauth client secret in instance settings (#9112)
* feat: mask oauth client secret in instance settings

* fix: address ci review - migrate nextcloud + use Password small prop

* fix: associate client secret labels with input via for/id
2026-05-11 22:30:15 +00:00
Ruben Fiszel 07d3ffbf34 system prompts refresh 2026-05-11 22:13:58 +00:00
hugocasa 9c6cd8c852 offline (URL-bound) license keys (#9089)
* [ee] feat(license): offline (URL-bound) license keys

Offline keys are a 4-segment variant for air-gapped customers — no
phone-home, embedded seat/CU caps, locked to the instance's base_url.
Existing 3-segment online keys are unchanged.

Companion PRs:
- windmill-labs/windmill-ee-private (full design + EE impl)
- windmill-labs/windmill-customer-service (issuance + portal)
- windmill-labs/windmill-cf-worker-keygen (signing)

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

* [ee] refactor(license): bind offline keys via instance hash; simpler CU enforcement

- /settings/license_status now surfaces an `instance_hash` superadmins share
  with support when requesting an offline key
- OfflineMetadata: `hash` replaces `base_url`; OfflineCapStatus reports
  `current_cu` (last 2min) and drops the grace-period fields
- verify_license_key now takes a db so EE can recheck the hash
- InstanceSetting.svelte: hash copy-block + simpler status panel
- Bump ee-repo-ref

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

* [ee] chore(license): bump ee-repo-ref

Pulls in the current_cu clamp + prod public key restoration.

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

* [ee] refactor(license): split instance_hash endpoint; minimal cap UI; restore workers expiry toast

- `instance_hash` is no longer part of /settings/license_status responses; it
  lives at GET /settings/instance_hash (super-admin only) so it isn't re-emitted
  on every status poll. The UI doesn't show it — admins fetch it explicitly when
  requesting a key from support.
- InstanceSetting offline cap UI is now two compact green/red status lines
  (Seats X.X/Y and CUs X.X/Y) placed above the action buttons, matching the
  existing "Latest key renewal" badge style. The block-panel is gone.
- "Latest key renewal" line and the "Renew key" button are now hidden when an
  offline key is loaded (renewal is server-disabled for offline keys).
- Restore parseLicenseKey + checkLicenseExpiration toast on /workers
  (works for both 3- and 4-segment keys).

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

* [ee] chore(license): bump ee-repo-ref

Pulls in the plain-SHA256 instance hash + stats_ee revert.

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

* [ee] chore(license): bump ee-repo-ref

Picks up the alert wording change.

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

* [ee] chore(license): bump ee-repo-ref

Picks up the instance_uid cache so the periodic verify_license_key cycle
no longer hits global_settings.

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

* [ee] refactor(license): rename /settings/license_status → /offline_license_status

The endpoint was only used by the offline-license UI; the other fields it
returned (license_key_id, license_key_valid, kind, offline metadata) were
unused. Rename to clarify scope and flatten the response — it now returns
just the OfflineCapStatus (or null when no offline license is loaded).

Frontend uses `offlineCapStatus != null` as the "is offline" check.

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

* [ee] fix(ci): regenerate sqlx cache for the inline worker_ping query

After reverting unused stats_ee helpers (fetch_worker_pings*), the
inline `sqlx::query_as!(WorkerPingRecord, ...)` in get_stats_payload
lost its cache entry — CI's check_ee_full + cargo_test were failing
under SQLX_OFFLINE=true with E0282 type-inference errors.

Re-running update_sqlx.sh regenerates the cache file under its
current hash and prunes a couple of stale entries.

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

* [ee] fix(license): address cubic-bot review

- get_offline_license_status: propagate enforce_offline_caps errors as 500
  instead of swallowing into a "no offline license" (Option::None) response
- canonical_base_url: rewrite the doc to match the actual fallback behavior
  (lowercase + trailing-slash strip on URL parse failure); the original
  cross-service contract is gone since the customer-service no longer
  canonicalizes (treats the instance hash as opaque)
- check_seat_cap_for_new_user: take an email and short-circuit when the
  email is already in `usr ∪ workspace_invite` so net-zero invite upserts
  and invite→user transitions aren't spuriously blocked at cap. Mirrors
  the dedup rule the count itself uses.
- Bump ee-repo-ref to pull in the EE-side change

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

* [ee] chore(license): bump ee-repo-ref

Picks up the exact-delta seat-cap check (replaces the simple existence
short-circuit). Regenerates the new sqlx cache for the bool_and query.

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

* [ee] fix(license): propagate get_instance_hash errors; bump ee-repo-ref

- get_instance_hash: replace `.ok().flatten()` with map_err+? so DB errors
  during instance_uid lookup surface as 500 instead of silently returning
  `{"instance_hash": null}` (same pattern get_offline_license_status already uses)
- Bump ee-repo-ref to pull in the enforce_offline_caps cached-state preservation

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

* chore: update ee-repo-ref to c6cd1afe2d9e04809b30751cd1687b28a65e62b1

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

Previous ee-repo-ref: a6d91016ae0d43c46604313aecae3aa9c778c8e0

New ee-repo-ref: c6cd1afe2d9e04809b30751cd1687b28a65e62b1

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-05-11 22:09:21 +00:00
Samuel Wilk 1abfe9de39 Add max-iterations to OpenAPI spec for AI Agent (#9103) 2026-05-11 22:03:04 +00:00
Ruben Fiszel f8ba0840d7 feat(vault): configurable JWT auth mount path and setup-doc fixes (#9100)
* chore: narrow secret-file Read deny rule to dotfiles/extensions

* feat(vault): configurable JWT auth mount path and fix setup docs

* chore: bump ee-repo-ref for vault jwt mount path

* chore: bump ee-repo-ref after rebase onto EE main

* chore: update ee-repo-ref to a1cd60b54e8595b4e5ce6b654e675e4bbe2253b2

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

Previous ee-repo-ref: c274f233a0ebb54afa296c3db15ff330e1baebcf

New ee-repo-ref: a1cd60b54e8595b4e5ce6b654e675e4bbe2253b2

Automated by sync-ee-ref workflow.

---------

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-05-11 21:54:40 +00:00
Ruben Fiszel 0a5f8dcd48 deps: pin tokio-postgres to forked branch with query_typed_raw deadlock fix (#9106)
* deps: pin tokio-postgres to MaterializeInc fork to fix query_typed_raw deadlock

`pg_executor`'s `Client::query_typed_raw` (and `Client::prepare` on the
streaming path) deadlock when the result schema contains a column whose
Oid the client doesn't know yet — citext, custom enums, custom domains,
postgis types. Easy to reproduce against any partitioned table with a
citext column: ~100+ rows is enough on localhost, less on slower links.
`psql` works fine for the same query because the simple-query protocol
doesn't trigger the typeinfo lookup path.

## Root cause (unchanged tokio-postgres bug for years)

`query::query_typed` calls `get_type(client, oid).await` synchronously
while still holding the original query's `Responses` stream. The
original query's `DataRow`s back up in the per-request
`mpsc::channel(1)`, `Connection::poll_read` stops draining the wire,
and the typeinfo sub-query response (queued on the same socket behind
those DataRows) never arrives. Classic head-of-line blocking.

## Fix

Pin `tokio-postgres` / `postgres-types` / `postgres-protocol` (via
[patch.crates-io]) and the workspace `rust-postgres` /
`rust-postgres-native-tls` aliases to the
[MaterializeInc rust-postgres fork at `78c1222577`](https://github.com/MaterializeInc/rust-postgres/tree/master).
MI's [PR #33 "bigger-channels"](https://github.com/MaterializeInc/rust-postgres/pull/33)
(merged 2025-12-11) resized the per-request response channel from
`mpsc::channel(1)` → `mpsc::channel(1024)`. That gives the connection
task 1024 batches of headroom while a streaming consumer is paused
mid-stream — orders of magnitude more than realistic typeinfo
deferral needs (≈3 batches).

## Why MaterializeInc and not a windmill-labs fork

`windmill-trigger-postgres` already depended on the imor fork for the
`postgres-replication` crate (logical replication: `CopyBothDuplex`,
`LogicalReplicationStream`, `TupleData` decoding including binary
tuples). That crate has never been on upstream rust-postgres — petrosagg's
[PR #752](https://github.com/rust-postgres/rust-postgres/pull/752) was
closed in 2021 in favour of a smaller split,
[PR #778](https://github.com/rust-postgres/rust-postgres/pull/778) is
still open today after five years. petrosagg keeps the replication work
alive on the MaterializeInc fork.

MaterializeInc is a strict superset of what we previously got from imor:
- imor's binary-tuple commit (sha `20265ef38e`) was merged into MI master.
- petrosagg has added perf + correctness fixes on top (allocation reuse,
  proper decoding fixes).
- The deadlock mitigation (`channel(1024)`) was added three weeks before
  this issue surfaced.

MI tracks upstream rust-postgres with a periodic catch-up merge (12-18 mo
cadence; last on 2025-12-03, ~100 commits picked up). Not an abandoned
fork.

## Why this works now (didn't on earlier attempt)

A previous attempt at this PR (`248ccb5a97`) hit CI failure because the
MI fork's `postgres-types 0.2.11` requires `serde_core ^1.0.221`, but
Windmill's workspace pinned `serde = "=1.0.220"` for swc_common 0.37.5's
`pub use serde::__private as serde;` hack. Bumping serde above 1.0.220
broke the swc_ecma_ast `Deserialize` derive under the
`enterprise,deno_core,…` feature set.

The earlier blocker is now resolved by #9111 which bumped the deno +
swc pin set to a "goldilocks" combination where `swc_common 14.0.4`
drops the `__private` hack, freeing the workspace serde pin to `^1`.
serde now resolves to 1.0.228, which satisfies MI's `serde_core ^1.0.221`
requirement transitively — no extra workspace pin needed.

## Diff shape

Two files only:
- `backend/Cargo.toml` (+34/-1): three new `[patch.crates-io]` entries
  (`tokio-postgres`, `postgres-types`, `postgres-protocol` → MI fork)
  plus comment block, plus the two workspace deps (`rust-postgres` /
  `rust-postgres-native-tls`) repointed from imor's fork to MI's.
- `backend/Cargo.lock` — auto-regenerated. Replaces all `imor/rust-postgres`
  references with `MaterializeInc/rust-postgres`, bumps the affected
  crate versions to MI's set (tokio-postgres 0.7.11 → 0.7.15,
  postgres-types 0.2.7 → 0.2.11, postgres-protocol 0.6.7 → 0.6.9,
  postgres-native-tls 0.5.0 → 0.5.2). No source code changes.

## Verification

- `cargo check --features quickjs` → clean.
- `cargo check -p windmill-worker --features quickjs` → clean (pg_executor
  builds).
- Repro tested earlier in the thread that produced this PR: the
  partitioned-citext-table query on Neon goes from "hangs indefinitely"
  (server idle on `wait_event=ClientRead` while client awaits typeinfo
  behind undrained DataRows) to "completes in ~1.0s, 100 rows" with the
  MI fork's `bounded(1024)` response channel.

## Caveats

- **`bounded(1024)` is a mitigation, not a closure.** Theoretical failure
  mode remains at >~64 MB single-query results with a custom-Oid column
  (typeinfo defers for >1024 batches of ~64 KB each). The strict-correct
  fix is `mpsc::unbounded()` — proposed as a follow-up PR to MI. For
  realistic Windmill workloads, 1024 batches of headroom is well past
  the ~3-batch typeinfo deferral that's actually needed.
- **`postgres-replication` is now upstream-of-fork's only home.** No
  realistic path to upstream rust-postgres merging it. The MI pin is
  intended to stay in place until either upstream changes course
  (unlikely) or MI publishes to crates.io (also unlikely — they don't
  publish releases of the fork).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* chore: update ee-repo-ref to 8fe0d290fb0b71c24184eb5ad99bbdc7c813697c

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

Previous ee-repo-ref: 4d01d171228196f28ddabc1150242bfab623d5cf

New ee-repo-ref: 8fe0d290fb0b71c24184eb5ad99bbdc7c813697c

Automated by sync-ee-ref workflow.

---------

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-05-11 21:43:18 +00:00
Ruben Fiszel e3a914fd48 download files via openapi client when token is set (#9102) 2026-05-11 21:39:41 +00:00
Ruben Fiszel 3cd0eac8c1 deps: bump deno_core / deno_ast / swc to the goldilocks pin set; drop serde ceiling (#9111)
* deps: bump deno_core / deno_ast / swc to the goldilocks pin set; drop serde ceiling

Bumps every deno_* and swc_* workspace dep to a hand-picked "goldilocks"
combination that drops the serde =1.0.220 ceiling without crashing into
the rustls / aws-sdk resolver wall that the obvious deno v2.6.0 target
hits.

## What's the goldilocks set

| crate            | old      | new       | source                                |
|------------------|----------|-----------|---------------------------------------|
| deno_core        | 0.336.0  | 0.352.0   | deno v2.4.0                           |
| deno_fetch       | 0.214.0  | 0.233.0   | deno v2.4.0                           |
| deno_tls         | 0.177.0  | 0.196.0   | deno v2.4.0 (last permissive-rustls)  |
| deno_console     | 0.190.0  | 0.209.0   | deno v2.4.0                           |
| deno_url         | 0.190.0  | 0.209.0   | deno v2.4.0                           |
| deno_webidl      | 0.190.0  | 0.209.0   | deno v2.4.0                           |
| deno_web         | 0.221.0  | 0.240.0   | deno v2.4.0                           |
| deno_io          | 0.100.0  | 0.119.0   | deno v2.4.0                           |
| deno_net         | 0.182.0  | 0.201.0   | deno v2.4.0                           |
| deno_permissions | 0.49.0   | 0.68.0    | deno v2.4.0                           |
| deno_telemetry   | 0.12.0   | 0.31.0    | deno v2.4.0                           |
| deno_error       | =0.5.5   | =0.6.1    | deno v2.4.0                           |
| deno_ast         | =0.44.0  | =0.51.0   | **override** — see "load-bearing" below |
| deno_fs          | (new)    | 0.119.0   | new workspace dep — FetchPermissions exposes deno_fs::CheckedPath / GetPath as public API |
| v8               | =130.0.7 | =137.1.0  | deno_core 0.352 transitive            |
| swc_common       | =0.37.5  | =14.0.4   | **the load-bearing pin**              |
| swc_ecma_ast     | =0.118.2 | =15.0.0   | matched set with swc_common 14.0.4    |
| swc_ecma_parser  | =0.149.1 | =24.0.3   | matched set                           |
| swc_ecma_visit   | =0.104.8 | =15.0.0   | matched set                           |
| serde            | =1.0.220 | ^1        | **freed** (resolves to 1.0.228+)      |

## Why this combination and not v2.6.0

The obvious target was deno v2.6.0 (with deno_ast 0.52 → swc_common 17,
well past the `__private` ceiling). That hits three resolver collisions:

1. libsqlite3-sys: deno_cache → rusqlite 0.37 → libsqlite3-sys 0.35
   vs sqlx → libsqlite3-sys 0.30. **Already killed by PR #9110** —
   we dropped deno_runtime, which is what pulled in deno_cache.
2. fqdn 0.4.6/0.4.7 yanked, required by deno_permissions 0.81.0. Solvable
   by injecting the yanked entry into Cargo.lock manually but ugly.
3. rustls: deno_tls 0.198+ hard-pins `=0.23.28`, but aws-sdk-bedrockruntime
   1.122.0 → aws-smithy-http-client 1.1.5 wants `^0.23.31`. Within-major
   conflict, no resolver path. The unbeatable wall.

Goldilocks-set choice sidesteps (2) and (3) entirely:

- `deno_tls 0.196.0` was the last version before deno tightened
  `rustls ^0.23.11` (range, accepts 0.23.31) to exact `=0.23.28`. With
  ^0.23.11, the resolver picks rustls 0.23.35 (latest 0.23 patch) which
  satisfies both deno_tls's `>=0.23.11` and aws-sdk's `>=0.23.31`. Verified
  empirically: lockfile has rustls 0.23.35 after this bump.
- `deno_permissions 0.68.0` (v2.4.0's pin) doesn't depend on fqdn at all.
  The fqdn dep was added in a later deno_permissions release.

## Why deno_ast =0.51.0 specifically (not 0.48.0 from v2.4.0)

`swc_common 14.0.4` is the first patch that **drops the
`pub use serde::__private as serde;` line** in `src/private/mod.rs`. Older
14.0.x and all 0.37.5–13.x revisions still have it, and that line is
what was capping `serde = "=1.0.220"` (the workspace pin's "stuck because
of swc" comment). Empirically verified by inspecting the tarballs of
14.0.0 / 14.0.1 / 14.0.2 / 14.0.3 / 14.0.4:

    14.0.0: has hack
    14.0.1: has hack
    14.0.2: has hack
    14.0.3: has hack
    14.0.4: NO HACK    ← inflection point

`deno_ast 0.51.0` pins `swc_common =14.0.4` exactly — older deno_ast
versions pin earlier swc_common patches that still have the hack.
Notably, deno v2.4.0 itself pins `deno_ast =0.48.0` (swc_common 9.2.0,
still has hack) — we deliberately deviate from v2.4.0's deno_ast pin
to escape the swc serde wall, while keeping the rest of v2.4.0's pin
set for resolver compatibility with aws-sdk. deno_ast 0.51 was never
shipped in any deno release (v2.4.5 used 0.49, v2.5.0 jumped to 0.50,
v2.6.0 to 0.52), but it's published on crates.io and compatible with
v2.4.0's deno_core 0.352.

## What this unblocks

- PR #9106's `serde = "=1.0.224"` bump variant can rebase onto this
  and resolve cleanly (MaterializeInc/rust-postgres' `postgres-types`
  needs `serde_core ^1.0.221`, which is satisfied now that we're on
  serde 1.0.228).
- Future deno_* / swc_* bumps no longer need to argue about the serde
  ceiling — it's gone.

## What changes in source code

This commit is Cargo.toml + Cargo.lock only. Source changes that the
new deno_core / deno_fetch API requires live in the follow-up commits:

- `parsers/windmill-parser-{ts,ts-asset,wac}`: swc 0.37 → 14
  (`code.into()` ambiguity fix at 5 sites)
- `windmill-runtime-nativets/build.rs` + `src/lib.rs`: deno_core 0.336
  → 0.352 API moves (`init_ops_and_esm()` → `init()`,
  `FetchPermissions` / `NetPermissions` trait signature updates,
  `deno_tls::Proxy` enum shape change)

A companion change in windmill-ee-private adjusts
`otel_tracing_proxy_ee.rs:521` for `deno_telemetry::init`'s second arg
becoming by-value (was `&OtelConfig`).

* fix(parsers): adapt to swc_common 14 BytesStr ambiguity

swc 0.37.5 → 14.0.4 changed `SourceMap::new_source_file`'s `src` argument
from `String` to `impl Into<BytesStr>`. With `BytesStr` available, the
existing call sites' `code.into()` on a `&str` becomes ambiguous between
`Into<Bytes>` (from the bytes crate) and `Into<BytesStr>` (from
bytes_str). Switch to `code.to_string()` to produce an owned `String`
that satisfies `From<String> for BytesStr` unambiguously.

Five call sites across three crates:
- windmill-parser-ts/src/lib.rs (3 sites)
- windmill-parser-ts-asset/src/lib.rs (1 site)
- windmill-parser-wac/src/typescript.rs (1 site)

* fix(nativets): adapt to deno_core 0.352 / deno_fetch 0.233 API changes

The goldilocks deno bump (deno_core 0.336 → 0.352, deno_fetch 0.214 →
0.233, etc.) ripples through nativets' build.rs and src/lib.rs.
Source-level changes required:

## 1. `extension!` macro: `init_ops_and_esm()` and `init_ops()` removed

deno_core 0.352's `extension!` macro now generates a single `init()`
function on the extension struct (full: ops + esm), plus `lazy_init()`
(ops only, with `needs_lazy_init = true` and a contract that the
caller invokes `JsRuntime::lazy_init_extensions` after construction).

- `build.rs` (snapshot creation, wants both ops and esm baked in):
  `X::init_ops_and_esm(...)` → `X::init(...)`.
- `src/lib.rs:create_nativets_runtime` (runtime, was using `init_ops()`
  because the snapshot already provides esm): also → `X::init(...)`.
  deno_core's snapshot path skips esm re-execution when the snapshot
  provides them, so the esm registration is a no-op at runtime. This
  is how deno's own v2.4.0 runtime works.

Avoided `lazy_init` because it requires plumbing
`JsRuntime::lazy_init_extensions(ext_args_vec)` correctly across the
codebase, which is invasive for no behavioural benefit.

## 2. Local `fetch` extension now declared in both build.rs and lib.rs

deno_core 0.352 validates extension order between snapshot and runtime.
Our snapshot's last extension is the local `fetch` ext (which provides
ext:fetch/src/runtime.js). To avoid a runtime panic:

    "Extensions from snapshot loaded in wrong order: expected fetch but got windmill"

…the runtime extension list now ends with `fetch::init()` matching the
snapshot order. The macro requires the same `esm` argument to type-check,
even though the ESM is not re-executed at runtime (it's in the snapshot).

## 3. `FetchPermissions` and `NetPermissions` trait shape

`deno_fetch::FetchPermissions` (deno_fetch 0.233.0) added new methods
and changed signatures:

- `check_read` / `check_write`: now take `path: Cow<'a, Path>` plus
  a new `get_path: &'a dyn deno_fs::GetPath` parameter, and return
  `Result<deno_fs::CheckedPath<'a>, FsError>` instead of `Result<Cow<Path>, FsError>`.
- New `check_write` (didn't exist) and `check_net_vsock` methods.

`deno_net::NetPermissions` (deno_net 0.201.0) gained `check_vsock`
and `check_write_path` now takes `Cow<'_, Path>`.

For `build.rs`'s `PermissionsContainer` (used only during snapshot
creation, where permissions are never actually checked): all methods
`unreachable!("snapshotting")`.

For `src/lib.rs`'s `PermissionsContainer` (used at runtime — the
nativets policy is "allow everything"): `check_read` / `check_write`
return `Ok(CheckedPath::Unresolved(path))`, `check_*_vsock` return
`Ok(())`. Smoke tests confirm fetch/net/url/web/blob/timers/structuredClone
behaviour is intact end-to-end.

## 4. `deno_tls::Proxy` is now an enum

`deno_tls::Proxy` was a struct, is now an enum with `Http`, `Https`,
`Socks5` variants. Our call site uses HTTP proxies — switched the
struct literal `deno_tls::Proxy { url, basic_auth }` to
`deno_tls::Proxy::Http { url, basic_auth }`.

## 5. New `deno_fs` direct workspace dep

`FetchPermissions` exposes `deno_fs::CheckedPath` and `deno_fs::GetPath`
as part of its public API. We can't avoid naming `deno_fs` directly any
more. Pinned to 0.119.0 (v2.4.0's matched version, transitively present
already through deno_fetch). Added to workspace `[dependencies]` plus
nativets's `[dependencies]` and `[build-dependencies]`.

## Validation

`cargo check --features enterprise,deno_core,duckdb,license,python,rust,scoped_cache,parquet,private,private_registry_test,csharp,php,ruby,mysql,quickjs,mcp,run_inline`
→ clean.

`cargo test -p windmill-runtime-nativets smoke -- --ignored --skip smoke_net_`
→ 8 passed; 0 failed (the full local smoke suite covering fetch,
setTimeout/Promise.all, URL/SearchParams, Blob/btoa/atob, large payload
roundtrip, error propagation, concurrent isolates, TS enum/union
transpile).

Network smoke tests (`smoke_net_fetch_example_com`,
`smoke_net_fetch_json_and_headers`) not run as part of the validation
gate but expected to pass — the change preserves deno_fetch behaviour
through the trait surface.

* chore: update ee-repo-ref to pick up deno_telemetry::init by-value fix

Points at windmill-ee-private branch deps/bump-deno-and-swc-goldilocks
which contains the companion otel_tracing_proxy_ee.rs adjustment for
deno_telemetry 0.12 → 0.31 (second arg of `init` is now by-value).
EE-only file, doesn't affect OSS build.

* chore(nix): bump rusty_v8 in flake.nix to 137.1.0 to match Cargo.toml

Cargo.toml's v8 pin moved from =130.0.7 to =137.1.0 as part of the
deno_core 0.336 → 0.352 bump, but I missed the comment directly above
the version pin:

    # Exact version NOTE: Do not forget to update version and hash in flake.nix

flake.nix provides the prebuilt librusty_v8 binary that the v8 crate
links against. A version mismatch would either fail to fetch (if the
137.1.0 release didn't exist) or cause link-time symbol mismatches.
Nix is used by rust-client-check.yml and rust_on_release.yml in CI,
plus the dev shell — stale flake pin breaks all of those.

Updates x86_64-linux's sha256 to match the actual hash of
librusty_v8_release_x86_64-unknown-linux-gnu.a.gz at the 137.1.0 tag.
Other targets (aarch64-linux, x86_64-darwin, aarch64-darwin) remain
as lib.fakeHash — they were already placeholders in the previous
pin, so we don't regress on them.

Caught by both cubic and Pi reviewers on PR #9111.

* docs(nativets): clarify snapshot-prefix rule in extension-order comment

Claude reviewer caught that the doc comment claimed the runtime
extension list matches the snapshot's order — implying an exact match.
The truth is more permissive: deno_core 0.352 requires the snapshot's
extension list to be a *prefix* of the runtime's, not an exact match.
Runtime is allowed to append extra extensions (which we do — the
windmill `ext` carrying our ops is the last entry at runtime but absent
from the snapshot).

The code is correct as-is; only the comment wording was misleading.

Also fixes the same wording in PR description.
2026-05-11 21:13:24 +00:00
Ruben Fiszel 36b316d9e8 deps(nativets): inline maybe_transpile_source, drop deno_runtime (#9110)
windmill-runtime-nativets was the workspace's only consumer of the
deno_runtime crate, and its only use of it was one call site in
build.rs:

    deno_runtime::transpile::maybe_transpile_source(specifier, source)

That function (`deno_runtime-0.198.0/transpile.rs`, ~80 lines) is a pure
deno_ast + deno_core + deno_error wrapper — it doesn't touch any
deno_runtime state. Inline it verbatim into our build.rs and drop the
entire deno_runtime dep.

Why this matters now: deno_runtime transitively pulls in deno_cache →
rusqlite → libsqlite3-sys. From deno_cache 0.128.0 (Feb-Mar 2025)
onwards, rusqlite was bumped to ^0.34, which means libsqlite3-sys ^0.35.
sqlx 0.8 transitively requires libsqlite3-sys ^0.30. Cargo's `links =
"sqlite3"` rule allows only one libsqlite3-sys in a build graph, so the
two crates collide on any deno release ≥ v2.5. Inlining the transpile
helper sidesteps the collision entirely — sqlx-sqlite stays the sole
libsqlite3-sys consumer at 0.30.1.

All other appearances of "deno_runtime" in the source tree are for a
Windmill-internal function named `setup_deno_runtime`, not the crate.

Build artifacts validated:
- `cargo check --features quickjs` → green.
- `cargo test -p windmill-runtime-nativets smoke -- --ignored --skip smoke_net_`
  → 8 passed (the in-process V8 runtime + deno_fetch + deno_web + swc
  transpilation surface still works end-to-end through the inlined
  function).
- `cargo tree --invert deno_cache` → "did not match any packages"
  (gone from the graph).
- Single `libsqlite3-sys` entry in Cargo.lock at 0.30.1 (sqlx's).
2026-05-11 20:21:46 +00:00
brone1323 9f79a86a68 fix: add Input, Result, Trigger to reserved flow step IDs (#9109)
Renaming a flow step to 'Input', 'Result', or 'Trigger' would silently
corrupt the UI — the flow editor panel would switch to rendering the
special Input/Result/Trigger node instead of the step's config panel,
making the step inaccessible without editing YAML directly.

These virtual node IDs were already handled as reserved by
multiSelectUtils.ts but were missing from the forbiddenIds list that
drives the IdEditorInput validation, so users got no warning.

Fixes #7139
2026-05-11 19:51:49 +00:00
Ruben Fiszel 1e89aff2d6 test(nativets): add #[ignore]'d smoke suite for deno_core / deno_ast / swc bumps (#9108)
Adds ten `#[ignore]`'d integration tests in
backend/windmill-runtime-nativets/src/smoke_tests.rs exercising the JS
API surface that the existing nativets tests in tests/worker.rs don't
reach. Run them when bumping the deno_core / deno_ast / deno_runtime /
swc_* pins in backend/Cargo.toml, not on every CI:

    cargo test -p windmill-runtime-nativets smoke -- --ignored
    # skip network-dependent ones with `--skip smoke_net_`

Why here and not in tests/worker.rs:
windmill-runtime-nativets is the only consumer of the deno_core crate
in the workspace — ScriptLang::Deno spawns the external `deno` binary
via deno_executor.rs, while ScriptLang::Nativets is the only path that
loads the in-process V8 runtime. So a deno_core / deno_ast bump can
only break things downstream of this crate. Co-locating the smoke
tests with the runtime they exercise means they hit the right surface
directly, skip the entire job-queue / worker / API-server stack, and
run in <1s end-to-end (vs. ~30-60s per test for the worker-level
nativets tests).

The tests use the existing `PrewarmedIsolate::spawn` API (already
public for the dedicated-worker path), which gives a clean
"compile-TS → load module → execute main(args) → return JSON" entry
point with no DB or queue plumbing required.

Coverage:
- smoke_basic_value_passing — args binding + return marshaling
- smoke_transpile_enum_and_union — TS-specific syntax (enums,
  discriminated unions, casts) through swc_ecma_parser / swc_ecma_ast
- smoke_set_timeout_and_promise_all — deno_web timer ops + V8
  microtask drain order
- smoke_url_and_searchparams — deno_url surface
- smoke_web_blob_btoa_atob — deno_web Blob + base64 ops
- smoke_large_payload_roundtrip — 512 KB string in/out through the
  op-table boundary
- smoke_error_propagation_with_message — thrown Error must surface
  in PrewarmedResult::Err with original message
- smoke_concurrent_isolates — 8 isolates spawned in parallel from
  the same tokio runtime; catches V8 isolate-setup races
- smoke_net_fetch_example_com — deno_fetch end-to-end against
  example.com
- smoke_net_fetch_json_and_headers — deno_fetch with custom request
  headers + Response.json() against httpbin.org/anything

`structuredClone` is not currently wired into the nativets global —
documented in the smoke_web_blob_btoa_atob test in case that ever
changes.

All ten tests pass locally against the current pinned versions
(deno_core 0.336.0 / deno_ast =0.44.0 / swc_common =0.37.5).
2026-05-11 18:43:54 +00:00
Diego Imbert 20ecd904e7 feat(operators): allow operators to access assets page (#9095)
* feat(operators): allow operators to access assets page

Adds the "assets" key to workspace operator_settings (defaulting to true
for existing and new workspaces) and toggles the frontend default so the
assets page is visible to operators by default.

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

* nit: remove settings btn when not available

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 18:36:34 +00:00
Ruben Fiszel 03e8bc8c14 perf: lazy-load script editor history and hit partial index (#9107) 2026-05-11 17:20:46 +00:00
centdix 6f7d31e56b refactor: move ai image handling to windmill-ai (#9098) 2026-05-11 14:59:40 +00:00
hugocasa bbef5c9dd4 ping PR author when auto-review verdict is not good to merge (#9101)
* feat(ci): ping PR author when auto-review verdict is not good to merge

* fix(ci): drop (unknown) author fallback and clarify verdict-line rule
2026-05-11 14:56:52 +00:00
Ruben Fiszel 05172ac3bd fix: populate raw_code for flowscript and appscript runs (#9104) 2026-05-11 13:54:50 +00:00
Diego Imbert e43a958c5c feat(forks): prompt to delete forked children when deleting a fork (#9097)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-11 12:30:37 +00:00
centdix 27acbbf3d5 refactor: move ai sse plumbing to windmill-ai (#9059)
* docs: refine windmill ai refactor plan

* refactor: move ai sse plumbing to windmill-ai

* refactor: remove ai re-export shims

* fix: update ee ai memory ref

* chore: update ee-repo-ref to d3bc7fa85195b46b7a38d43c2f806520bf8b5454

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

Previous ee-repo-ref: ff35bf7cc198e13884b33654e1d6dbd8a8b314d3

New ee-repo-ref: d3bc7fa85195b46b7a38d43c2f806520bf8b5454

Automated by sync-ee-ref workflow.

---------

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-05-11 10:01:45 +00:00
hugocasa 23bb1b541e fix(frontend): mark Path dirty when folder picker changes selection (#9096)
* fix(frontend): enable move button when only folder changes

* fix(frontend): mark Path dirty when folder picker changes selection

* fix(frontend): preserve script auto-derive for new items in Path dirty effect
2026-05-11 10:01:13 +00:00
Diego Imbert da9e416b8e workspace specific nit fixes (#9072)
* fix: capture linked variables in trash on bulk resource delete

delete_resources_bulk grew linked-variable cascade deletion in an
earlier commit on this branch but only mirrored the deletion side of
delete_resource — not the trashbin capture side. Linked variables
deleted via bulk were permanently lost while their single-delete
counterparts could be recovered from trash.

Fetch each resource's linked variable rows as JSON before bulk delete
and stash them under `trash_data['linked_variables']` of that
resource's trash entry, matching the shape produced by single-resource
delete.

* fix: ws_specific cleanup gaps in variable rename + bulk delete; tooltip

Four spots:

1. update_variable rename block: when a variable is renamed and a
   linked resource at the same path is renamed alongside, also move
   any explicit ws_specific 'resource' marker from the old path to
   the new one. Symmetric with what update_resource already does for
   ws_specific 'variable'.

2. delete_variables_bulk: clean ws_specific 'resource' rows for any
   linked resource paths before the resource DELETE. Without this,
   bulk-delete leaves orphaned markers that would cause a freshly
   recreated resource at the same path to be falsely treated as
   workspace-specific. (linked_resource trash capture is already
   present in the bulk path — the reviewer note about that was
   inaccurate against the current code.)

3. list_ws_specific: ORDER BY item_kind, path so the CLI sees a
   stable list across pulls/pushes — cheap on a small per-workspace
   row set and avoids spurious diffs.

4. VariableForm tooltip: mirror the resource form so users who find a
   variable already toggled know it may have been auto-marked by a
   workspace-specific resource referencing it, and that disabling
   doesn't retroactively un-mark the referencing resource.

* sqlx prepare
2026-05-11 07:56:52 +00:00
Ruben Fiszel b95f0e2379 style(log-viewer): tighter top bar (icons, hyphenated label, scoped overflow) (#9094)
- duration/mem-peak labels replaced by Timer/Cpu icons with tooltips
- 'Auto scroll' -> 'auto-scroll' (lowercase, hyphenated, whitespace-nowrap)
- top bar gets overflow-x-auto so it scrolls horizontally instead of pushing the entire log panel into overflow when narrow
2026-05-10 12:06:25 +00:00
Ruben Fiszel 43b18006f3 feat(cli): auto-infer args for wmill app push (#9091)
Run `wmill app push` from inside an app folder (e.g. `f/foo/my_app.app/`)
with no args. The local path defaults to CWD, and the remote path is
derived from CWD relative to `wmill.yaml`, with `.app`/`.raw_app`/
`__app`/`__raw_app` suffixes stripped. Either, both, or neither
positional argument can be passed.

Also resolves `file_path` against the user's original CWD before
`resolveWorkspace` may chdir to the wmill.yaml root, so a relative
`file_path` argument is interpreted from where the user invoked the
command (previously it could resolve against the wrong directory).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 08:38:47 +00:00
Ruben Fiszel 91ddb930c3 chore(main): release 1.699.0 (#9082)
* chore(main): release 1.699.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.699.0
2026-05-08 18:03:06 +00:00