Úterý 14.07.2026 06:06
Představuju si to jako novou vrstvu rozšiřitelnosti Salamanderu mezi dnešním Automation skriptem a plnohodnotným nativním C++ pluginem.
Dnes už Automation obsahuje dobrý základ: skript může pracovat přes objektový model Salamanderu, přistupovat k panelům a jejich položkám, vytvářet formuláře a používat pomocné funkce pro práci s cestami. Skripty mohou být napsané v libovolném jazyce, pro který je dostupný Windows Script Host engine; nativně tedy JScript a VBScript, přes dodatečné enginy například i Python a další. (altap.cz)
Já bych ale udělal krok dál:
Salamander by neposkytoval jen možnost „spustit skript“, ale obecný framework, pomocí kterého lze psát lehká skriptovaná rozšíření integrovaná do aplikace.
A to je docela zásadní rozdíl.
Viděl bych to takhle:
-¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¬
- Full native plugin -
- -
- C++ / DLL / Plugin SDK -
- Maximální možnosti -
- Filesystem plugin, viewer, archiver... -
L¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦-
^
-
-¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¬
- Lightweight scripted extension -
- -
- Python / PowerShell / JavaScript / ... -
- Commands, menus, buttons, events, dialogs -
- Dlouhodobá integrace se Salamanderem -
L¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦-
^
-
-¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¬
- Simple automation script -
- -
- Spustit › něco udělat › skončit -
L¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦-
Současný Automation je nejblíž spodní vrstvě, přestože původní stránky Salamanderu ho už popisují jako jednodušší cestu pro vytváření rozšíření a jeho object model byl zamýšlen k dalšímu rozšiřování. (forum.altap.cz)
Ten nový framework by vytvořil hlavně tu prostřední vrstvu.
Například:
Calculate Checksums.py
Uživatel označí deset souborů a spustí skript.
Skript:
checksums.sha256,To je klasická automatizace:
start
ˇ
execute
ˇ
finish
Žádný persistentně běžící komponent, žádné události, žádný vlastní příkaz integrovaný trvale do UI.
Například hypoteticky v Pythonu:
files = Salamander.source_side.selected_items
with Salamander.ui.progress("Calculating checksums") as progress:
for index, file in enumerate(files):
hash = calculate_sha256(file.path)
progress.update(index + 1, len(files), file.name)
Salamander.panels.refresh()
Tohle je jen ilustrace API, které si představuju, ne existující syntaxe.
Tady je ten zajímavější rozdíl.
Mohl bys mít třeba:
extensions/
L¦¦ GitTools/
+¦¦ extension.json
+¦¦ main.py
+¦¦ icon.svg
L¦¦ README.md
extension.json:
{
"id": "org.opensalamander.git-tools",
"name": "Git Tools",
"version": "1.2.0",
"runtime": "python",
"entryPoint": "main.py",
"minimumSalamanderVersion": "5.1"
}
Salamander při startu rozšíření objeví, načte manifest a main.py může například zaregistrovat:
Takže například:
Plugins
L¦¦ Git Tools
+¦¦ Open Repository on GitHub
+¦¦ Copy Current Branch Name
+¦¦ Show Changed Files
+¦¦ Create Release Archive
L¦¦ Repository Information...
A po pravém kliknutí na adresář:
Open
Explore
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
Git Tools
Open Repository on GitHub
Copy Repository URL
Show Status
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
Properties
To už není obyčejný skript. Rozšíření skutečně žije uvnitř Salamanderu.
Tohle bych považoval za úplný střed celé koncepce.
Nedělal bych:
Python API
PowerShell API
JavaScript API
ale:
-¦¦¦¦¦¦¦¦¦¦¦¦¬
- Python -
+¦¦¦¦¦¦¦¦¦¦¦¦+
- PowerShell -
+¦¦¦¦¦¦¦¦¦¦¦¦+
- JavaScript -
+¦¦¦¦¦¦¦¦¦¦¦¦+
- VBScript -
L¦¦¦¦¦T¦¦¦¦¦¦-
-
ˇ
-¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¬
- Salamander Script API -
L¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦-
-
ˇ
-¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¬
- Salamander Core -
L¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦-
Každý podporovaný jazyk by dostával stejný logický object model.
Třeba:
Salamander
-
+¦¦ Application
+¦¦ Window
+¦¦ Commands
+¦¦ LeftSide
+¦¦ RightSide
+¦¦ ActiveSide
+¦¦ SourceSide
+¦¦ TargetSide
+¦¦ FileOperations
+¦¦ UI
+¦¦ Events
+¦¦ Storage
L¦¦ Environment
A teď podrobněji.
LeftSide a RightSideVe forku Samandarin jsem provedl mnoho změn ve „stranách“ Salamanderu a tabech, proto bych nové API už nestavěl jen kolem staré abstrakce LeftPanel a RightPanel, ale kolem stran, které mohou obsahovat více tabů:
Salamander.LeftSide
-
+¦¦ ActiveTab
+¦¦ Tabs
+¦¦ Path
+¦¦ Items
+¦¦ SelectedItems
+¦¦ FocusedItem
+¦¦ TreeView
L¦¦ ViewMode
Například:
left = Salamander.left_side
print(left.active_tab.path)
for tab in left.tabs:
print(tab.path)
Nebo:
$activeTab = $Salamander.RightSide.ActiveTab
$activeTab.Path = "C:\Repositories\Salamander"
To je podle mě důležitá modernizace object modelu, protože současný Automation historicky pracuje s objekty jako LeftPanel, RightPanel, SourcePanel a TargetPanel. (altap.cz)
V moderním Salamanderu s taby bych spíš chtěl:
LeftSide/MainSide
Tab 1
Tab 2
Tab 3
RightSide/DetachedSide
Tab 1
Tab 2
A stále současně:
SourceSide
TargetSide
podle toho, která strana je právě aktivní.
Tady bych viděl jednu z největších přidaných hodnot.
Skript by neměl muset sám znovu implementovat kopírování, mazání, archivaci nebo přejmenování, když už tyto věci umí Salamander.
Takže například:
Salamander.commands.execute("Copy")
nebo konkrétněji:
Salamander.file_operations.copy(
sources=Salamander.source_side.selected_items,
target=Salamander.target_side.path
)
Nebo:
Salamander.commands.execute("CreateDirectory")
Salamander.commands.execute("Pack")
Salamander.commands.execute("CalculateDirectorySizes")
Salamander.commands.execute("CompareDirectories")
Dávalo by mi smysl rozlišovat dvě úrovně.
Salamander.commands.execute("Copy")
Chovají se stejně, jako kdyby uživatel stiskl F5. Tedy případně otevřou standardní Salamander dialog a pokračují existujícím workflow.
Salamander.file_operations.copy(
source=["C:\\foo.txt"],
destination="D:\\Backup",
overwrite="ask"
)
To dovoluje mnohem jemnější automatizaci.
A právě tady by podle mě bylo možné velmi dobře využít existující implementaci Salamanderu namísto jejího opakování v každém skriptu.
Rozšíření by mohlo při inicializaci říct:
Salamander.commands.register(
id="git.openOnGitHub",
title="Open Repository on GitHub",
handler=open_on_github
)
Tím by vznikl příkaz uvnitř Salamanderu.
A ten samý příkaz by potom mohl být umístěn:
Plugins menu
Toolbar
Hotkey
Context menu
Command palette – pokud by někdy vznikla
Důležité je, že funkce a její umístění v UI by nebyly totéž.
Jednou zaregistruješ:
git.openOnGitHub
a potom můžeš říct:
Salamander.ui.menu.add(
location="plugins",
command="git.openOnGitHub"
)
Salamander.ui.context_menu.add(
context="directory",
command="git.openOnGitHub"
)
To mi přijde podstatně čistší než nutit autora extensionu implementovat každou integraci zvlášť.
Tohle je podle mě možná úplně největší rozdíl mezi skriptem a extensionem.
Obyčejný skript:
uživatel ho spustí
ˇ
něco udělá
ˇ
skončí
Extension může reagovat:
něco se v Salamanderu stane
ˇ
framework vyvolá event
ˇ
extension na něj reaguje
Například:
OnStartup
OnShutdown
OnActiveSideChanged
OnActiveTabChanged
OnPathChanged
OnSelectionChanged
OnBeforeFileOperation
OnFileOperationCompleted
OnFileCreated
OnFileRenamed
OnFileDeleted
OnTabCreated
OnTabClosed
OnWindowDetached
OnWindowAttached
Například Python extension:
def on_path_changed(event):
if is_git_repository(event.new_path):
update_git_toolbar_state(event.side)
Salamander.events.path_changed += on_path_changed
Nebo:
def on_selection_changed(event):
total_size = sum(item.size for item in event.selected_items)
update_status(total_size)
Tady už se opravdu otevírá prostor pro funkce, které dnes vyžadují nativní plugin nebo zásah přímo do core.
Dnešní Automation už má mechanismus pro persistentní ukládání hodnot. (altap.cz)
V novém frameworku bych to formalizoval třeba takto:
settings = Salamander.storage.for_extension()
settings["repositoryUrl"] = "https://..."
settings["autoRefresh"] = True
A framework se postará o:
Například:
Configuration/
L¦¦ Extensions/
L¦¦ org.opensalamander.git-tools/
L¦¦ settings.json
Autor extensionu nemusí řešit registry ani hledat, kam si má ukládat konfiguraci.
Současná Automation už umí runtime-created forms a několik dialogových metod, takže ani toto by nezačínalo na zelené louce. (altap.cz)
Novější framework by mohl nabídnout například:
form = Salamander.ui.create_dialog(
title="Git Repository Information",
width=500,
height=300
)
form.add_textbox(
id="branch",
label="Current branch:",
readonly=True
)
form.add_button(
id="refresh",
text="Refresh"
)
form.show()
A vizuálně by se vytvořil standardní nativní Salamander dialog.
To považuju za důležité: nenutil bych autory extensionů vozit s sebou Qt, Tkinter, Electron ani jiné UI frameworky. Pro běžné použití by měli dostat jednoduché nativní Salamander UI API.
Třeba:
MessageBox
InputBox
SelectFile
SelectDirectory
ProgressDialog
Form
ListView
TreeView
TextBox
ComboBox
CheckBox
RadioButton
Button
TabControl
A pro Python extension by to byl pořád jen objektový model:
dialog = Salamander.ui.dialog("Find Duplicates")
path = dialog.add_path_picker("Search in:")
recursive = dialog.add_checkbox("Include subdirectories", checked=True)
if dialog.show() == "ok":
find_duplicates(path.value, recursive.checked)
Každá složitější extension by podle mě měla manifest.
Například:
{
"id": "org.opensalamander.image-tools",
"name": "Image Tools",
"description": "Simple image processing commands",
"version": "2.1.0",
"author": "Example Developer",
"runtime": {
"type": "python",
"version": ">=3.12"
},
"entryPoint": "main.py",
"commands": [
"resize",
"convert",
"stripMetadata"
]
}
Uživatel pak nemusí řešit:
Kam mám ten
.pydát? Jak ho Salamander pozná? Jak se objeví v menu? Jak mu nastavím ikonu?
Prostě:
ImageTools.salamander-extension
nebo ZIP:
ImageTools/
+¦¦ extension.json
+¦¦ main.py
+¦¦ icon.svg
L¦¦ locales/
+¦¦ en.json
L¦¦ cs.json
A Salamander:
Plugins › Extensions › Install Extension...
Rozbalí ji do správné složky a načte.
Tady existuje několik možných modelů.
Extension řekne:
"runtime": "python"
a Salamander hledá dostupný Python.
Výhoda:
Nevýhoda:
Tohle se mi líbí víc:
Automation Framework
-
+¦¦ JavaScript Runtime
+¦¦ Python Runtime
+¦¦ PowerShell Runtime
L¦¦ Legacy WSH Runtime
Každý runtime by byl samostatná komponenta.
Takže třeba:
Plugins
L¦¦ Automation
+¦¦ JavaScript Runtime ?
+¦¦ PowerShell Runtime ?
L¦¦ Python Runtime Not installed
Když nainstaluju Python extension:
This extension requires the Python runtime,
which is not currently installed.
[ Install Runtime ] [ Cancel ]
To by umožnilo oddělit samotný Salamander Extension API od jednotlivých jazyků.
A to je podle mě správná architektura:
Python ?
\
PowerShell ¦› Runtime adapters › Common Extension API › Salamander
/
JavaScript ?
Představme si třeba extension:
Exif Metadata Tools
V Pythonu:
from PIL import Image
from PIL.ExifTags import TAGS
selected = Salamander.source_side.selected_items
for item in selected:
image = Image.open(item.path)
print(image.getexif())
Samotný Salamander by poskytoval:
které soubory jsou vybrané
kde se nacházejí
progress dialog
refresh panelu
vlastní menu command
A Python poskytne svůj ekosystém.
To je jedna z věcí, která by podle mě takový framework dělala velmi silným: Salamander nemusí implementovat všechno. Poskytne integraci a runtime udělá zbytek.
Například:
Windows Administration Tools
Při pravém kliknutí:
Windows Administration
+¦¦ Show File Owner
+¦¦ Show Effective Permissions
+¦¦ Take Ownership
+¦¦ Show Open Handles
L¦¦ Show Authenticode Signature
PowerShell:
$item = $Salamander.SourceSide.FocusedItem
Get-Acl $item.Path
Nebo:
Get-AuthenticodeSignature $item.Path
Díky Salamander API by ale extension nemusela řešit:
To poskytne framework.
Například:
const selected = Salamander.sourceSide.selectedItems;
for (const item of selected) {
Salamander.log.info(item.path);
}
Takový runtime by mohl být velmi malý a třeba přímo distribuovaný se Salamanderem.
A zde bych osobně zachoval i zpětnou kompatibilitu s existujícím Automation pluginem a jeho skripty, protože dnešní plugin má stále reálné uživatele a ještě v roce 2025 se na fóru objevovalo praktické používání VBScript automatizace. (forum.altap.cz)
Tady bych to pro uživatele dotáhl ještě dál:
Plugins › Extensions...
A otevře se:
-¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¬
- Extensions -
+¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦+
- ? Git Tools 1.2.0 Python -
- ? Image Tools 2.1.0 Python -
- ? Windows Admin 1.4.2 PowerShell -
- ? Rename Collection 1.0.0 JavaScript -
- ? Old Backup Tool 0.8.0 JavaScript -
+¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦+
- [ Install... ] [ Remove ] [ Enable/Disable ] [ Configure ] -
L¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦-
Tím se scripted extensions stávají skutečnou prvotřídní součástí Salamanderu.
Ne:
„někam jsem nakopíroval
.vbsa doufám, že ho Automation najde“.
Ale skutečně:
Mám nainstalovaná tato rozšíření Salamanderu.
Zároveň bych z toho ale nedělal těžkopádný systém.
Pro jednoduché skripty:
scripts/
+¦¦ Calculate Hashes.py
+¦¦ Rename from Clipboard.js
L¦¦ Create Backup.ps1
Ty se automaticky objeví:
Plugins
L¦¦ Automation
+¦¦ Calculate Hashes
+¦¦ Rename from Clipboard
L¦¦ Create Backup
Jakmile chce autor víc:
vlastní ikonu
více příkazů
eventy
konfiguraci
lokalizaci
dependencies
udělá z toho extension package s manifestem.
Takže:
one file script
ˇ
simple extension package
ˇ
complex scripted extension
ˇ
native C++ plugin
A žádný z těch stupňů není nutně „správnější“ než jiný.
Představ si extension napsanou v Pythonu:
Folder Watcher
Uživatel otevře:
Plugins › Folder Watcher › Add Current Directory
Extension si uloží:
C:\Builds\Output
Pak se registruje na události.
Když v adresáři přibude nový .zip:
OnFileCreated
ˇ
extension zjistí .zip
ˇ
zobrazí notification
ˇ
případně zvýrazní tab
Například:
def on_file_created(event):
if event.path.endswith(".zip"):
Salamander.ui.notify(
title="New build available",
message=event.name
)
Tohle už není typická jednorázová automatizace. Je to malé funkční rozšíření, ale stále kvůli němu nemusíš psát nativní DLL.
Třeba:
Copy Relative Paths
Uživatel označí:
C:\Repositories\Salamander\src\core\main.cpp
C:\Repositories\Salamander\src\core\panel.cpp
Spustí:
Copy Paths Relative to Repository Root
A do clipboardu dostane:
src/core/main.cpp
src/core/panel.cpp
Taková funkce by byla deset, dvacet, třicet řádků Pythonu nebo JavaScriptu.
Kvůli něčemu takovému je C++ plugin nesmyslně těžký. Ale právě pro scripted extension je to ideální.
Pozdější verze frameworku by teoreticky mohla dovolit jednoduché UI integrace.
Například extension:
Git Status
A při práci v Git repozitáři:
-¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¬
- Files -
+¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦+
- main.cpp -
- panel.cpp -
- dialogs.cpp -
+¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦+
- Git Status -
+¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦+
- Branch: feature/dark-mode -
- -
- M src/main.cpp -
- M src/panel.cpp -
- ? test.txt -
L¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦-
Tady už bych byl opatrný, protože obecné custom UI může dramaticky zvýšit složitost frameworku. Ale jako dlouhodobý směr si to představit umím.
První verzi bych určitě omezil na:
Custom dockable panes až později.
Nechtěl bych vytvořit druhé kompletní Plugin SDK.
Tedy ne:
„V Pythonu můžeš úplně všechno, co v C++ pluginu.“
To by podle mě skončilo obrovským a obtížně udržovatelným API.
Spíš bych jasně stanovil hranici:
To zachovává rozumnou hranici.
Kdybych to měl navrhnout postupně, nešel bych hned do deseti runtimeů, package manageru a custom panelů.
1. Společné modernizované Salamander Automation API
2. JavaScript runtime
3. Registrace vlastních příkazů
4. Přístup k:
- left/right side
- tabs
- paths
- items
- selection
- clipboard
5. Spouštění interních Salamander příkazů
6. Dialogy a progress
7. Několik základních events
8. Jednoduché per-extension storage
Pak:
9. PowerShell adapter
10. Python adapter
11. Extension manifests
12. Extension Manager
13. Kontextová menu
14. Toolbar buttons
15. Více events
16. Pokročilejší UI
Takhle by to nebylo nutné implementovat jako jeden gigantický projekt.
Já bych to formuloval asi takto:
Dnes má Salamander Plugin SDK pro plnohodnotné nativní pluginy a Automation plugin pro spouštění skriptů. Mezi těmito dvěma úrovněmi ale existuje velký prostor pro lehká skriptovaná rozšíření, která se mohou dlouhodobě integrovat do Salamanderu, registrovat vlastní příkazy a UI prvky, reagovat na události a používat společné Salamander API z různých programovacích jazyků.
A přesně v tom podle mě spočívá největší potenciál toho nápadu.
Nejde vlastně primárně o:
„Přidejme Python do Automation pluginu.“
Ale spíš o:
„Udělejme ze Salamander Automation obecnou platformu pro tvorbu jednoduchých a středně složitých rozšíření bez nutnosti psát a kompilovat plnohodnotný nativní plugin.“
A u open-source Salamanderu mi to přijde obzvlášť zajímavé. Zdrojový kód byl zveřejněn pod GPLv2 jako Open Salamander 5.0 a vývoj probíhá na veřejném GitHub repozitáři; právě snížení vstupní bariéry z „musím znát starší rozsáhlý WinAPI C++ codebase“ na „můžu napsat sto řádků Pythonu, PowerShellu nebo JavaScriptu“ by podle mě mohlo výrazně rozšířit okruh lidí schopných vytvořit pro Salamander praktickou funkcionalitu. To poslední je moje inference, ale vychází přímo z rozdílu mezi stávajícím nativním Plugin SDK a jednodušší Automation cestou, kterou samotný projekt již historicky nabízí. (GitHub)
A upřímně: já bych ten původní ticket vůbec nepojmenoval „Support more languages in Automation plugin“, protože to by tu myšlenku dost zmenšovalo — zejména když Automation už historicky přes WSH další jazyky podporovat umí. Viděl bych to spíš jako „Extend Automation into a general-purpose scripting and lightweight extension framework“.
A tady se mi začínají spojovat tři původně oddělené myšlenky do jedné docela elegantní architektury:
A právě ten třetí bod mi přijde mimořádně zajímavý, protože by to nebyl žádný obecný „AI chat přilepený k file manageru“. Byl by to účelově omezený programátor Salamanderu na vyžádání.
Uživatel má například v levé straně:
IMG_20250713_194501.jpg
IMG_20250713_194530.jpg
IMG_20250714_082012.jpg
IMG_20250714_082144.jpg
A napíše:
Přejmenuj označené fotografie podle data jejich pořízení na
YYYY-MM-DD_HH-MM-SS, a pokud dvě fotografie mají stejný čas, přidej_2,_3atd.
AI dostane:
Vygeneruje třeba JavaScript:
const items = Salamander.SourceSide.SelectedItems;
for (const item of items) {
const dateTaken = item.Metadata.DateTaken;
const newName = formatDate(dateTaken);
Salamander.FileOperations.Rename(item, newName, {
ResolveCollisions: "AppendNumber"
});
}
A Salamander zobrazí něco jako:
┌──────────────────────────────────────────────────────────────┐
│ AI Automation │
├──────────────────────────────────────────────────────────────┤
│ You asked: │
│ │
│ Rename selected photos according to their Date Taken value, │
│ resolving duplicate names by adding a numeric suffix. │
│ │
│ This automation will: │
│ │
│ Rename 27 files │
│ Modify no file contents │
│ Delete no files │
│ │
│ [ Show Script ] [ Run ] [ Save as Script... ] │
└──────────────────────────────────────────────────────────────┘
A tohle bych považoval za ideální základ.
Tohle je důležitý architektonický bod.
Nedělal bych systém:
AI
↓
simuluje klávesy
↓
kliká na menu
↓
nějak se pokouší ovládat UI
To je křehké a zbytečné.
Místo toho:
User request
│
▼
┌─────────────────┐
│ AI model │
└────────┬────────┘
│
generates
│
▼
┌─────────────────┐
│ Automation code │
└────────┬────────┘
│
executes via
│
▼
┌───────────────────────────────┐
│ Salamander Automation API │
└───────────────┬───────────────┘
│
▼
Salamander Core
Takže AI nemá své vlastní speciální privilegované API.
Používá úplně stejný framework jako člověk, který píše skript ručně.
To má podle mě několik krásných důsledků:
A hlavně: AI je jen další autor skriptu.
To mi přijde koncepčně velmi čisté.
Představoval bych si například příkaz:
Commands
└── Automate with AI...
Nebo klávesovou zkratku.
Otevře se:
┌──────────────────────────────────────────────────────────────┐
│ Automate with AI │
├──────────────────────────────────────────────────────────────┤
│ │
│ What would you like to do? │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Find all duplicate files in the current directory and │ │
│ │ its subdirectories according to SHA-256. Show me a │ │
│ │ dialog with the duplicate groups, but don't delete │ │
│ │ anything automatically. │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ Context: │
│ Source: C:\Photos │
│ Selected: 0 items │
│ │
│ [ Generate Automation ] │
└──────────────────────────────────────────────────────────────┘
AI vytvoří script.
Pak třeba:
┌──────────────────────────────────────────────────────────────┐
│ Generated Automation │
├──────────────────────────────────────────────────────────────┤
│ Find duplicate files │
│ │
│ The automation will: │
│ │
│ • Recursively enumerate C:\Photos │
│ • Calculate SHA-256 hashes │
│ • Group identical files │
│ • Display the results in a dialog │
│ • Make no filesystem changes │
│ │
│ Estimated scope: 4,281 files │
│ │
│ [ Show Script ] [ Modify Request... ] [ Run ] [ Save... ] │
└──────────────────────────────────────────────────────────────┘
Po spuštění použije normální UI API:
┌──────────────────────────────────────────────────────────────┐
│ Duplicate Files │
├──────────────────────────────────────────────────────────────┤
│ ▼ Group 1 8.4 MB │
│ C:\Photos\2024\holiday.jpg │
│ C:\Photos\Backup\holiday-copy.jpg │
│ │
│ ▼ Group 2 125 MB │
│ C:\Videos\clip.mp4 │
│ C:\Videos\Old\clip.mp4 │
│ │
│ [ Close ] [ Export Results... ] │
└──────────────────────────────────────────────────────────────┘
A pak:
„Tohle používám často.“
Klikneš na:
Save as Script...
a najednou se jednorázová AI automatizace stane normálním uloženým skriptem:
Plugins
└── Automation
└── Find Duplicate Files
Tohle propojení jednorázového přirozeného jazyka → skriptu → trvalé funkce mi přijde asi nejsilnější část celého konceptu.
Nemuselo by skončit u jednoho promptu.
Uživatel:
Najdi ve vybraných souborech všechny obrázky větší než 4K a převeď je na maximálně 3840×2160.
AI vygeneruje automation.
Uživatel pak řekne:
Ale zachovej poměr stran a nepřepisuj originály.
AI skript upraví.
Pak:
Výsledné soubory dej do nové podsložky
Resized.
Znovu upraví.
Pak:
A ukaž progress bar s náhledem aktuálního souboru.
A pokud to UI API umožňuje, znovu upraví.
Takže:
Natural language request
↓
Generated automation v1
↓
"Don't overwrite originals"
↓
Generated automation v2
↓
"Put results into Resized"
↓
Generated automation v3
↓
"Save this permanently"
↓
MyResizer extension/script
Uživatel tak vlastně interaktivně programuje Salamander, aniž by nutně psal kód.
Tím, že podobné obecné UI API chybí i klasickým pluginům, byla by škoda vytvořit:
Automation.UI
jako speciální věc dostupnou jen skriptům.
Já bych spíš viděl:
Salamander UI Framework
│
┌─────────────┴─────────────┐
│ │
Native Plugin API Automation API
│ │
C++ plugin JS / Python / PS
Takže například společné koncepty:
UI.MessageBox
UI.InputBox
UI.ProgressDialog
UI.Dialog
UI.Form
UI.FilePicker
UI.FolderPicker
UI.ListView
UI.TreeView
UI.TextBox
UI.ComboBox
UI.CheckBox
UI.RadioButton
UI.Button
UI.TabControl
Nativní plugin by třeba dostal C++ interface:
auto dialog = Salamander->UI()->CreateDialog(...);
Python:
dialog = Salamander.ui.create_dialog(...)
JavaScript:
const dialog = Salamander.ui.createDialog(...);
PowerShell:
$dialog = $Salamander.UI.CreateDialog(...)
Ale všechny čtyři cesty používají stejný Salamander UI framework a stejnou nativní vizuální podobu.
To by podle mě bylo hodnotné samo o sobě, i bez AI.
A pro AI je to mimořádně důležité, protože model pak nemusí generovat WinAPI, HTML, Tkinter nebo něco podobného. Stačí, že zná jednoduchou sadu komponent:
CreateDialog
AddLabel
AddTextBox
AddListView
AddButton
ShowModal
To dramaticky snižuje prostor pro chyby.
Automation framework se postará o runtimy. Představuju si to zhruba takto:
Scripts / Extensions
│
┌────────────────────────┼────────────────────────┐
│ │ │
JavaScript Python PowerShell
│ │ │
▼ ▼ ▼
JS Runtime Python Runtime PS Runtime
└────────────────────────┼────────────────────────┘
│
▼
┌────────────────────────┐
│ Automation Framework │
├────────────────────────┤
│ Common object model │
│ Events │
│ Commands │
│ UI API │
│ Storage │
│ Permissions/context │
│ Runtime management │
└────────────┬───────────┘
│
▼
Salamander Core
A jednotlivé runtimy nemusí být nutně součástí základní instalace.
Například:
Plugin Manager
Installed
─────────
✓ Automation Framework
✓ JavaScript Runtime
✓ PowerShell Runtime
Available
─────────
○ Python Runtime
○ Lua Runtime
V případě forku Samandarin, žádný nový Extensions Manager není potřeba. Když už Salamander má Plugin Manager se sources, tak scripted extensions mohou být jednoduše další source nebo další typ položek v existující infrastruktuře:
Sources:
✓ Official Plugins
✓ Community Plugins
✓ Automation Extensions
✓ Runtime Components
Případně jedna source může obsahovat různé typy balíčků a Plugin Manager je jen označí:
Git Tools Scripted Extension Python
Image Resizer Scripted Extension JavaScript
Python Runtime Runtime Component
7-Zip Native Plugin
To mi přijde mnohem lepší než paralelně stavět druhý manager.
Tady bych rozlišoval AI integration a AI model.
Neudělal bych framework závislý na jednom konkrétním modelu:
Salamander AI
│
└── some-model.gguf
Spíš:
AI Automation Assistant
│
Model Provider API
│
┌────────────────────┼─────────────────────┐
│ │ │
Built-in Local External Local Remote API
Runtime Provider Provider
│ │ │
local model Ollama etc. optional
Pro skutečně samostatnou bezplatnou instalaci mi připadá zajímavá možnost použít jako inference backend něco na způsob llama.cpp: jde o C/C++ inference knihovnu, kterou lze přímo integrovat, a podporuje také serverové API a gramatiky omezující výstup modelu na definovaný formát. (GitHub)
Zároveň by bylo možné připojit externí lokální backend. Například Ollama dnes poskytuje jak structured outputs podle JSON Schema, tak tool calling, což je přesně typ mechanismu použitelný pro komunikaci mezi AI modelem a pevně definovaným Automation API. (Ollama)
Ale osobně bych pro Salamander první AI vrstvu navrhl tak, aby model nemusel mít přímý tool calling vůbec.
Proč? Protože úkol je velmi přesně definovaný:
Vygeneruj program proti této verzi Salamander Automation API.
To je menší a kontrolovatelnější problém než obecný autonomní agent.
Například framework má:
Automation API v3
A spolu s ním existuje něco jako:
{
"version": "3.0",
"objects": {
"Salamander.SourceSide": {
"properties": {
"Path": "string",
"SelectedItems": "ItemCollection",
"FocusedItem": "Item|null"
}
},
"Salamander.FileOperations": {
"methods": {
"Rename": {
"parameters": [
"item",
"newName",
"options"
]
}
}
}
}
}
Nemusí to být přesně JSON; jde o princip.
AI při každém požadavku nedostane sto tisíc tokenů textové dokumentace. Framework vybere jen relevantní části:
Uživatel chce přejmenovávat soubory.
Relevantní API:
- SourceSide.SelectedItems
- Item.Name
- Item.Path
- Item.Metadata
- FileOperations.Rename
- UI.ProgressDialog
A model generuje proti přesné verzi skutečně dostupného API.
To je mimochodem velmi důležité proti halucinování metod typu:
Salamander.SuperMagicRenameEverything()
která neexistuje. 😄
Structured output nebo formální gramatika může navíc vynutit, aby model vracel přesně požadovanou strukturu, například oddělený popis akce, potřebné capabilities a samotný skript. Takovou formu omezeného výstupu podporují například llama.cpp přes GBNF gramatiky i Ollama přes JSON Schema structured outputs. (GitHub)
Například:
{
"title": "Rename photos by Date Taken",
"description": "Renames the selected JPEG files according to EXIF Date Taken.",
"capabilities": [
"read-selection",
"read-file-metadata",
"rename-files"
],
"estimatedEffects": {
"renameFiles": true,
"modifyContents": false,
"deleteFiles": false
},
"script": "..."
}
Pak Salamander nemusí hádat, co skript dělá.
Může zobrazit:
This automation requests:
✓ Read current selection
✓ Read image metadata
✓ Rename files
It does not request:
— Delete files
— Modify file contents
— Execute external programs
— Access network
A zde bych neviděl „permissions“ jen jako bezpečnostní mechanismus. Má to velkou hodnotu i čistě UXově: uživatel na první pohled vidí rozsah automatizace.
Já bych dokonce rozlišoval:
AI pouze vytvoří skript:
Request → Generate → Preview script
Uživatel si ho může prohlédnout, editovat, spustit nebo uložit.
Uživatel napíše:
V levém panelu vyber všechny
.dll, které nemají platný digitální podpis, a přesuň je doUnsigned.
Salamander:
Understanding request...
Generating automation...
Zobrazí:
The automation will:
• Check Authenticode signatures of 143 DLL files
• Create the directory "Unsigned" if it does not exist
• Move files without a valid signature into it
[ Show details ] [ Run ]
A provede ji.
Tady přesně dostáváme to, co byla moje prvotní myšlenka:
Teď potřebuju řešení na tohle a tohle, tak mi to proveď.
Neinstaluju plugin.
Nehledám utilitu.
Nehledám na Googlu PowerShell command.
Nepíšu skript.
Prostě řeknu Salamanderu, co potřebuji udělat s právě otevřenými soubory.
Třeba zjistíš, že pořád používáš AI požadavek:
Z označených souborů vytvoř Markdown tabulku s názvem, velikostí, SHA-256 a relativní cestou a zkopíruj ji do clipboardu.
Poprvé:
AI → vygeneruje → provede
Podruhé:
AI → vygeneruje → provede
Pak řekneš:
Save as automation...
A máš:
Plugins
└── Automation
└── Copy selected files as Markdown table
Můžeš mu přiřadit:
Hotkey: Ctrl+Shift+M
Nebo toolbar button.
A pokud bys šel ještě dál:
Convert to Extension...
vytvoří se základní extension package:
MarkdownFileTable/
├── extension.json
├── main.js
└── icon.svg
Takže mezi jednotlivými vrstvami je přirozená cesta:
Natural-language request
↓
One-shot generated script
↓
Saved automation
↓
Scripted extension
↓
Native plugin, only if really necessary
Tohle mi přijde fantasticky soudržné. Nejsou to čtyři nesouvisející technologie. Jsou to čtyři stupně téže věci.
Příklad:
Přidej ke každému PDF první stránku jako thumbnail přímo do sloupce v panelu.
Model dostane dokumentaci API a zjistí:
Automation API currently cannot:
- register custom panel columns
- provide thumbnails
Pak nemá halucinovat řešení.
Měl by vrátit:
This cannot currently be implemented through the Automation API.
Missing capabilities:
• Register custom panel column
• Provide thumbnail image for a file item
A to je pro vývoj Salamanderu překvapivě cenné.
Protože po určité době můžeme zjistit:
Most commonly requested unavailable Automation capabilities:
1. Register panel column 238 requests
2. Add file overlay icon 191 requests
3. Access archive API 174 requests
4. Create dockable UI pane 91 requests
Najednou samotné AI použití může ukazovat, co uživatelé chtějí automatizovat, ale současné API jim v tom brání.
Upřímně si myslím, že právě tady nemusí být potřeba obrovský obecný model.
Úloha je omezená:
Input:
- uživatelská instrukce,
- přesně definované API,
- pár příkladů,
- aktuální kontext.
Output:
- krátký script používající toto API.
To je výrazně užší problém než být všeobecný ChatGPT.
Navíc Salamander může modelu dodat:
Takže může fungovat opravná smyčka:
AI generates script
↓
Static validation
↓
Unknown method:
Salamander.File.Rename()
↓
Framework tells AI:
Use Salamander.FileOperations.Rename()
↓
AI fixes script
↓
Valid
A protože lokální inference dnes může být integrována například přes nativní C/C++ knihovnu llama.cpp nebo obsluhována přes externí lokální model server, není nutné uživatele vázat na jedinou cloudovou službu. (GitHub)
┌───────────────────────────────────────────────────────────────────────┐
│ Salamander │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ Shared Salamander Services │ │
│ │ │ │
│ │ File Operations │ Commands │ UI │ Panels │ Tabs │ Events │ │
│ └───────────────────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌─────────────────────┴─────────────────────┐ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ Native Plugin API │ │ Automation Framework│ │
│ │ │ │ │ │
│ │ C++ │ │ Common Script API │ │
│ └─────────────────────┘ └──────────┬──────────┘ │
│ │ │
│ ┌─────────────┬─────────────┼──────────┐ │
│ ▼ ▼ ▼ ▼ │
│ JavaScript Python PowerShell ... │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ AI Automation Assistant │ │
│ │ │ │
│ │ Natural language → Generate script → Preview → Run → Save │ │
│ │ │ │
│ │ Local model │ External local provider │ Optional API │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ Existing Plugin Manager │
│ Plugins │ Runtimes │ Scripted Extensions │
└───────────────────────────────────────────────────────────────────────┘
A upřímně: mně se tohle jako celek líbí ještě víc než původní nápad „rozšiřme Automation o Python a PowerShell“. Protože tady už vzniká skutečný systém:
Salamander má jednotné aplikační a UI API. Nativní pluginy i skriptovaná rozšíření ho mohou používat. Automation Framework poskytuje různé jazykové runtimy. A nad nejjednodušší vrstvou automatizace může sedět AI, která uživateli na požádání vytvoří přesně ten jednorázový nástroj, který v daném okamžiku potřebuje — a pokud se osvědčí, může ho uložit jako trvalou součást svého Salamanderu.
Tohle je podle mě velmi silná vize moderního Salamanderu, aniž by přestal být Salamanderem. AI není přilepený chatbot, Python není alternativní Plugin SDK a scripted extensions nejsou druhotřídní pluginy. Všechno vyrůstá z jednoho společného API a liší se jen úrovní permanence a složitosti.