* feat(cli): add --yes, --secret/--no-secret and --description to variable add
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(cli): cover variable add create/update flag semantics
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(cli): warn on secret downgrade in variable add and pin preserve semantics in test
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(cli): improve agent prompts/skills and workspace fork workflow
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(cli): refuse fork --from-branch rename of a base branch
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(cli): auto-detect fork branch workflow, drop rt.d.ts refresh and legacy-name warning
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(skills): reconcile raw-app generate-metadata stance (agent offers+runs)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(skills): agent runs all CLI commands, gated on intent not on user typing them
Extends #9467's safe-vs-destructive model: the agent runs consequential commands (sync push, generate-metadata) itself too, gated on explicit user intent rather than handed to the user to type. The explicit-intent rule is the safeguard; an approval prompt is treated as a possible backstop, not assumed (auto-approve/headless runs have none).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Revert "docs(skills): agent runs all CLI commands, gated on intent not on user typing them"
Reverts 9225e1759b. That commit over-reached: #9467 already established the safe-vs-destructive split, and the targeted item-6 fix already removed the passive "tell the user they can run <safe next step>" phrasing. The blanket "agent runs everything" principle pushed deploys to be more eager and carried a wrong "permission layer prompts for approval" claim (untrue in auto-approve/headless mode). Keep deploys conservative.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(cli): default fork workspace name/id to the current branch when renaming it
When 'wmill workspace fork' converts the current working branch into the fork branch, default the fork's name and id to that branch (sanitized to a slug, since branch names can contain '/'). Interactive: the prompt is pre-filled (enter to accept); non-interactive (--yes): used automatically. Adds a unit test for the slug derivation.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(cli): address fork review — guard fork-branch rename, cap+validate fork id
Two P2s from review:
- --from-branch refused when the current branch is already a fork branch (would detach the existing fork by renaming its branch).
- fork id slug capped to 42 chars (backend max 50 incl. wm-fork- prefix); auto-derived id is slugged; full id validated client-side before existsWorkspace/datatable cloning so an invalid id fails fast instead of leaving cloned Postgres databases behind.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: clear conflict error + force delete when reusing a fork workspace id
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: guard fork force-delete against double submit
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(flow): support worker tag override on AI agent steps
* refactor: drop ineffective tag passthrough in nested agent tool path
* chore: regenerate openflow-derived system prompt artifacts
* docs(skills): decouple safe local commands from destructive sync push
The schedules, triggers, and resources skill templates lumped every CLI
command under a blunt "do NOT run them yourself" directive. This conflated
two very different risk profiles and forbade the agent from running even
read-only/local commands, creating needless friction.
Align these three with the nuanced policy flow-cli.md already uses: keep
`wmill sync push` defensive (it deploys and can be destructive to remote
state — only run when the user explicitly asks to deploy/publish/push),
while letting read-only commands (`sync pull`, `schedule`, `resource
list`) be run freely. Regenerated auto-generated skills + skills.gen.ts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(cli): warn that sync push is destructive in dry-run output
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(skills): clarify sync pull mutates local files, not read-only
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: centdix <farhadg110@gmail.com>
* fix(cli): reconcile case-only path drift during sync on case-insensitive filesystems
Windmill paths are case-sensitive, but Windows (and the default macOS
setup) use case-insensitive filesystems. The real-world failure behind
WIN-2020 is not a user authoring both f/Caps and f/caps — it is a single
capitalized folder whose on-disk casing silently drifts (Windows stores
and reports whatever case the directory was first created with,
regardless of the server's path). The diff then sees the drifted local
path as a brand-new item and emits a destructive "delete f/Caps +
add f/caps" pair, so a capitalized folder appears to vanish and a
lowercase clone shows up out of nowhere — and a push can clobber the
real server item.
Fix: on a case-insensitive filesystem, reconcile case-only drift before
diffing. The server's path casing is authoritative, so compareDynFSElement
now rewrites local keys that differ from a remote key only by case to the
server's casing (canonicalizeCaseInsensitiveKeys), making the diff treat
them as the same item. Case-insensitivity is auto-detected by probing the
sync directory, with a WMILL_CASE_INSENSITIVE_FS=true/false override to
force Windows behaviour (or emulate it for tests / cross-platform repos)
on any host. Reconciled paths are summarized in a single info line.
Genuinely unrepresentable collisions — two DISTINCT server paths that
differ only by case — cannot be canonicalized to one target; those are
detected and warned about on every platform so a case-sensitive-Linux
author learns their tree won't round-trip for a Windows/macOS teammate.
Tests:
- Pure unit tests for findCaseInsensitiveCollisions,
canonicalizeCaseInsensitiveKeys and summarizeCaseRewrites (platform
independent).
- An end-to-end drift test that runs on BOTH CI jobs: on the Windows
runner it exercises the real case-insensitive NTFS + auto-probe; on
Linux it reproduces the drift via rename, asserts the destructive
phantom appears without the fix, and asserts a clean no-op push with
the fix forced on.
Fixes WIN-2020
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(cli): canonicalize local-only descendants of drifted folders; dedupe nested case collisions
Address two review findings on the WIN-2020 case-insensitive sync fix:
P1 (correctness): canonicalizeCaseInsensitiveKeys previously only rewrote
local keys with an exact full-path remote match. A brand-new local file
under a drifted folder (e.g. adding f/caps/New.ts when the server has
f/Caps but no f/caps/New.ts) had no exact match, so it kept its lowercase
casing and push uploaded it as-is — recreating f/caps beside f/Caps and
reintroducing the very collision the fix prevents. Canonicalization is now
segment-by-segment against a trie of remote paths, so local-only
descendants inherit the longest unambiguous server folder casing. A segment
is only adopted when the server casing is unambiguous; at the first
ambiguous/unknown segment the remainder keeps local casing. The original
key's separator style is preserved so rewritten keys still round-trip.
P2 (nit): findCaseInsensitiveCollisions reported the folder group AND a
nested per-file group when case-variant folders held same-named files,
inflating the "Found N path(s)" count. It now reports only the shallowest
clash (drops a group whose ancestor prefix is itself a collision).
Tests: add unit coverage for the new-file-under-drifted-folder rewrite, the
stop-at-first-unguided-segment behavior, and shallowest-only collision
reporting; extend the e2e drift test to assert a new item added under the
drifted folder is pushed under the server's folder casing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(flows): early stop can include the stopping step's result in the raised error
When a step uses Early Stop with "Raise an error message if stopped", the
flow result was entirely replaced with a static error object
({"error": {"name": "EarlyStopError", "message": "..."}}), discarding the
stopping step's own output. This made it impossible to stop+fail a flow
while preserving the data the step produced (e.g. an API that returns
HTTP 200 with a userErrors payload).
Add an opt-in `error_include_result` flag on StopAfterIf. When enabled on
the raise-error path, the raised payload becomes
{"error": {...}, "result": <step result>} instead of dropping the result.
Default is false, so existing behavior is unchanged. The option is threaded
through the worker's stop-after-if handling (including stop_after_all_iters_if
for loops/branchall) and exposed in the flow editor's Early Stop panel.
Fixes WIN-2012
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(flows): cover early-stop error_include_result payload shaping
Add a regression test asserting that a step using Early Stop with a raised
error message and error_include_result=true fails the flow while preserving
the step output as {"error": {..}, "result": <step result>}, and that with
the flag off the result is the bare {"error": {..}} object.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(flows): nest early-stop step result inside the error object
Embed the stopping step's result under `error.result` rather than as a
top-level sibling of `error`. This keeps the flow result shape as
`{ "error": { .. } }` — identical to a normal error — so consumers that
key off the top-level shape (single `error` key) keep working, while the
data is still preserved for those that look inside the error object.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(flows): always include the stopping step's result in early-stop errors
Drop the opt-in `error_include_result` gate. Since the step result is nested
inside the error object (`error.result`), the top-level result shape stays
`{ "error": .. }` — identical to a normal error — so consumers that detect or
parse failures by the top-level shape are unaffected. Gating it added schema
surface, plumbing, and a UI toggle for no real compatibility benefit.
Now, whenever a step early-stops with a raised error message, the flow fails
and the raised error embeds the stopping step's own result under
`error.result` (aggregated iteration results for loops/branchall). This
reverts the `StopAfterIf.error_include_result` field, its threading, the
OpenAPI/generated-client surface, and the editor toggle; the "Raise an error
message" tooltip now notes that the step result is included.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(flows): gate early-stop result inclusion behind opt-in flag
Re-introduce the per-step `error_include_result` flag (default off) instead
of always embedding the step result. Although nesting the result under
`error.result` keeps the result *shape* backward-compatible, it does not
address data exposure: a failed flow's result is propagated to synchronous
webhook callers, the flow's failure module, and the workspace/global error
handler (commonly a Slack/email/outbound-webhook notifier). Always including
the step output would surface previously-redacted intermediate data to all of
those sinks for every existing error-stop flow.
Gating keeps the existing behavior (bare `{ "error": .. }`) as the default and
only embeds `error.result` when the flow author explicitly opts in, matching
the original issue's intent.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(flows): omit error_include_result when false; refresh generated prompts
- Add `skip_serializing_if = "is_false"` to `StopAfterIf.error_include_result`
so serialized flows are byte-identical when the flag is off. Fixes the
`flowmodule_serde` round-trip test (cargo_test) and avoids churn on existing
flows.
- Regenerate `system_prompts/auto-generated/` and `cli/src/guidance/skills.gen.ts`
for the new OpenFlow `error_include_result` property. Fixes check-freshness.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(flows): cover error_include_result for the loop "stop after all iters" path
Add a regression test for the stop_after_all_iters_if branch, where `nresult`
already holds the aggregated iteration results — confirming `error.result`
carries each iteration's output (distinct from the per-step fallback path).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(cli): push whole raw app instead of treating frontend files as scripts
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(cli): shorten raw-app handleFile comment
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor: resolve workspace imports via /f/,/u/ not $f/,$u/ aliases
Keep the CLI managed tsconfig.wmill.json / `refresh tsconfig` / Deno
import-map QoL from #9378, but re-key it on the existing /f/,/u/ workspace
paths instead of the new $f/,$u/ specifiers. Verified /f/,/u/ resolves in
tsc, Bun, Deno, the in-app ATA editor, and the worker, so the $-prefixed
alias added no value. Drop the $f/,$u/ handling from the parser, dep-map,
deno_executor, bun loaders, ATA, relative_imports and monaco paths; revert
the windmill-parser-wasm-ts bump (1.714.0 -> 1.695.0). Also fold in the
cli/package-lock.json sync for the already-committed pg-gateway dependency.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: drop duplicate relative-path check and restore rustfmt formatting
Follow-up cleanups to the previous commit's full-file reverts, which
restored pre-#9378 state that main had since improved:
- relative_imports.ts: remove the redundant duplicate d.startsWith('/')
(pre-#9378 had it; #9378 had repurposed that line, so main has no dup).
- windmill-parser-ts/src/lib.rs: restore the multi-line new_source_file(...)
formatting required by backend/rustfmt.toml (the single-line revert would
fail `cargo fmt --check`). Now differs from main only by the $f//$u/ removal.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`cli/src/utils/utils.ts` imported `VERSION` from `cli/src/main.ts`, while
`main.ts` transitively imports `utils.ts` (via `workspace.ts`). When a module
load order entered the graph through `workspace.ts -> utils.ts -> main.ts`,
`main.ts`'s top-level command tree ran while `workspace.ts` was still
mid-initialization, so the `workspace` binding was still in its temporal dead
zone at `.command("workspace", workspace)`:
ReferenceError: Cannot access 'workspace' before initialization
This surfaced as 56 failing CLI tests on Windows CI (the Windows runner's test
module-load order triggers the bad path; it reproduces on any platform via
`bun -e 'await import("./src/commands/workspace/workspace.ts")'`).
Move `VERSION` to `cli/src/core/constants.ts` (already the "minimal imports"
module), re-export it from `main.ts` for backwards compatibility, and have
`utils.ts` read it from `constants.ts` — eliminating the cycle. Release tooling
(`.github/change-versions*.sh`) is updated to rewrite the `VERSION` line in its
new location.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: support $f/ and $u/ import path aliases for scripts
$f/ and $u/ are local-friendly aliases for the absolute workspace
import paths /f/ and /u/. Unlike the /-prefixed form (which local tools
treat as a filesystem-root path), the $-prefixed form is a bare specifier
that can be remapped via tsconfig paths / Deno import maps, so the same
import resolves on the Windmill worker and in a local editor.
- worker: recognize $f//$u/ in the Deno import map and both Bun loaders
- dep-map/parser: normalize $f/->f/, $u/->u/ for lockgen + dep tracking
- cli: emit $f/$u path aliases in generated tsconfig.json / deno.json
- frontend: ATA + Monaco paths resolve $f//$u/ type hints in the editor
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(cli): split generated tsconfig into managed + user file with refresh command
Mirror the AGENTS.cli.md/AGENTS.md prompts model for the IDE tsconfig so the
recommended settings can evolve without ever clobbering user customizations:
- tsconfig.wmill.json: wmill-managed, always refreshed, holds recommended
compilerOptions incl. the $f/$u path aliases (Deno: import_map.wmill.json)
- tsconfig.json: user-owned, created once, just extends the managed file;
warn (never auto-edit) when an existing one doesn't reference it
- add 'wmill refresh tsconfig'; init generates it unconditionally (no longer
gated behind resource-type namespace / a bound workspace)
- regenerate CLI guidance docs for the new subcommand
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(cli): address PR review on $f/ tsconfig generation
- handle existing deno.jsonc so we don't shadow it with a new deno.json
(P1 identified by cubic)
- fix the bun-types hint that pointed users at the managed do-not-edit
tsconfig.wmill.json; tell them to install + re-run 'wmill refresh tsconfig'
- document the .ts-extension-only local-resolution limitation (cross-flavor
.bun.ts/.deno.ts/.fetch.ts scripts won't resolve in a local editor)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(cli): warn when a project's tsconfig isn't wired to tsconfig.wmill.json
Mirror the prompts freshness check for the managed tsconfig so users with an
existing setup actually discover they're missing $f//$u/ resolution:
- embed a version hash in tsconfig.wmill.json (excludes the env-dependent
bun-types 'types' entry so it doesn't false-positive)
- add warnIfTsconfigStale to the main.ts freshness hook, gated identically to
the prompts check (skips init/refresh/help/version). When a tsconfig.json
exists it warns one line (stderr) if the managed file is missing, not
referenced via extends, or out of date; silent for non-TS projects.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(cli): make tsconfig setup equivalent to prompts (auto-wire + stale-only)
Unify the two managed-file systems so they behave identically:
- auto-wire an existing unlinked tsconfig.json/deno.json on init/refresh
(add extends / importMap; merge into an array extends), instead of only
warning. Parses JSON and falls back to a warning when it can't round-trip
(JSONC comments, or a conflicting deno imports/importMap) — never corrupts.
- narrow warnIfTsconfigStale to stale-only, gated on the managed file
existing, exactly like warnIfPromptsStale: it no longer nags about a
missing or unlinked tsconfig.json, so a deliberately-custom/unlinked setup
stays silent and a not-yet-initialized project isn't bothered.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(cli): place tsconfig.wmill.json first in extends to preserve user base config
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(cli): migrate legacy tsconfig and require consent for custom configs
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(cli): align prompts wiring to the same consent model
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(cli): bump windmill-parser-wasm-ts to 1.714.0 for $f/ $u/ aliases
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(worker): resolve $f/ and $u/ in deno lock generation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test: narrow relative-imports lock-gen guard to deno import-map failure
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(cli): sync bun.lock with windmill-parser-wasm-ts 1.714.0
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(cli): warn when a custom tsconfig's paths would shadow $f/ $u/ aliases
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(cli): stop git-sync promotion deploys from dropping triggers/schedules
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore: bump git-sync hub script to hub/28261 (windmill-cli 1.713.2)
Points LATEST_GIT_SYNC_SCRIPT_PATH at the republished sync-script-to-git-repo
that pins windmill-cli@1.713.2, which carries the promotion include-derivation
fix in this PR.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
When encryption_key.yaml changes and is pushed via `wmill sync push`,
pushWorkspaceKey prompted interactively to confirm re-encrypting the
remote secrets with the new key. That prompt ignored `--yes` and had no
TTY guard, so a CI/non-interactive push that included the key would
block (or behave undefinedly) on the prompt.
Thread a key-push options object (non-interactive flag + explicit
re-encryption choice) through pushObj into pushWorkspaceKey:
- Non-interactive (`--yes` or no TTY) and no explicit choice: skip the
prompt and default to re-encrypting all remote secrets with the new
key (matches the interactive default), preserving their plaintext
values.
- New `--skip-reencrypt-on-key-change` flag (and the
WMILL_NO_REENCRYPT_ON_KEY_CHANGE=true env var for CI) opt out of
re-encryption — only safe when the remote ciphertexts are already
encrypted with the new key (e.g. workspace/instance migration).
- Interactive behavior (TTY, no `--yes`) is unchanged.
Regenerates system_prompts for the new option and adds unit tests for
the no-op, re-encrypt-by-default, flag-skip, and env-skip paths.
Fixes WIN-2005
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(flows): preserve step/subflow worker tags under a custom-tagged flow
A flow running on a custom worker tag force-propagates that tag to every
descendant step, script and nested sub-flow, overriding their own declared
tags. This made it impossible to route a specific step or sub-flow to a
different worker group. The new opt-in FlowValue.preserve_step_tags lets a
step that declares its own non-empty tag run on it; untagged steps still
inherit the flow tag. Defaults off to preserve existing behavior.
* chore: regenerate system prompts for preserve_step_tags
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(flows): nest preserve_step_tags toggle under flow worker tag setting
The toggle only affects routing when the flow has a custom worker tag, so
show it as a sub-setting of the Worker Group tag picker, visible only once a
tag is set, instead of as a standalone option.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(flows): allow step worker tag picker when preserve_step_tags is enabled
When a flow defines a worker tag, the per-step tag picker was replaced by a
read-only "Flow's WG" label. With preserve_step_tags enabled the step's own
tag is honored, so the picker must remain editable in that case.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(flows): propagate preserve_step_tags to branch and loop bodies
payload_from_modules built the synthetic RawFlow for branch/loop bodies with
a default FlowValue, dropping preserve_step_tags. Tagged steps inside a
branch or loop therefore still inherited the parent flow tag even with the
flag enabled. Thread the flag through to the synthetic FlowValue so the
behavior is consistent for nested containers.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(flows): clear preserve_step_tags when flow worker tag is removed
Avoids the flag lingering as invisible state after the flow tag (and its
toggle) are removed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(flows): repair preserve_step_tags propagation to branch/loop bodies
The previous commit added flow.preserve_step_tags at the payload_from_modules
call sites but the parameter and FlowValue field were not actually threaded
through (a failed edit left the function unchanged), so the crate did not
compile. This completes the change: payload_from_modules takes preserve_step_tags
and sets it on the synthetic FlowValue for branch/loop bodies.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(flows): complete preserve_step_tags propagation to branch/loop bodies
Previous two commits left windmill-worker uncompilable: payload_from_modules
received flow.preserve_step_tags at its call sites but the parameter and the
synthetic FlowValue field were not actually added. This adds the parameter,
sets preserve_step_tags on the synthetic FlowValue, and threads
flow.preserve_step_tags through all five call sites.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(flows): clear preserve_step_tags whenever the flow worker tag is removed
The flag was only reset when the Worker Group toggle was switched off, not
when the tag was cleared directly in the picker (or via the YAML editor),
leaving preserve_step_tags=true as invisible state with the advanced badge
still reporting it active. Move the cleanup into the reactive block that
already tracks the flow tag so every clear path is covered.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* docs(skills): document mandatory //native marker for bunnative and nativets
* docs(skills): clarify windmill-client is the only allowed library in native mode
* docs(skills): remove legacy nativets skill in favor of bunnative
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(skills): fix bunnative import rule - any bundleable lib, not just windmill-client
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CLI deploys (sync push, set-permissioned-as) went through the same
create/update endpoints as a UI "deploy from draft", which delete the
draft at that path. That silently wiped teammates' in-progress drafts on
every push. Add a transient skip_draft_deletion deploy flag (mirroring
deployment_message) that the CLI sets; the backend then skips the
DELETE FROM draft for scripts, flows, and apps. UI deploys are unchanged.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [ee] fix(git-sync): publish fork branch on only_create_branch from the CLI
Fixes WIN-1997. Forking a git-sync-configured workspace must push a
`wm-fork/<branch>/<id>` branch to the repo, but the integration test
`test_workspace_fork_creates_branch` failed: the fork callback job
succeeded yet no branch appeared.
Root cause: the fork-branch callback runs the sync script with
`only_create_branch: true` and no items. The hub sync script delegates
branch checkout to `wmill sync git-deploy --only-create-branch` and runs
its own in-process commit+push ONLY for the `!only_create_branch` path
(`if (!only_create_branch) git_push(...)`). #9284 had moved commit+push
out of the CLI to the caller for the GPG-cache-warmth invariant
(WIN-1974) — but it also dropped the CLI's push for the branch-only
case. A branch-only publish has no commit, so no signing is involved and
the GPG concern does not apply; with neither the CLI nor the hub script
pushing, the empty fork branch was never published.
Restore the CLI push for the `only_create_branch` path (a bare
`git push --porcelain` of the checked-out branch ref). Adds a
deterministic CLI regression test that runs `git-deploy
--only-create-branch` for a fork workspace and asserts the branch
reaches the remote with no caller-side push.
EE companion: format the fork-branch commit message with Display instead
of Debug (no more `Some("...")` leak).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to a30079e75dc5b7d7413aa8ee20e40e80bfea9cbd
This commit updates the EE repository reference after PR #597 was merged in windmill-ee-private.
Previous ee-repo-ref: 8b02336fcebdfae4b9d2795cbb74fa7046530bcb
New ee-repo-ref: a30079e75dc5b7d7413aa8ee20e40e80bfea9cbd
Automated by sync-ee-ref workflow.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
referencesIncludeLine required the include token to be the entire
trimmed line. The wmill-default CLAUDE.md template is
`Instructions are in @AGENTS.md` — include mid-sentence — so the
migration prompt fired every run on files wmill itself wrote.
Accept the include as a whitespace-separated token on any non-comment
line.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(cli): redact encryption_key diff in stdout by default
Sync diff output previously printed the full encryption_key contents on
stdout whenever the workspace key changed locally or on the remote, which
made it easy to leak the key via shell history, CI logs, etc. Now the
diff is replaced with a redacted notice for any encryption_key change in
both prettyChanges and showConflict. Pass --show-encryption-key-diff
(also configurable via wmill.yaml's showEncryptionKeyDiff) to opt back
into the full diff.
Fixes WIN-1992
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(cli): redact encryption_key diff with fixed-length mask
Drop the --show-encryption-key-diff opt-in and always redact: the diff
now keeps the first 5 chars of the key so rotations are still visible
(different prefixes), then replaces every remaining char with `*` so the
length of the key is preserved without leaking it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(typescript-client): add deleteS3File + optional workspace arg on S3 helpers
Customer-requested ergonomics for the TypeScript SDK:
- New `deleteS3File(s3object, workspace?)` wrapper around the existing
`HelpersService.deleteS3File` (backend endpoint is already there). Saves
callers from having to either hand-roll `denoS3LightClientSettings()` +
AWS SDK calls, or wire up `HelpersService` directly.
- `denoS3LightClientSettings`, `loadS3File`, `loadS3FileStream`, `writeS3File`,
and the new `deleteS3File` all gain an optional trailing `workspace?: string`
parameter that falls back to the `WM_WORKSPACE` env var via `getWorkspace()`.
Mirrors the calling convention customers already expect from helpers like
`getVariable` / `runScript`.
`build.sh` and `build.jsr.sh` are updated to export `deleteS3File` from both
the NPM and JSR entry points.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: regenerate system_prompts auto-generated for new S3 helpers
`python system_prompts/generate.py` after adding deleteS3File and the
optional workspace param to the existing S3 helpers, so the agent-facing
docs (CLI skills, TS SDK prompt, script skills) reflect the new signatures.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>