launchline 0.1.0__tar.gz → 0.2.1.dev0__tar.gz

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.
Files changed (44) hide show
  1. launchline-0.2.1.dev0/.generated-go-semantic-release-changelog.md +23 -0
  2. {launchline-0.1.0 → launchline-0.2.1.dev0}/.github/workflows/release.yml +8 -1
  3. {launchline-0.1.0 → launchline-0.2.1.dev0}/CHANGELOG.md +15 -0
  4. {launchline-0.1.0 → launchline-0.2.1.dev0}/PKG-INFO +19 -12
  5. {launchline-0.1.0 → launchline-0.2.1.dev0}/README.md +18 -11
  6. {launchline-0.1.0 → launchline-0.2.1.dev0}/src/launchline/__main__.py +5 -0
  7. {launchline-0.1.0 → launchline-0.2.1.dev0}/src/launchline/cli.py +6 -0
  8. {launchline-0.1.0 → launchline-0.2.1.dev0}/src/launchline/config.py +17 -3
  9. {launchline-0.1.0 → launchline-0.2.1.dev0}/tests/test_cli.py +60 -0
  10. {launchline-0.1.0 → launchline-0.2.1.dev0}/tests/test_config.py +57 -0
  11. launchline-0.1.0/.generated-go-semantic-release-changelog.md +0 -46
  12. {launchline-0.1.0 → launchline-0.2.1.dev0}/.github/workflows/ci.yml +0 -0
  13. {launchline-0.1.0 → launchline-0.2.1.dev0}/.gitignore +0 -0
  14. {launchline-0.1.0 → launchline-0.2.1.dev0}/.markdownlint.json +0 -0
  15. {launchline-0.1.0 → launchline-0.2.1.dev0}/.python-version +0 -0
  16. {launchline-0.1.0 → launchline-0.2.1.dev0}/.semrel/linux_amd64/changelog-generator-default/1.15.0/changelog-generator-default_v1.15.0_linux_amd64 +0 -0
  17. {launchline-0.1.0 → launchline-0.2.1.dev0}/.semrel/linux_amd64/commit-analyzer-default/1.15.0/commit-analyzer-cz_v1.15.0_linux_amd64 +0 -0
  18. {launchline-0.1.0 → launchline-0.2.1.dev0}/.semrel/linux_amd64/condition-github/1.11.0/condition-github_v1.11.0_linux_amd64 +0 -0
  19. {launchline-0.1.0 → launchline-0.2.1.dev0}/.semrel/linux_amd64/files-updater-npm/1.11.0/files-updater-npm_v1.11.0_linux_amd64 +0 -0
  20. {launchline-0.1.0 → launchline-0.2.1.dev0}/.semrel/linux_amd64/provider-github/1.19.0/provider-github_v1.19.0_linux_amd64 +0 -0
  21. {launchline-0.1.0 → launchline-0.2.1.dev0}/LICENSE +0 -0
  22. {launchline-0.1.0 → launchline-0.2.1.dev0}/assets/launchline.ico +0 -0
  23. {launchline-0.1.0 → launchline-0.2.1.dev0}/assets/launchline.png +0 -0
  24. {launchline-0.1.0 → launchline-0.2.1.dev0}/assets/launchline.svg +0 -0
  25. {launchline-0.1.0 → launchline-0.2.1.dev0}/docs/images/demo.gif +0 -0
  26. {launchline-0.1.0 → launchline-0.2.1.dev0}/docs/images/hero.png +0 -0
  27. {launchline-0.1.0 → launchline-0.2.1.dev0}/docs/images/navigate.png +0 -0
  28. {launchline-0.1.0 → launchline-0.2.1.dev0}/docs/images/search.png +0 -0
  29. {launchline-0.1.0 → launchline-0.2.1.dev0}/pyproject.toml +0 -0
  30. {launchline-0.1.0 → launchline-0.2.1.dev0}/src/launchline/__init__.py +0 -0
  31. {launchline-0.1.0 → launchline-0.2.1.dev0}/src/launchline/assets/launchline.ico +0 -0
  32. {launchline-0.1.0 → launchline-0.2.1.dev0}/src/launchline/exceptions.py +0 -0
  33. {launchline-0.1.0 → launchline-0.2.1.dev0}/src/launchline/fuzzy.py +0 -0
  34. {launchline-0.1.0 → launchline-0.2.1.dev0}/src/launchline/keys.py +0 -0
  35. {launchline-0.1.0 → launchline-0.2.1.dev0}/src/launchline/runner.py +0 -0
  36. {launchline-0.1.0 → launchline-0.2.1.dev0}/src/launchline/ui.py +0 -0
  37. {launchline-0.1.0 → launchline-0.2.1.dev0}/tests/__init__.py +0 -0
  38. {launchline-0.1.0 → launchline-0.2.1.dev0}/tests/conftest.py +0 -0
  39. {launchline-0.1.0 → launchline-0.2.1.dev0}/tests/test_cross_platform.py +0 -0
  40. {launchline-0.1.0 → launchline-0.2.1.dev0}/tests/test_runner.py +0 -0
  41. {launchline-0.1.0 → launchline-0.2.1.dev0}/tests/test_ui.py +0 -0
  42. {launchline-0.1.0 → launchline-0.2.1.dev0}/tools/generate_icon.py +0 -0
  43. {launchline-0.1.0 → launchline-0.2.1.dev0}/tools/generate_screenshots.py +0 -0
  44. {launchline-0.1.0 → launchline-0.2.1.dev0}/uv.lock +0 -0
@@ -0,0 +1,23 @@
1
+ ## 0.2.0 (2026-03-30)
2
+
3
+ #### Feature
4
+
5
+ * accept command as string or array in config (db1b1857)
6
+ * add --config-path flag to print active config file location (fe98125a)
7
+
8
+ #### Bug Fixes
9
+
10
+ * apply ruff format to test_cli.py (45b9375b)
11
+ * capitalize docstrings to satisfy ruff D403 (8e51bff1)
12
+ * wrap long lines in test_cli.py to satisfy ruff E501 (9eef319e)
13
+ * use absolute URLs for images in README for PyPI rendering (7dc2878d)
14
+ * restrict release asset glob to dist archives only (827cbec5)
15
+
16
+ #### Documentation
17
+
18
+ * update changelog for v0.2.0 (557d5475)
19
+
20
+ #### Build
21
+
22
+ * auto-rewrite README image paths during release (90e2ec08)
23
+
@@ -34,6 +34,11 @@ jobs:
34
34
  - uses: astral-sh/setup-uv@v6
35
35
  - run: uv sync --group dev
36
36
  - run: uv run pytest
37
+
38
+ - name: Rewrite README image paths for PyPI
39
+ run: |
40
+ sed -i "s|(docs/|(https://raw.githubusercontent.com/${{ github.repository }}/v${{ steps.semrel.outputs.version }}/docs/|g" README.md
41
+
37
42
  - run: uv build
38
43
 
39
44
  - uses: actions/upload-artifact@v4
@@ -49,7 +54,9 @@ jobs:
49
54
  with:
50
55
  tag_name: "v${{ steps.semrel.outputs.version }}"
51
56
  generate_release_notes: true
52
- files: dist/*
57
+ files: |
58
+ dist/*.tar.gz
59
+ dist/*.whl
53
60
 
54
61
  pypi:
55
62
  needs: release
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+
12
+ - `command` config key now accepts a list of strings (e.g.,
13
+ `command = ["ssh", "-t", "my server"]`) for easier argument handling,
14
+ especially with values containing spaces
15
+ - `--config-path` CLI flag to print the active configuration file path
16
+
17
+ ### Fixed
18
+
19
+ - PyPI package page now renders README images correctly (paths are rewritten
20
+ to absolute URLs during the release build)
21
+ - Release artifacts no longer accidentally include non-distribution files
22
+
8
23
  ## [0.1.0] - 2026-03-30
9
24
 
10
25
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: launchline
3
- Version: 0.1.0
3
+ Version: 0.2.1.dev0
4
4
  Summary: A lightweight terminal launcher for interactive CLI tools.
5
5
  Project-URL: Homepage, https://github.com/mikejhill/launchline
6
6
  Project-URL: Repository, https://github.com/mikejhill/launchline
@@ -29,7 +29,7 @@ A lightweight terminal launcher for interactive CLI tools. Define your frequentl
29
29
  used commands in a TOML config file, then pick them from a fuzzy-searchable menu
30
30
  instead of remembering flags and paths.
31
31
 
32
- ![LaunchLine demo](docs/images/demo.gif)
32
+ ![LaunchLine demo](https://raw.githubusercontent.com/mikejhill/launchline/v0.2.0/docs/images/demo.gif)
33
33
 
34
34
  ## Why
35
35
 
@@ -50,7 +50,7 @@ instead.
50
50
 
51
51
  | Fuzzy search | Arrow-key navigation |
52
52
  | :-------------------------------: | :-----------------------------------: |
53
- | ![Search](docs/images/search.png) | ![Navigate](docs/images/navigate.png) |
53
+ | ![Search](https://raw.githubusercontent.com/mikejhill/launchline/v0.2.0/docs/images/search.png) | ![Navigate](https://raw.githubusercontent.com/mikejhill/launchline/v0.2.0/docs/images/navigate.png) |
54
54
 
55
55
  ## Installation
56
56
 
@@ -123,21 +123,24 @@ Config file format is [TOML](https://toml.io). The file has an optional
123
123
 
124
124
  Each `[[entries]]` table defines one launchable tool:
125
125
 
126
- | Key | Type | Required | Default | Description |
127
- | ------------------- | --------------- | -------- | ------- | -------------------------------------------------------------- |
128
- | `name` | string | yes | — | Display name shown in the menu |
129
- | `command` | string | yes | — | Executable to run |
130
- | `args` | list of strings | no | `[]` | Arguments passed to the command |
131
- | `description` | string | no | `""` | Short description shown next to the name |
132
- | `working_directory` | string | no | — | Working directory for the subprocess |
133
- | `env` | table | no | `{}` | Extra environment variables (`KEY = "value"`) |
126
+ | Key | Type | Required | Default | Description |
127
+ | ------------------- | ------------------------- | -------- | ------- | -------------------------------------------------------------- |
128
+ | `name` | string | yes | — | Display name shown in the menu |
129
+ | `command` | string or list of strings | yes | — | Executable to run (with optional inline arguments) |
130
+ | `args` | list of strings | no | `[]` | Additional arguments appended after any inline command args |
131
+ | `description` | string | no | `""` | Short description shown next to the name |
132
+ | `working_directory` | string | no | — | Working directory for the subprocess |
133
+ | `env` | table | no | `{}` | Extra environment variables (`KEY = "value"`) |
134
134
 
135
135
  ### Validation Rules
136
136
 
137
137
  - At least one `[[entries]]` table is required.
138
138
  - Every entry must have both `name` and `command`.
139
+ - `command` may be a string (`"pwsh"`) or a list (`["ssh", "-t", "host"]`).
140
+ When a list, the first element is the executable and the rest are arguments.
139
141
  - `on_exit` must be `"restart"` or `"exit"`.
140
- - `args` must be a list (not a bare string).
142
+ - `args` must be a list (not a bare string). These are appended after any
143
+ arguments provided inline in a `command` list.
141
144
  - `env` must be a TOML table (not a string or list).
142
145
  - If `working_directory` does not exist at load time, it is silently reset to
143
146
  `None` (a warning is logged).
@@ -168,6 +171,10 @@ name = "PowerShell"
168
171
  command = "pwsh"
169
172
  args = ["-NoProfile"]
170
173
  env = { TERM = "xterm-256color" }
174
+
175
+ [[entries]]
176
+ name = "Remote Server"
177
+ command = ["ssh", "-t", "my server", "bash"]
171
178
  ```
172
179
 
173
180
  ## Usage
@@ -7,7 +7,7 @@ A lightweight terminal launcher for interactive CLI tools. Define your frequentl
7
7
  used commands in a TOML config file, then pick them from a fuzzy-searchable menu
8
8
  instead of remembering flags and paths.
9
9
 
10
- ![LaunchLine demo](docs/images/demo.gif)
10
+ ![LaunchLine demo](https://raw.githubusercontent.com/mikejhill/launchline/v0.2.0/docs/images/demo.gif)
11
11
 
12
12
  ## Why
13
13
 
@@ -28,7 +28,7 @@ instead.
28
28
 
29
29
  | Fuzzy search | Arrow-key navigation |
30
30
  | :-------------------------------: | :-----------------------------------: |
31
- | ![Search](docs/images/search.png) | ![Navigate](docs/images/navigate.png) |
31
+ | ![Search](https://raw.githubusercontent.com/mikejhill/launchline/v0.2.0/docs/images/search.png) | ![Navigate](https://raw.githubusercontent.com/mikejhill/launchline/v0.2.0/docs/images/navigate.png) |
32
32
 
33
33
  ## Installation
34
34
 
@@ -101,21 +101,24 @@ Config file format is [TOML](https://toml.io). The file has an optional
101
101
 
102
102
  Each `[[entries]]` table defines one launchable tool:
103
103
 
104
- | Key | Type | Required | Default | Description |
105
- | ------------------- | --------------- | -------- | ------- | -------------------------------------------------------------- |
106
- | `name` | string | yes | — | Display name shown in the menu |
107
- | `command` | string | yes | — | Executable to run |
108
- | `args` | list of strings | no | `[]` | Arguments passed to the command |
109
- | `description` | string | no | `""` | Short description shown next to the name |
110
- | `working_directory` | string | no | — | Working directory for the subprocess |
111
- | `env` | table | no | `{}` | Extra environment variables (`KEY = "value"`) |
104
+ | Key | Type | Required | Default | Description |
105
+ | ------------------- | ------------------------- | -------- | ------- | -------------------------------------------------------------- |
106
+ | `name` | string | yes | — | Display name shown in the menu |
107
+ | `command` | string or list of strings | yes | — | Executable to run (with optional inline arguments) |
108
+ | `args` | list of strings | no | `[]` | Additional arguments appended after any inline command args |
109
+ | `description` | string | no | `""` | Short description shown next to the name |
110
+ | `working_directory` | string | no | — | Working directory for the subprocess |
111
+ | `env` | table | no | `{}` | Extra environment variables (`KEY = "value"`) |
112
112
 
113
113
  ### Validation Rules
114
114
 
115
115
  - At least one `[[entries]]` table is required.
116
116
  - Every entry must have both `name` and `command`.
117
+ - `command` may be a string (`"pwsh"`) or a list (`["ssh", "-t", "host"]`).
118
+ When a list, the first element is the executable and the rest are arguments.
117
119
  - `on_exit` must be `"restart"` or `"exit"`.
118
- - `args` must be a list (not a bare string).
120
+ - `args` must be a list (not a bare string). These are appended after any
121
+ arguments provided inline in a `command` list.
119
122
  - `env` must be a TOML table (not a string or list).
120
123
  - If `working_directory` does not exist at load time, it is silently reset to
121
124
  `None` (a warning is logged).
@@ -146,6 +149,10 @@ name = "PowerShell"
146
149
  command = "pwsh"
147
150
  args = ["-NoProfile"]
148
151
  env = { TERM = "xterm-256color" }
152
+
153
+ [[entries]]
154
+ name = "Remote Server"
155
+ command = ["ssh", "-t", "my server", "bash"]
149
156
  ```
150
157
 
151
158
  ## Usage
@@ -80,6 +80,11 @@ def main() -> None:
80
80
  print(CommandLineInterface.icon_path())
81
81
  return
82
82
 
83
+ if args.config_path:
84
+ config_path = ConfigLoader.resolve_path(args.config)
85
+ print(config_path)
86
+ return
87
+
83
88
  logging.basicConfig(
84
89
  level=args.log_level,
85
90
  format="%(asctime)s %(levelname)s %(name)s: %(message)s",
@@ -64,6 +64,12 @@ class CommandLineInterface:
64
64
  default=False,
65
65
  help="Print the path to the bundled icon and exit.",
66
66
  )
67
+ parser.add_argument(
68
+ "--config-path",
69
+ action="store_true",
70
+ default=False,
71
+ help="Print the path to the active config file and exit.",
72
+ )
67
73
 
68
74
  args = parser.parse_args(argv)
69
75
  args.log_level = getattr(logging, args.log_level)
@@ -188,7 +188,19 @@ description = "PowerShell 7"
188
188
  entries: list[EntryConfig] = []
189
189
  for i, entry_raw in enumerate(raw_entries, 1):
190
190
  name = entry_raw.get("name", "")
191
- command = entry_raw.get("command", "")
191
+ raw_command = entry_raw.get("command", "")
192
+
193
+ if isinstance(raw_command, list):
194
+ if not raw_command:
195
+ raise ConfigurationError(
196
+ f"Entry {i}: 'command' list must not be empty."
197
+ )
198
+ command = str(raw_command[0])
199
+ command_args = tuple(str(a) for a in raw_command[1:])
200
+ else:
201
+ command = str(raw_command)
202
+ command_args = ()
203
+
192
204
  if not name or not command:
193
205
  raise ConfigurationError(
194
206
  f"Entry {i}: 'name' and 'command' are required."
@@ -200,6 +212,8 @@ description = "PowerShell 7"
200
212
  f"Entry {i}: 'args' must be a list of strings."
201
213
  )
202
214
 
215
+ combined_args = command_args + tuple(str(a) for a in raw_args)
216
+
203
217
  wd_raw = entry_raw.get("working_directory")
204
218
  wd: Path | None = None
205
219
  if wd_raw:
@@ -221,8 +235,8 @@ description = "PowerShell 7"
221
235
  entries.append(
222
236
  EntryConfig(
223
237
  name=str(name),
224
- command=str(command),
225
- args=tuple(str(a) for a in raw_args),
238
+ command=command,
239
+ args=combined_args,
226
240
  description=str(entry_raw.get("description", "")),
227
241
  working_directory=wd,
228
242
  env={str(k): str(v) for k, v in raw_env.items()},
@@ -99,6 +99,20 @@ class TestParseArgs:
99
99
  f"Expected icon_path=False by default, got {args.icon_path!r}"
100
100
  )
101
101
 
102
+ def test_config_path_flag_parsed(self) -> None:
103
+ """--config-path flag is stored as boolean True."""
104
+ args = CommandLineInterface.parse_args(["--config-path"])
105
+ assert args.config_path is True, (
106
+ f"Expected config_path=True, got {args.config_path!r}"
107
+ )
108
+
109
+ def test_config_path_defaults_to_false(self) -> None:
110
+ """config_path defaults to False when not specified."""
111
+ args = CommandLineInterface.parse_args([])
112
+ assert args.config_path is False, (
113
+ f"Expected config_path=False by default, got {args.config_path!r}"
114
+ )
115
+
102
116
 
103
117
  class TestIconPath:
104
118
  """Tests for CommandLineInterface.icon_path."""
@@ -108,3 +122,49 @@ class TestIconPath:
108
122
  path = CommandLineInterface.icon_path()
109
123
  assert path.exists(), f"Bundled icon not found at {path}"
110
124
  assert path.suffix == ".ico", f"Expected .ico file, got {path.suffix}"
125
+
126
+
127
+ class TestConfigPathFlag:
128
+ """Tests for --config-path flag behaviour via main()."""
129
+
130
+ def test_prints_explicit_config_path(
131
+ self,
132
+ tmp_path: Path,
133
+ monkeypatch: pytest.MonkeyPatch,
134
+ capsys: pytest.CaptureFixture[str],
135
+ ) -> None:
136
+ """--config-path with --config prints the explicit path."""
137
+ cfg = tmp_path / "custom.toml"
138
+ cfg.write_text("[settings]\n[[entries]]\nname='x'\ncommand='y'\n")
139
+
140
+ from launchline.__main__ import main
141
+
142
+ monkeypatch.setattr(
143
+ "sys.argv",
144
+ ["launchline", "--config-path", "--config", str(cfg)],
145
+ )
146
+ main()
147
+ assert capsys.readouterr().out.strip() == str(cfg), (
148
+ "Expected --config-path to print the explicit config file path"
149
+ )
150
+
151
+ def test_prints_default_config_path(
152
+ self,
153
+ tmp_path: Path,
154
+ monkeypatch: pytest.MonkeyPatch,
155
+ capsys: pytest.CaptureFixture[str],
156
+ ) -> None:
157
+ """--config-path without --config resolves via standard lookup."""
158
+ cfg = tmp_path / "config.toml"
159
+ cfg.write_text("[settings]\n[[entries]]\nname='x'\ncommand='y'\n")
160
+
161
+ from launchline.__main__ import main
162
+ from launchline.config import ConfigLoader
163
+
164
+ monkeypatch.setattr(ConfigLoader, "DEFAULT_PATH", cfg)
165
+ monkeypatch.setattr("sys.argv", ["launchline", "--config-path"])
166
+ monkeypatch.delenv("LAUNCHLINE_CONFIG", raising=False)
167
+ main()
168
+ assert capsys.readouterr().out.strip() == str(cfg), (
169
+ "Expected --config-path to print the default config file path"
170
+ )
@@ -152,6 +152,63 @@ class TestLoadConfig:
152
152
  with pytest.raises(ConfigurationError, match="'args' must be a list"):
153
153
  ConfigLoader.load(cfg)
154
154
 
155
+ def test_command_as_array(self, tmp_path: Path) -> None:
156
+ """Command as list splits into executable + args."""
157
+ cfg = tmp_path / "config.toml"
158
+ cfg.write_text(
159
+ '[[entries]]\nname = "X"\ncommand = ["ssh", "-t", "my server"]\n',
160
+ encoding="utf-8",
161
+ )
162
+ config = ConfigLoader.load(cfg)
163
+ assert config.entries[0].command == "ssh", (
164
+ f"Expected command='ssh', got {config.entries[0].command!r}"
165
+ )
166
+ assert config.entries[0].args == ("-t", "my server"), (
167
+ f"Expected args=('-t', 'my server'), got {config.entries[0].args!r}"
168
+ )
169
+
170
+ def test_command_array_with_extra_args(self, tmp_path: Path) -> None:
171
+ """Command array args are prepended before explicit args."""
172
+ cfg = tmp_path / "config.toml"
173
+ cfg.write_text(
174
+ '[[entries]]\nname = "X"\n'
175
+ 'command = ["ssh", "-t"]\n'
176
+ 'args = ["my server", "bash"]\n',
177
+ encoding="utf-8",
178
+ )
179
+ config = ConfigLoader.load(cfg)
180
+ assert config.entries[0].command == "ssh", (
181
+ f"Expected command='ssh', got {config.entries[0].command!r}"
182
+ )
183
+ assert config.entries[0].args == ("-t", "my server", "bash"), (
184
+ f"Expected combined args, got {config.entries[0].args!r}"
185
+ )
186
+
187
+ def test_command_array_single_element(self, tmp_path: Path) -> None:
188
+ """Single-element command array is valid."""
189
+ cfg = tmp_path / "config.toml"
190
+ cfg.write_text(
191
+ '[[entries]]\nname = "X"\ncommand = ["pwsh"]\n',
192
+ encoding="utf-8",
193
+ )
194
+ config = ConfigLoader.load(cfg)
195
+ assert config.entries[0].command == "pwsh", (
196
+ f"Expected command='pwsh', got {config.entries[0].command!r}"
197
+ )
198
+ assert config.entries[0].args == (), (
199
+ f"Expected empty args, got {config.entries[0].args!r}"
200
+ )
201
+
202
+ def test_command_empty_array_rejected(self, tmp_path: Path) -> None:
203
+ """Empty command array is an error."""
204
+ cfg = tmp_path / "config.toml"
205
+ cfg.write_text(
206
+ '[[entries]]\nname = "X"\ncommand = []\n',
207
+ encoding="utf-8",
208
+ )
209
+ with pytest.raises(ConfigurationError, match="must not be empty"):
210
+ ConfigLoader.load(cfg)
211
+
155
212
  def test_rejects_invalid_env_type(self, tmp_path: Path) -> None:
156
213
  cfg = tmp_path / "config.toml"
157
214
  cfg.write_text(
@@ -1,46 +0,0 @@
1
- ## 0.1.0 (2026-03-30)
2
-
3
- #### Feature
4
-
5
- * replace entry icon with title_prefix and bundle icon in package (10583207)
6
- * add icon assets, entry icon config, fix URLs and changelog (b29358bb)
7
- * enable ghost_text by default, restore original screenshots (470ff45e)
8
- * add ghost_text and instant_numeric_launch feature flags, cross-platform classifier (b1d412c4)
9
- * initial LaunchLine implementation (df1e8602)
10
-
11
- #### Bug Fixes
12
-
13
- * sync icon generator gray color with latest SVG (#94A3B8) (1aae2dc7)
14
- * regenerate icons with proper rendering, add generate_icon tool (4e3410b1)
15
- * make tests and mypy cross-platform for Linux CI (cd5accfa)
16
-
17
- #### Documentation
18
-
19
- * add screenshot/GIF generation tool and README images (4bc81d70)
20
- * fix markdown table alignment for MD060 (59b5ab59)
21
- * update AI disclaimer to info block with simplified text (89de06d1)
22
- * add workflow status badges to README (ff5890e0)
23
- * add AI-generated project disclaimer to README (49ba23c6)
24
-
25
- #### Tests
26
-
27
- * add CLI and cross-platform tests, improve suite quality (3dc2fd6e)
28
-
29
- #### Code Refactoring
30
-
31
- * remove title_prefix feature from entry configuration (b2fcce7b)
32
- * rename instant_numeric_launch to numeric_trigger, reorder settings (898cf209)
33
- * improve source documentation and organize code into classes (8dedef8c)
34
-
35
- #### Chores
36
-
37
- * set v0.1.0 release date (a70d982b)
38
- * add pytest-cov and enforce 85% coverage threshold (dc5616b5)
39
- * add PyPI publish job to release workflow (92df1a40)
40
- * add MIT license (1cc39ec2)
41
-
42
- #### Build
43
-
44
- * consolidate release into single workflow with dry-run safety (22314e02)
45
- * switch to hatch-vcs for dynamic version from git tags (f03de3d3)
46
-
File without changes
File without changes
File without changes