Commit Graph

14331 Commits

Author SHA1 Message Date
AlexRV12 9653eab493 feat: show the session plan as a segmented bar in the session header 2026-08-11 13:59:12 +02:00
AlexRV12 da4b0211a6 feat: give session chats create/update/list task tools 2026-08-11 13:59:12 +02:00
AlexRV12 4059bf8211 feat: persist a per-session AI task list in IndexedDB 2026-08-11 13:59:12 +02:00
AlexRV12 26f7ec9661 test: wait for the session record instead of a tick before rehydrating 2026-08-11 13:59:12 +02:00
Ruben Fiszel ec99108cf6 feat(triggers): nested filter groups and dotted paths (#10625)
* feat(triggers): nested any_of / all_of filter groups

A trigger filter entry can now be a group — `{"any_of": [...]}` or
`{"all_of": [...]}` — nesting further entries, so criteria like
`A AND B AND (C OR D)` are expressible. Existing flat `{key, value}` lists keep
their meaning, combined by the trigger's `filter_logic` as before.

Filters are compiled once per connection: the set of top-level keys the whole
tree references is collected up front, so a message is parsed in a single
streaming pass that captures only those keys, instead of one full pass per leaf
filter as before. Filters that fail to parse are now logged rather than dropped
silently, since a nested group is easier to mistype than a flat entry.

The editor gains "Add group", rendering groups recursively with their own
AND/OR selector; Kafka and WebSocket triggers share it.

Fixes WIN-2345

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

* fix(triggers): drop empty filter groups instead of evaluating them

A group with no criterion cannot evaluate to a constant: true makes an `or`
filter list accept every message, false mutes an `and` list. Two clicks in the
editor ("Add group", save) produced one. Drop it when compiling so its siblings
stay in force, and reject at save time the filters the listener would otherwise
drop silently.

Also restore the item shape of `$ref`-typed arrays in the generated agent
schemas: the extractor only resolved refs at the property level, so moving
`filters.items` to a shared schema flattened it to a bare object. Resolving them
inside `items` too also recovers the shapes `initial_messages` and the MQTT
`topics` had already lost.

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

* fix(triggers): name the offending entry when a nested filter is invalid

Serde's untagged error only reports that the outermost entry matched no
variant, whatever depth is actually wrong, which defeats the point of
validating a group at save time. Walk the tree instead and report the path.

Normalize the WebSocket editor's filters to [] on load, as the Kafka editor
does, so the list component can rely on an array.

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

* fix(triggers): key filter rows by node so deletion keeps values aligned

The value editor seeds itself from `code` once, so an index-keyed row reused
for a different filter kept showing the deleted row's value.

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

* chore: bump ee-repo-ref after merging main

The merge pulled OSS code that needs EE symbols newer than the companion
branch's base, so the companion was merged with EE main too.

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

* perf(triggers): keep filter short-circuiting from materializing unread fields

The single-pass scan deserialized every referenced key before the boolean tree
ran, so an AND whose first leaf rejects the message still allocated the large
objects the later leaves name — the shape this feature exists for. Borrow the
wanted keys as raw slices during the scan and parse a field only when
evaluation actually reaches it.

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

* feat(triggers): none_of filter group

Negation of a nested group, so a trigger can exclude what it must not react to
without inverting every other criterion. A key the message does not carry
satisfies it: there is nothing there to match.

Only groups can negate — the root's operator is the trigger's filter_logic
column, which has no value for it.

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

* feat(triggers): address a nested field with a dotted path

`{path: "a.b.c", value: v}` alongside the existing `{key, value}`, so the common
case reads the way people write it instead of nesting the shape into the value.
A separate field rather than dots in `key`, which already means the top-level
field spelled that way — overloading it would resettle what existing triggers
over flattened payloads match.

Paths address objects only for now: a path through an array does not match
rather than guessing an element, and array containment stays on the value side.

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

* docs(triggers): mention none_of in the filter_logic description

Plus a test for the empty-path-segment rejection, which had none.

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

* chore: update ee-repo-ref to 78859aab0c6e78283ec8d2b37e8c410963afdc83

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

Previous ee-repo-ref: 0e42ba72ccc38a6b0a380f58afe0db36d284f4c9

New ee-repo-ref: 78859aab0c6e78283ec8d2b37e8c410963afdc83

Automated by sync-ee-ref workflow.

* fix(triggers): reject a criterion naming both key and path

The untagged enum takes such an entry as a `key` criterion and drops the
`path`, which is the silent-ignore the save-time validation exists to prevent.

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

* refactor(triggers): drop the label next to the key/path toggle

The toggle already shows which one is selected.

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

* fix(triggers): reject an entry that combines a criterion with a group

Generalizes the key+path fix: the untagged enum settles a half-and-half entry
on the first variant that fits and ignores the rest, so a criterion carrying a
group key lost the whole subtree without a word.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-08-11 11:07:12 +02:00
hugocasa 5125467de4 fix: accept a bodyless request that advertises a JSON content type (#10628)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 10:28:43 +02:00
Ruben Fiszel 4fafe59371 fix: bump the bundled DuckDB engine to 1.5.5 (#10588)
* fix: bump the bundled DuckDB engine to 1.5.5

The 1.5.5 duckdb crate no longer hands back a 96-bit `rust_decimal`, so a
DECIMAL wider than that renders instead of panicking inside an `extern "C"`
frame — which, being unable to unwind, aborted the whole worker process and
left the job running as a zombie. `SELECT
'1234567890123456789012345678.9012345678'::DECIMAL(38, 10)` was enough.

Adapting to the crate's API: `Value` is now `#[non_exhaustive]` and gained
`UHugeInt` and `Geometry`, and `rust_decimal` became an optional feature that
the `decimal`/`numeric` argument path still needs.

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

* fix: address review findings on the duckdb bump

Run the FFI crate's own tests in CI: it is excluded from the workspace, so the
`cargo test --all` in backend-test never reached them and the new guard against
the worker-aborting DECIMAL would not have run. build_dev.sh now honors a
caller-pinned CARGO_TARGET_DIR so the test build reuses that compile instead of
building the bundled engine a second time.

Also pin UHUGEINT rendering, and correct the rust_decimal rationale —
`Decimal::new` is public without the feature, so the reason is that the feature
reproduces the exact binding the crate used to derive, not that nothing else can.

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

* fix: address review nits on the duckdb bump

Name the unsupported DuckDB type rather than dumping the value, which may be
arbitrarily large or hold data that does not belong in an error message, and
say which column it came from.

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

* chore: pin the ee ref to the narrowed duckdb extension allowlist

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

* chore: pin the ee ref to the verified duckdb extension allowlist

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

* chore: pin the ee ref to the allowlist regression test

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

* chore: update ee-repo-ref to 04dd9c5c352f04995cd0470400a877261f956561

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

Previous ee-repo-ref: fe7eb440a5bbae37774d3a96b69ab5c46c0b8936

New ee-repo-ref: 04dd9c5c352f04995cd0470400a877261f956561

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-11 09:34:27 +02:00
Ruben Fiszel ede4e7781d unbreak the JSR publish of the typescript client (#10627)
* fix(sdk): unbreak the JSR publish of the typescript client

`Sql` is `export type Sql = string`, but build.jsr.sh re-exported it as a
value, so `deno publish` fails type-checking with TS1205 under
isolatedModules. Every `v*` tag since has published nothing to JSR.

The npm build never noticed because it lists the same symbol as `type Sql`;
the two scripts keep separate copies of the export list.

Record both JSR-only constraints next to the list, since neither shows up
until a release tag runs publish.jsr.sh.

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

* fix(sdk): scope the slow-types note to what deno actually rejects

Deno's fast check only rejects a return type it cannot trivially infer;
setClient, appendToResultStream and streamResult are all exported without
one and publish fine. The previous wording read as if the current list were
already non-compliant.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 09:24:47 +02:00
Ruben Fiszel d9b9137e17 feat(sdk): add cancelJob to the TypeScript client (#10624)
* feat(sdk): add cancelJob to the TypeScript client

The Python client has had cancel_job since forever; the TypeScript one had no
way to cancel a job at all. Wire the same jobs_u/queue/cancel endpoint, with a
default reason when none is given, and export it from both the named and
default exports of the npm package as well as the JSR one.

* chore: regenerate system prompts for cancelJob

check-system-prompts triggers on typescript-client/**, so the agent-facing SDK
reference has to carry the new function.

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

---------

Co-authored-by: Tushar <tusharanshu18@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 08:45:48 +02:00
Ruben Fiszel 13b521651b fix(python-client): return at most size bytes from S3BufferedReader.read (#10623)
* feat: add unit tests for S3BufferedReader.read and improve read method implementation

* feat: refactor S3BufferedReader.read method and add unit tests for its functionality

* feat: implement peek() on S3BufferedReader with buffered reads

* fix(python-client): keep the read(size) contract and trim the test surface

Drop the duplicated `TestS3BufferedReaderRead` class from
`python-client/tests/wmill_client_test.py`: CI runs `pytest tests/` from
`python-client/wmill`, so that legacy manual harness never executes, and the
same assertions already live in `python-client/wmill/tests/test_s3_reader.py`.

Narrow that file to the four behaviours a future change could break, and make
the `bytes_generator` guard actually call `bytes_generator`.

Align `peek()` with `io.BufferedReader.peek`, which does at most one read on
the underlying stream, rather than looping until `size` bytes are buffered.

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

* fix(python-client): hold read1 to one underlying read

read1 forwarded to read, so read1(-1) drained the whole object — the same
unbounded buffering this branch removes from read. Now that a buffer exists,
read1 can honour its own contract: fill only when the buffer is empty, then
serve from it.

Also treat read(None) as read(-1), per the BufferedReader contract, and pin
that read(0) does not pull from the stream: that holds only because the
drain sentinel is a negative size, and widening it to any falsy size would
reintroduce whole-file buffering.

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

* fix(python-client): return from read1(0) without touching the stream

A zero-length read has nothing to serve, so pulling a chunk to satisfy it
both wastes a round trip and advances the stream. Guard it ahead of the
fill, and pin it with a chunk source that counts pulls.

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

---------

Co-authored-by: Tushar <tusharanshu18@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 23:04:27 +02:00
hugocasa 06c6b8780c fix: scope a fork's cloned app policy and custom path to its creator (#10595)
* fix: scope a fork's cloned app policy and custom path to its creator

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

* fix: gate a cloned anonymous app on the parent's own deployment rule

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

* docs: state why a cloned anonymous app is gated more strictly than create_app

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

* style: wrap an over-long comment line in clone_apps

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

* fix: clone an app's execution_mode unchanged

Forcing `publisher` on a cloned app was a speed bump rather than a boundary:
protection rules are workspace-scoped and are not cloned, so the fork's creator
can publish an anonymous app there with no rule in the way. It was also the one
policy field a deploy back to the parent carries verbatim, since `update_app`
recomputes the identity but writes the policy wholesale, so a fork's copy could
silently close the parent's public endpoint.

The identity rewrite is what closes the hole this addresses: the fork's endpoint
no longer runs as whoever the parent published it as.

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

* fix: ignore an app's run-as identity when comparing workspaces

`compare_two_apps` hashed the whole policy, so a fork whose apps were re-pointed
at their creator reported every one of them as changed. Nothing could clear those
entries: the deploy offers the target's current identity, the deployer's, or a
typed-in one, never the source's, so the difference survives however many times
the item is deployed. `script` and `flow` already compare no identity.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 22:59:21 +02:00
Ruben Fiszel cf3ddaa3cc chore(main): release 1.784.0 (#10603)
* chore(main): release 1.784.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.784.0
2026-08-10 22:56:55 +02:00
hugocasa 5ed846abd2 chore: internal accounting update (#10602)
* chore: bump ee ref and refresh query cache

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

* chore: bump ee ref

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

* chore: bump ee ref

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

* chore: bump ee ref

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

* chore: bump ee ref

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

* chore: update ee-repo-ref to 236115e11f074d86675aa5acdf5061dd3e64f43c

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

Previous ee-repo-ref: 62bc50118d09374b8a45756504520cfb6e5f0210

New ee-repo-ref: 236115e11f074d86675aa5acdf5061dd3e64f43c

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>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2026-08-10 21:55:09 +02:00
Ruben Fiszel 2748d019f5 fix(cli): load the app's ESM svelte compiler, not its CJS one (#10622) 2026-08-10 21:50:03 +02:00
hugocasa c09de594b6 feat: version resource values with history, diff and restore (#10596)
* feat: version resource values with history, diff and restore

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

* fix: record resource versions in a trigger so direct writes are covered

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

* fix: show the selected version's value and tighten history write access

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

* perf: gate resource version recording in trigger WHEN clauses

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

* feat: clear a resource's past versions, and address review nits

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

* fix: restore the displayed version and keep author attribution on pooled writes

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

* fix: scope history to the selected workspace and gate clearing on ownership

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

* fix: gate restore on write access and clearing on the signed-in workspace

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

* refactor(frontend): share the version-history row between script and resource drawers

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

* perf: trim resource version history in the monitor sweep, not on write

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

* fix(frontend): match the script versions drawer shell for resource history

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

* perf(frontend): highlight version values instead of mounting monaco

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

* fix(frontend): match the script drawer's code preview presentation

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

* fix: rank version trim in one windowed pass instead of a correlated delete

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

* refactor(frontend): treat the newest version as current by position

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

* perf: gate the resource version trim to an hourly sweep

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

* fix: unnest the version row action and correct the trim cadence docs

* perf: cap the history listing and use sets for reference lookup

* feat: warn when a resource is written more than 60 times a minute

* fix: lower the resource write advisory to 20 per minute

* fix: discard stale history loads and never diff against an unread value

* fix: correct the write advisory boundary and document the eviction lock

* fix: read history and the live value from one snapshot

* refactor: read the drawer's diff baseline from versions, not the live resource

* fix: open the history drawer with no version selected

* fix: disarm the clear confirmation and clear the pane when the selection moves

* fix: explain the missing diff and drop a guard that can no longer fire

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 21:32:18 +02:00
Ruben Fiszel 5b0a159a01 fix(smtp): explain why a test email failed instead of 'deadline has elapsed' (#10620)
* fix(smtp): explain why a test email failed instead of 'deadline has elapsed'

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

* fix(smtp): keep non-SMTP error codes and retire a stale test alert

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

* chore: update ee-repo-ref to f0df8b82c4c089d384423ed64b8504506084820d

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

Previous ee-repo-ref: 1ffaf3dea81e007c6c11146c1e12e97e83f5b938

New ee-repo-ref: f0df8b82c4c089d384423ed64b8504506084820d

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-10 21:21:14 +02:00
Vladislav Kuzmin bf1b2cdcf9 fix(duckdb): cast list columns in quicksearch so tables containing them can be previewed (#10614)
* fix(duckdb): cast columns in quicksearch so nested types can be previewed

DuckDB's `CONCAT` implicitly casts scalars but rejects nested types:

    D SELECT CONCAT(' ', ['a','b']);
    Binder Error: Cannot concatenate types VARCHAR and VARCHAR[] - an explicit
    cast is required

Quicksearch concatenates every visible column, so one LIST, STRUCT or MAP column
makes a table impossible to preview — both the grid and its row count fail:

    Binder Error: Cannot concatenate types VARCHAR, VARCHAR, BIGINT, ...,
    VARCHAR[], ... and TIMESTAMP WITH TIME ZONE - an explicit cast is required
    LINE 1: ... FROM "raw"."accounts" WHERE ($1 = '' OR CONCAT(' ', "id", ...

Every scalar in that list concatenates fine on its own — VARCHAR, BIGINT,
DOUBLE, BOOLEAN, DATE and TIMESTAMPTZ were each checked individually — so the
array column is the entire cause.

Cast each column in the predicate. The comparison is textual either way, so no
result changes, and the projection is untouched: casting there would change the
types the caller reads back. This follows the shape already used for MSSQL in
`mssql_needs_cast_for_eq`.

Both DuckDB quicksearch sites are covered, SELECT and COUNT. Fixing one leaves
the grid rendering while the row count still errors.

Tests include the live path: the Database Manager sends a
`-- WM_INTERNAL_DB_SELECT {...}` marker and the backend expands it, so the new
test drives that expansion with the real 27-column definition captured from a
failing job, `sync_id VARCHAR[]` included. It fails without the fix and passes
with it.

* fix(frontend): cast columns in the DuckDB quicksearch

Same defect as the Rust query builders, in the implementation that actually
runs. `make_select_query` / `make_count_query` in windmill-common have no callers
anywhere in the repo; the query the browser sends is built here.

DuckDB's CONCAT implicitly casts scalars but rejects nested types, and
quicksearch concatenates every visible column, so one LIST column makes a table
impossible to preview — both the page and its row count fail with

    Binder Error: Cannot concatenate types VARCHAR, ..., VARCHAR[], ... and
    TIMESTAMP WITH TIME ZONE - an explicit cast is required

The helper lives in select.ts and is imported by count.ts so the two cannot
drift, and both call sites are fixed: fixing only SELECT leaves the grid
rendering while the row count still errors.

* fix(duckdb): cast only list columns in quicksearch, leaving other SQL byte-identical

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

* test(frontend): pin the DuckDB quicksearch column list byte-for-byte

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

---------

Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 20:48:19 +02:00
Ruben Fiszel 8c65511e81 fix: raw app new-app modal ignores instance-level AI settings (#10619)
* fix: stop the new raw app modal claiming AI is unconfigured before it knows

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

* fix: require a resolved workspace before trusting the loaded AI config

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

* fix: drop the unreachable token guard and point superadmins at instance settings

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

* fix: show the instance settings link to superadmins who are not workspace admins

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 20:39:38 +02:00
Ruben Fiszel b7d2052b03 block the whole 0.0.0.0/8 range in the SSRF filters (#10597) 2026-08-10 19:57:29 +02:00
AlexRV12 77adf85ccd feat: version history for session artifacts (#10574)
* fix: never replace an in-flight indexeddb open, only a settled one

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

* feat: keep a version history for session artifacts

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

* feat: let the assistant browse an artifact's earlier versions

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

* feat: pick an older artifact version from the preview panel

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

* test(ai_evals): cover the change note the assistant writes on each edit

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

* fix: bound every indexeddb open, not only one told it is blocked

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 19:51:29 +02:00
Ruben Fiszel 4a69cd616e keep the logins state declaration from narrowing to undefined (#10618) 2026-08-10 19:45:27 +02:00
Ruben Fiszel 9eef70ea8b fix(cli): attach the right job path to preview runs (#10606)
* fix(cli): attach the right job path to preview runs

* fix(cli): keep a deliberately-absent file in the directory it was named in

* fix(cli): resolve links for a path naming a file that is not there
2026-08-10 19:37:46 +02:00
Ruben Fiszel c725d62fb0 fix(frontend): call a dev workspace a dev workspace in the merge UI (#10605)
* fix(frontend): call a dev workspace a dev workspace in the merge UI

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

* refactor(frontend): drop the unreachable dev-workspace guard on the fork modals

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 19:30:24 +02:00
Guilhem 85916cedf8 fix: order workspace members and invites by email (#10604)
`list_users` and `list_pending_invites` had no ORDER BY, so Postgres returned
rows in heap order. An UPDATE rewrites the row at the end of the heap, which
sent the member whose role was just toggled to the bottom of the list the
settings page refetches right after.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 19:26:25 +02:00
Ruben Fiszel 1a709d49f9 unblock the frontend check (type error + svelte-check OOM) (#10617)
* fix(frontend): count login options inside a closure so tsc keeps their type

* ci: give svelte-check a heap above node's 4GB default
2026-08-10 19:25:02 +02:00
Guilhem 676256bacc feat(flow-editor): measure step panel placement (#10543)
* feat(flow-editor): measure the redesigned step panels

Instruments the flow editor's step, loop and branch panels on the existing
anonymous `feature_usage` channel, so the redesign can be judged on how the
panels are actually used rather than on nothing.

Eight event kinds under a new `flow_editor` feature: panel opens and their
dwell (bucketed, per placement), placement-preference overrides, which
settings get configured or cleared, settings that read as invalid, the
prop-picker connect lifecycle, AI input suggestions, and the step header
menu that "Save to workspace" now lives behind.

Settings changes are diffed off `describeStepSettings`, the same view the
graph badges render, so the telemetry vocabulary cannot drift from the one
on screen. Only `panel_open` and `setting` carry an entity id — one opaque
id per editor mount — since a per-entity row is only worth its cost where
the spread per editing session is the question.

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

* fix(flow-editor): keep the panel telemetry honest

Review follow-ups on the instrumentation:

- The top dwell bucket was `120s+`, and `+` is outside the charset
  `is_identifier_shaped` accepts, so `log_feature_usage` skipped those
  events and still answered 204 — the longest visits vanished with no
  error on either side. Renamed to `120s_plus` and pinned every emittable
  key against the backend's charset in a test, since the producer is
  TypeScript and the validator is Rust.
- Dropped the per-session entity id from `setting`: it would pay a row per
  session per day across twenty-four keys, for a distribution its plain
  counter already largely answers.
- An armed connect that went away with its component never reported, so
  `open` did not balance against `insert` + `abandon`.
- Session preview tabs keep hidden editors mounted, which billed panel
  time nobody spent. `FlowEditorView` now publishes the visibility it
  already knows about.
- Re-picking the active placement row logged a move, which also made
  `auto:from_docked` mean two different things.
- The last dwell of a session was lost on tab close, since Svelte tears
  components down on navigation but not on `pagehide`.

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

* refactor(flow-editor): narrow the telemetry to panel placement

The eight-kind instrumentation measured more than could be read. With nothing
recorded before the redesign there is no baseline to compare panel opens, dwell
times, settings usage or connect funnels against, so those counters answered
questions nobody could act on while costing a row per key per day in an
instance-wide table.

What remains are the three numbers the modal panel is actually judged on: how
often the 1280px breakpoint puts the panel in a modal, and how often people
override that in each direction.

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

* fix(flow-editor): stop counting placement in session preview tabs

Preview tabs keep every flow editor mounted and laid out at panel width
whether or not it is the visible one, and that panel is narrower than the
breakpoint by construction. Each flow tab opened in a session therefore
emitted a `breakpoint_modal` on mount, and one drag of the session panel
across 1280px emitted one per mounted tab — with no host dimension in the
key to separate that from the crossings the counter exists to measure.

Also corrects the comment on the no-op placement guard, which justified
itself with a key vocabulary that no longer exists.

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

* fix(flow-editor): make the three placement counters comparable

Sessions were excluded from the breakpoint counter but not from the two
override counters, so a pin made in a session landed in the same bucket
used to judge the breakpoint, with no crossing in the denominator to read
it against. All three are now gated together.

An override is also only counted when it moves the panel. Choosing
"Detached" on an editor the width had already put in a modal states a
preference without changing anything, and the aggregate carries no width
to separate that from the wide-screen override that is the actual signal.

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

* docs(flow-editor): describe the two override keys by what emits them

They documented themselves as overriding `auto`, which is no longer the
rule: pinning Attached on a wide editor overrides `auto` and emits
nothing, while going from an Attached pin to Detached below the
breakpoint emits `force_detach` even though `auto` would have produced a
modal there too. This file is what someone reads when interpreting the
numbers, and "override of auto" is the misreading the emission rule
exists to prevent.

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

* fix(flow-editor): count the panel moving, not the breakpoint being armed

The tracker held "the breakpoint is responsible for this modal" rather
than "the panel is modal", so on a narrow editor pinning Detached and
releasing it back to Auto emitted a second breakpoint_modal for a panel
that never moved. It also died with the editor, which FlowBuilder rebuilds
through a `{#key}` on every reload — each rebuild re-armed it and counted
the same narrow editor again.

Both inflate the denominator that the two override counters are read
against, and both bias it the same way: toward concluding that nobody
overrides the breakpoint.

The tracker now follows the panel's placement across preference changes,
and FlowBuilder owns it from above the `{#key}`, which also puts the
session exclusion in one place instead of at each call site. The
moves-only rule moves into `forcedPlacementEvent` so both halves of it sit
in the module the tests can reach.

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

* fix(flow-editor): ignore placements measured before the editor is laid out

A reload rebuilds the editor through `{#key renderCount}`, and the panel
controller is rebuilt with it: its width restarts at zero, which resolves to
`docked` because that is what is safe to render rather than because the editor
is wide. The breakpoint tracker read that transient as the panel having docked
and counted the real width landing as a fresh crossing, inflating the
denominator both override ratios are read against.

`useFlowPanelMode` now exposes `measured`, and the tracker skips anything
unmeasured instead of recording it as a placement.

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

* docs(flow-editor): state the placement invariants once each

The width-zero rule had accumulated at four sites, two of which forward it
without being able to break it. Keep it beside the guards that enforce it.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 12:29:31 +02:00
Guilhem d638fab5f6 stack login options in one column below four (#10598)
* fix(frontend): stack login options in one column below four

* style(frontend): drop redundant w-full on login buttons
2026-08-08 00:07:23 +02:00
Ruben Fiszel 099efa358a chore(main): release 1.783.0 (#10578)
* chore(main): release 1.783.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.783.0
2026-08-07 12:41:05 +02:00
hugocasa 330175f83b Revert "fix: scope a fork's cloned app policy and custom path to its creator …" (#10592)
This reverts commit 8e95bfe615.
2026-08-07 12:39:44 +02:00
hugocasa 8e95bfe615 fix: scope a fork's cloned app policy and custom path to its creator (#10589)
* fix: scope cloned app policy and custom path to the fork's creator

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

* refactor: share the app custom-path scoping rule across its call sites

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

* docs: tighten the cloned-app-policy comments

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

* docs: correct the execution_mode and custom-path scoping rationale

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 12:37:04 +02:00
Ruben Fiszel 0459dda1bf correct typo in NATS consumer name description (#10585)
The consumer name field in the NATS trigger config read "Required is using
JetStream" instead of "Required if using JetStream", matching the wording
already used by the sibling stream name field.

Fixes WIN-2335

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 23:13:43 +02:00
Ruben Fiszel deaf1ca537 drop the unread npm lockfile, bun.lock is the CLI's (#10580)
* fix(cli): sync package-lock.json with package.json

`npm ci` fails in cli/ because the lockfile predates two manifest changes:
windmill-parser-wasm-yaml was bumped to 1.770.0 and windmill-yaml-validator
1.1.1 was added, neither of which reached the lockfile.

Regenerated with `npm install --package-lock-only`; the only entries touched
are those two packages and windmill-yaml-validator's transitive deps.

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

* fix(cli): drop the unread npm lockfile, bun.lock is the CLI's

Every install path in cli/ runs `bun install`: cli-tests.yml, git-sync-test.yml,
backend-test.yml, build.sh, and install_dev.sh (its --node branch installs the
generated npm/ bundle, which carries its own manifest). build-npm.ts synthesises
the published package.json from scratch, and change-versions.sh regenerates the
frontend and yaml-validator lockfiles but not this one.

So package-lock.json was read by nothing and verified by nothing, and drifted out
of sync with package.json unnoticed until `npm ci` refused to install. Deleting it
removes the second source of truth rather than hand-repairing it again on the next
bun-driven dependency change.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 23:05:28 +02:00
Ruben Fiszel 8c6211c277 feat: offer more dev workspace environment labels (#10570)
* feat: allow custom dev workspace environment labels

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

* fix: reject dev labels that shadow a tracked branch's namespace

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

* fix: guard dev labels against a repo's assumed default branch

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

* chore: state the badge-cap rationale once and drop unenforceable openapi constraints

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

* refactor: offer a fixed list of environment labels instead of free text

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

* fix: match the accepted label set to the openapi enum exactly

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

* docs: stop describing the label set as dev/staging only

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 18:32:19 +00:00
Ruben Fiszel 57ed0f77e1 fix(frontend): hide the fork workspace banner from operators (#10575)
* fix(frontend): hide the fork workspace banner from operators

* fix(frontend): scope the operator gate to the workspace its role was fetched for

* fix(frontend): drop superseded whoami responses instead of writing a stale role

* fix(frontend): guard the remaining workspace-switch userStore writers
2026-08-06 19:04:41 +02:00
Ruben Fiszel 3c1403ee09 trim narration comments and drop duplicated badge hover palette (#10579) 2026-08-06 17:40:01 +02:00
Guilhem d0089758e6 feat: open a session edit in the preview panel from the edits list (#10486)
* feat: open a session edit in the preview panel from the edits list

* refactor: move the deploy-kind preview mapping next to its siblings

* feat: make preview the primary action in the session edits list

Clicking a row in the Edits popover now opens the item in the session
preview panel; kinds the panel cannot host fall back to their diff. Each
row gains an explicit Diff button for that item, and a pinned footer row
opens Review & deploy for the whole set.

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

* refactor: fold the open-and-flash rule into SessionPreviewTabs

The rule for when a preview open should flash the tab was written out at
three call sites, one of them with a looser condition. Move it onto the
tab owner as openAndPulse so the three agree.

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

* feat: preview data-pipeline edits from the edits list

A pipeline bundle is stored at `f/<folder>/data_pipeline` while its editor
is the folder's pipeline view, so the deploy-kind mapping has to route on
the folder. Without it the one remaining previewable kind fell through to
the drawer. Also pin the open-and-flash rule with tests.

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

* refactor: state the pipeline bundle path layout once

`f/<folder>/data_pipeline` was parsed independently in the compare page,
the home list and the session preview mapping — two of them disagreeing on
whether the trailing segment is checked — and built by hand in the editor.
Route all four through $lib/pipelinePaths.

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

* refactor: route the pipeline page through the shared bundle path

The route built the bundle path by hand and passed the draft kind as a
literal, the two halves of the editor disagreeing on where the layout is
stated.

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

* fix: name a pipeline edit by its folder in the edits list

The bundle path is an implementation detail and the row's click lands on
the folder's editor, so showing `f/<folder>/data_pipeline` named something
the click doesn't open. Also derive the bundle regex from the draft-kind
const it has to agree with.

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

* chore(cli): drop unrelated package-lock.json change

The lockfile diff was an incidental regeneration from an older manifest
(it downgraded the locked svelte range below what cli/package.json
requires) and had nothing to do with this PR. Reset to main's version.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2026-08-06 17:37:03 +02:00
hugocasa c61404a0f4 feat: preview merge result in git-sync PR diff check (#10542)
* feat: preview PR merge result in git-sync diff check

* chore: update ee-repo-ref

* fix: match pr diff sentinels as structured field, tighten comments

* chore: update ee-repo-ref

* fix: neutral verdict for unfetchable pr head, testable sentinel parse

* chore: bump git-sync pull script pin to hub/28889

* chore: bump git-sync pull script pin to hub/28890

* fix: cover failed history deepening in unavailable-head check text

* chore: update ee-repo-ref to 181fa0c206d7f84a289b4396a7f7764bc815d284

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

Previous ee-repo-ref: 36f5c0e9d147f9eed63ebc316f2aef9f86b500af

New ee-repo-ref: 181fa0c206d7f84a289b4396a7f7764bc815d284

Automated by sync-ee-ref workflow.

---------

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2026-08-06 17:27:49 +02:00
hugocasa 4de1bf5beb refactor(recordings): build recordings from the completed run (#10571)
* refactor(recordings): build recordings from the completed run instead of live event capture

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

* fix(recordings): budget and isolate replay synthesis against hostile recordings

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

* fix(recordings): capture full logs and the run-time flow, upgrade v1 files

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

* feat(recordings): pick an existing run for the hub recording

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

* fix(recordings): cap recorded logs under the replay loader's text budget

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

* fix(recordings): pin picked runs to their executed version, keep v1 streamed logs

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

* fix(recordings): bound pipeline finalize fan-out, pin flow schema to run version

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

* fix(recordings): warn on mixed-version fallback, bound code fetches

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 17:22:13 +02:00
Ruben Fiszel 5ce29b3436 feat: add public sharing option for job pages (#10573)
* feat: add public sharing option for job pages

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

* fix: gate public run sharing and address review findings

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

* fix: address review nits on public run sharing

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

* fix: key public run view on workspace, job and token

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 17:18:29 +02:00
Ruben Fiszel fdd76a6f13 fix(frontend): collapse the dev-workspace edit notice into a badge (#10576) 2026-08-06 15:12:51 +00:00
Ruben Fiszel d592fb75eb chore(main): release 1.782.0 (#10566)
* chore(main): release 1.782.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.782.0
2026-08-06 12:55:48 +02:00
Guilhem c6c46eca62 shimmer highlight uses text-emphasis instead of white (#10569) 2026-08-06 12:48:02 +02:00
AlexRV12 8bab579665 stop destroying AI sessions in workspaces reached without a usr row (#10567)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 12:45:34 +02:00
Guilhem 94a1e01699 keep the input transform header full width (#10568)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 12:45:09 +02:00
Guilhem c2a6936e7d fix: keep the mermaid fullscreen dialog in its pane and its emoji vector (#10541)
* fix: keep the mermaid fullscreen dialog inside its pane and its emoji vector

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

* fix: load only the fonts a diagram needs and size chrome per breakpoint

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

* fix: cover every emoji class in the font preload without restyling diagrams

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

* fix: keep the dialog chrome allowance in rem so it scales with the root font

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

* fix: decode mermaid entity codes when sampling text for the font preload

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

* fix: match mermaid's decimal-only entity codes and decode the Inter sample too

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

* fix: drop emoji format characters from the font sample

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

* docs: state the emoji subset spread and modifier exclusions precisely

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

* refactor: re-render once fonts settle instead of hand-picking emoji subsets

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

* refactor: give Modal a fill-height mode instead of measuring its chrome

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

* fix: guard the post-fonts re-render against a newer render

The re-render after document.fonts.ready assigned svg without re-checking
renderSeq after its own await. renderedCode is set before that await, so a
stale re-render landing last leaves svg holding the previous diagram while
renderedCode names the current source — showSvg stays true and paints the
wrong diagram.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 12:44:47 +02:00
hugocasa fc1e11cb3d fix: compact ai chat context for models with unknown context windows (#10564)
* fix: compact ai chat context for models with unknown context windows

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

* docs: correct stale comment on unknown-model context window handling

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

* fix: surface assumed context window in usage indicator for unlisted models

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 12:13:15 +02:00
Ruben Fiszel 956210ea06 feat: improve duckdb isolation (#10565)
* [ee] feat: improve duckdb isolation

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

* chore: update ee-repo-ref to c4e6cbc1a1efeca5b71920c7903db2347d0eeda0

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

Previous ee-repo-ref: f630f7e73cb863e312430738d81d802a3971f7cd

New ee-repo-ref: c4e6cbc1a1efeca5b71920c7903db2347d0eeda0

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-08-06 12:01:12 +02:00
hugocasa c8ba771797 chore: track origin EE branch in worktree setup when absent locally (#9504)
* chore: track origin EE branch in worktree setup when absent locally

* chore: pass --track to worktree add so upstream is set regardless of git config

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

* chore: guard first worktree arm on local branch to avoid remote-only DWIM

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 10:13:16 +02:00
Ruben Fiszel c03bd34be9 chore(main): release 1.781.3 (#10563)
* chore(main): release 1.781.3

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
v1.781.3
2026-08-06 10:02:27 +02:00
Ruben Fiszel 1846bd5ce5 fix(frontend): take the editor's post-edit content, not setCode's argument (#10562)
#10560 changed the script editor's change handler to read `e.detail` instead of
`editorCode`, on the reasoning that the two only diverge while the editor is
being torn down. They also diverge in a live editor: `setCode` dispatches the
string it was handed, but `alignCodeWithEditor` applies that string to Monaco
first, and the resulting `onDidChangeModelContent` runs `updateCode`
re-entrantly — so if the model normalized the text (EOL is the reachable case;
`ScriptBuilder` builds template content with a `\r\n` join), `editorCode`
already holds the buffer's version and the payload is the pre-normalization
one. Taking the payload leaves `code` disagreeing with what the editor shows,
which the external-write effect then tries to reconcile on every change.

The language-switch fix in that PR is `alignCodeWithEditor` clearing the timer
its own write armed; that part stands and is unaffected. This restores the
handler to the buffer-true read.

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