From 553721726e9b091fb59f95e5c48cff70f509ff30 Mon Sep 17 00:00:00 2001 From: Jiahao Zhu Date: Sat, 24 Jan 2026 07:50:48 +0800 Subject: [PATCH] feat(templates): add auto-run toggle and quick start templates in session (#6) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add autoRun boolean to templates (default true for backwards compat) - When autoRun is false, template populates prompt without executing - Show quick start templates in session empty state - Rename runTemplate → applyTemplate to reflect new behavior - Update Rust backend to serialize autoRun in frontmatter --- packages/app/src/app/app.tsx | 17 ++- .../app/src/app/components/template-modal.tsx | 21 +++ packages/app/src/app/pages/dashboard.tsx | 8 +- packages/app/src/app/pages/session.tsx | 133 ++++++++++++------ packages/app/src/app/pages/templates.tsx | 10 +- packages/app/src/app/template-state.ts | 73 ++++++++-- packages/app/src/app/types.ts | 1 + packages/app/src/app/utils/templates.ts | 6 + packages/app/src/i18n/locales/en.ts | 4 +- packages/app/src/i18n/locales/zh.ts | 4 +- packages/desktop/src-tauri/src/types.rs | 6 + .../desktop/src-tauri/src/workspace/files.rs | 3 + .../src-tauri/src/workspace/templates.rs | 2 + 13 files changed, 218 insertions(+), 70 deletions(-) diff --git a/packages/app/src/app/app.tsx b/packages/app/src/app/app.tsx index b5fdd4ec..99a9f71d 100644 --- a/packages/app/src/app/app.tsx +++ b/packages/app/src/app/app.tsx @@ -722,12 +722,14 @@ export default function App() { setTemplateDraftPrompt, templateDraftScope, setTemplateDraftScope, + templateDraftAutoRun, + setTemplateDraftAutoRun, workspaceTemplates, globalTemplates, openTemplateModal, saveTemplate, deleteTemplate, - runTemplate, + applyTemplate, loadWorkspaceTemplates, } = templateState; @@ -1436,8 +1438,15 @@ export default function App() { applyThemeMode(isDark ? "dark" : "light"); }); + // Listen for setPrompt events from template system (when autoRun is disabled) + const handleSetPrompt = (e: CustomEvent) => { + setPrompt(e.detail); + }; + window.addEventListener("openwork:setPrompt", handleSetPrompt as EventListener); + onCleanup(() => { unsubscribeTheme(); + window.removeEventListener("openwork:setPrompt", handleSetPrompt as EventListener); }); createEffect(() => { @@ -2051,7 +2060,7 @@ export default function App() { setTemplateDraftScope(scope); }, openTemplateModal, - runTemplate, + applyTemplate, deleteTemplate, refreshSkills: (options?: { force?: boolean }) => refreshSkills(options).catch(() => undefined), refreshPlugins: (scopeOverride?: PluginScope) => @@ -2224,6 +2233,8 @@ export default function App() { sessionStatus={selectedSessionStatus()} renameSession={renameSessionTitle} error={error()} + workspaceTemplates={workspaceTemplates()} + applyTemplate={applyTemplate} /> @@ -2293,12 +2304,14 @@ export default function App() { description={templateDraftDescription()} prompt={templateDraftPrompt()} scope={templateDraftScope()} + autoRun={templateDraftAutoRun()} onClose={() => setTemplateModalOpen(false)} onSave={saveTemplate} onTitleChange={setTemplateDraftTitle} onDescriptionChange={setTemplateDraftDescription} onPromptChange={setTemplateDraftPrompt} onScopeChange={setTemplateDraftScope} + onAutoRunChange={setTemplateDraftAutoRun} /> void; onSave: () => void; onTitleChange: (value: string) => void; onDescriptionChange: (value: string) => void; onPromptChange: (value: string) => void; onScopeChange: (value: "workspace" | "global") => void; + onAutoRunChange: (value: boolean) => void; }; export default function TemplateModal(props: TemplateModalProps) { @@ -88,6 +90,25 @@ export default function TemplateModal(props: TemplateModalProps) { />
{translate("templates.prompt_hint")}
+ + {/* Auto-run Toggle */} +
+
+
{translate("templates.auto_run_label")}
+
{translate("templates.auto_run_hint")}
+
+ +
diff --git a/packages/app/src/app/pages/dashboard.tsx b/packages/app/src/app/pages/dashboard.tsx index a20d4c1a..69ae6593 100644 --- a/packages/app/src/app/pages/dashboard.tsx +++ b/packages/app/src/app/pages/dashboard.tsx @@ -78,7 +78,7 @@ export type DashboardViewProps = { setTemplateDraftScope: (value: "workspace" | "global") => void; openTemplateModal: () => void; resetTemplateDraft?: (scope?: "workspace" | "global") => void; - runTemplate: (template: WorkspaceTemplate) => void; + applyTemplate: (template: WorkspaceTemplate) => void; deleteTemplate: (templateId: string) => void; refreshSkills: (options?: { force?: boolean }) => void; refreshPlugins: (scopeOverride?: PluginScope) => void; @@ -537,7 +537,7 @@ export default function DashboardView(props: DashboardViewProps) { {(t) => ( )} @@ -698,7 +698,7 @@ export default function DashboardView(props: DashboardViewProps) { setTemplateDraftScope={props.setTemplateDraftScope} openTemplateModal={props.openTemplateModal} resetTemplateDraft={props.resetTemplateDraft} - runTemplate={props.runTemplate} + applyTemplate={props.applyTemplate} deleteTemplate={props.deleteTemplate} /> diff --git a/packages/app/src/app/pages/session.tsx b/packages/app/src/app/pages/session.tsx index 6762277a..38954fa3 100644 --- a/packages/app/src/app/pages/session.tsx +++ b/packages/app/src/app/pages/session.tsx @@ -9,11 +9,13 @@ import type { TodoItem, View, WorkspaceDisplay, + WorkspaceTemplate, } from "../types"; import { AlertTriangle, ArrowRight, + FileText, HardDrive, Shield, Zap, @@ -93,6 +95,8 @@ export type SessionViewProps = { setSessionAgent: (sessionId: string, agent: string | null) => void; saveSession: (sessionId: string) => Promise; sessionStatusById: Record; + workspaceTemplates: WorkspaceTemplate[]; + applyTemplate: (template: WorkspaceTemplate) => void; }; export default function SessionView(props: SessionViewProps) { @@ -323,7 +327,7 @@ export default function SessionView(props: SessionViewProps) { } setPrevArtifactCount(count); }); - + createEffect(() => { const files = props.workingFiles; const count = files.length; @@ -718,56 +722,101 @@ export default function SessionView(props: SessionViewProps) { } `} - + -
-
- +
+
+
+ +
+

Ready to work

+

+ Describe a task. I'll show progress and ask for permissions when needed. +

-

Ready to work

-

- Describe a task. I'll show progress and ask for permissions when needed. -

+ + {/* Spacer */} +
+ + {/* Quick Start Templates */} + 0}> +
+
+

+ Quick Start Templates +

+ +
+
+ + {(t) => ( + + )} + +
+
+
- -
-
- } - > - - - {runLine()} + 0}> + +
+
+ } + > + + + {runLine()} +
+ {runElapsedLabel()}
- {runElapsedLabel()}
-
- ) : undefined - } - /> + ) : undefined + } + /> +
(messagesEndEl = el)} />
- + chatContainerEl} messages={props.messages} /> @@ -777,7 +826,7 @@ export default function SessionView(props: SessionViewProps) {
- void; openTemplateModal: () => void; resetTemplateDraft?: (scope?: "workspace" | "global") => void; - runTemplate: (template: WorkspaceTemplate) => void; + applyTemplate: (template: WorkspaceTemplate) => void; deleteTemplate: (templateId: string) => void; }; @@ -68,9 +68,9 @@ export default function TemplatesView(props: TemplatesViewProps) {
{formatRelativeTime(t.createdAt)}
-
-