diff --git a/docs/superpowers/specs/2026-03-29-parameterize-and-save-design.md b/docs/superpowers/specs/2026-03-29-parameterize-and-save-design.md new file mode 100644 index 00000000..a78b1867 --- /dev/null +++ b/docs/superpowers/specs/2026-03-29-parameterize-and-save-design.md @@ -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