docs: add parameterize-and-save design spec
Design for fixing AI-generated scripts saving to library without parameters, adding parameter detection/review to the save flow, and a "New from Script" paste entry point on the library page. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
# Parameterize & Save — Script Library Integration
|
||||
|
||||
> **Date:** 2026-03-29
|
||||
> **Status:** Approved
|
||||
> **Scope:** Fix AI-generated scripts saving to library without parameters; add parameter detection/review to save flow; add "New from Script" paste entry point
|
||||
|
||||
---
|
||||
|
||||
## Problem
|
||||
|
||||
When the AI Script Builder generates a script and the user saves it to the Script Library:
|
||||
|
||||
1. **`parameters_schema` is hardcoded to `{"parameters": []}`** in `save_to_library()` — no parameter detection runs
|
||||
2. **The script body uses raw PowerShell `param()` syntax**, not the `{{ key }}` template placeholders that `ScriptTemplateEngine.render()` expects
|
||||
|
||||
The result: saved templates have no parameters and can't be rendered with user-provided values. The template engine has nothing to substitute.
|
||||
|
||||
The frontend already has working parameter detection (`scriptParameterDetector.ts`) and a review UI (`ParameterDetectorStepper`), but they're only wired into `ScriptTemplateEditor` — not the save-to-library flow.
|
||||
|
||||
## Solution
|
||||
|
||||
A shared `ParameterizeAndSavePanel` component that:
|
||||
|
||||
1. Shows the script with live preview of `{{ }}` replacements
|
||||
2. Auto-runs parameter detection and lets the user review/accept/skip each candidate
|
||||
3. Collects minimal metadata (name, description, category, share toggle)
|
||||
4. Sends the rewritten script body + built parameters schema to the backend
|
||||
|
||||
Used in two entry points:
|
||||
- **AI Script Builder** — replaces the current `SaveToLibraryDialog`
|
||||
- **Script Library page** — "New from Script" button for pasting raw scripts
|
||||
|
||||
> **Note:** Parameter detection currently supports PowerShell only. Bash and Python scripts will show "No parameters detected" and save as-is. Detection for those languages is planned for a future iteration.
|
||||
|
||||
---
|
||||
|
||||
## Design
|
||||
|
||||
### `ParameterizeAndSavePanel` Component
|
||||
|
||||
A slide-in panel from the right, ~480px wide, semi-transparent scrim behind it. Close via X button or scrim click.
|
||||
|
||||
**Layout (top to bottom):**
|
||||
|
||||
1. **Script Preview** — read-only code block showing the script body. As parameters are accepted via the stepper, the preview updates live to show `{{ key }}` replacements highlighted in amber.
|
||||
|
||||
2. **Parameter Detection Zone** — auto-runs `detectParameterCandidates()` when the panel opens.
|
||||
- If candidates found: renders the existing `ParameterDetectorStepper` inline
|
||||
- If no candidates found: shows "No parameters detected — script will be saved as-is"
|
||||
|
||||
3. **Metadata Fields** — name (required), description, category dropdown, share-with-team toggle. Same fields as the current `SaveToLibraryDialog`.
|
||||
|
||||
4. **Save Button** — sends rewritten script body + parameters schema + metadata to the backend.
|
||||
|
||||
**Two modes controlled by props:**
|
||||
|
||||
- **`script` mode** (from AI builder): script body + language provided, skips straight to preview + detection
|
||||
- **`paste` mode** (from library page): shows a textarea + language picker at the top of the panel, above the preview area. Once pasted and confirmed, textarea collapses into the read-only preview and detection runs.
|
||||
|
||||
**State:** Local React state (not Zustand). Tracks:
|
||||
- `workingScript`: the in-progress script body, mutated as candidates are accepted
|
||||
- `parametersSchema`: accumulated `ScriptParameter[]` array
|
||||
- `metadata`: name, description, categoryId, shareWithTeam
|
||||
- `mode`: paste vs script (derived from props)
|
||||
|
||||
### Entry Point 1: AI Script Builder
|
||||
|
||||
`ScriptBuilderPage` currently opens `SaveToLibraryDialog`. Replace with `ParameterizeAndSavePanel` in `script` mode.
|
||||
|
||||
**Props:**
|
||||
- `scriptBody`: `session.latest_script`
|
||||
- `language`: `session.language`
|
||||
- `defaultName`: suggested filename minus extension
|
||||
- `onSave`: calls `scriptBuilderApi.saveToLibrary()` with enriched payload
|
||||
- `onClose`: closes the panel
|
||||
|
||||
### Entry Point 2: Script Library Page
|
||||
|
||||
Add a "New from Script" button on `ScriptLibraryPage` (near the "Manage Templates" link). Opens `ParameterizeAndSavePanel` in `paste` mode.
|
||||
|
||||
**Props:**
|
||||
- `scriptBody`: `undefined` (triggers paste mode)
|
||||
- `language`: `undefined` (user picks in the panel)
|
||||
- `onSave`: calls `scriptsApi.createTemplate()` directly
|
||||
- `onClose`: closes the panel
|
||||
|
||||
### Backend Changes
|
||||
|
||||
**`SaveToLibraryRequest` schema** (`backend/app/schemas/script_builder.py`):
|
||||
|
||||
Add two optional fields:
|
||||
```python
|
||||
script_body: str | None = None # Rewritten script with {{ }} placeholders
|
||||
parameters_schema: dict | None = None # Built parameter schema from frontend
|
||||
```
|
||||
|
||||
**`save_to_library()` service** (`backend/app/services/script_builder_service.py`):
|
||||
|
||||
Add `script_body: str | None = None` and `parameters_schema: dict | None = None` to the function signature. Use provided values instead of hardcoding:
|
||||
```python
|
||||
template = ScriptTemplate(
|
||||
...
|
||||
script_body=script_body or session.latest_script,
|
||||
parameters_schema=parameters_schema or {"parameters": []},
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
**`save_to_library` endpoint** (`backend/app/api/endpoints/script_builder.py`):
|
||||
|
||||
Pass `data.script_body` and `data.parameters_schema` from the request through to the service function.
|
||||
|
||||
**No new endpoints needed.** The library paste flow uses the existing `POST /scripts/templates` which already accepts `script_body` + `parameters_schema`.
|
||||
|
||||
### Script Rewriting Logic
|
||||
|
||||
The `ParameterizeAndSavePanel` reuses the same approach as `ScriptTemplateEditor.handleAcceptCandidate()`:
|
||||
|
||||
When a candidate is accepted:
|
||||
1. Find the matched line in the working script
|
||||
2. Replace the default value portion with `'{{ key }}'`
|
||||
3. Add the parameter to the accumulated schema
|
||||
|
||||
This happens in the panel's local state. The stepper emits accept/skip events; the panel handles the rewriting.
|
||||
|
||||
---
|
||||
|
||||
## File Changes
|
||||
|
||||
### New Files
|
||||
- `frontend/src/components/scripts/ParameterizeAndSavePanel.tsx` — shared panel component
|
||||
|
||||
### Modified Files
|
||||
- `frontend/src/pages/ScriptBuilderPage.tsx` — replace `SaveToLibraryDialog` with `ParameterizeAndSavePanel` (script mode)
|
||||
- `frontend/src/pages/ScriptLibraryPage.tsx` — add "New from Script" button, render `ParameterizeAndSavePanel` (paste mode)
|
||||
- `backend/app/schemas/script_builder.py` — add `script_body` and `parameters_schema` to `SaveToLibraryRequest`
|
||||
- `backend/app/services/script_builder_service.py` — use provided values in `save_to_library()`
|
||||
- `backend/app/api/endpoints/script_builder.py` — pass new fields through
|
||||
|
||||
### Deleted Files
|
||||
- `frontend/src/components/script-builder/SaveToLibraryDialog.tsx` — replaced entirely
|
||||
|
||||
### Unchanged (reused as-is)
|
||||
- `frontend/src/components/script-editor/ParameterDetectorStepper.tsx`
|
||||
- `frontend/src/lib/scriptParameterDetector.ts`
|
||||
- `frontend/src/components/script-editor/ScriptTemplateEditor.tsx`
|
||||
- `POST /scripts/templates` endpoint
|
||||
|
||||
---
|
||||
|
||||
## Scope Boundaries
|
||||
|
||||
**In scope:**
|
||||
- `ParameterizeAndSavePanel` component with script/paste modes
|
||||
- Parameter detection + stepper review in the save flow
|
||||
- Script body rewriting with `{{ }}` placeholders
|
||||
- Backend accepting enriched save payload
|
||||
- "New from Script" button on library page
|
||||
- PowerShell parameter detection only
|
||||
|
||||
**Out of scope:**
|
||||
- Bash/Python parameter detection (future iteration)
|
||||
- Changes to `ScriptTemplateEditor` or `ParameterSchemaBuilder`
|
||||
- Changes to `ScriptTemplateEngine` rendering logic
|
||||
- New API endpoints
|
||||
Reference in New Issue
Block a user