From ef870a52e421f6d7f5c7b99276c294ae3eb4662b Mon Sep 17 00:00:00 2001 From: Guilhem Lemouel Date: Tue, 13 Oct 2026 02:39:42 -0700 Subject: [PATCH] fix: keep the refused form on the side it is showing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closing the JSON editor when the form starts refusing writes mounted `SchemaForm` in its place, and `PasswordArgInput` mints a variable from the literal it opens on without consulting `disabled` — so a reader who typed a plaintext secret into JSON view had it stored by the act of entering plan mode, with no run and no Run press. The form no longer swaps sides while it refuses: `JsonInputs` takes `readOnly` and the editor stays mounted and uneditable. The JSON toggle is already hidden in that state, which is what keeps the fields from mounting from the other direction. Co-Authored-By: Claude Opus 5 (1M context) --- frontend/src/lib/components/JsonInputs.svelte | 8 +++++++- frontend/src/lib/components/RunForm.svelte | 12 ++++++++---- .../src/lib/components/details/FlowDetail.svelte | 6 +++++- .../src/lib/components/details/ScriptDetail.svelte | 6 +++++- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/frontend/src/lib/components/JsonInputs.svelte b/frontend/src/lib/components/JsonInputs.svelte index 2f4b04f8e4..546ab36069 100644 --- a/frontend/src/lib/components/JsonInputs.svelte +++ b/frontend/src/lib/components/JsonInputs.svelte @@ -13,13 +13,18 @@ * payload nobody has typed into tracks the schema instead of going stale. The first edit * hands the buffer to the user and later changes stop overwriting it. */ initialCode?: string + /** Show the payload without taking edits. For a caller that must keep this editor + * mounted while refusing writes: swapping it for the fields instead would mount the + * widgets, and a `password` field mints a variable from whatever literal it opens on. */ + readOnly?: boolean } let { updateOnBlur = true, placeholder = 'Write a JSON payload. The input schema will be inferred.

Example:

{
  "foo": "12"
}', selected = false, - initialCode = '' + initialCode = '', + readOnly = false }: Props = $props() let pendingJson = $state(untrack(() => initialCode)) @@ -130,6 +135,7 @@ bind:code={pendingJson} lang="json" class="h-full json-inputs-editor" + {readOnly} {placeholder} /> diff --git a/frontend/src/lib/components/RunForm.svelte b/frontend/src/lib/components/RunForm.svelte index cede84f394..c01f7598ca 100644 --- a/frontend/src/lib/components/RunForm.svelte +++ b/frontend/src/lib/components/RunForm.svelte @@ -135,10 +135,13 @@ } | undefined /** Set to refuse every write this form can make, and to say so when a run is - * attempted. No edits, no dynamic-select helper, no JSON, and no run — `run()` mints - * the `password` arguments it is about to send, so refusing in `runAction` is already - * too late. For a form standing in for a chat card under plan mode, which promised - * none of it. */ + * attempted: the fields are disabled, the dynamic-select helper is not wired, the JSON + * editor is read-only, and `run()` refuses before it mints the `password` arguments it + * would send — so a caller cannot gate this in `runAction`, which comes after that + * mint. For a form standing in for a chat card under plan mode, which promised none of + * it. The caller must also leave this form on the side it is showing: swapping fields + * for JSON or back mounts a `password` widget, which mints from the literal it opens + * on regardless of being disabled. */ runRefusal?: string runAction: ( scheduledForStr: string | undefined, @@ -349,6 +352,7 @@ > { // The other way into the arguments, and the one disabling the fields misses. if (argsReadonly) return diff --git a/frontend/src/lib/components/details/FlowDetail.svelte b/frontend/src/lib/components/details/FlowDetail.svelte index 8612f871f9..b9ca597f6d 100644 --- a/frontend/src/lib/components/details/FlowDetail.svelte +++ b/frontend/src/lib/components/details/FlowDetail.svelte @@ -865,6 +865,10 @@ {inputSelected} /> + {#if hasSchema && !pendingRun?.planModeActive} diff --git a/frontend/src/lib/components/details/ScriptDetail.svelte b/frontend/src/lib/components/details/ScriptDetail.svelte index acb61567f8..6d463434eb 100644 --- a/frontend/src/lib/components/details/ScriptDetail.svelte +++ b/frontend/src/lib/components/details/ScriptDetail.svelte @@ -1059,6 +1059,10 @@ }} {inputSelected} /> + {#if hasSchema && !pendingRun?.planModeActive}