Ú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.


1. Tři úrovně rozšiřitelnosti

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.


2. Co by byl obyčejný skript

Například:

Calculate Checksums.py

Uživatel označí deset souborů a spustí skript.

Skript:

  1. získá označené položky ze zdrojové strany,
  2. spočítá SHA-256,
  3. zobrazí progress,
  4. uloží checksums.sha256,
  5. obnoví panel,
  6. skončí.

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.


3. Co by bylo skriptované rozšíření

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.


4. Společné Salamander API

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.


5. LeftSide a RightSide

Ve 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í.


6. Přístup k interním příkazům Salamanderu

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ě.

Vysokoúrovňové příkazy

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.

Programové API

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.


7. Registrace vlastních příkazů

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ášť.


8. Události — tady se z Automation stává skutečný framework

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.


9. Extension by mohla mít vlastní stav

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.


10. Vlastní dialogy a UI

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)

11. Extension manifest

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 .py dá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.


12. Co s Pythonem a jeho runtime

Tady existuje několik možných modelů.

Varianta A: uživatel si runtime instaluje sám

Extension řekne:

"runtime": "python"

a Salamander hledá dostupný Python.

Výhoda:

Nevýhoda:


Varianta B: runtime adaptér jako samostatný plugin

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 ?

13. Python extension by přesto mohla používat normální Python knihovny

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.


14. PowerShell extension by mohla dělat úplně jiné věci

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.


15. JavaScript může být nejlehčí vestavěná cesta

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)


16. Extension Manager

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 .vbs a doufám, že ho Automation najde“.

Ale skutečně:

Mám nainstalovaná tato rozšíření Salamanderu.


17. Mohla by existovat jednoduchá extension bez manifestu

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ý.


18. Praktický příklad: „Folder Watcher“

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.


19. Jiný příklad: vlastní příkaz nad panely

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í.


20. Ještě silnější příklad: vlastní panel informací

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.


21. Co bych naopak nedělal

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:

Scripted extension je vhodná pro:

Native plugin zůstává potřeba pro:

To zachovává rozumnou hranici.


22. Jak bych viděl první realistickou verzi

Kdybych to měl navrhnout postupně, nešel bych hned do deseti runtimeů, package manageru a custom panelů.

První verze:

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.


A úplně nejpodstatnější myšlenka

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:

  1. Společné UI API pro celý Salamander — použitelné jak nativními pluginy, tak scripted extensions.
  2. Automation Framework, který abstrahuje jednotlivé runtimy a poskytuje společné Salamander API.
  3. AI-assisted automation, kde uživatel vůbec nemusí umět programovat: popíše, co právě potřebuje udělat, AI vytvoří jednorázový skript proti známému Automation API a Salamander ho provede.

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í.

Představa z pohledu uživatele

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, _3 atd.

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.


AI by podle mě neměla „klikat na Salamander“

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é.


Můj oblíbený workflow: Ask → Preview → Run → Save

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.


A ještě lepší: pokračující konverzace nad skriptem

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.


A právě tady získává UI API obrovský význam

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 jako prostředník pro runtimy

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.


A co přesně s tím free AI modelem?

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.


Ještě bych AI poskytoval strojově čitelný popis API

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)


Já bych možná nechal AI vracet víc než jen skript

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.


Dvě úrovně AI automatizace

Já bych dokonce rozlišoval:

1. Generate script

AI pouze vytvoří skript:

Request → Generate → Preview script

Uživatel si ho může prohlédnout, editovat, spustit nebo uložit.

2. Do it for me

Uživatel napíše:

V levém panelu vyber všechny .dll, které nemají platný digitální podpis, a přesuň je do Unsigned.

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.


A přitom se z toho může stát „nová funkce Salamanderu“

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.


A napadá mě ještě jedna zásadní vlastnost: AI sama může objevit omezení API

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í.


Jak velký AI model je vlastně potřeba?

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)


Za mě by tedy výsledný celek vypadal takto

┌───────────────────────────────────────────────────────────────────────┐
│                              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.