omagem 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2344de2cc3f80a70f3d4b6a11ebb165bee0889404128750aa48ea8ee405b2b4f
4
+ data.tar.gz: ccd3fc5c8bd1520787c27fd15936ffc289de0efd9e3451abb73554c11d6cc4c0
5
+ SHA512:
6
+ metadata.gz: e4fff8c4af197d669db31d245cf82309ff5ceccf96073a94d6892d333f9feb10b25efdfff9b26fceb42e55163bb0427b6977b8db8c69bf69058d7a6152c61f9f
7
+ data.tar.gz: a5a0e991ac167211d827f38d5734a1fde76f3c37a0405749202ab94d788d24b906b3b9a74bb6edecf4feaecfd3b2c9e0cc57d821f7c965a3431561df8ccfd1c3
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 azzen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,211 @@
1
+ # Omarchy
2
+
3
+ [![CI](https://github.com/azzenabidi/OmaGem/actions/workflows/ci.yml/badge.svg)](https://github.com/azzenabidi/OmaGem/actions/workflows/ci.yml)
4
+ [![Gem Version](https://img.shields.io/gem/v/omagem)](https://rubygems.org/gems/omagem)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
6
+
7
+ A small Ruby DSL for configuring and managing [Omarchy](https://omarchy.org/)
8
+ Linux systems: themes, backgrounds, packages, services, the shell bar,
9
+ plugins, toggles, snapshots, and system operations. It wraps the single
10
+ `omarchy` CLI, so it stays in sync with the real command surface.
11
+
12
+ Designed to be used both in scripts and inside a Rails application.
13
+
14
+ ## Requirements
15
+
16
+ - Ruby 3.0+
17
+ - An [Omarchy](https://omarchy.org/) system with the `omarchy` CLI on your `PATH`
18
+
19
+ ## Installation
20
+
21
+ Add this line to your application's Gemfile:
22
+
23
+ ```ruby
24
+ gem "omagem"
25
+ ```
26
+
27
+ Or install directly from the repository:
28
+
29
+ ```ruby
30
+ gem "omagem", github: "azzenabidi/OmaGem", branch: "main"
31
+ ```
32
+
33
+ And then execute:
34
+
35
+ ```bash
36
+ bundle install
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ ```ruby
42
+ require "omarchy"
43
+
44
+ Omarchy.run do
45
+ theme "catppuccin"
46
+ background "/home/me/Pictures/forest.png"
47
+
48
+ add_packages "docker", "git"
49
+ add_packages "yay-bin", aur: true
50
+
51
+ install_service "tailscale"
52
+ install_dev_env "ruby"
53
+ install_browser "firefox"
54
+
55
+ nightlight :on
56
+ touchpad :on
57
+
58
+ bar_set "omarchy.clock", "format", "HH:mm"
59
+ clone_plugin "omarchy.workspaces"
60
+
61
+ update(yes: false)
62
+ end
63
+ ```
64
+
65
+ Every method is documented on `Omarchy::Config`. The block is evaluated
66
+ against a fresh `Config`, so you can call any DSL method directly:
67
+
68
+ ```ruby
69
+ config = Omarchy.run do
70
+ theme "catppuccin"
71
+ add_packages "git"
72
+ end
73
+
74
+ config.executed # => [["theme", "set", "catppuccin"], ["pkg", "add", "git"]]
75
+ config.client.run("theme", "current").stdout # raw command passthrough
76
+ ```
77
+
78
+ ## DSL reference
79
+
80
+ ### Themes & backgrounds
81
+
82
+ ```ruby
83
+ theme "catppuccin" # apply a theme ("Tokyo Night" or "tokyo-night" both work)
84
+ themes # list available themes
85
+ install_theme "https://...git" # install from a git repo
86
+ remove_theme "my-theme" # remove a user-installed theme
87
+ refresh_theme # re-apply current theme from templates
88
+ update_themes # update installed git themes
89
+
90
+ background "/path/to/image.png" # set the desktop background
91
+ background_next # cycle to next background
92
+ background_switcher # open the background switcher
93
+ ```
94
+
95
+ ### Packages
96
+
97
+ ```ruby
98
+ add_packages "docker", "git" # install Arch packages if missing
99
+ add_packages "yay-bin", aur: true # install from the AUR
100
+ drop_packages "vim" # remove packages if installed
101
+
102
+ package_present?("docker") # true unless ALL listed are installed
103
+ package_installed?("docker", "git") # true when ALL listed are installed
104
+ ```
105
+
106
+ ### Services, apps, tools
107
+
108
+ ```ruby
109
+ install_service "tailscale" # 1password, dropbox, nordvpn, once, signal, spotify, sunshine, tailscale
110
+ remove_service "tailscale"
111
+
112
+ install_browser "firefox" # chrome, brave, brave-origin, edge, firefox, zen
113
+ install_editor "helix" # emacs, helix, vscode, zed
114
+ install_terminal "kitty" # alacritty, foot, ghostty, kitty
115
+ install_dev_env "ruby" # ruby, node, bun, deno, go, laravel, symfony, php, python, elixir, phoenix, rust, java, zig, ocaml, dotnet, clojure, scala
116
+ install_game "steam" # steam, heroic, lutris, retroarch, battlenet, geforce-now, xbox-cloud, xbox-controllers, gpu-lib32
117
+ install_app "ChatGPT", "openai-chatgpt"
118
+ ```
119
+
120
+ ### System
121
+
122
+ ```ruby
123
+ update(yes: true) # full system + Omarchy update (-y skips prompts)
124
+ version # installed version
125
+ lock # lock screen
126
+ reboot / shutdown / logout
127
+
128
+ channel "stable" # stable, rc, edge, dev
129
+ default_terminal "kitty" # alacritty, foot, ghostty, kitty
130
+ default_browser "zen" # chromium, chrome, brave, brave-origin, edge, firefox, zen
131
+ default_editor "nvim" # code, cursor, zed, sublime_text, helix, vim, emacs, nvim
132
+
133
+ font "JetBrainsMono Nerd Font"
134
+ current_font
135
+
136
+ create_snapshot / restore_snapshot
137
+ debug
138
+ ```
139
+
140
+ ### Bar, plugins, toggles
141
+
142
+ ```ruby
143
+ bar "local.neon-bar" # switch bar layout
144
+ bar_position "top" # top, bottom, left, right
145
+ bar_transparent true # true, false, :toggle
146
+ bar_set "omarchy.clock", "format", "HH:mm"
147
+ bar_move "omarchy.clock", ["--section", "center", "--index", "0"]
148
+
149
+ add_plugin "https://...git", enable: true
150
+ clone_plugin "omarchy.workspaces"
151
+ enable_plugin "omarchy.clock"
152
+ disable_plugin "omarchy.clock"
153
+ remove_plugin "omarchy.clock"
154
+ list_plugins(json: false)
155
+
156
+ nightlight :on # :on, :off, :toggle
157
+ touchpad :off
158
+ touchscreen :on
159
+ idle :toggle
160
+ bar_visible :toggle
161
+ notification_silencing # do-not-disturb
162
+ ```
163
+
164
+ ### Misc
165
+
166
+ ```ruby
167
+ screenshot
168
+ screenrecord(fullscreen: true, desktop_audio: true, webcam: false)
169
+ stop_screenrecord
170
+ reminder 15, "Pick up Jack"
171
+ focus_app "org.mozilla.firefox"
172
+ ```
173
+
174
+ ## From a Rails app
175
+
176
+ Because `Omarchy.run` returns the `Config` (and records every executed
177
+ command), you can invoke it from a controller, job, or service and inspect
178
+ the results:
179
+
180
+ ```ruby
181
+ result = Omarchy.run { theme params[:theme] }
182
+ flash[:notice] = result.current_theme
183
+ ```
184
+
185
+ ### Reusable, non-destructive configuration
186
+
187
+ Pass a fake (recording) client to build a config without touching the system:
188
+
189
+ ```ruby
190
+ config = Omarchy::Config.new(client: Omarchy::Client::Fake.new)
191
+ config.theme "catppuccin"
192
+ config.executed # => [["theme", "set", "catppuccin"]]
193
+ ```
194
+
195
+ ## Errors
196
+
197
+ - `Omarchy::CommandFailed` — a command exited non-zero (set `ignore_errors: true` in `Omarchy.run` to raise nothing and keep going).
198
+ - `Omarchy::CommandNotFound` — the `omarchy` binary isn't on `PATH` (`ensure_command!`).
199
+ - `Omarchy::ArgumentError` — an invalid enum value (e.g. an unknown terminal).
200
+
201
+ ## Development
202
+
203
+ ```bash
204
+ bundle install
205
+ bundle exec rake test
206
+ bundle exec rubocop
207
+ ```
208
+
209
+ ## License
210
+
211
+ MIT
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+
5
+ module Omarchy
6
+ # Wraps the `omarchy` CLI. It shells out to the single `omarchy` binary and
7
+ # exposes the resulting output, whether the command succeeded, and the exit
8
+ # status. Errors raised by the command are captured rather than thrown.
9
+ #
10
+ # The class is designed to be subclassed or stubbed in tests (see
11
+ # Omarchy::Client::Fake) so the DSL can be exercised without a live system.
12
+ class Client
13
+ Result = Struct.new(:success, :stdout, :stderr, :status, keyword_init: true) do
14
+ def success?
15
+ success
16
+ end
17
+
18
+ def output
19
+ stdout
20
+ end
21
+ end
22
+
23
+ def initialize(command: 'omarchy')
24
+ @command = command
25
+ end
26
+
27
+ # Run an `omarchy` command as in: client.run("theme", "set", "catppuccin")
28
+ def run(*args)
29
+ cmd = [@command, *args.map(&:to_s)]
30
+ stdout, stderr, status = Open3.capture3(*cmd)
31
+ Result.new(
32
+ success: status.success?,
33
+ stdout: stdout.to_s.strip,
34
+ stderr: stderr.to_s.strip,
35
+ status: status.exitstatus
36
+ )
37
+ end
38
+
39
+ # A no-op client that records every call instead of running anything.
40
+ # Useful for tests and for "dry run" configuration building.
41
+ class Fake < Client
42
+ attr_reader :calls
43
+
44
+ def initialize
45
+ super(command: 'omarchy')
46
+ @calls = []
47
+ end
48
+
49
+ def run(*args)
50
+ @calls << args
51
+ Result.new(success: true, stdout: '', stderr: '', status: 0)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'client'
4
+ require_relative 'errors'
5
+
6
+ module Omarchy
7
+ # The DSL surface. A Config instance exposes all the management methods
8
+ # (theme, package, service, system, ...). The methods are defined in
9
+ # feature modules mixed in below, so the DSL is easy to extend and keep
10
+ # organized.
11
+ #
12
+ # To build a reusable configuration without executing anything, pass a
13
+ # fake (recording) client to Config.new.
14
+ class Config
15
+ attr_reader :client
16
+
17
+ def initialize(client: Omarchy::Client.new, ignore_errors: false)
18
+ @client = client
19
+ @ignore_errors = ignore_errors
20
+ @executed = []
21
+ end
22
+
23
+ # Every command that ran through #run, in order. Each entry is the
24
+ # argument array.
25
+ attr_reader :executed
26
+
27
+ # Run an Omarchy command and return the Omarchy::Client::Result.
28
+ # Records the call and validates the exit status unless ignore_errors.
29
+ def run(*args)
30
+ @executed << args
31
+ result = client.run(*args)
32
+ raise CommandFailed.new(args, result) unless result.success?
33
+
34
+ result
35
+ end
36
+
37
+ # Raise CommandNotFound if the underlying `omarchy` binary cannot be run.
38
+ def ensure_command!
39
+ # A lightweight availability check: run "omarchy version".
40
+ run('version')
41
+ rescue Errno::ENOENT
42
+ raise CommandNotFound, 'the `omarchy` CLI could not be found on PATH'
43
+ end
44
+
45
+ # -- Helpers shared by the feature DSL ---------------------------------
46
+
47
+ # True when at least one of the named packages is installed.
48
+ def package_present?(*names)
49
+ client.run('pkg', 'present', *names).success?
50
+ end
51
+
52
+ # True when every named package is installed.
53
+ def package_installed?(*names)
54
+ !client.run('pkg', 'missing', *names).success?
55
+ end
56
+
57
+ # Current theme name (from `omarchy theme current`).
58
+ def current_theme
59
+ client.run('theme', 'current').stdout
60
+ end
61
+
62
+ def valid_theme?(name)
63
+ available_themes.include?(name)
64
+ end
65
+
66
+ def available_themes
67
+ client.run('theme', 'list').stdout.lines.map(&:strip).reject(&:empty?)
68
+ end
69
+
70
+ # Raise Omarchy::ArgumentError unless value is in the allowed list.
71
+ def validate_in!(value, allowed, label)
72
+ return if allowed.include?(value.to_s)
73
+
74
+ raise ArgumentError, "unknown #{label} #{value.inspect}; expected one of: #{allowed.join(', ')}"
75
+ end
76
+ end
77
+ end
78
+
79
+ require_relative 'dsl/theme'
80
+ require_relative 'dsl/package'
81
+ require_relative 'dsl/service'
82
+ require_relative 'dsl/system'
83
+ require_relative 'dsl/bar'
84
+ require_relative 'dsl/plugin'
85
+ require_relative 'dsl/toggle'
86
+ require_relative 'dsl/snapshot'
87
+ require_relative 'dsl/misc'
88
+
89
+ Omarchy::Config.include(Omarchy::DSL::Theme)
90
+ Omarchy::Config.include(Omarchy::DSL::Package)
91
+ Omarchy::Config.include(Omarchy::DSL::Service)
92
+ Omarchy::Config.include(Omarchy::DSL::System)
93
+ Omarchy::Config.include(Omarchy::DSL::Bar)
94
+ Omarchy::Config.include(Omarchy::DSL::Plugin)
95
+ Omarchy::Config.include(Omarchy::DSL::Toggle)
96
+ Omarchy::Config.include(Omarchy::DSL::Snapshot)
97
+ Omarchy::Config.include(Omarchy::DSL::Misc)
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omarchy
4
+ module DSL
5
+ # The status bar: which bar and widget layout is used, plus widget layout.
6
+ module Bar
7
+ POSITIONS = %w[top bottom left right].freeze
8
+
9
+ # Switch to a bar layout by id, or `:defaults`/`:reset`.
10
+ def bar(id)
11
+ run('bar', 'use', id)
12
+ end
13
+
14
+ def bar_position(pos)
15
+ validate_in!(pos, POSITIONS, 'bar position')
16
+ run('bar', 'position', pos)
17
+ end
18
+
19
+ def bar_transparent(value = :toggle)
20
+ run('bar', 'transparent', value.to_s)
21
+ end
22
+
23
+ # Put a widget somewhere; placement e.g. ["--after", "omarchy.clock"].
24
+ def bar_put(id, placement = [])
25
+ run('bar', 'put', id, *placement)
26
+ end
27
+
28
+ # Move a widget; placement e.g. ["--section", "center", "--index", "0"].
29
+ def bar_move(id, placement = [])
30
+ run('bar', 'move', id, *placement)
31
+ end
32
+
33
+ # Set a widget key/value; e.g. bar_set("omarchy.clock", "format", "HH:mm").
34
+ def bar_set(id, key, value)
35
+ run('bar', 'set', id, key, value)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omarchy
4
+ module DSL
5
+ # Misc: reminders, screen capture, launch app, focus app, default agent.
6
+ module Misc
7
+ # Full-screen screenshot saved to disk.
8
+ def screenshot
9
+ run('capture', 'screenshot', 'fullscreen', 'save')
10
+ end
11
+
12
+ def screenrecord(fullscreen: false, desktop_audio: false, microphone: false, webcam: false)
13
+ args = %w[capture screenrecording]
14
+ args << '--fullscreen' if fullscreen
15
+ args << '--with-desktop-audio' if desktop_audio
16
+ args << '--with-microphone-audio' if microphone
17
+ args << '--with-webcam' if webcam
18
+ run(*args)
19
+ end
20
+
21
+ def stop_screenrecord
22
+ run('capture', 'screenrecording', '--stop-recording')
23
+ end
24
+
25
+ # Set a desktop notification reminder; minutes accepts decimals.
26
+ def reminder(minutes, message)
27
+ run('reminder', minutes.to_s, message)
28
+ end
29
+
30
+ def focus_app(name)
31
+ run('hyprland', 'focus', 'app', name)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../errors'
4
+
5
+ module Omarchy
6
+ module DSL
7
+ # Package management: add / drop Arch and AUR packages, plus queries.
8
+ module Package
9
+ # Install one or more Arch packages if missing.
10
+ def add_packages(*names, aur: false)
11
+ if aur
12
+ run('pkg', 'aur', 'add', *names)
13
+ else
14
+ run('pkg', 'add', *names)
15
+ end
16
+ names.size == 1 ? names.first : names
17
+ end
18
+ alias install_packages add_packages
19
+
20
+ # Remove one or more packages if they are installed.
21
+ def drop_packages(*names)
22
+ run('pkg', 'drop', *names)
23
+ names.size == 1 ? names.first : names
24
+ end
25
+ alias remove_packages drop_packages
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omarchy
4
+ module DSL
5
+ # Shell plugin and bar-widget management.
6
+ module Plugin
7
+ # Add a shell plugin from a git URL. enable: true enables it immediately.
8
+ def add_plugin(url, enable: false)
9
+ args = ['plugin', 'add', url]
10
+ args << '--enable' if enable
11
+ args << '--yes'
12
+ run(*args)
13
+ end
14
+
15
+ # Clone a built-in plugin into the user config (switch to user copy).
16
+ def clone_plugin(id)
17
+ run('plugin', 'clone', id)
18
+ end
19
+
20
+ def enable_plugin(id, placement = nil)
21
+ args = ['plugin', 'enable', id]
22
+ args << placement if placement
23
+ run(*args)
24
+ end
25
+
26
+ def disable_plugin(id)
27
+ run('plugin', 'disable', id)
28
+ end
29
+
30
+ def remove_plugin(id)
31
+ run('plugin', 'remove', id, '--yes')
32
+ end
33
+
34
+ def list_plugins(json: false)
35
+ args = %w[plugin list]
36
+ args << '--json' if json
37
+ out = run(*args).stdout
38
+ json ? out : out.lines.map(&:strip).reject(&:empty?)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../errors'
4
+
5
+ module Omarchy
6
+ module DSL
7
+ # Install/manage optional software, services, apps, browsers, editors,
8
+ # terminals, development environments, and gaming.
9
+ module Service
10
+ # Install a supported standalone app, e.g. install_app("ChatGPT")
11
+ # wraps `omarchy install <display-name> <packages>`.
12
+ def install_app(display_name, packages)
13
+ run('install', 'app', display_name, packages)
14
+ end
15
+
16
+ # -- Optional software installers ------------------------------------
17
+
18
+ def install_browser(name)
19
+ validate_in!(name, %w[chrome brave brave-origin edge firefox zen], 'browser')
20
+ run('install', 'browser', name)
21
+ end
22
+
23
+ def install_editor(name)
24
+ validate_in!(name, %w[emacs helix vscode zed], 'editor')
25
+ run('install', 'editor', name)
26
+ end
27
+
28
+ def install_terminal(name)
29
+ validate_in!(name, %w[alacritty foot ghostty kitty], 'terminal')
30
+ run('install', 'terminal', name)
31
+ end
32
+
33
+ # -- Services ---------------------------------------------------------
34
+
35
+ SERVICES = %w[1password dropbox nordvpn once signal spotify sunshine tailscale].freeze
36
+
37
+ # Install and start a supported service (or bundle downloads a full version).
38
+ def install_service(name)
39
+ validate_in!(name, SERVICES, 'service')
40
+ run('install', 'service', name)
41
+ end
42
+
43
+ def remove_service(name)
44
+ validate_in!(name, SERVICES, 'service')
45
+ run('remove', 'service', name)
46
+ end
47
+
48
+ # -- Development environments (install dev-env <ruby|node|...>) ------
49
+
50
+ def install_dev_env(env)
51
+ allowed = %w[ruby node bun deno go laravel symfony php python elixir phoenix rust java zig ocaml dotnet clojure
52
+ scala]
53
+ validate_in!(env, allowed, 'dev env')
54
+ run('install', 'dev-env', env)
55
+ end
56
+
57
+ # -- Gaming -----------------------------------------------------------
58
+
59
+ def install_game(platform)
60
+ allowed = %w[steam heroic lutris retroarch battlenet geforce-now xbox-cloud xbox-controllers gpu-lib32]
61
+ validate_in!(platform, allowed, 'gaming platform')
62
+ run('install', 'gaming', platform)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omarchy
4
+ module DSL
5
+ # System snapshots via snapper.
6
+ module Snapshot
7
+ def create_snapshot
8
+ run('snapshot', 'create')
9
+ end
10
+
11
+ def restore_snapshot
12
+ run('snapshot', 'restore')
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omarchy
4
+ module DSL
5
+ # System-level operations: updates, reboot/shutdown/lock, default apps,
6
+ # font, snapshots, and diagnostics.
7
+ module System
8
+ # Perform a full system + Omarchy update. Pass yes: true to skip prompts.
9
+ def update(yes: false)
10
+ args = ['update']
11
+ args << '-y' if yes
12
+ run(*args)
13
+ end
14
+
15
+ def version(channel: false)
16
+ args = ['version']
17
+ args << 'channel' if channel
18
+ run(*args).stdout
19
+ end
20
+
21
+ def reboot
22
+ run('system', 'reboot')
23
+ end
24
+
25
+ def shutdown
26
+ run('system', 'shutdown')
27
+ end
28
+
29
+ def lock
30
+ run('system', 'lock')
31
+ end
32
+
33
+ def logout
34
+ run('system', 'logout')
35
+ end
36
+
37
+ def channel(name = nil)
38
+ return run('channel', 'current').stdout if name.nil?
39
+
40
+ validate_in!(name, %w[stable rc edge dev], 'channel')
41
+ run('channel', 'set', name)
42
+ end
43
+
44
+ # Set the default terminal used by xdg-terminal-exec.
45
+ def default_terminal(name)
46
+ validate_in!(name, %w[alacritty foot ghostty kitty], 'terminal')
47
+ run('default', 'terminal', name)
48
+ end
49
+
50
+ def default_browser(name)
51
+ validate_in!(name, %w[chromium chrome brave brave-origin edge firefox zen], 'browser')
52
+ run('default', 'browser', name)
53
+ end
54
+
55
+ def default_editor(name)
56
+ validate_in!(name, %w[code cursor zed sublime_text helix vim emacs nvim], 'editor')
57
+ run('default', 'editor', name)
58
+ end
59
+
60
+ # Set the system monospace font.
61
+ def font(name)
62
+ run('font', 'set', name)
63
+ end
64
+
65
+ def current_font
66
+ run('font', 'current').stdout
67
+ end
68
+
69
+ def debug
70
+ run('debug', '--no-sudo', '--print').stdout
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../errors'
4
+
5
+ module Omarchy
6
+ module DSL
7
+ # Theme management: apply, list, install, remove, refresh, backgrounds.
8
+ module Theme
9
+ # Apply a theme by name. `"Tokyo Night"` and `"tokyo-night"` both work.
10
+ def theme(name)
11
+ run('theme', 'set', name)
12
+ end
13
+ alias apply_theme theme
14
+
15
+ # List themes Omarchy knows about.
16
+ def themes
17
+ run('theme', 'list').stdout.lines.map(&:strip).reject(&:empty?)
18
+ end
19
+
20
+ # Install a theme from a git repository URL.
21
+ def install_theme(url)
22
+ run('theme', 'install', url)
23
+ end
24
+
25
+ # Remove a user-installed theme by name.
26
+ def remove_theme(name)
27
+ run('theme', 'remove', name)
28
+ end
29
+
30
+ # Re-apply the current theme from its templates.
31
+ def refresh_theme
32
+ run('theme', 'refresh')
33
+ end
34
+
35
+ # Update user-installed git themes.
36
+ def update_themes
37
+ run('theme', 'update')
38
+ end
39
+
40
+ # -- Backgrounds ------------------------------------------------------
41
+
42
+ # Set the desktop background to the given image path.
43
+ def background(path)
44
+ run('theme', 'bg', 'set', path)
45
+ end
46
+ alias set_background background
47
+
48
+ # Cycle to the next background for the current theme.
49
+ def background_next
50
+ run('theme', 'bg', 'next')
51
+ end
52
+
53
+ # Open the background switcher.
54
+ def background_switcher
55
+ run('theme', 'bg-switcher')
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omarchy
4
+ module DSL
5
+ # Toggle Omarchy features on/off: nightlight, touchpad, Bluetooth, etc.
6
+ module Toggle
7
+ # Toggle a named feature: toggle("nightlight") or
8
+ # toggle("nightlight", :on | :off | :toggle).
9
+ def toggle(name, state = :toggle)
10
+ run('toggle', name, state.to_s)
11
+ end
12
+
13
+ def nightlight(state = :toggle)
14
+ run('toggle', 'nightlight', state.to_s)
15
+ end
16
+
17
+ def touchpad(state = :toggle)
18
+ run('toggle', 'touchpad', state.to_s)
19
+ end
20
+
21
+ def touchscreen(state = :toggle)
22
+ run('toggle', 'touchscreen', state.to_s)
23
+ end
24
+
25
+ def idle(state = :toggle)
26
+ run('toggle', 'idle', state.to_s)
27
+ end
28
+
29
+ def bar_visible(state = :toggle)
30
+ run('toggle', 'bar', state.to_s)
31
+ end
32
+
33
+ def notification_silencing
34
+ run('toggle', 'notification silencing')
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omarchy
4
+ # Base class for all Omarchy::DSL errors.
5
+ class Error < StandardError; end
6
+
7
+ # Raised when the `omarchy` CLI is not available on the system.
8
+ class CommandNotFound < Error; end
9
+
10
+ # Raised (unless swallowed with `ignore_errors: true`) when an `omarchy`
11
+ # command exits with a non-zero status.
12
+ class CommandFailed < Error
13
+ attr_reader :args, :result
14
+
15
+ def initialize(args, result)
16
+ @args = args
17
+ @result = result
18
+ super("omarchy #{args.join(' ')} failed (exit #{result.status}): #{result.stderr}")
19
+ end
20
+ end
21
+
22
+ # Raised when a DSL value is outside the set of values Omarchy accepts.
23
+ class ArgumentError < Error; end
24
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omarchy
4
+ VERSION = '0.1.0'
5
+ end
data/lib/omarchy.rb ADDED
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'omarchy/version'
4
+ require_relative 'omarchy/errors'
5
+ require_relative 'omarchy/client'
6
+ require_relative 'omarchy/config'
7
+
8
+ # Omarchy is a Ruby DSL for configuring and managing Omarchy Linux systems.
9
+ #
10
+ # require "omarchy"
11
+ #
12
+ # Omarchy.run do
13
+ # theme "catppuccin"
14
+ # add_packages "docker", "git"
15
+ # install_service "tailscale"
16
+ # nightlight :on
17
+ # end
18
+ #
19
+ # The block is evaluated against an Omarchy::Config, which exposes every
20
+ # DSL method. See Omarchy::Config for the full list.
21
+ module Omarchy
22
+ class << self
23
+ # Execute a DSL block against a fresh Omarchy::Config. Returns the config
24
+ # so the caller can inspect what ran via config.executed / config.client.
25
+ #
26
+ # config = Omarchy.run { theme "catppuccin" }
27
+ def run(client: Omarchy::Client.new, ignore_errors: false, &block)
28
+ config = Config.new(client: client, ignore_errors: ignore_errors)
29
+ config.instance_eval(&block) if block
30
+ config
31
+ end
32
+ end
33
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: omagem
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - azzen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-09-09 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A tiny Ruby DSL that wraps the `omarchy` CLI so you can manage themes,
14
+ packages, services, the shell bar, and more from Ruby or a Rails application.
15
+ email:
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - LICENSE
21
+ - README.md
22
+ - lib/omarchy.rb
23
+ - lib/omarchy/client.rb
24
+ - lib/omarchy/config.rb
25
+ - lib/omarchy/dsl/bar.rb
26
+ - lib/omarchy/dsl/misc.rb
27
+ - lib/omarchy/dsl/package.rb
28
+ - lib/omarchy/dsl/plugin.rb
29
+ - lib/omarchy/dsl/service.rb
30
+ - lib/omarchy/dsl/snapshot.rb
31
+ - lib/omarchy/dsl/system.rb
32
+ - lib/omarchy/dsl/theme.rb
33
+ - lib/omarchy/dsl/toggle.rb
34
+ - lib/omarchy/errors.rb
35
+ - lib/omarchy/version.rb
36
+ homepage: https://github.com/azzenabidi/OmaGem
37
+ licenses:
38
+ - MIT
39
+ metadata:
40
+ rubygems_mfa_required: 'true'
41
+ post_install_message:
42
+ rdoc_options: []
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '3.0'
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ requirements: []
56
+ rubygems_version: 3.5.22
57
+ signing_key:
58
+ specification_version: 4
59
+ summary: Ruby DSL to configure and manage Omarchy Linux systems
60
+ test_files: []