feat: Script Generator Phase 1 — backend models, engine, API, and AD templates #105

Merged
chihlasm merged 78 commits from feat/script-generator into main 2026-03-15 00:19:00 +00:00
Showing only changes of commit 7334d55cf2 - Show all commits

View File

@@ -44,7 +44,7 @@ This is a cross-column relocation of the Generate/Download/Copy controls:
## New Work (not pre-existing)
The **Copy button in the action bar** is new — it does not exist in the current `ScriptGeneratorPanel`. It must be implemented as a new button in `ScriptConfigurePane` that copies `generatedScript` (or `displayScript` from `ScriptPreview`'s computation). Since `ScriptPreview` owns the substitution logic, the simplest approach is for the action-bar Copy to copy `generatedScript` from the store when available, and fall back to the draft preview via a shared utility or by co-locating the substitution logic. Implementation note: the action-bar Copy can duplicate `ScriptPreview`'s `handleCopy` behavior using `store.generatedScript` for the generated state; the draft substitution case is handled by `ScriptPreview`'s own overlay copy button.
The **Copy button in the action bar** is new — it does not exist in the current `ScriptGeneratorPanel`. It copies `generatedScript` from the store. It is **disabled** when `generatedScript === null` (i.e., before the user has clicked Generate). The draft preview's copy needs are handled by `ScriptPreview`'s existing overlay copy button. No draft-substitution logic needs to be duplicated in `ScriptConfigurePane`.
---
@@ -129,7 +129,7 @@ Two sub-states:
<p className="text-sm text-muted-foreground">Select a template to get started</p>
</div>
) : (
<div className="glass-card-static h-full overflow-y-auto p-4">
<div className="glass-card-static h-full overflow-hidden p-4">
<ScriptPreview />
</div>
)}
@@ -167,7 +167,10 @@ Transitions:
1. `selectTemplate(id)` is called (sets `isLoadingDetail: true` in store)
2. `setPaneMode('configure')` is called immediately — user sees the loading spinner in configure mode
**`selectTemplate` failure case:** If `selectTemplate` throws (network error), the store resets `isLoadingDetail: false` but leaves `selectedTemplate` unchanged. The pane mode remains `'configure'`. If this is the first selection (`selectedTemplate === null`), the configure pane will show neither a spinner nor template content — it will render nothing. `ScriptConfigurePane` must handle this: if `!isLoadingDetail && !selectedTemplate`, render an error state ("Failed to load template. ← Back to library").
**`selectTemplate` failure case:** If `selectTemplate` throws (network error), the store resets `isLoadingDetail: false` but leaves `selectedTemplate` unchanged. The pane mode remains `'configure'`.
- **First-selection failure** (`selectedTemplate === null` before the call): `ScriptConfigurePane` must handle `!isLoadingDetail && !selectedTemplate` — render an error state: "Failed to load template." with a "← Back to library" link.
- **Subsequent-selection failure** (`selectedTemplate` is still set from the previous template): the configure pane silently shows the previous template's form with stale data. This is an accepted edge case — network errors mid-session are rare and the user can press Back to recover. No special handling required.
**`paramValues` and `formErrors` on Back:** `clearOutput()` does not reset `paramValues` or `formErrors`. This is intentional — if the user returns to browse mode and then clicks "Configure →" on the same template again, `selectTemplate` will repopulate `paramValues` from defaults, discarding any edits. If they configure a different template, `selectTemplate` again repopulates from that template's defaults. There is no scenario where stale param values from a prior template persist into a new template's form. No additional cleanup is needed on Back.