Commit Graph
7178 Commits
Author SHA1 Message Date
Guilhem LemouelandClaude Fable 5.1 7ad7312cd0 feat: store the version a draft forked from in one draft.base column
Every kind kept its fork base under a different name and type inside the
value: parent_hash (hex) for scripts, version_id for flows, parent_version for
apps. draft.base holds it as one text id, derived on save from the value so
every writer fills it the same way, backfilled by the migration (rows holding a
NUL are skipped, since ->> raises on them). The get-by-path overlay exposes it
as draft_base and the drafts list as base; the editors and the compare page
read that one field and compare it to the head as text.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 10:35:18 +02:00
Guilhem LemouelandClaude Fable 5.1 22638d33e9 test: move_to asserts the response status
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 20:11:05 +02:00
Guilhem LemouelandClaude Fable 5.1 60a4b083f9 feat: stale prompt links to a diff that names and lets you pick the deployed version
The stale-draft prompt gains "See what changed", which opens the diff drawer. The
drawer resolves the deployed side by the draft row's own path (not the typed path,
which after a rename still names the archived row), labels which version the left
pane is, and offers a picker over the item's deployed history for scripts, flows
and raw apps. The history endpoints return created_by (and created_at for apps)
so each entry can name its deployer. "Restore to deployed" moves to the header
actions.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 20:11:04 +02:00
Guilhem LemouelandClaude Fable 5.1 366f9cfb5b feat: drop the restamp and tri-state; a move relocates the draft row only
A deploy that renames an item is a deploy like any other: every draft on the item
goes stale, and the stale prompt with its diff is the single mechanism to catch up.
move_drafts_for_path now touches only the row's path column, so the value keeps the
base version the draft actually forked from, and the "moved" patch carries no
version restamp. DraftBaseVersion shrinks to the three per-kind lineage fields.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 20:10:43 +02:00
Guilhem LemouelandClaude Opus 5 9cd227515d docs: point the empty down at the grant it is declining to revoke
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 14:28:44 +02:00
Guilhem LemouelandClaude Opus 5 ad97bcf110 test: pin the two-key move, and stop the down migration breaking instances
Revoking the sequence grant would strip a privilege a healthy instance had
before this migration ran — the grant it adds is indistinguishable in the
catalog from the one ALTER DEFAULT PRIVILEGES gives at creation time — so the
down is a comment, matching the other grant-only migrations.

The mirror rewrite is spread over three sites that have to agree and fails
silently when they don't, so it gets a test: a draft carrying both path keys
has both moved, and one carrying neither mirror does not gain one. It reads
the value back over HTTP rather than with `sqlx::query!`, which would need an
offline cache entry of its own.

Also drops twelve `.sqlx` entries this branch added and then superseded, and
corrects the doc and openapi text that still described only the typed path
being rewritten.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 14:20:37 +02:00
Guilhem LemouelandClaude Opus 5 0406c3625d fix: carry both path keys on a move, and grant the draft sequence
The upsert now runs as `windmill_user`, so it calls nextval on `draft_id_seq`
as that role. The only thing granting that is the ALTER DEFAULT PRIVILEGES in
20250205131523, whose DO block swallows failures — so an instance where it
errored would fail every autosave with `permission denied for sequence`.

A draft value carries two path keys: the typed one and a mirror the editors
keep in step with it while it differs from the row's path. Rewriting only the
typed one left the mirror naming the old location, and the loaders prefer the
mirror — reopening a moved session script restored the old path and the next
save un-did the move. Both keys now follow, in the move endpoint and in the
passive carry, under the same tri-state rule.

`typed_path_field` answered `draft_path` for every non-script kind, including
resources, variables and triggers, which have no such key. It returns `None`
for them now, and `move_draft` reads its guard off that mapping so the movable
set and the field mapping cannot drift apart.

Also documents that `move_drafts_for_path` mutates every owner's row and
enforces nothing itself, and parses the draft payload once per save instead of
three times.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 14:06:17 +02:00
Guilhem LemouelandClaude Opus 5 f79812cc44 docs: state the RLS and restamp constraints once each
The RLS envelope was argued at three sites in drafts.rs; it now sits only on
`resolve_moved_to_in`, whose signature is what a caller would break. The
restamp scoping was copy-pasted at all three deploy call sites while already
documented in full on `move_drafts_for_path`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 12:51:59 +02:00
Guilhem LemouelandClaude Opus 5 3528054801 docs: name the real deploy path and stop restating the RLS constraint
`update_path` is not a symbol in this repo; a script move goes through
`create_script`. The re-assert's comment re-derived the disclosure argument
that already sits on `resolve_moved_to_in`, where a caller would break it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 12:43:40 +02:00
Guilhem LemouelandClaude Opus 5 4ad0cca327 test: pin the moved answer to what the saver can see
The post-write re-assert names a path and a username, and nothing at any
layer stopped it reading them off a raw pool connection. Swapping the
transaction back to `db.begin()` compiles and passes everything else, so
the guard has to be a test: a non-admin saving at a path whose item moved
into a folder they cannot see gets `saved`, while the admin gets `moved`.

Also drops two doc comments still arguing that clearing the write gate at
the old path removes the need for an RLS envelope. It does not — the gate
resolves the old path and the re-assert asks about the new one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 12:38:17 +02:00
Guilhem LemouelandClaude Opus 5 e716db5291 fix: run the post-write moved re-assert under RLS, not the raw pool
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 12:25:05 +02:00
Guilhem LemouelandClaude Opus 5 0b0822cd2f fix: gate operators earlier, skip the write tx without lineage, unblock a chained move
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 10:02:07 +02:00
Guilhem LemouelandClaude Opus 5 c33789e266 fix: address CI review — auth order, save race, carry failure, path validation
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 09:00:50 +02:00
Guilhem LemouelandClaude Opus 5 4c4738c970 fix: name the attempted operation in the NUL rejection message
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 13:00:52 +02:00
Guilhem LemouelandClaude Opus 5 c04942e341 fix: report a NUL-poisoned draft on move instead of 500ing
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 12:56:58 +02:00
Guilhem LemouelandClaude Opus 5 e895cdd4db fix: skip NUL-poisoned rows in every draft-value rewrite, not just the first
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 12:40:08 +02:00
Guilhem LemouelandClaude Opus 5 c6bf9ca965 fix: reject unsupported kinds in move_draft, survive NUL-poisoned draft rows
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 12:24:14 +02:00
Guilhem LemouelandClaude Opus 5 5b806a5e3c fix: carry a flow draft's baseline path so deploying it cannot un-move the flow
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 11:36:09 +02:00
Guilhem LemouelandClaude Opus 5 7350705cea fix: read the app move's author from the head version, not the draft's base
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 11:20:45 +02:00
Guilhem LemouelandClaude Opus 5 6093206ad2 fix: scope the moved-save restamp to the mover as well
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 10:58:32 +02:00
Guilhem LemouelandClaude Opus 5 fdfbbc2c50 fix: restamp only the deployer's own carried draft
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 10:49:35 +02:00
Guilhem LemouelandClaude Opus 5 98bce2576c fix: keep a staged rename when a move carries the draft
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 15:06:02 +02:00
Guilhem LemouelandClaude Opus 5 1bcc051f43 fix: address review findings on the draft-carry path
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FaEacdxR6M6VDej6C9r39
2026-09-07 12:16:11 +02:00
Guilhem Lemouel 96cee83914 Merge remote-tracking branch 'origin/main' into glm/improve-multiselect
# Conflicts:
#	frontend/src/lib/components/common/table/RawAppRow.svelte
#	frontend/src/lib/components/home/ItemsList.svelte
#	frontend/src/lib/components/home/TreeView.svelte
2026-09-03 15:07:48 +02:00
Ruben Fiszelandrubenfiszel 38fc0d3a12 chore(main): release 1.803.0 (#10952)
* chore(main): release 1.803.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-09-03 13:08:33 +02:00
hugocasaandClaude Opus 5 e474e8803c feat: expose request headers to scripts invoked via MCP (#10903)
* feat: expose allowlisted request headers to scripts invoked via MCP

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

* fix: close header-forgery routes flagged in review of MCP header passthrough

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

* fix: match allowlisted headers exactly and withdraw every model-args run path

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

* fix: address review nits on MCP header passthrough

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

* fix: stop over-withdrawing deleteScriptByHash and align schema strip key space

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

* refactor: move MCP header field detail into a label tooltip

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

* fix: bound include_header parsing and narrow the duplicate-header drop

* feat: handle runnable-executing tools instead of withdrawing them

* docs: record the preprocessor kind seam on proxied run-by-path

* fix: strip every runnable argument map and open the field to gateway tokens

* fix: withhold connection credentials from runnables unless explicitly named

* fix: keep endpoint control arguments out of the transport-owned strip

* fix: exempt workspace_id from the strip only where it routes the call

* style: reindent the MCP header tooltip block

* refactor: deliver MCP request headers through the preprocessor only

* fix: widen the proxy-owned header set and clear docs left by the redesign

* fix: count proxied header delivery and finish the redesign doc sweep

* fix: forward proxied headers only to a runnable that has a preprocessor

* refactor: drop include_header and the MCP credential deny list

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

* chore: restore the blank line in CreateToken

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

* refactor: drop the mcp header_passthrough feature usage counter

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

* test: pin that a caller credential other than the hop's own travels

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

* refactor: deliver headers only through the direct script and flow tools

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

* feat: withhold connection credentials and pin MCP header delivery end to end

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

* test: send every credential the withheld-list assertions cover

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

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 11:30:20 +02:00
GuilhemandClaude Opus 5 e39dd7eb12 docs: teach agents to pass a resource as $res:<path> in run arguments (#10927)
* docs: teach agents to pass a resource as $res:<path> in run arguments

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

* docs: extend run-argument rule to in-editor chats, fix run-as wording

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

* docs: tighten resource run-argument rule after review

- Drop the false rationale that "$var:" only works inside a resource value
  from the write_variable description and its runtime rejection message; keep
  the rule (a variable cannot reference itself).
- MCP resource-argument description: the title fallback renders "No title",
  so say the title is only a label rather than that it can be empty. Guard the
  real-newline fix with asserts in the existing enrichment test.
- Eval: assert the full "$res:f/evals/global/github_main" value as one prefix
  so a wrong path with a right prefix fails.
- resources.md: narrow "a trigger's payload" to its configured static args.

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

* docs: scope the run-argument rule to global chat, add an exact eval matcher

The ai_evals A/B on the two in-editor modes showed no effect: script mode
sonnet 5/5 both with and without the description, flow mode sonnet 5/5 and
haiku 5/5 on the baseline alone. A flow's input schema already carries
`format: resource-<type>`, so those modes have a signal global mode does not
give. Revert both files to keep the tool schemas free of a description that
buys nothing per iteration; global mode keeps it, where haiku goes 0/5 -> 5/5.

Add `stringEqualsAnyOf` to toolCallArgs and use it for the resource reference:
nothing in the eval resolves the value, so a prefix match accepted a near-miss
path like `$res:f/evals/global/github_main_backup`.

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

* docs: address cubic review — CLI wording, mock resource getter

- `-d --data` help on all four run/preview commands: give $res: and $var:
  their own clauses instead of a parenthetical that read as if a resource
  were a kind of variable.
- Mock backend: `getBenchmarkResource` now resolves AI-provider seeds as well
  as plain ones, so it agrees with `existsResource` and `listResource` — both
  report either kind, and a case that listed a resource and then read it by
  path got a row it could not fetch.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 11:29:54 +02:00
Ruben FiszelandClaude Fable 5.1 ca8800959a fix: bump git sync hub scripts to cli 1.802.1, test the fork ui pull (#10955)
* fix: bump git sync hub scripts to cli 1.802.1, test the fork ui pull

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011yMLnAWdjpCEs5VyGMn9ww

* test: guard the ui pull preview shape and pin the pull script ids together

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011yMLnAWdjpCEs5VyGMn9ww

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 11:23:23 +02:00
Ruben FiszelandClaude Fable 5.1 9b64a89cd4 fix: let operators use wmill.datatable() from within running jobs (#10931)
* fix: let operators use wmill.datatable() from within running jobs

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHR4fytgt6m4q37WCXs2Rp

* fix: refuse content-driven redirects and deferral in the operator datatable exemption

* fix: check the datatable exemption against the expanded query, not the raw content

* fix: fail closed on a language-overriding expansion and state the exemption's real scope

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 08:43:52 +02:00
Ruben FiszelandClaude Fable 5.1 4fef1195ad fix: apply object-storage test SSRF validation to all non-super-admins (#10933)
* fix: apply object-storage test SSRF validation to all non-super-admins

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJLqsE5br9r5e7qy8ULwUg

* fix: name the job-token case in object-storage test rejections

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJLqsE5br9r5e7qy8ULwUg

* fix: run object-storage connection tests with a short-lived user token

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJLqsE5br9r5e7qy8ULwUg

* fix: test object-storage resources from the browser, mint a token only for the worker test

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJLqsE5br9r5e7qy8ULwUg

* fix: resolve variable and resource references before the browser-side object-storage test

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJLqsE5br9r5e7qy8ULwUg

* fix: bound the browser-side object-storage test to 15s

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJLqsE5br9r5e7qy8ULwUg

* fix: explain object-storage test rejections and name the way out

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJLqsE5br9r5e7qy8ULwUg

* fix: keep the server-resolved address out of the object-storage test rejection

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJLqsE5br9r5e7qy8ULwUg

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 22:29:01 +02:00
hugocasaandClaude Opus 5 d472193e5b feat: add retention cleanup for the otel_traces table (#10949)
* feat: add retention cleanup for the otel_traces table

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

* fix: vacuum otel_traces and badge its retention setting EE

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 19:41:46 +02:00
hugocasaandClaude Opus 5 17ba521c35 fix: record supplied script lock hashes so importers can skip relocking (#10915)
* fix: record supplied script lock hashes so importers can skip relocking

Creating a script with a caller-supplied lock — a CLI push, a git-sync deploy,
any create carrying a lockfile — stored the lock on `script` but never wrote the
matching `lock_hash(workspace_id, path, hash_script(lock))` row. Only
worker-generated locks did.

`try_skip_relock` treats a missing hash for an imported script as changed, so no
importer of such a script could ever satisfy the skip predicate: every deploy of
it relocked every importer, forever.

The create transaction now records the hash for any lock it accepts, including
the empty one a codebase or a language with no lock generation carries — the
worker writes `hash_script("")` there, and a path going from a real lock to an
empty one has to stop matching what its importers recorded. Only a lock left to
a dependency job is skipped, because that job writes it.

A workspace clone now carries `lock_hash` too, without which every
dependency-map snapshot the clone later recorded held NULL and nothing in it
could ever skip. `dependency_map.imported_lockfile_hash` is deliberately not
copied: it records what an importer resolved against when it was last locked,
the clone runs READ COMMITTED, and a relock landing in the source between the
scripts being cloned and that statement would attach a hash the cloned
importer's lock was never resolved against — a hash older than the cloned
scripts costs one relock, a newer one skips a relock that was needed.

Lock generation is untouched, as is everything a relock does once it runs. The
only behavior that moves is which relocks are skipped.

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

* fix: narrow to the create-path lock hash

Drop the workspace-clone copy of lock_hash. It sits outside the reported
bug, and its double join over `script` can emit a path twice where two
versions are live, which the unique key on (workspace_id, path) then
rejects, failing the whole fork.

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

* fix: restore the workspace-clone lock hash copy, guarded against fanout

A path can hold two live versions, and both joins match on path alone, so
the select can emit it four times against a primary key that admits one.
Every such row carries the single hash the path has, so ON CONFLICT DO
NOTHING settles it rather than aborting the fork.

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

* fix: hash a clone's own locks rather than copying the source's rows

A source row is only as current as the last write to it, and a supplied
lock deployed before this was recorded leaves one naming a lock the path
no longer holds. Copying that into a fork hands an importer a hash it
never resolved against; hashing what the clone holds cannot.

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

* test: pin the lock hash written on a no-op push

Removing that write leaves the assertion with no row, which is the state
a script deployed before this shipped would stay in.

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

* refactor: share one lock hash writer between the create and clone paths

Both wrote the same upsert with different SQL. The existing writers fold
theirs into the statement that writes the lock itself, which is what keeps
the two consistent; these two have nothing to fold it into, so they take a
shared one instead. The clone walks its pages by path rather than listing
them first, dropping a query with it.

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

* fix: stream a clone's locks rather than reading them in pages

script.lock is unbounded, so a page of them is bounded only by how many
it holds. Hashing each as it arrives keeps one in memory at a time and
lets the clone site collapse to a single call.

Also states on both writers that they check no access to the workspace
they write, which their callers are the ones to have established.

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

* fix: make the lock hash writer safe to repeat and free when unchanged

A path given twice in one call would have Postgres reject the whole
statement, so the last hash for each wins. And recording a hash a path
already has cut a row version for nothing on every unchanged sync, which
is the mode the no-op push runs in.

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

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 19:20:49 +02:00
Ruben FiszelandClaude Fable 5.1 419741e5d2 fix: sandbox script-controlled content types in result_to_response (#10932)
* fix: sandbox script-controlled content type in result_to_response

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WFhu2MHsJVMqdMfdgbwNkT

* fix: reject hop-by-hop wm_headers so a proxy cannot strip the sandbox

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WFhu2MHsJVMqdMfdgbwNkT

* docs: condense sandbox comments and record the surface in the threat model

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WFhu2MHsJVMqdMfdgbwNkT

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:27:18 +02:00
Ruben FiszelandClaude Fable 5.1 fdd3b36423 feat: workspace setting to hide the AI assistant, agent steps unaffected (#10941)
* feat: workspace setting to hide the AI assistant, agent steps unaffected

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011eNweUugVqerex6MLxjbeL

* fix: load workspace AI config on cold /sessions load and say hidden, not disabled

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011eNweUugVqerex6MLxjbeL

* fix: follow workspace switches on /sessions gate and drop deprecated button size

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011eNweUugVqerex6MLxjbeL

* fix: key the /sessions hidden-assistant gate on the acting workspace's own config

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011eNweUugVqerex6MLxjbeL

* fix: tag the /sessions hidden-assistant verdict with its workspace and drop superseded reads

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011eNweUugVqerex6MLxjbeL

* fix: overlay the /sessions hidden-assistant gate so warm sessions survive workspace switches

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011eNweUugVqerex6MLxjbeL

* fix: hide the pipeline insert menu AI prompt and refuse chat turns where the assistant is hidden

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011eNweUugVqerex6MLxjbeL

* fix: shrink the home Build with AI / CLI / Hub line to a flush hint row

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011eNweUugVqerex6MLxjbeL

* fix: frame the workspace toggle as hide AI sessions at the bottom of the AI settings

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011eNweUugVqerex6MLxjbeL

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:21:10 +02:00
Ruben Fiszelandrubenfiszel 74c1813f98 chore(main): release 1.801.0 (#10921)
* chore(main): release 1.801.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-09-02 01:01:01 +02:00
94af8d0fb5 fix: let a principal without a login account own a draft (#10925)
* fix: let a principal without a login account own a draft

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

* fix: keep an accountless draft owner from colliding or reading as legacy

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

* fix: drop the unnameable draft owner everywhere and guard the no-op rename

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

* fix: drop the unused Acquire import in the draft rename test

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

* docs: drop the stale draft_users claim from the fork-clone rationale

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

* chore: update ee-repo-ref to f5b783d2f7608e1ff3a817caa8b719e06f8b8981

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

Previous ee-repo-ref: f3dba016e9274ee9bbe46b4f070d3ed29843e5fd

New ee-repo-ref: f5b783d2f7608e1ff3a817caa8b719e06f8b8981

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-09-01 23:42:08 +02:00
af8ff38687 fix: tolerate string app_id in GHES app config deserialization (#10923)
* fix: tolerate string app_id in GHES app config deserialization

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

* fix: address review — strict app_id validation, drop dead variant

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

* chore: update ee-repo-ref to b52c6471d517d979a9887f207a36347b1af376c8

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

Previous ee-repo-ref: ab2dc653719f9d65eb10964d1e2b5bc1b94d6535

New ee-repo-ref: b52c6471d517d979a9887f207a36347b1af376c8

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-09-01 23:31:43 +02:00
GuilhemandClaude Opus 5 5d5ad4e897 feat: edit folders and groups in a drawer that saves once (#10873)
* fix: portal the confirmation modal so drawers cannot cover it

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

* fix: log a folder acl grant under the permission it granted

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

* fix: keep a table's actions column at its right edge

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

* feat: edit a folder in a drawer that saves once

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

* refactor: call the people on a folder or item members

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

* fix: edit a folder against the workspace the drawer targets

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

* refactor: drop the now-unused sticky actions column

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

* docs: correct the script editor drawer's modal placement note

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

* fix: pin the actions column without losing the row's hover tint

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

* feat: show the pinned column's seam only while the table overflows

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

* fix: draw the pinned column's seam as a shadow so it does not scroll away

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

* fix: fade the pinned column's tint in step with its row

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

* refactor: address review nits on the folder editor and pinned cell

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

* fix: keep the folder draft across a user-store refresh

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

* refactor: extract and test the folder draft's dirty check and permission diff

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

* fix: stop the folder editor showing state the server refused

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

* fix: keep a folder draft that no request ever reached the server

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

* fix: keep unapplied folder edits dirty when a save partially fails

* fix: block folder form edits while a save is in flight

* fix: commit a typed folder label before save snapshots the draft

* fix: count a typed folder label as an unsaved change

* fix: keep escape in the label input from closing what encloses it

* fix: capitalize folder table headers and drop a dead portal target

* refactor: make the confirmation modal portal opt-in per call site

* docs: name the stacking context that actually traps the discard dialog

* fix: report a half-landed member removal so the baseline reconciles

* feat: edit a group in a drawer that saves once

* fix: freeze the group name once the group exists

* fix: revoke the caller's own group acl last so the rest of the save is authorized

* docs: state the group call-ordering invariant once

* fix: report a failing post-save reload instead of dropping the rejection

* fix: hand the folder list reload back so a failure is reported

* fix: treat a rejected group create as inconclusive and catch a throwing onSaved

* revert: stop inferring a group was created from its name being taken

* fix: say when a failed group create may have saved the group anyway

* fix: key the may-have-been-created hint on the name conflict, not the status

* fix: skip the may-have-been-created hint when the group is known to exist

* feat: open a folder's group member from its row

* fix: stop showing the caller as an admin when the read failed

* fix: give up the caller's own folder admin last, and label a create as one

* fix: drop a folder member's acl before its owner entry

* fix: remove a folder owner before their acl, and correct the rls rationale

* docs: say the refusal is on the caller's last admin handle

* fix: defer only the folder rows the caller is an admin through

* docs: describe callerOwners as what the caller passes in

* docs: drop the call-site restatement of the diff's own invariant

* docs: record manager as a legacy group role

* fix: treat a sent request as possibly committed when reconciling

* fix: reconcile on any failed edit, and compare members as a set

* fix: keep write access when only the reconcile read fails

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 23:22:55 +02:00
Ruben Fiszelandwindmill-internal-app[bot] cfcfe298dd feat(ai-chat): make reusable skills ai_skill resources you select per workspace (#10914)
* feat(ai-chat): make reusable skills ai_skill resources you select per workspace

* chore: pin the ee ref to the skill telemetry counters

* fix: address review findings on skill authoring, import and migration

* fix: enforce skill selection in read_skill and stop imports clobbering resources

* feat: carry format_extension from the hub into synced resource types

* fix: let an edit set or clear a resource type's format_extension

* fix: regenerate the sqlx cache and close the review round findings

* fix: close the round-2 findings on folder ACLs, cached sync and truncation

* refactor: make the skills migration non-destructive and use design-system inputs

* fix: close the round-4 findings on folder owners, startup sync and truncation

* fix: clear obsolete extensions, guard folder owners, and report skipped skills

* fix: honor explicit-null extensions and report same-type migration conflicts

* fix: scope skill actions to the committed workspace and paginate the listing

* fix: keep the drawer scoped to the live workspace and surface truncation

* fix: discard a skills refresh for a workspace the chat has left

* chore: update ee-repo-ref to 6efe7a73c745c2e1377a34498523c00d89010a3d

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

Previous ee-repo-ref: 55998c142bc72edd08532748af1974b16035658d

New ee-repo-ref: 6efe7a73c745c2e1377a34498523c00d89010a3d

Automated by sync-ee-ref workflow.

---------

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-09-01 12:51:27 +00:00
Ruben Fiszelandrubenfiszel 870f67121d chore(main): release 1.800.1 (#10910)
* chore(main): release 1.800.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-09-01 11:34:32 +02:00
Ruben Fiszel db0f004613 fix: keep windmill-indexer out of builds without tantivy (#10908)
* fix: keep windmill-indexer out of builds without tantivy

* chore: drop the vcpkg openssl-windows port from the other windows jobs
2026-08-31 22:50:21 +02:00
Ruben Fiszelandrubenfiszel 412eb90c0d chore(main): release 1.800.0 (#10888)
* chore(main): release 1.800.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-08-31 20:29:23 +02:00
716ce2ece0 feat: free AI tokens + home search/filter revamp (#10020)
* feat: add free Claude Opus tier with per-user token limit

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

* nit move alert

* Home AI Chat

* wire home ai chat

* auto send prompt

* refactor: remove keyboard arrow-navigation from home list

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

* feat: replace home search bar with unified FilterSearchbar

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

* feat: replace home quick tags with FilterSearchbar presets

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

* feat: add content filter to home FilterSearchbar with EE-gated content view

- Clear the kind filter by deleting the key (was showing a 'kind: null' tag on All)
- Remove the standalone Content button
- Add a 'content' filter; when set, render the Ctrl-K content-search view
  (ContentSearchInner) which shows text-match snippets and its own EE warning

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

* feat: disable home AI chat and prompt to configure AI when no model

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

* track cost instead of tokens

* nit

* fix: load copilot config on home so AI chat isn't wrongly gated

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

* Home page update

* nits

* example prompts

* nit

* feat: switch free AI tier to DeepSeek with daily cost budgets

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

* nit

* Move bottom buttons to HomeAIChat

* [ee] feat: surface free AI tier state and make its metering abort-proof

Makes the free Windmill AI tier legible to the user and closes an abuse hole.

Backend:
- AIConfig gains a response-only free_tier marker (skip_deserializing so a
  client can't store a forged one via edit_copilot_config). get_copilot_info
  keeps returning it once the grant is spent, so the client knows AI is off
  because the grant ran out, not because nothing was configured.
- Per-user grant becomes one-time (migration drops the day key from
  ai_free_token_usage); the daily table stays as the instance kill-switch.
- Reserve-then-reconcile metering (see EE commit) so a mid-stream disconnect
  can no longer dodge the usage report and get metered zero.

Frontend:
- copilotInfo carries freeTier; model settings show a "Free" pill and a
  usage meter that warns past 80%.
- The home chat and the session chat show a dedicated "you've used your free
  Windmill AI, add your own API key" state instead of the generic
  "no provider configured" one.
- A failed send re-fetches copilot_info so the exhausted state (and its
  banner) appears live, without a page reload.

Bumps ee-repo-ref.txt to the matching EE commit.

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

* feat: free AI usage meter reusing the context-usage gauge

Show free-tier spend with the same gauge as context usage instead of a
bespoke block:

- Extract the meter+tooltip into a shared UsageMeter; ContextUsageIndicator
  uses it, and a new FreeTierUsageIndicator renders it from
  copilotInfo.freeTier. Placed in the session-chat toolbar and next to the
  home-chat model settings; the old meter block in the model-settings
  dropdown is removed (the "Free" pill stays).
- Hide the context-usage bar while on the free tier so the free meter takes
  that slot.
- Refresh copilotInfo after every free-tier turn (AIChatManager finally) so
  the meter advances live and the turn that exhausts the grant flips to the
  exhausted state, instead of both only updating on reload. Gated to active
  free-tier users, so it costs nothing for configured-key users.

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

* docs: fix stale free-tier comments after DeepSeek/cost rework

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

* feat: always show context bar, replace free-tier meter with usage banner

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

* nit

* fix: atomic free-tier budget reservation (ee ref + sqlx)

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

* fix: keep CLI/MCP and Hub buttons unblurred on AI chat hover

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

* Add back arrow nav

* nit

* nit

* fix: three review P1s in the home AI chat & search

- AIChatManager: refreshFreeTierUsage now bails unless the global copilot
  state still belongs to the completing manager's workspace, so a warm
  session finishing after a workspace switch can't reload its (background)
  workspace over the active one's models/client/copilotWorkspace.
- HomeAIChat: block submission until the copilot config is loaded AND
  enabled (new `canSend`), so a prompt submitted during the unknown-config
  window isn't handed to a session that never sends it and silently lost.
  The disabled overlay still gates on config-loaded to avoid a flash.
- ItemsList: the content-search reload effect now depends on $workspaceStore
  so content results follow the active workspace instead of showing the
  previous one's.

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

* [ee] fix: harden the three home-AI-chat/search P1s after deeper review

Follow-up to the previous P1 commit; sharper review found the earlier guards
insufficient:

- refreshFreeTierUsage now compares against the most-recently-*requested*
  workspace (new copilotWorkspaceRequested in aiStore, set synchronously in
  loadCopilot), not the last-*resolved* one — otherwise a warm session
  finishing while a newer workspace's load is still in flight could win the
  monotonic token and restore its stale workspace over the one being loaded.
- The content-search view is keyed by workspace ({#key $workspaceStore}) so a
  switch remounts ContentSearchInner; late in-flight responses from the
  previous workspace can no longer land in the new one's component.

Backend (EE, via ee-repo-ref bump to 03ef0eb): the free-tier reservation now
also prices the worst-case input cap (at the cache-miss rate), and
enforce_free_tier_body rejects oversized prompts and pins n=1 — so an aborted
large-prompt request can no longer dodge the input bill that reconciliation
would otherwise charge.

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

* fix: exclude service accounts from the free AI tier

Free-tier eligibility was keyed solely on authed.email. Workspace admins can
create and impersonate arbitrary service accounts (synthetic *.sa.wm.dev
identities), each of which would receive its own one-time grant — letting one
tenant mint many grants and drain the instance-wide daily allowance. Skip the
free-tier fallback for *.sa.wm.dev identities.

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

* fix: activate free AI tier when clearing a workspace provider

edit_copilot_config returned AIConfig::default() when the saved workspace
config had no providers and no instance config existed; the frontend applies
that response immediately, disabling AI even though the free-tier key is
available. A later get_copilot_info (on reload) returns the synthetic free-tier
config, so clearing a provider behaved inconsistently until reload. Give this
response path the same free-tier fallback as get_copilot_info.

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

* fix: gate the home AI composer behind the global-AI dev flag

The "Build with AI" composer starts a session and navigates to /sessions, which
lives behind the same wm_dev_global_ai dev gate as the global AI chat. With the
gate off (the default), /sessions renders only its gate message, SessionWrapper
never mounts, and the queued prompt is silently dropped. Hide the home entry
point behind isGlobalAiEnabled() so it isn't exposed before the sessions gate
opens.

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

* [ee] chore: bump ee-repo-ref for deepseek-v4-flash price/model fix

Points at the EE commit that pins deepseek-v4-flash and its real prices
(pico-precision accounting).

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

* [ee] fix: provable byte bound for the free-tier input cap (ee-repo-ref)

Bumps ee-repo-ref to the EE commit that caps the raw request body byte length
directly (token_count <= byte_count is provable), replacing the unsafe
body.len()/2 token estimate that high-entropy prompts could beat.

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

* nit isGlobalAiEnabled

* empty commit

* fix(frontend): address Codex review on free-tier / home filters

- P1: home filters now sync from the URL reactively, so browser Back/Forward
  updates the chips, kind toggle and results (and clears keys dropped from the
  URL) instead of leaving them stale until the next filter edit.
- Free-tier banner buttons drop deprecated Button props (size/color/border
  variant) for unifiedSize + a supported variant.
- Condense refreshFreeTierUsage comments to a single race-condition constraint
  beside the guard.

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

* fix(frontend): hide empty kind badge on draft-only scripts

A draft-only script can carry an empty `kind`, which still isn't 'script' so the
row rendered a blue badge whose only content was capitalize('') — an empty pill
left of the "Draft only" badge. Guard the badge on a non-empty kind.

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

* feat(frontend): animate home tree-view group expand/collapse

Wrap each owner group's children in ResizeTransitionWrapper so height changes
animate. A slide transition only animates the initial mount, but a freshly-opened
owner fetches its rows and passes through a transient empty state before they land
— the ResizeObserver animates that second growth too. Nested TreeViews inherit the
wrapper's context and skip their own, so one observer per top-level owner animates
the whole subtree.

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

* feat(frontend): FilterSearchbar boolean auto-set and string-filter presets

- A default-false boolean filter has only one useful value, so selecting it sets
  true immediately instead of opening a true/false picker. A default-true boolean
  (e.g. "Include library scripts") still shows the picker, where false is the
  meaningful choice — expressed via a new optional `default` on the schema.
- A plain string filter now surfaces any presets targeting it (`<tag>:<value>`)
  as suggestions once selected, integrated into menuItems so keyboard nav works —
  previously selecting e.g. "Owner" showed nothing.

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

* feat(frontend): home page toolbar and content-filter revamp

- "New" create-menu button (scripts/flows/apps/…) replaces the old Content button;
  the search bar moves to the right of the toggle group.
- Restore the content filter dropped in a merge: a `content` searchbar filter swaps
  the list for the full-text ContentSearchInner view (EE), aligned flush with -mx-2.
- Move the owner/group and label chips off the page into FilterSearchbar presets;
  ownerFilter/labelFilter now derive from the searchbar keys (data layer unchanged).
- Move the list controls (select / tree view / expand-all / sort) inline into the
  top row between the toggle group and search bar; add margin above the list.
- Beta tag on the home AI chat; a bit more bottom margin under it; tighten the gap
  between the admin/tutorial banners and the list.

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

* fix(ai): pass the request body to the free-tier reservation

Thread the prompt body into resolve_free_tier_credentials so the free tier can size its
upfront reservation from the actual request length instead of a fixed worst case (EE
c2e248b), fixing normal chats being rejected as "too large". Updates the OSS stub signature
and bumps ee-repo-ref.

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

* fix(frontend): gate home Create/Import menu on edit permissions

The relocated CreateActionsMenu rendered unconditionally, so operators and users in
workspaces protected from direct deployment saw create/import actions they can't use.
Restore the original gate (!operator && showEditButtons, the latter from NoDirectDeployAlert).

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

* fix(frontend): address Codex review on filter searchbar

- P1: the boolean shortcut now goes through the same tag-insertion path as the normal
  branch, so it removes the typed search segment instead of leaving it as a stray
  free-text (_default_) term.
- Mark the Runs `show_future_jobs` filter default: true so selecting it opens the picker
  (false is the meaningful choice) rather than being a no-op.
- Home owner/label presets now emit the canonical `key:\ value` form so the applied-preset
  check matches after a reparse and can't re-offer a duplicate; update the suggestion
  extraction to strip the leading separator.
- Replace deprecated Button props (size/spacingSize/color) on the relocated list controls
  with unifiedSize.
- Fix stale comments: UsageMeter no longer claims a free-tier consumer; the home filter
  schema comment describes presets, not the removed ListFilters/label badges.

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

* fix(frontend): boolean filter shortcut sets value canonically

The round-1 shortcut baked `true` into the tag text, which merged into a following tag
(e.g. `archived:\ truekind:\ flow`). Instead remove the typed segment, set the value, and
reparse so the text is rebuilt canonically — no lingering free-text and no merge.

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

* docs(ai): restate free-tier caller identity contract in the OSS stub; bump ee-repo-ref

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

* fix(frontend): keep flanking tags separate when boolean shortcut drops a segment

Joining `before`/`after` directly fused the tags a removed mid-segment sat between
(e.g. `kind:\ flowsummary:\ bar`). Join with a space; reparse then canonicalizes. Also
trims the comment to the essential constraint.

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

* chore(ai): update sqlx cache for free-tier daily-day queries; bump ee-repo-ref

The reserve/reconcile daily-usage queries now bind the reservation day (EE change); refresh
their offline query cache and point ee-repo-ref at the EE commit.

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

* fix(ai): activate free tier when instance ai_config has no provider

An instance ai_config row won precedence just by existing, so an empty {} (valid via global
settings / declarative config) suppressed the free-tier fallback and left AI disabled — even
though build_copilot_settings_state already treats it as unconfigured. Apply the same
has_providers() check to the instance config in the proxy and edit_copilot_config paths.
Also refresh the sqlx cache for the reservation ceiling change and bump ee-repo-ref.

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

* fix(frontend): migrate legacy Home filter URLs to the searchbar keys

The old Home UI stored free-text in `search`, owner scope in `filter`, and could write
`kind=all`; the generic searchbar sync uses `_default_`, `owner`, and a kind enum without
`all`. Rewrite those params once before the sync reads the URL so shared/bookmarked links
restore, and drop `kind=all` which would otherwise wedge later filter edits.

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

* fix(ai): empty instance config in get_copilot_info; label user-disabled Home AI

- get_copilot_info returned any existing instance ai_config row before the free-tier
  fallback, so an empty {} disabled AI in the copilot-info UI even though the proxy now
  serves the free tier. Apply the same has_providers() gate here.
- The Home chat overlay said "No AI provider is configured" when the user had disabled AI
  in account settings (providers still present). Distinguish that state ("Windmill AI is
  disabled in your account settings") as the docked chat does, and drop the misleading
  workspace-config button in that case.

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

* chore(ai): drop redundant proxy service-account check; trim TreeView comment

The service-account exclusion now lives in the free-tier helper, so the proxy calls it
directly. Also condense the tree-view resize-transition comment to the essential reason.
Bumps ee-repo-ref.

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

* docs(frontend): the Home content filter is not EE-gated

ContentSearchInner loads the workspace's scripts/flows/apps/resources and matches their
contents client-side, so it works on any instance. Drop the misleading "(EE)" from the
filter label and the "EE indexer / off-EE fallback" comments.

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

* chore(ee): bump ee-repo-ref for free-tier pricing + exhaustion fixes

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

* fix(frontend): show disabled Home AI overlay statically, not on hover

The disabled-state overlay (reason + configure/add-key action) was opacity-0 and
pointer-events-none until group-hover, so keyboard and touch users saw an inert composer
with no visible remedy. Render it and the composer blur statically when disabled instead.

Also bumps ee-repo-ref for the trimmed free-tier comments.

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

* fix(frontend): give account-disabled Home AI overlay a recovery action

The account-disabled branch showed a reason but hid every action, on the mistaken premise
that account settings has no linkable route. It opens from the #user-settings hash (the
same one the sidebar Account menu uses), so link there. Bumps ee-repo-ref for the
free-tier fixes.

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

* fix(frontend): gate Home AI composer for operators; a11y and filter-sync fixes

- Home composer now uses prefersSessionHandoff($userStore?.operator) instead of
  isGlobalAiEnabled(): operators reached this route and could submit a prompt into a
  /sessions page that refuses them, silently dropping it. Also drops the leftover empty
  header spacer div above the chat.
- HomeAIChat: mark the blurred/disabled subtrees inert so keyboard users can't tab into
  the unreadable textarea (pointer-events-none didn't stop Tab).
- ItemsList: keep the role-dependent searchbar keys (include_library, only_user_folders)
  in the schema unconditionally and toggle `hidden` instead, so useUrlSyncedFilterInstance
  (which snapshots the key set once) still URL-syncs a key that first appears after a
  workspace switch.
- Bumps ee-repo-ref for the indexer non-parquet build fix.

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

* fix(frontend): keep CLI/MCP connect row for operators; trim filter comment

The previous commit gated all of HomeAIChat behind the operator/session check, which also
removed the AI-independent CLI/MCP "Connect workspace" drawer that operators (and the
sessions-beta opt-out) had on main. Render HomeAIChat for the same audience as before
(isGlobalAiEnabled) and gate only the composer (title, input, examples, overlay) on
operator status inside the component; the connect row always shows. Also trims the
role-dependent filter-schema comment to the <=4 line rule.

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

* fix(frontend): reconnect Home keyboard navigation to the unified searchbar

The searchbar migration replaced the <input id="home-search-input"> the ItemsList keyboard
handler keys off, so Arrow/Enter no longer drove the results list. Thread an `id` down to the
searchbar's contenteditable (via TaggedTextInput/FilterSearchbar `inputId`) so the handler and
the workspace-switch focus restoration find it again; read the caret through the Selection API
instead of an <input>'s selectionStart/End; and stand the list's arrows down while the
searchbar's suggestion dropdown is open (tracked via onDropdownVisibleChange). In free-text
mode the searchbar no longer opens its dropdown on a bare arrow key, so an empty box passes
Arrow/Enter to the list as before.

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

* fix(frontend): stop searchbar Enter inserting a newline; idle typewriter for operators

- TaggedTextInput is a single-line filter input, so Enter now preventDefaults the
  contenteditable's newline insertion (surrounding suggestion-select / list-open handlers
  still run on bubble). Previously Enter with no row highlighted dropped a literal \n into
  the query.
- HomeAIChat's placeholder typewriter effect now runs only while the composer is shown, so
  it no longer loops forever driving an unrendered input for operators.

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

* chore: update ee-repo-ref to f2a31156ac08ecb02d89dbc66d72be58e9c877ff

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

Previous ee-repo-ref: e59b96a2eea5d1110b40c842f17b337ab051bdd3

New ee-repo-ref: f2a31156ac08ecb02d89dbc66d72be58e9c877ff

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-08-31 20:09:53 +02:00
0c2eb0ae3d perf: add service log documents to the index one batch at a time (#10906)
* perf: add service log documents to the index one batch at a time

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

* chore: update ee-repo-ref to df60763d1f243b0048dfc3fe700bc026b257bea8

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

Previous ee-repo-ref: f9a0b98080eecdc2885720e0f8506933a0675bb5

New ee-repo-ref: df60763d1f243b0048dfc3fe700bc026b257bea8

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-08-31 16:08:19 +00:00
Ruben Fiszelandwindmill-internal-app[bot] 831370cdde fix: harden the service log indexer's recovery and read paths (#10904)
* [ee] fix: an unreadable ingest cursor should not stop the server booting

Three follow-ups to #10894, all in the service log indexer: a corrupt cursor no
longer takes the server down at boot, the queue's writes are covered against a
real database rather than by hand, and a read skips the dedupe when the partition
it reads holds a single object.

* [ee] test: place the queue's rows relative to the clock the statement reads

Also drops the two `.sqlx` entries the query extraction orphaned: sqlx keys on the
literal including its indentation, so moving a query into a function leaves the
old copy behind.

* [ee] test: make the pair-exactness and rebuild-dedupe tests actually bite

* [ee] docs: state the cursor and dedupe rules without their history

* chore: update ee-repo-ref to 90a368362896ebcc2fcfaaf9510dc9be68c929f7

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

Previous ee-repo-ref: e3423705aa8f2d585bc65474cfd0c4c762ec4ad5

New ee-repo-ref: 90a368362896ebcc2fcfaaf9510dc9be68c929f7

Automated by sync-ee-ref workflow.

---------

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-08-31 16:01:28 +00:00
aa4a6ffd66 fix: track outstanding service log files on the rows themselves (#10894)
* fix: track outstanding service log files on the rows themselves

Adds `log_file.indexed_at` so the service log ingest can read outstanding rows
instead of walking a cursor over `log_ts`. A row registered after the pass had
gone by its minute was skipped for good, and no ordering fixes that — an arrival
sequence fails the same way, since a row can take a lower value and commit after
a higher one has moved the cursor past it.

The migration marks existing rows with a sentinel; the first pass returns the
ones the old cursor had not reached to the queue.

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

* [ee] refactor: drop the claim/confirm phase from the service log ingest queue

Two states are enough: a row is outstanding or it is marked. The migration no
longer creates the index for the claim sentinel, and the sqlx cache loses the
two queries the event-time cursor used.

* [ee] fix: make re-indexing a service log file idempotent

Corrects the `init_last_log_file_sent` note: a rewritten row keeps the
`indexed_at` it had, so one the indexers already took is not offered again.

* [ee] fix: let a rebuild take the rows it covered out of the ingest queue

Adds the query that releases them; the index layout stays v4.

* [ee] fix: index the lookup a rebuild releases rows by

A rebuild takes rows out of the queue by the file it read out of the store, which
is the one lookup that arrives without a `log_ts`. The primary key is
`(hostname, log_ts)`, so nothing covered it and each batch scanned every
outstanding row — worst in exactly the state a rebuild follows. Verified at 50k
outstanding rows: sequential scan becomes an index scan.

Also records `log_file.indexed_at` in the schema reference.

* [ee] fix: treat a state handed back without its line count as behind

* [ee] fix: give the converted state a line count

* [ee] fix: keep the converted cursor from being rewound by the rebuild

* [ee] fix: inherit the legacy cursor from one source, not field by field

* [ee] fix: count a file's lines against the buffer before reading it

* [ee] fix: bound the row buffer on what it holds, not on reported counts

* [ee] fix: settle the upgrade from the store rather than from event time

* [ee] docs: describe the conversion's second half as it now works

* [ee] refactor: settle the upgrade with one rebuild instead of reconciling

The migration records existing rows as done rather than marking them with a
sentinel: the indexer puts back what the old cursor had not reached on its first
pass, which is the only place that cursor's position is known.

* [ee] fix: repair the rows the old cursor skipped instead of recording them as done

The migration marks pre-existing rows with a sentinel again, so the indexer can
tell them from rows registered since and put the window's worth back on the queue.

* [ee] fix: keep a source file whole in one partition

* [ee] revert the file-atomic partition change

* [ee] fix: dedupe the public reads, and repair an index without a cursor

* [ee] fix: repair an index whose cursor is gone, and keep what the repair found

* [ee] fix: seed a pass from both axes of what a rebuild recovered

* [ee] fix: settle the cursor on what the store holds, not on what was read

* [ee] fix: an empty rebuild must not claim ground it has not covered

* [ee] test: pin the cursor a rebuild settles on

* chore: update ee-repo-ref to bc0c7051585194474078b6c1941a3fb73893d9e5

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

Previous ee-repo-ref: 328f5a90afeae9c683bf3294f0d9eb293a3e1a92

New ee-repo-ref: bc0c7051585194474078b6c1941a3fb73893d9e5

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-08-31 14:06:29 +02:00
Ruben Fiszelandwindmill-internal-app[bot] 2fb790338d upgrade argon2 to 0.6 and migrate the password hashing API (#10902)
* fix: upgrade argon2 to 0.6 and migrate the password hashing API

* test: pin that an unparseable stored hash reads as a failed login

* chore: update ee-repo-ref to 58738c39ac41d57917bbd9400318704763d997f7

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

Previous ee-repo-ref: 02a89fc4d27e49a494112fa91a8812e3ee4fb8a6

New ee-repo-ref: 58738c39ac41d57917bbd9400318704763d997f7

Automated by sync-ee-ref workflow.

---------

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-08-31 08:48:27 +02:00
Ruben FiszelandClaude Opus 5 ac56586c0e fix: correct the service log ingest flush boundary (#10898)
Claude-Session: https://claude.ai/code/session_014KnE8my2okxQGCx47cWMjf

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-30 07:40:34 +02:00
d91ee4614a feat: day-partition the service log index and expire whole chunks (#10893)
* feat: day-partition the service log index and expire whole chunks

The service log index becomes one tantivy index per UTC day. The substance is
in windmill-ee-private#753; this side carries the EE ref and moves the log
indexer writer instead of cloning it, because sealing a chunk takes sole
ownership of its tantivy writer.

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

* fix: do not adopt the superseded watermark after an explicit index clear

A clear asks for the retention window to be read again, and a watermark says
it already has been — and the v3 copy in object storage is kept for rollback,
so it outlives the local one the clear removes. Both copies of that watermark
are now read and the newer wins, for the same reason the v4 one is taken from
the store when it is ahead: a replica that lost the lock keeps a local file
frozen where it stopped while the store went on.

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

* fix: delete a day's raw files at its checkpoint, and rebuild whole days

Bumps the EE ref for windmill-ee-private#753.

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

* fix: make an interrupted rebuild detectable, and pin the rebuild floor

Bumps the EE ref for windmill-ee-private#753.

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

* fix: keep the rebuild marker in the object store, not on local disk

Bumps the EE ref for windmill-ee-private#753.

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

* fix: two more routes to a partial index being accepted as complete

Bumps the EE ref for windmill-ee-private#753.

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

* fix: trust a local chunk only when the tracker vouches for it

Bumps the EE ref for windmill-ee-private#753.

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

* chore: condense the stale-chunk guard's doc to the four-line limit

Bumps the EE ref for windmill-ee-private#753.

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

* chore: update ee-repo-ref to 17ef439b087b400889ff19109be9d2c810142278

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

Previous ee-repo-ref: 3e79901b4742906d2285dd943e24fac0f735f199

New ee-repo-ref: 17ef439b087b400889ff19109be9d2c810142278

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-08-30 07:16:09 +02:00
Ruben FiszelandClaude Opus 5 7639d83a42 chore: bump ee-repo-ref to the merged EE main (#10896)
windmill-ee-private#756 was squash-merged, so the commit ee-repo-ref names is not on EE main
and the branch carrying it is gone. The content is identical, so nothing builds differently —
but a dangling ref is one garbage collection away from an EE build that cannot fetch what it
is pinned to.


Claude-Session: https://claude.ai/code/session_01WsnpNSM6K3oyjwntRwJtVN

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 19:45:12 +02:00