plugins: rename init to execute

Alessandro committed Mar 16, 2026 at 17:13 UTC 2a6820064ded5b35ec3027c903cb0e9b2e04bd9f
8 files changed +81 -79
api/plugins.py
+18 -19
@@ -17,7 +17,6 @@ class Plugins(ApiHandler):
17 async def process(self, input: dict, request: Request) -> dict | Response:
18 action = input.get("action", "")
19
20 - # Accept legacy aliases during migration.
20 if action == "get_config":
21 return self._get_config(input)
22
@@ -45,11 +44,11 @@ class Plugins(ApiHandler):
44 if action == "get_doc":
45 return self._get_doc(input)
46
48 - if action == "run_init_script":
49 - return self._run_init_script(input)
47 + if action == "run_execute_script":
48 + return self._run_execute_script(input)
49
51 - if action == "get_init_exec":
52 - return self._get_init_exec(input)
50 + if action == "get_execute_record":
51 + return self._get_execute_record(input)
52
53 return Response(status=400, response=f"Unknown action: {action}")
54
@@ -275,7 +274,7 @@ class Plugins(ApiHandler):
274 return {"ok": True, "content": files.read_file(file_path), "filename": filename}
275
276 @extension.extensible
278 - def _run_init_script(self, input: dict) -> dict | Response:
277 + def _run_execute_script(self, input: dict) -> dict | Response:
278 plugin_name = input.get("plugin_name", "")
279 if not plugin_name:
280 return Response(status=400, response="Missing plugin_name")
@@ -284,14 +283,14 @@ class Plugins(ApiHandler):
283 if not plugin_dir:
284 return Response(status=404, response="Plugin not found")
285
287 - init_script = files.get_abs_path(plugin_dir, "execute.py")
288 - if not files.exists(init_script):
286 + execute_script = files.get_abs_path(plugin_dir, "execute.py")
287 + if not files.exists(execute_script):
288 return Response(status=404, response="execute.py not found")
289
290 executed_at = datetime.now(timezone.utc).isoformat()
291 try:
292 result = subprocess.run(
294 - [sys.executable, init_script],
293 + [sys.executable, execute_script],
294 stdout=subprocess.PIPE,
295 stderr=subprocess.STDOUT,
296 text=True,
@@ -307,12 +306,12 @@ class Plugins(ApiHandler):
306 exit_code = -1
307 output = f"Error: {str(e)}"
308
310 - exec_record = {"executed_at": executed_at, "exit_code": exit_code}
311 - exec_path = plugins.determine_plugin_asset_path(
312 - plugin_name, "", "", "init_exec.json"
309 + execute_record = {"executed_at": executed_at, "exit_code": exit_code}
310 + execute_record_path = plugins.determine_plugin_asset_path(
311 + plugin_name, "", "", "execute_record.json"
312 )
314 - if exec_path:
315 - files.write_file(exec_path, json.dumps(exec_record))
313 + if execute_record_path:
314 + files.write_file(execute_record_path, json.dumps(execute_record))
315
316 return {
317 "ok": exit_code == 0,
@@ -322,17 +321,17 @@ class Plugins(ApiHandler):
321 }
322
323 @extension.extensible
325 - def _get_init_exec(self, input: dict) -> dict | Response:
324 + def _get_execute_record(self, input: dict) -> dict | Response:
325 plugin_name = input.get("plugin_name", "")
326 if not plugin_name:
327 return Response(status=400, response="Missing plugin_name")
328
330 - exec_path = plugins.determine_plugin_asset_path(
331 - plugin_name, "", "", "init_exec.json"
329 + execute_record_path = plugins.determine_plugin_asset_path(
330 + plugin_name, "", "", "execute_record.json"
331 )
333 - if exec_path and files.exists(exec_path):
332 + if execute_record_path and files.exists(execute_record_path):
333 try:
335 - data = json.loads(files.read_file(exec_path))
334 + data = json.loads(files.read_file(execute_record_path))
335 return {"ok": True, "data": data}
336 except Exception:
337 pass
helpers/plugins.py
+3 -3
@@ -87,7 +87,7 @@ class PluginListItem(BaseModel):
87 has_config_screen: bool = False
88 has_readme: bool = False
89 has_license: bool = False
90 - has_init_script: bool = False
90 + has_execute_script: bool = False
91 toggle_state: ToggleState = "disabled"
92 current_commit: str = ""
93 current_commit_timestamp: str = ""
@@ -162,7 +162,7 @@ def get_enhanced_plugins_list(
162 has_config_screen = files.exists(str(d / "webui" / "config.html"))
163 has_readme = files.exists(str(d / "README.md"))
164 has_license = files.exists(str(d / "LICENSE"))
165 - has_init_script = files.exists(str(d / "execute.py"))
165 + has_execute_script = files.exists(str(d / "execute.py"))
166 toggle_state = get_toggle_state(d.name)
167 current_commit = ""
168 current_commit_timestamp = ""
@@ -187,7 +187,7 @@ def get_enhanced_plugins_list(
187 has_config_screen=has_config_screen,
188 has_readme=has_readme,
189 has_license=has_license,
190 - has_init_script=has_init_script,
190 + has_execute_script=has_execute_script,
191 toggle_state=toggle_state,
192 current_commit=current_commit,
193 current_commit_timestamp=current_commit_timestamp,
plugins/_plugin_installer/webui/install-detail.html
+2 -2
@@ -84,9 +84,9 @@
84 <span class="icon material-symbols-outlined">gavel</span> License
85 </button>
86 </template>
87 - <template x-if="$store.pluginInstallStore.installedPluginInfo.has_init_script">
87 + <template x-if="$store.pluginInstallStore.installedPluginInfo.has_execute_script">
88 <button type="button" class="button"
89 - @click="$store.pluginInstallStore.handleOpenInit()">
89 + @click="$store.pluginInstallStore.handleOpenExecute()">
90 <span class="icon material-symbols-outlined">terminal</span> Script
91 </button>
92 </template>
plugins/_plugin_installer/webui/pluginInstallStore.js
+3 -3
@@ -6,7 +6,7 @@ import { toastFrontendSuccess, toastFrontendError } from "/components/notificati
6 import { showConfirmDialog } from "/js/confirmDialog.js";
7 import { store as imageViewerStore } from "/components/modals/image-viewer/image-viewer-store.js";
8 import { store as pluginListStore } from "/components/plugins/list/pluginListStore.js";
9 -import { store as pluginInitStore } from "/components/plugins/list/plugin-init-store.js";
9 +import { store as pluginExecuteStore } from "/components/plugins/list/plugin-execute-store.js";
10
11 const PLUGIN_API = "plugins/_plugin_installer/plugin_install";
12 const PER_PAGE = 20;
@@ -611,9 +611,9 @@ const model = {
611 }
612 },
613
614 - handleOpenInit() {
614 + handleOpenExecute() {
615 if (this.installedPluginInfo) {
616 - pluginInitStore.open(this.installedPluginInfo);
616 + pluginExecuteStore.open(this.installedPluginInfo);
617 }
618 },
619
webui/components/plugins/list/plugin-execute-modal.html renamed
+32 -32
@@ -1,55 +1,55 @@
1 <html>
2 <head>
3 - <title>Plugin Init</title>
3 + <title>Plugin Execute</title>
4 <script type="module">
5 - import { store } from "/components/plugins/list/plugin-init-store.js";
5 + import { store } from "/components/plugins/list/plugin-execute-store.js";
6 </script>
7 </head>
8 <body>
9 <div x-data>
10 - <template x-if="$store.pluginInitStore">
11 - <div x-destroy="$store.pluginInitStore.cleanup()"
12 - x-create="$el.closest('.modal')?.querySelector('.modal-title') && ($el.closest('.modal').querySelector('.modal-title').textContent = 'Init: ' + $store.pluginInitStore.pluginDisplayName)"
13 - class="plugin-init-root">
10 + <template x-if="$store.pluginExecuteStore">
11 + <div x-destroy="$store.pluginExecuteStore.cleanup()"
12 + x-create="$el.closest('.modal')?.querySelector('.modal-title') && ($el.closest('.modal').querySelector('.modal-title').textContent = 'Execute: ' + $store.pluginExecuteStore.pluginDisplayName)"
13 + class="plugin-execute-root">
14
15 - <div class="plugin-init-idle"
16 - x-show="!$store.pluginInitStore.running && $store.pluginInitStore.exitCode === null && !$store.pluginInitStore.output">
15 + <div class="plugin-execute-idle"
16 + x-show="!$store.pluginExecuteStore.running && $store.pluginExecuteStore.exitCode === null && !$store.pluginExecuteStore.output">
17 <span class="material-symbols-outlined idle-icon">terminal</span>
18 <div class="idle-text">
19 - <span class="idle-headline">Press <strong>Run</strong> to initialize <strong x-text="$store.pluginInitStore.pluginDisplayName"></strong></span>
20 - <span class="idle-sub">This will execute the plugin's <code>execute.py</code> setup script.</span>
21 - <template x-if="$store.pluginInitStore.lastExec">
19 + <span class="idle-headline">Press <strong>Run</strong> to execute <strong x-text="$store.pluginExecuteStore.pluginDisplayName"></strong></span>
20 + <span class="idle-sub">This will run the plugin's <code>execute.py</code> script.</span>
21 + <template x-if="$store.pluginExecuteStore.lastExecution">
22 <span class="last-exec-info">
23 Last run:
24 - <span x-text="new Date($store.pluginInitStore.lastExec.executed_at).toLocaleString()"></span>
24 + <span x-text="new Date($store.pluginExecuteStore.lastExecution.executed_at).toLocaleString()"></span>
25 &nbsp;&mdash;&nbsp;
26 - <span :class="$store.pluginInitStore.lastExec.exit_code === 0 ? 'exit-ok' : 'exit-err'"
27 - x-text="$store.pluginInitStore.lastExec.exit_code === 0 ? 'succeeded' : 'failed (exit ' + $store.pluginInitStore.lastExec.exit_code + ')'">
26 + <span :class="$store.pluginExecuteStore.lastExecution.exit_code === 0 ? 'exit-ok' : 'exit-err'"
27 + x-text="$store.pluginExecuteStore.lastExecution.exit_code === 0 ? 'succeeded' : 'failed (exit ' + $store.pluginExecuteStore.lastExecution.exit_code + ')'">
28 </span>
29 </span>
30 </template>
31 - <template x-if="!$store.pluginInitStore.lastExec">
32 - <span class="last-exec-info never-run">Never initialized</span>
31 + <template x-if="!$store.pluginExecuteStore.lastExecution">
32 + <span class="last-exec-info never-run">Never executed</span>
33 </template>
34 </div>
35 </div>
36
37 - <div class="plugin-init-status" x-show="$store.pluginInitStore.running">
37 + <div class="plugin-execute-status" x-show="$store.pluginExecuteStore.running">
38 <span class="material-symbols-outlined spin">progress_activity</span>
39 <span>Running execute.py...</span>
40 </div>
41
42 - <div class="plugin-init-exit" x-show="!$store.pluginInitStore.running && $store.pluginInitStore.exitCode !== null">
42 + <div class="plugin-execute-exit" x-show="!$store.pluginExecuteStore.running && $store.pluginExecuteStore.exitCode !== null">
43 <span class="material-symbols-outlined"
44 - :class="$store.pluginInitStore.exitCode === 0 ? 'exit-ok' : 'exit-err'"
45 - x-text="$store.pluginInitStore.exitCode === 0 ? 'check_circle' : 'error'">
44 + :class="$store.pluginExecuteStore.exitCode === 0 ? 'exit-ok' : 'exit-err'"
45 + x-text="$store.pluginExecuteStore.exitCode === 0 ? 'check_circle' : 'error'">
46 </span>
47 - <span x-text="$store.pluginInitStore.exitCode === 0 ? 'Completed successfully (exit 0)' : 'Exited with code ' + $store.pluginInitStore.exitCode"></span>
47 + <span x-text="$store.pluginExecuteStore.exitCode === 0 ? 'Completed successfully (exit 0)' : 'Exited with code ' + $store.pluginExecuteStore.exitCode"></span>
48 </div>
49
50 - <pre class="plugin-init-output"
51 - x-show="$store.pluginInitStore.output || $store.pluginInitStore.running"
52 - x-text="$store.pluginInitStore.output || ''"></pre>
50 + <pre class="plugin-execute-output"
51 + x-show="$store.pluginExecuteStore.output || $store.pluginExecuteStore.running"
52 + x-text="$store.pluginExecuteStore.output || ''"></pre>
53 </div>
54 </template>
55 </div>
@@ -57,22 +57,22 @@
57 <div class="modal-footer" data-modal-footer>
58 <button class="btn btn-action footer-btn"
59 x-data
60 - :disabled="$store.pluginInitStore?.running"
61 - @click="$store.pluginInitStore?.run()">
60 + :disabled="$store.pluginExecuteStore?.running"
61 + @click="$store.pluginExecuteStore?.run()">
62 <span class="icon material-symbols-outlined">play_arrow</span>
63 - <span x-text="$store.pluginInitStore?.exitCode !== null || $store.pluginInitStore?.output ? 'Rerun' : 'Run'">Run</span>
63 + <span x-text="$store.pluginExecuteStore?.exitCode !== null || $store.pluginExecuteStore?.output ? 'Rerun' : 'Run'">Run</span>
64 </button>
65 <button class="btn btn-cancel footer-btn" @click="window.closeModal?.()">Close</button>
66 </div>
67
68 <style>
69 - .plugin-init-root {
69 + .plugin-execute-root {
70 display: flex;
71 flex-direction: column;
72 width: 100%;
73 }
74
75 - .plugin-init-idle {
75 + .plugin-execute-idle {
76 display: flex;
77 align-items: flex-start;
78 gap: 1rem;
@@ -114,7 +114,7 @@
114 font-style: italic;
115 }
116
117 - .plugin-init-status {
117 + .plugin-execute-status {
118 display: flex;
119 align-items: center;
120 gap: 0.5rem;
@@ -123,7 +123,7 @@
123 font-size: var(--font-size-small);
124 }
125
126 - .plugin-init-exit {
126 + .plugin-execute-exit {
127 display: flex;
128 align-items: center;
129 gap: 0.5rem;
@@ -139,7 +139,7 @@
139 color: var(--color-error, #e74c3c);
140 }
141
142 - .plugin-init-output {
142 + .plugin-execute-output {
143 font-family: "Courier New", Courier, monospace;
144 font-size: 0.82rem;
145 background: var(--color-bg-secondary, #1e1e1e);
webui/components/plugins/list/plugin-execute-store.js renamed
+17 -14
@@ -11,7 +11,7 @@ const model = {
11 output: "",
12 running: false,
13 exitCode: null,
14 - lastExec: null,
14 + lastExecution: null,
15
16 async open(plugin) {
17 if (!plugin?.name) return;
@@ -19,20 +19,20 @@ const model = {
19 this.pluginDisplayName = plugin.display_name || plugin.name;
20 this.output = "";
21 this.exitCode = null;
22 - this.lastExec = null;
23 - window.openModal?.("components/plugins/list/plugin-init-modal.html");
24 - await this.fetchLastExec();
22 + this.lastExecution = null;
23 + window.openModal?.("components/plugins/list/plugin-execute-modal.html");
24 + await this.fetchLastExecution();
25 },
26
27 - async fetchLastExec() {
27 + async fetchLastExecution() {
28 try {
29 const response = await api.callJsonApi("plugins", {
30 - action: "get_init_exec",
30 + action: "get_execute_record",
31 plugin_name: this.pluginName,
32 });
33 - this.lastExec = response.data || null;
33 + this.lastExecution = response.data || null;
34 } catch (e) {
35 - this.lastExec = null;
35 + this.lastExecution = null;
36 }
37 },
38
@@ -43,22 +43,25 @@ const model = {
43 this.running = true;
44 try {
45 const response = await api.callJsonApi("plugins", {
46 - action: "run_init_script",
46 + action: "run_execute_script",
47 plugin_name: this.pluginName,
48 });
49 this.output = response.output || "";
50 this.exitCode = response.exit_code ?? null;
51 if (response.executed_at) {
52 - this.lastExec = { executed_at: response.executed_at, exit_code: response.exit_code ?? null };
52 + this.lastExecution = {
53 + executed_at: response.executed_at,
54 + exit_code: response.exit_code ?? null,
55 + };
56 }
57 } catch (e) {
58 this.output = e.message || String(e);
59 this.exitCode = -1;
60 notificationStore.frontendError(
61 e.message || String(e),
59 - "Failed to run init script",
62 + "Failed to run execute script",
63 3,
61 - "pluginInit",
64 + "pluginExecute",
65 defaultPriority,
66 true,
67 );
@@ -73,8 +76,8 @@ const model = {
76 this.output = "";
77 this.running = false;
78 this.exitCode = null;
76 - this.lastExec = null;
79 + this.lastExecution = null;
80 },
81 };
82
80 -export const store = createStore("pluginInitStore", model);
83 +export const store = createStore("pluginExecuteStore", model);
webui/components/plugins/list/plugin-list.html
+2 -2
@@ -107,11 +107,11 @@
107 <span class="icon material-symbols-outlined">settings</span> Config
108 </button>
109 </template>
110 - <template x-if="plugin.has_init_script">
110 + <template x-if="plugin.has_execute_script">
111 <button type="button"
112 class="button"
113 title="Execute"
114 - @click="$store.pluginListStore.openPluginInit(plugin)">
114 + @click="$store.pluginListStore.openPluginExecute(plugin)">
115 <span class="icon material-symbols-outlined">terminal</span> Execute
116 </button>
117 </template>
webui/components/plugins/list/pluginListStore.js
+4 -4
@@ -2,7 +2,7 @@ import { createStore } from "/js/AlpineStore.js";
2 import * as api from "/js/api.js";
3 import { store as pluginSettingsStore } from "/components/plugins/plugin-settings-store.js";
4 import { store as pluginToggleStore } from "/components/plugins/toggle/plugin-toggle-store.js";
5 -import { store as pluginInitStore } from "/components/plugins/list/plugin-init-store.js";
5 +import { store as pluginExecuteStore } from "/components/plugins/list/plugin-execute-store.js";
6 import { store as markdownModalStore } from "/components/modals/markdown/markdown-store.js";
7 import { callJsExtensions } from "/js/extensions.js";
8 import {
@@ -71,9 +71,9 @@ const model = {
71 window.openModal?.(`/plugins/${plugin.name}/webui/main.html`);
72 },
73
74 - openPluginInit(plugin) {
75 - if (!plugin?.name || !plugin?.has_init_script) return;
76 - pluginInitStore.open(plugin);
74 + openPluginExecute(plugin) {
75 + if (!plugin?.name || !plugin?.has_execute_script) return;
76 + pluginExecuteStore.open(plugin);
77 },
78
79 async openPluginConfig(plugin) {