Commit Graph
14607 Commits
Author SHA1 Message Date
Guilhem LemouelandClaude Opus 5 b5c148dd8d fix(frontend): cap the inferred username at what the column holds
`usr.username` is VARCHAR(50) while the provider name and email it is
derived from run to 255, and `create_workspace` inserts the value
untruncated — so a long first name failed the same way the invalid
characters did: posted invisibly, refused on insert, with nothing on
screen naming the field. Undefined instead, which the form already
routes to the full one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-04 17:48:19 +02:00
Guilhem LemouelandClaude Opus 5 7d0794adfa fix: sanitize the inferred username, and stop counting an unread setup step as clean
`loadUsernamePolicy` derived a username by stripping dots, so `O'Connor`
and `alice+demo` both produced values the `proper_username` constraint
refuses — posted invisibly by the simple form, which then failed with
nothing on screen explaining why. `usernameFromName` keeps only `[\w-]`
and answers undefined when nothing usable is left, which is already the
form's cue to open the full one.

The credentials step offers Finish when the export could not be read,
since it cannot tell what is outstanding — and that landed in
`template_setup` as `filled`, the bucket meaning the step came out
clean. It reports whether it checked anything, and an unread step counts
as `unchecked`.

Also drops an orphaned `.sqlx` entry left by the create-at-signup query
this branch abandoned, and rewrites the stepper's first-frame comment,
which argued from a meaning of `resourceCount` that main has narrowed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-04 15:18:56 +02:00
Guilhem Lemouel 4558b766eb Merge remote-tracking branch 'origin/main' into glm/onboarding-cloud
# Conflicts:
#	backend/ee-repo-ref.txt
#	frontend/src/lib/components/ImportSetupStep.svelte
#	frontend/src/lib/components/InstanceSettings.svelte
#	frontend/src/lib/components/home/ItemsList.svelte
#	frontend/src/routes/(root)/(logged)/projects/import/+page@(root).svelte
2026-09-04 14:00:17 +02:00
Guilhem LemouelandClaude Opus 5 f14e60cc38 fix(frontend): make the import counters answer what they claim to
`template_abandon` folded a landed import closed with the X into `idle`,
the bucket read as "opened this and bounced" — three outcomes in one
number. It gets its own `done` stage.

`template_setup` counted skipped rows through `value`, which is an
increment: `skipped` accumulated rows while `filled` and `none` counted
imports, two units in one counter with no way to recover one from the
other. The row count becomes a bucket in the key, so every event is one
import and the buckets compare.

The import dialog also asked for the hub URL settings at init, and the
home list now mounts it for everyone on every arrival — two GETs for a
string only the project card renders. Deferred to the first pick.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-04 13:42:32 +02:00
Guilhem LemouelandClaude Opus 5 7812095c8d feat(frontend): reach the hub importer from the create menu, and count the funnel
The picker only existed inside the empty state, which disappears as soon
as a workspace holds one item — nothing else in the product linked to
`/projects/import`. New → Import now offers a hub project, opening the
catalogue in a dialog: a popover anchored to an item inside an open
dropdown leaves two melt layers arguing over focus. The list and the
import dialog move up to ItemsList, so one dialog serves both doors.

`template_setup` records how the credentials step ended — `filled` only
when nothing was outstanding, `skipped` carrying how many rows were left
— and `template_abandon` records where a dismissed import was given up.
`template_picker_open` gains a key naming the entry point.

Also on the workspace picker: logging out is a text link on the line
that says who you are and an item in the settings menu, rather than the
page's accent action, and onboarding's Previous joins the row it belongs
to instead of hanging under the button that finishes the form.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-04 13:26:09 +02:00
fda7b3f086 feat(ai-sessions): replace the context panel with an assistant settings modal (#10919)
* 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

* feat(ai-sessions): add a context panel listing what the chat can use

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

* fix: track the prompt rebuild signal and trim the review round's nits

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

* fix: keep the panel from perturbing an in-flight turn

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

* fix: count a folder by its readable children

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

* feat(ai-sessions): replace the context panel with an assistant settings modal

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

* feat(ai-sessions): page-based MCP editing and fuzzy tool search

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

* feat(ai-sessions): tool detail page and a shared list row

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

* feat(ai-sessions): add a files & folders section to the assistant settings

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

* chore: point the ee ref at the merged ee branch

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

* fix: keep hidden sections from answering keys and swallowing a failed save

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

* fix: restore the staged-fork write guard and narrow the round-2 findings

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

* fix: restore the workspace-race guards and extend them to MCP

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

* fix: keep an in-flight settings read from overwriting typed instructions

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

* docs: describe the tool row as the one line it renders

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

* fix: keep the prompt entries on the home composer, which has no settings modal

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

* fix: create the editor with the gutter its caller asked for

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

* test: restore the attachment status label guard dropped in the merge

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

* fix: surface a refused mcp selection write instead of painting the switch

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

* fix: refuse instruction writes to a staged fork's parent, and read the target's role

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

* fix: pin the instructions role and field to the target workspace

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

* fix: retry a deferred instructions reload, and use Button for the row label

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

* fix: leave the arrows to a control that answered them, and say when a role read failed

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

* chore: update ee-repo-ref to a2776856c50e80c9dbcf6e689a66ce86567c03fa

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

Previous ee-repo-ref: dd7466e749753568a23c91ba5e165020769206b8

New ee-repo-ref: a2776856c50e80c9dbcf6e689a66ce86567c03fa

Automated by sync-ee-ref workflow.

* fix: withhold the page navigator from a parked section

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Guilhem Lemouel <guilhemlemouel@gmail.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-09-04 10:53:02 +02:00
0d6bce4a12 keep the SSO group reconciler alive in oauth2-less builds (#10969)
* chore: stop denying reads of secret files in claude settings

Any Read() deny rule makes Claude Code resolve the file operands of every
Bash command that reads files. A path it cannot resolve, such as one that
follows a cd into a directory the analyzer does not track, escalates to a
permission prompt even under bypassPermissions. A plain recursive grep in
the repo root escalates too, because it could reach .env.

Drop the read rules and widen the write rules to cover the same files, so
secrets still cannot be written through Edit, Write, or a shell redirect.
Reads of those files are no longer blocked.

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

* fix: keep the sso group reconciler alive in oauth2-less builds

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

* chore: update ee-repo-ref to d6297e6844dc2aab4745fce328e32ccab508969f

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

Previous ee-repo-ref: eec88486fb2df0ba15998ef285f52fc67af90b1e

New ee-repo-ref: d6297e6844dc2aab4745fce328e32ccab508969f

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-04 01:23:59 +02:00
Ruben FiszelandClaude Fable 5.1 11138284ac fix: deploy a relocked script version only when its lock changed (#10966)
* fix: deploy a relocked script version only when its lock changed

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

* fix: write the unchanged relock hash under the row lock and skip the phantom tally

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

* fix: requeue a superseded relock and read the live head past the script cache

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

* fix: re-read the relock head after waiting on its lock and keep module locks

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

* fix: bound the relock head re-read instead of reading once

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

* chore: refresh the sqlx cache entry for the re-indented lock write

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

* test: pin the waiting-relock requeue and the multi-file importer no-op

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

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 01:01:36 +02:00
Ruben FiszelandClaude Opus 5 6a7a6d9144 chore: stop denying reads of secret files in claude settings (#10968)
Any Read() deny rule makes Claude Code resolve the file operands of every
Bash command that reads files. A path it cannot resolve, such as one that
follows a cd into a directory the analyzer does not track, escalates to a
permission prompt even under bypassPermissions. A plain recursive grep in
the repo root escalates too, because it could reach .env.

Drop the read rules and widen the write rules to cover the same files, so
secrets still cannot be written through Edit, Write, or a shell redirect.
Reads of those files are no longer blocked.


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

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 00:40:34 +02:00
Diego ImbertandClaude Opus 5 3e3d2a6363 fix: keep braces inside string tool arguments out of JSON depth count (#10965)
Claude-Session: https://claude.ai/code/session_013vvU4UWCpib25ovmmAD7HH

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 22:30:19 +02:00
79426a1a68 feat: reconcile IdP instance groups from the SSO groups claim (#10957)
* feat: add sso_groups_claim setting for login-time instance group sync

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

* chore: bump ee-repo-ref for the SSO groups claim reconcile

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

* chore: update ee-repo-ref to 3b89bfc11314a326a191101cfe3ef65f6f7f82a8

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

Previous ee-repo-ref: e388527f9adbbe466fe050ca8d1d236ce3342bc3

New ee-repo-ref: 3b89bfc11314a326a191101cfe3ef65f6f7f82a8

Automated by sync-ee-ref workflow.

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-09-03 22:23:43 +02:00
Ruben FiszelandClaude Fable 5.1 b100606da6 fix: patch critical CVEs in the worker image (#10962)
* fix: patch critical CVEs in the worker image (go, node, php, helm, libtiff)

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

* ci: run the backend tests on node 24 to match the image

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

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 17:02:08 +00:00
Guilhem LemouelandClaude Opus 5 c324d2294c fix(frontend): keep the stopped-import toast off the Finish path
`done` survives a retry, so Finish is clickable while the run is going
again, and its own closing reaches the same falling edge the X does.
Abandon the run either way; say it was stopped only when that is what
the click asked for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-03 18:38:21 +02:00
Guilhem LemouelandClaude Opus 5 cc7d176911 fix(frontend): stop a dismissed project import from running on
Modal reports dismissal only through its bindable `open` — the X, Escape
and the backdrop dispatch neither `confirmed` nor `canceled`. Bind it, so
clearing `pick` follows the dialog closing: re-picking the same project
opens it again, and a run still in flight is abandoned with a toast
instead of writing to the workspace with no UI in front of it.

Also mark the inline-link buttons as sanctioned rather than oversights,
and give Log out `text-accent` instead of `text-blue-500`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-03 18:30:56 +02:00
Guilhem LemouelandClaude Opus 5 2c6730ce02 fix(frontend): stop a dismissed project import from running on
Modal reports dismissal only through its bindable `open` — the X, Escape
and the backdrop dispatch neither `confirmed` nor `canceled`. Bind it, so
clearing `pick` follows the dialog closing: re-picking the same project
opens it again, and a run still in flight is abandoned with a toast
instead of writing to the workspace with no UI in front of it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-03 18:29:04 +02:00
Guilhem LemouelandClaude Opus 5 dc3689eb40 refactor(frontend): drop the InfiniteList containerClass prop
Added for the template picker, which turns out not to need it: DataTable's own
container is already `h-full`, so `containerClass="h-full"` merged to nothing and
the height the list pages against comes from the flex chain above it. A prop with
no effect at its only call site is public surface for free. InfiniteList is back
to what it was.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-03 17:48:44 +02:00
Guilhem LemouelandClaude Opus 5 b3aa4a4cd3 fix(frontend): open the template picker downward and size it from the popover
The popover's default positioning caps its height to the viewport, and the list
inside it carried a fixed one, so a capped box overflowed its own frame — visible
with the AI composer hidden, where the caption sits high and `placement: top`
left almost no room above it. It opens downward now, with flip fallbacks, at a
definite `min(72vh, 520px)`; the list fills what the header leaves, which is
still the definite height it needs to page.

`creating` on the create form becomes `onCreatingChange`: `$bindable(default)` on
an optional prop is banned, and this is something the form reports rather than
state it shares.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-03 17:37:08 +02:00
Guilhem LemouelandClaude Opus 5 5537247082 fix(frontend): count a pending invite as somewhere to go
Onboarding read `listUserWorkspaces`, which returns membership. An invite is a
`workspace_invite` row until `accept_invite` runs, so an invited teammate reached
the last step owning nothing and was walked into creating a personal workspace,
with the invite nowhere on the page. Invites are fetched alongside the
workspaces, the way the picker already gates the same decision.

A failed load now reads as placed rather than not: the picker can work the
decision out, while the create step's only way forward is creating.

The create form reports when it is handing over, so the Previous button beside
it stands down for the ~900ms rather than offering a way back out of a workspace
that now exists.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-03 15:29:48 +02:00
Guilhem LemouelandClaude Opus 5 d9718d80c9 refactor: create the workspace in onboarding rather than at signup
Signup no longer makes a personal workspace, so the last onboarding step creates
one instead of renaming it — the same one-field `SimpleCreateWorkspace` the
workspace picker falls back to, so a user who leaves onboarding early meets the
form again rather than something new. The id now comes from the name they type
rather than from their email, and there is one creation path instead of two.

`insert_workspace` goes back to being private: the extraction existed only so the
EE signup path could call it, and nothing outside `create_workspace` does now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-03 15:14:41 +02:00
Guilhem LemouelandClaude Opus 5 ff3842aeb3 fix(frontend): let Skip wait for the workspace onboarding names
`loadWorkspaceStep()` was fired and dropped, while Skip and the use-case Continue
branch on `ownWorkspace` in their `finally`. Skip awaits one POST that starts
after those two GETs and can finish before them, so a first-frame Skip fell
through to `leaveOnboarding()` and landed in the workspace with the backend's
name — the step this flow exists for, silently gone. Both exits await the load;
`isSubmitting` already covers the wait.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-03 14:45:37 +02:00
Guilhem LemouelandClaude Opus 5 d197d68fc8 fix(frontend): use unifiedSize on the new onboarding step's buttons
`size` and `color` are deprecated on Button; the new step copied them from the
survey steps above it. AGENTS.md: deprecated props survive at old call sites,
copying one forward is still a bug.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-03 14:36:37 +02:00
Guilhem LemouelandClaude Opus 5 c6b6764e96 fix(frontend): gate the empty state and repair the derived workspace id
Review findings from the first round.

The empty state offers a template import and the New menu, and neither checks a
permission — so an operator, or a workspace whose direct-deploy protection
cleared `showEditButtons`, was offered both. It now sits behind the same gate as
the create menu thirty lines above it.

`validateWorkspaceId` answers with the *reason* an id is unusable, so
`if (validateWorkspaceId(next)) break` stopped on the first invalid candidate and
returned it: someone named Global got the reserved `global`, and a 50-char seed
got a taken one. Invalid candidates are skipped instead, and when none works the
caller opens advanced settings rather than posting a name the server refuses.

Also: `rd` may be absolute (the CLI login sends one) and `goto` refuses those,
which would strand the caller on the "Creating …" screen with the workspace
already made; the hub host is parsed defensively, since the instance setting is
whatever an admin typed and `new URL` was throwing in render; `insert_workspace`
says which authorization its callers still own; and the two arrival animations'
comments now describe when they actually play.

Tests for the two pure helpers the review named: `defaultWorkspaceName` and
`hubProjectDescription`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-03 14:29:27 +02:00
Guilhem LemouelandClaude Opus 5 c760f8cbc9 feat(frontend): make a new cloud workspace the thing onboarding produces
Signup already makes a personal workspace; nothing let its owner name it, and a
user who ended up without one landed on a workspace picker whose only action was
a button. Onboarding now ends on the workspace itself, and the empty home that
follows says what a workspace is for rather than "Welcome to Windmill".

Onboarding gains a third step that names the workspace signup created, prefilled
from the login provider's name or the email local part — `ruben@…` gives "Ruben's
workspace". Skipping the survey reaches it too: the questions are ours, the
workspace is theirs. Advanced settings swaps in the real creation form for
someone setting up for a team.

The workspace picker stands down when it has nothing to offer: no workspace to
enter and no invite to accept leaves one action on the page, so the page is that
action — one field, prefilled, "Create workspace". Both hand-overs hold a loading
state for 900ms and the app fades in behind them, so creating a workspace reads
as something that happened.

The empty home draws three static placeholder rows in the shape of real ones,
under a caption offering a template or the New menu. "Start from a template"
opens a popover listing the hub's projects, most-starred first, preloaded when
the empty state renders and paged as you scroll. Picking one opens the import
wizard in a dialog: its two destination steps are already answered by being in a
workspace, so it starts at the import itself and pages to the credentials step
with the animation the paged-modal pattern provides.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-03 14:10:19 +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>
v1.803.0
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
GuilhemandClaude Opus 5 582761e37c feat: reuse an existing workspace resource in the project import wizard (#10935)
* feat: let the import wizard reuse an existing workspace resource

The project import wizard always opened the create-resource drawer, so a
workspace that already had, say, an SMTP resource still ended up with a second
one. Step 4 now offers a choice: fill in a new resource as before, or pick an
existing one of the same type.

Picking an existing resource rewrites the deployed items to point at it and
then deletes the imported stub. The rewrite covers scripts, flows, apps, raw
apps and every workspace trigger kind, and holds two rules: it writes nothing
unless every referrer can be rewritten, and it only touches items under the
target folder.

Raw apps re-upload the bundle shipped in the project export instead of
rebuilding it, and the retarget refuses when the deployed sources have moved on
since the import — that bundle was built from the export's sources, so
re-uploading it over edited sources would revert them.

Adds `update` to the trigger-kind table for the eleven kinds whose service
takes a plain config body; schedule keeps its own branch because
updateSchedule takes a different shape.

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

* feat: only ask about resources the project actually points at

A project declares one resource per `resource-<type>` input schema as well as one
per `$res:` reference, so an app that pins `f/calendly/google_calendar` for a
script whose schema says `resource-gcal` ships an unreferenced `f/calendly/gcal`
alongside it. Step 4 listed both and asked you to fill in each.

Only the referenced ones have to hold a credential for the project to work. The
rest are still created — a standalone run picks from them in the argument picker
— but they no longer reach the checklist, and `resourceCount` counts the same
set so the wizard does not offer a fourth step that has nothing on it. Across
the twelve published hub projects this drops 9 of 19 rows, including three
non-credential input shapes in `typeform`.

Also fixes a miss in the retarget: a trigger holds its resource as a bare path in
its own `*_resource_path` field rather than as a `$res:` token, so a token-only
scan left it pointing at a stub that was then deleted. Detection now mirrors
`rewriteTriggerConfig` through a shared `referencesResourcePath`, which matches
the parsed structure rather than its serialization — keeping `f/proj/db` out of
`$res:f/proj/db_prod` as well.

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

* fix: refuse a resource retarget the scan or the rewriters cannot cover

Uncompiled trigger features 404 on their list route; that is the instance not
having the kind, not a listing that failed, so it no longer blocks every
retarget on a stock build. The `listSearch*` endpoints cap server-side with no
ordering and no pagination, so a full page is refused rather than read as the
whole workspace. An item that names the resource path outside a `$res:` token is
refused at plan time — no rewriter relocates it — and the trigger row keeps its
own `script_path` so a runnable sharing the path is not repointed. A raw app
whose sources the export cannot yield carries no entry at all, so the refusal
its comment promises actually fires. The reused row offers text instead of a
button that leads to a deleted resource.

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

* refactor: let an incomplete scan keep the stub instead of refusing the retarget

The scan behind "nothing is written unless every referrer can be rewritten"
cannot be proven complete: the listings come back capped, a trigger kind can
fail to list, and a reference can sit where no rewriter reaches. Gating the
whole run on that claim made every such case a refusal.

Rewriting an item onto the chosen resource is safe on its own — the item
resolves whether or not the stub survives — so only the delete needs the claim.
`planRetarget` now answers with the referrers it can move plus the gaps it
cannot account for, `applyRetarget` always moves the first set, and a gap keeps
the stub rather than stopping the run. A referrer outside the project's folder
is one of those gaps: the listings are workspace-wide, so it is seen for free,
it stays the user's own, and its existence is why the stub stays.

The outcome carries what moved and why the stub was kept, so the row settles to
the chosen resource either way and says when the placeholder is still there.

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

* fix: preserve a retargeted item's deployed identity, and send back its own bundle

Every write here edits a deployed item in place, but none of them said so.
Without `preserve_on_behalf_of` the backend replaces the item's stored run
identity with whoever opened the wizard, and `updatePolicy(next, undefined)`
rebuilt an app's policy from nothing — dropping its sandbox rules and forcing
`execution_mode: publisher`, which puts a viewer app on the publisher's
identity even though the backend would otherwise have kept the deployed mode.
The policy is now recomputed from the deployed one, which is what the
triggerables rekeying actually needs.

The raw-app bundle no longer comes from the project export. The browser can
read a deployed bundle back — mint the app's public secret and fetch
`/apps/get_data/v/{secret}.{ext}`, the same route the Hub publish reads — so
the bundle sent back is the deployed one whoever last edited it. That removes
`ExportedAppFiles`, its plumbing through the setup step, `rawSourcesDiverged`,
and the two raw-app gaps: an app "edited since the import" is no longer a case
that exists.

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

* perf: carry the trigger row from the scan into its write

`rewriteTrigger` listed the whole kind again to find the row it had just read,
once per trigger — and for schedules a listing is itself a listing plus a
detail fetch per row. The scan already holds the row, so the referrer carries
it.

Pins two properties that nothing covered: the trigger update body leaves
`enabled` out, so pointing a trigger at a credential cannot also start it; and
a write that fails partway keeps the stub while reporting what had already
moved.

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

* fix: keep unfilled resources out of the reuse chooser

The chooser offered every resource of the row's type except the ones this import
created, so a stub left behind by an earlier import of the same project showed up
as a credential to reuse. Pointing a project at another project's empty
placeholder is never the answer, and nothing downstream would have complained.

Candidates are now read back and the unfilled ones dropped, using the same test
the checklist uses to call one of the project's own resources blank. Past a cap
they are all offered rather than costing a request each: a workspace with that
many resources of the outstanding types is not the case this filters for.

Also drops the chooser's promise that the imported placeholder is removed. That
was true when the delete was unconditional; the stub is now kept whenever the
scan cannot account for everything, and the row says which happened once it has.

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

* fix: move a retargeted item's bundle and identity, and see the paths it spells out

Four gaps between what the retarget claimed and what it did.

A trigger states its run identity as `permissioned_as`, not the `on_behalf_of`
the other kinds use, and the backend keeps the row's value only when
`preserve_permissioned_as` says so. Without the pair, a trigger created under a
folder's `default_permissioned_as` started running as whoever picked the
credential.

A raw app's bundle is compiled from its sources, so a `$res:` a source spells out
is baked into it. The import rewrites that copy — `retargetProjectExport` runs
while `/bundle.js` is still one of `files` — but the retarget fetched the
deployed bundle after that split and sent it back untouched, then deleted the
stub the app still read. The fetched bundle is now rewritten too, and a path it
names any other way keeps the stub instead.

A script's content is one string, so the whole-string match that finds a bare
path in a flow or an app could not see one written inside it. `getResource("f/…")`
was invisible to both the scan, which then deleted the stub under it, and the
step-4 filter, which dropped the row so nobody was asked to fill it.

Trigger listings cap at the server's DEFAULT_PER_PAGE, which this table does not
page past. A full page is now read the way a full `listSearch*` page is: as a
listing that cannot account for the rest.

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

* fix: see a path a flow or app spells out, and name why an item did not move

The script scan was taught to see a resource path written inside code; flows and
apps were left on the whole-string test, which cannot. A flow whose inline module
runs `getResource("f/proj/db")`, or a raw app whose source does, was neither
rewritten nor recorded as a gap, so the stub was deleted while the deployed item
still read it. Reachable from the wizard, because the step-4 filter does see such
a reference and offers the row.

Both branches now use the same test as the script branch, and gap rather than
rewrite: the stub survives either way, so a `$res:` token in the same item still
resolves, and rewriting half an item would only make the plan and the write
disagree about what moved.

Each rewriter now says why it left an item alone instead of answering yes or no,
so a raw-app bundle that spells the path out is reported as a reference nothing
could move rather than as a concurrent edit.

Also corrects the resource-listing comment — `perPage` bounds the answer, the
route does not default to 30 — and asks the askable-resource question against the
export as published rather than the retargeted copy, so the step and the stepper
that decides whether to offer it give one answer. A path spelled out in code is
not retargeted, so only the raw export has its references and its resource paths
agreeing.

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

* fix: a kept placeholder is still something to fill in

Reuse marked the row done and replaced its action with static text even when the
stub survived. A kept stub is empty and is still what every item the scan could
not move reads, so the step reported "You're all set" over a project running on a
placeholder, with no way back to filling it. Reachable from one hub project: a
raw app whose source spells the resource path out gaps everything, nothing is
rewritten, and the row went green anyway.

Such a row now stays outstanding, keeps its button, says which path items still
read, and re-checks on refresh so filling that placeholder in closes it.

Flows and apps also went back to being rewritten as well as gapped, matching what
the script branch already did — the reason given for skipping them was
contradicted by that branch, and a comment merely naming the path was enough to
strand an item's real `$res:` token on the stub.

Two things had to become precise for that to hold. What counts as rewritable is
now the presence of a `$res:` token rather than any reference, since a whole
string equal to the path is the unreachable case, not a movable one. And the
post-rewrite check reads tokens only: a path the item also spells out is the
plan's gap to record, and re-reading it at write time reported one item twice,
as both unmovable and changed underfoot. Writers now skip a write that would
change nothing.

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

* fix: rewrite only the tokens, and let a filled placeholder close its row

The import's flow and app rewriters also remap a runnable's own path on an exact
match. That is right for the folder-wide map the import hands them, where every
path is moving. Here the map holds one entry, a resource path — and scripts,
flows and resources share a namespace, so a project shipping both a script and a
resource named `smtp` had the step calling it repointed at the credential.
Triggers were already guarded against exactly this; flows, apps and raw apps were
not. All three now rewrite the serialized value, which moves the tokens and
leaves every path alone.

A kept placeholder that the user then fills in now closes its row: `stubKept` is
cleared by the read that finds it filled, so the row stops saying items still
need it while showing a green check beside "You're all set".

A kept-stub row's button also goes straight to filling that placeholder rather
than reopening the chooser. A second retarget from there can only be a no-op —
every rewritable referrer is already off the stub — and it would have relabelled
the row after moving nothing.

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

* fix: check staleness where it can be seen, and stop trusting a client-side licence

The post-rewrite check could no longer fail: since the rewrite became token-only
it ran over exactly what the check looked for, so it read as a guard while
guarding nothing. The staleness it named is real — the plan classifies items from
the search listings and each write re-reads its item by path — so the check now
happens on that fresh read, and looks for the spelling no rewrite reaches. A
referrer the plan already recorded as unreachable skips it: the stub survives
either way, and re-reporting the same item would say it was both unmovable and
changed underfoot.

Trigger kinds are no longer skipped by the client-side licence store. That store
is empty on an EE instance whose licence is unset or whose fetch failed, while
the rows are still in the database and the routes still answer — and a kind
skipped that way left no gap, so the stub went while an EE trigger still pointed
at it. On CE those routes are not registered and the 404 branch already says so,
from the server rather than from a store.

`askableResources` now pairs the export's resources with the retargeted ones by
position, the way `retargetProjectExport` maps them, instead of rebuilding the
path by slicing a prefix. An external path the bundle pulled in lands at
`f/<folder>/<name>` with a `_2` suffix on collision, which no slicing recovers —
and the row would have gone missing from a checklist the stepper still counted.

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

* fix: a scan the caller is not shown all of cannot clear the stub for deletion

The listings the scan reads run as the caller, and row-level security filters
them inside the query. For anyone but a workspace admin that means an item they
cannot read is not absent from the answer so much as invisible in it: it does not
appear, and it does not count towards the full-page test that catches a truncated
listing either. A colleague's private script referencing the stub is exactly that
shape, so the scan reported a clean sweep and the stub was deleted out from under
it, with nothing said.

That is the one input to the completeness proof the destructive step rests on
that was never checked. A caller who is not shown the whole workspace now records
a gap like any other, so the rewrite still happens in full and the placeholder
stays.

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

* fix: ask whether this workspace's listings are complete, not a stale record's

`UserExt` is per-workspace and outlives a workspace change, which is why it
carries `workspace_id`. Reading `is_admin` off it without checking which
workspace it describes answers for the wrong one. Step 4 is reachable by reload —
it is built to be — and nothing on that path re-fetches the record, so it still
describes the workspace the user came from. An admin of their own workspace
importing into a shared one they are a plain member of got a clean scan over
row-level-security-filtered listings, and the stub was deleted under a referrer
they were never shown.

The question is now asked of the target workspace, through a predicate that can
be tested. An instance superadmin bypasses the policies everywhere, so that is
asked separately rather than read off the same stale record.

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

* style: format the wizard retarget files

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

* fix: leave a trigger's runnable references alone, and read the app kind rather than guess it

A trigger's `on_failure`, `on_recovery`, `on_success` and `url` name a runnable,
and `rewriteTriggerConfig` remaps one on an exact match — right for the
folder-wide map the import hands it, wrong for a map holding a single resource
path. A schedule whose error handler ran a script sharing that path had the
handler pointed at the credential instead. The same reason `path` and
`script_path` were already restored; only the two prefixed shapes it remaps are,
so a field holding a `$res:` token still moves.

The scan guessed raw from low-code by looking for `files` and `runnables`,
because `list_search_apps` returns only the path and the value. Both writers
re-read the app anyway, and that record carries `raw_app`, so the write now
dispatches on it. A guess wrong in either direction was a deploy the backend
refuses for changing an app's kind, which aborted the run at that referrer.

Also drops the past-tense clauses from four test comments. Each already states
the invariant it guards; the rest described iterations of this branch that no
reader will have seen.

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

* fix: restore a trigger's bare runnable references too

The prefixed spellings were put back after the rewrite; the bare ones were not.
`dynamic_skip`, `error_handler_path` and a websocket initial message's
`runnable_result.path` each hold a plain script path, which `rewriteTriggerConfig`
remaps on a whole-string match — so a trigger whose error handler ran a script
sharing the stub's path had that handler pointed at the credential.

All of them now come back from the row, taken from what `triggerHandlerRefs`
reads rather than enumerated by hand. A prefixed field is still restored only
when it holds the runnable spelling, so a `$res:` token in one still moves; a
bare field is a path and nothing else, so it is always restored.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 11:28: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 Fiszel 8a9233ac62 home nit 2026-09-03 09:30:41 +02:00
Ruben FiszelandClaude Fable 5.1 3d089b5734 fix: fade the home Build with AI placeholder every 10s instead of typing it (#10953)
* fix: fade the home Build with AI placeholder every 10s instead of typing it

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

* fix: restore placeholder visibility when the home composer hides mid-fade

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

* fix: smoother and slightly more frequent home placeholder fade

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

* fix: keep the home placeholder static under prefers-reduced-motion

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

* fix: draw the home example prompt over the textarea so the fade runs in every browser

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

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 09:17:16 +02:00
Ruben FiszelandClaude Fable 5.1 0f5a1db2ab fix(cli): make a sync push into a fork converge on schedules and inline names (#10951)
* fix(cli): make a sync push into a fork converge on schedules and inline names

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

* fix(cli): gate the fork schedule lookup, tolerate fork-conflict, keep rendered names unique

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

* test(cli): use the OS path separator in the push convergence fixtures

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

* fix(cli): report a set-aside fork schedule flag and keep checkout inline names inside the flow folder

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

* fix(cli): enable a fork-only schedule on create, and treat a fork with no parent as owning its schedules

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

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 08:45:39 +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 Fiszel 06ff9ff45f chore(main): release 1.802.0 (#10934) v1.802.0 2026-09-02 22:37:43 +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
AlexRV12andClaude Opus 5 f10ac6c2b3 feat: open path links from chat messages in the session preview panel (#10881)
A workspace path mentioned in a chat message rendered as a link that always
opened a new browser tab. On the sessions page, which hosts a preview panel,
a plain click now opens the item in that panel instead. Modifier clicks still
reach a new tab, and surfaces with no panel keep their previous behaviour.

Scripts, flows and raw apps are supported. Legacy drag-and-drop apps are not:
the panel has no editor that can host one, so their links stay outbound.

The link pill's kind icon and action icon now cross-fade inside a fixed 12px
box, so the pill is the same width at rest and on hover and the surrounding
sentence never reflows.

`openItemPreviewAction` moves to a new import-free leaf module so a chat
message can reach it at runtime without dragging monaco, zod and the openai
client into the render path.


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

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 19:30:54 +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 FiszelandClaude Fable 5.1 ccf84761dd feat: restore owner and label filter chips on the homepage (#10942)
* feat: restore label filter chips on the homepage

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

* feat: restore owner filter chips on the homepage

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

* refactor: render homepage label chips through ListFilters with a 20-chip cap

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

* chore: drop no-op small prop and stale chip comments on the homepage filters

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

* feat: homepage owner and label chips on one line, capped at 10, labels ranked by count

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

* fix: count a homepage label once per row and describe the window-local ranking

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

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:18:50 +02:00
d3747d6255 feat(sessions): offer the item you came from when starting a new session (#10940)
* fix: connect to dev server instead of localhost

* fix: derive WebSocket scheme from location.protocol

Mirror the protocol-aware pattern used by initSqlWebSocket in dev.ts
so the WebSocket connects over wss:// when the dev server is reached
through an HTTPS proxy/tunnel, avoiding mixed-content blocking.

* refactor: drop now-unused port parameter of wmillTsDev

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

* feat(sessions): offer the item you came from when starting a new session

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

* docs(sessions): state the new-session seed latch's real lifetime

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

* fix(sessions): let Enter act on the focused answer of the new-session offer

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

* feat(sessions): start on the item instead of resuming a stale session from the rail

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

* fix(sessions): hand the rail's item entry through the editor's own hand-off

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

* fix(sessions): snap the rail toggle back when a session switch does not navigate

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

---------

Co-authored-by: Nathan A. Ferch <nf+github@marginal.net>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 17:17:58 +02:00
Ruben FiszelandClaude Fable 5.1 95b6bbd46a fix: preselect first row of AI agent and AI sandbox insert panes (#10937)
* fix: preselect first row of AI agent and AI sandbox insert panes

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

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

* fix: keep Enter for focused controls in the AI insert panes

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

Claude-Session: https://claude.ai/code/session_019vjSnhnewkUbx6mR9iCeK8
2026-09-02 13:49:31 +02:00
Guilhem LemouelandClaude Opus 5 970796a031 Merge branch 'main' into glm/onboarding-cloud
Conflicts:
- home page and ItemsList: main moved the Hub / CLI-MCP row and the create
  menu into HomeAIChat and the items search row, and replaced the owner
  chips with searchbar filters. Took main's layout and re-applied the
  empty-workspace gating on top of it, keeping the AI composer and the
  New menu visible when the workspace is empty.
- onboarding: folded main's `?rd=` destination into leaveOnboarding, which
  now honours a requested path first and otherwise dives into the single
  workspace.
- TutorialBanner: stays deleted.
- ee-repo-ref: points at the merge of EE main into the EE branch.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-02 10:22:04 +02:00
Guilhem LemouelandClaude Opus 5 9b5ec32b4a feat(frontend): suggest Hub projects on an empty workspace home
A workspace with nothing in it showed only "Welcome to Windmill". Replace
that with a grid of ready-made Hub projects to import, and hide the search
box, kind toggles and the sort/filter row while the workspace is empty —
they would act on an empty list. A search that matches nothing still keeps
its controls and shows the no-match message.

The project list is seeded locally for now; the Hub endpoint that ranks
them is not there yet, and Import is still a placeholder.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-02 10:15:11 +02:00
Guilhem LemouelandClaude Opus 5 a582eb526e chore(frontend): remove the tutorial system
Deletes the guided-tour feature: the tutorials directory, the per-editor
wrappers, the home banner and button, the /tutorials route, and the
driver.js dependency they were built on. Also removes what only existed to
serve them — the `tutorialsToDo` / `skippedAll` / `isCurrentlyInTutorial`
stores, the `disableTutorials` prop chain through the flow editor, the
`?tutorial=` deep links, PopupV2's clickOutside exemption for the driver
popover, and the selector-anchor class on the flow editor tabs.

The backend `tutorial_progress` endpoints and table stay: nothing calls
them now, and removing them is a public-API break plus a migration that
would drop existing progress.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-02 10:15:03 +02:00
Guilhem LemouelandClaude Opus 5 a72f79322d feat(frontend): land cloud users in their workspace after onboarding
Cloud signup creates exactly one workspace for the new user, so the picker
that followed onboarding was a page with a single choice on it. Switch to
that workspace and go to the home page instead, falling back to the picker
whenever there is a real choice: an invite to accept, several workspaces,
or none.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fRjnaHLwjpHN84gNNxah9
2026-09-02 10:14:47 +02:00
337154b830 fix: connect to dev server instead of localhost (#10912)
* fix: connect to dev server instead of localhost

* fix: derive WebSocket scheme from location.protocol

Mirror the protocol-aware pattern used by initSqlWebSocket in dev.ts
so the WebSocket connects over wss:// when the dev server is reached
through an HTTPS proxy/tunnel, avoiding mixed-content blocking.

* refactor: drop now-unused port parameter of wmillTsDev

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

---------

Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 08:51:38 +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>
v1.801.0
2026-09-02 01:01:01 +02:00
Ruben FiszelandClaude Opus 5 772fafec83 feat: make the home Build with AI composer dismissible, quiet the rest of the home page (#10930)
* feat: let the home Build with AI composer be dismissed, and hide it in locked workspaces

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

* style: quiet the home tutorial banner down to an inline row

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

* style: enlarge the empty home page state

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 00:57:44 +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