diff --git a/specs/cli.allium b/specs/cli.allium index fafa095..c677476 100644 --- a/specs/cli.allium +++ b/specs/cli.allium @@ -68,7 +68,8 @@ rule AirplaneGate { } rule RebuildFull { - when: CliCommandExecuted(command: rebuild) + when: CliCommandExecuted(command) + requires: command = rebuild requires: not CliInvocation.incremental -- The same step sequence as the GUI "Rebuild Database" -- (BDS.Maintenance.full_rebuild_steps — posts, media, scripts, @@ -78,7 +79,8 @@ rule RebuildFull { } rule RebuildIncremental { - when: CliCommandExecuted(command: rebuild) + when: CliCommandExecuted(command) + requires: command = rebuild requires: CliInvocation.incremental -- Metadata diff, then auto-apply file→db for every difference and -- import every orphan file. @@ -86,7 +88,8 @@ rule RebuildIncremental { } rule Repair { - when: CliCommandExecuted(command: repair) + when: CliCommandExecuted(command) + requires: command = repair -- Subcommand argument selects the repair part: post-links, -- media-links, thumbnails, embeddings, or search — the standard -- rebuild tasks outside the full rebuild. @@ -94,7 +97,8 @@ rule Repair { } rule Render { - when: CliCommandExecuted(command: render) + when: CliCommandExecuted(command) + requires: command = render -- Default: render all site sections plus the search index. -- --incremental: validate the generated output and apply only the -- differences (targeted render + extra-file deletion + calendar). @@ -104,14 +108,16 @@ rule Render { } rule Upload { - when: CliCommandExecuted(command: upload) + when: CliCommandExecuted(command) + requires: command = upload -- Uses the project publishing preferences (ssh host/user/path/mode) -- exactly like the app's upload, and waits for the publish job. ensures: SiteUploaded() } rule GitSync { - when: CliCommandExecuted(command: push | pull) + when: CliCommandExecuted(command) + requires: command = push or command = pull -- push: git push of the project repository to origin. -- pull: git pull --ff-only, then the incremental cache update -- (metadata diff auto-apply + orphan import) so the database @@ -120,7 +126,8 @@ rule GitSync { } rule CreatePost { - when: CliCommandExecuted(command: post) + when: CliCommandExecuted(command) + requires: command = post -- Post data from parameters or JSON on stdin (LLM-friendly). -- Language is auto-detected when missing: the configured AI -- endpoint (airplane mode routes to the local model), falling back @@ -132,7 +139,8 @@ rule CreatePost { } rule CreateMedia { - when: CliCommandExecuted(command: media) + when: CliCommandExecuted(command) + requires: command = media -- Imports the image, then best-effort AI enrichment: generated -- title, alt text, caption, and translations to all configured -- blog languages (the gallery pipeline without post linking). @@ -140,7 +148,8 @@ rule CreateMedia { } rule CreateGallery { - when: CliCommandExecuted(command: gallery) + when: CliCommandExecuted(command) + requires: command = gallery -- Creates the post, then runs the shared gallery import pipeline -- for every referenced image: import, mandatory post link, AI -- enrichment, translations; finally the post auto-translation. @@ -149,7 +158,8 @@ rule CreateGallery { } rule Preferences { - when: CliCommandExecuted(command: config) + when: CliCommandExecuted(command) + requires: command = config -- get/list expose effective global preferences shared with the app: -- canonical defaults overlaid by persisted values. Project-file settings and -- internal maintenance state are outside this list. Secret-backed keys remain @@ -159,21 +169,24 @@ rule Preferences { } rule Projects { - when: CliCommandExecuted(command: project) + when: CliCommandExecuted(command) + requires: command = project -- list, add (register a folder in the cache database), and -- switch (change the active project). ensures: ProjectRegistryUpdated() } rule Tui { - when: CliCommandExecuted(command: tui) + when: CliCommandExecuted(command) + requires: command = tui -- The native CLI enters TUI boot mode so the interactive terminal UI owns -- the terminal. ensures: TuiStarted() } rule Server { - when: CliCommandExecuted(command: server) + when: CliCommandExecuted(command) + requires: command = server -- Starts the dedicated headless SSH host with optional bind address, port, -- database path, and data-directory overrides. The standalone bds-server -- executable is not distributed. @@ -181,7 +194,8 @@ rule Server { } rule RunLuaTask { - when: CliCommandExecuted(command: lua) + when: CliCommandExecuted(command) + requires: command = lua -- Runs a utility ("task", long-running) script from the database by -- slug in the active project, with the managed-job execution budget -- (unlimited time/reductions) but synchronously. Macro and @@ -190,7 +204,8 @@ rule RunLuaTask { } rule InstallLauncher { - when: CliInstallRequested() or CliCommandExecuted(command: install) + when: CliInstallRequested() or CliCommandExecuted(command) + requires: command = install -- Settings/Data, the future TUI settings action, and `bds-cli install` -- share one guarded installer. A forwarding launcher written to -- ~/.local/bin/bds-cli executes the packaged native CLI in place, so it diff --git a/specs/events.allium b/specs/events.allium index 525d634..ff87466 100644 --- a/specs/events.allium +++ b/specs/events.allium @@ -60,7 +60,8 @@ rule ClientUnsubscription { } rule ServerSideUiLanguage { - when: GlobalSettingWritten(key: "ui.language") + when: GlobalSettingWritten(key) + requires: key = "ui.language" -- The UI language is a single server-side setting: changing it in any -- client persists it and re-renders every connected client. The OS -- locale is only the fallback when the setting is unset. diff --git a/specs/media_processing.allium b/specs/media_processing.allium index 816d4bd..3ddfa52 100644 --- a/specs/media_processing.allium +++ b/specs/media_processing.allium @@ -384,7 +384,7 @@ config { -- ============================================================================ rule IndexMediaForSearch { - when: SearchIndexUpdated(media: media/Media) + when: SearchIndexUpdated(media) -- Index fields: title, alt, caption, original_name, tags -- Plus all translation titles, alts, and captions let all_text = concat( diff --git a/specs/server.allium b/specs/server.allium index 2571c56..94177d7 100644 --- a/specs/server.allium +++ b/specs/server.allium @@ -52,13 +52,15 @@ rule ModeResolution { } rule DesktopBoot { - when: ApplicationStarted(mode: desktop) + when: ApplicationStarted(mode) + requires: mode = desktop -- Unchanged behavior: wx window shell, loopback HTTP endpoint. ensures: DesktopWindowStarted() } rule ServerBoot { - when: ApplicationStarted(mode: server) + when: ApplicationStarted(mode) + requires: mode = server -- Started by `bds-cli server` or explicit desktop boot mode. Headless: no -- desktop UI children at all. Works on macOS, Windows, Linux. ensures: LoopbackEndpointStarted() diff --git a/specs/tui.allium b/specs/tui.allium index d904cd7..e2f15c1 100644 --- a/specs/tui.allium +++ b/specs/tui.allium @@ -24,7 +24,8 @@ surface TuiSurface { } rule SidebarNavigation { - when: TuiKeyPressed(code: "up" | "down" | "j" | "k") + when: TuiKeyPressed(code, _) + requires: code = "up" or code = "down" or code = "j" or code = "k" -- Selection moves over the flattened sidebar items and skips -- section headers; data comes from BDS.UI.Sidebar.view, identical -- to the GUI sidebar content. @@ -32,7 +33,8 @@ rule SidebarNavigation { } rule OpenEntry { - when: TuiKeyPressed(code: "enter") + when: TuiKeyPressed(code, _) + requires: code = "enter" -- Posts open in the editor by default (title + textarea seeded from -- the persisted form; syntax highlighting and word wrap on; ctrl+e -- switches to the rendered preview). New empty posts created with @@ -43,7 +45,9 @@ rule OpenEntry { } rule SaveAndPublish { - when: TuiKeyPressed(code: "s" | "p", modifiers: "ctrl") + when: TuiKeyPressed(code, modifiers) + requires: code = "s" or code = "p" + requires: modifiers = "ctrl" -- ctrl+s saves the draft, ctrl+p saves and publishes — both through -- BDS.UI.PostEditor.Persistence, so files, embeddings, search, and -- the event bus behave exactly as a GUI save. @@ -51,7 +55,9 @@ rule SaveAndPublish { } rule EditorMode { - when: TuiKeyPressed(code: "e", modifiers: "ctrl") + when: TuiKeyPressed(code, modifiers) + requires: code = "e" + requires: modifiers = "ctrl" -- ctrl+e toggles between the syntax-highlighted editor (the default -- mode when opening a post) and the read-only rendered-Markdown -- preview (rendered through tui-markdown so headings/emphasis/lists @@ -72,7 +78,9 @@ rule CodeEditorWrapping { } rule AiQuickAction { - when: TuiKeyPressed(code: "g", modifiers: "ctrl") + when: TuiKeyPressed(code, modifiers) + requires: code = "g" + requires: modifiers = "ctrl" -- One-shot AI post analysis (title/excerpt suggestions). Gated by -- airplane mode: without a local endpoint the TUI shows a status -- message instead of calling out. @@ -80,7 +88,8 @@ rule AiQuickAction { } rule ProjectSwitcher { - when: TuiKeyPressed(code: "p") + when: TuiKeyPressed(code, _) + requires: code = "p" -- "p" opens the projects overlay: all projects from the caching -- database with the active one marked; enter activates the selected -- project (BDS.Projects.set_active_project) and reloads the sidebar. @@ -100,7 +109,8 @@ rule ProjectSwitcher { } rule SidebarSearch { - when: TuiKeyPressed(code: "/") + when: TuiKeyPressed(code, _) + requires: code = "/" -- "/" in sidebar focus opens a vi-style search prompt in the status -- line that live-filters the current view through the same -- BDS.UI.Sidebar filter params the GUI sidebar uses (posts, pages, @@ -113,7 +123,8 @@ rule SidebarSearch { } rule CommandPrompt { - when: TuiKeyPressed(code: ":") + when: TuiKeyPressed(code, _) + requires: code = ":" -- Vi-style prompt: ":" opens a filterable list of the parameterless -- Blog-menu shell commands (metadata diff, validate site, force -- render, rebuilds, reindex, translations, duplicates, upload, @@ -127,7 +138,8 @@ rule CommandPrompt { } rule SettingsPanel { - when: TuiKeyPressed(code: "6") + when: TuiKeyPressed(code, _) + requires: code = "6" -- "6" opens the settings panel (issue #29), matching the GUI panel -- numbering: the sidebar lists the same preference sections as the -- settings backends (Project, Editor, Content, AI, Technology, @@ -145,7 +157,8 @@ rule SettingsPanel { } rule TagsPanel { - when: TuiKeyPressed(code: "5") + when: TuiKeyPressed(code, _) + requires: code = "5" -- "5" opens the tags view (issue #34), matching the GUI panel -- numbering. The sidebar lists the same three sections as the GUI -- tags editor (Tag Cloud, Create / Edit, Merge Tags — from @@ -165,7 +178,8 @@ rule TagsPanel { } rule GitPanel { - when: TuiKeyPressed(code: "7") + when: TuiKeyPressed(code, _) + requires: code = "7" -- "7" opens the git panel (issue #30) for content sync: the sidebar -- lists the changed files from git status (code + path, branch with -- ahead/behind counts in the title) with the commit history in its @@ -183,7 +197,8 @@ rule GitPanel { } rule ReportPanels { - when: ShellTaskCompleted(route: "metadata_diff" | "site_validation") + when: ShellTaskCompleted(route) + requires: route = "metadata_diff" or route = "site_validation" -- Completed metadata diff and site validation tasks open a -- scrollable report panel showing the differences. Enter applies -- the whole report — metadata diff repairs all items from the @@ -204,7 +219,8 @@ rule MultiClientSync { } rule ServerSideLocale { - when: TuiSettingsChanged(key: "ui.language") + when: TuiSettingsChanged(key) + requires: key = "ui.language" -- The TUI re-reads the server-side UI language and re-renders; all -- clients always share one language. ensures: TuiRelocalized()