comma-command 0.1.0__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.
- comma_command-0.1.0/.github/workflows/ci.yml +27 -0
- comma_command-0.1.0/.gitignore +12 -0
- comma_command-0.1.0/LICENSE +21 -0
- comma_command-0.1.0/PKG-INFO +143 -0
- comma_command-0.1.0/README.md +112 -0
- comma_command-0.1.0/pyproject.toml +55 -0
- comma_command-0.1.0/src/comma_command/__init__.py +4 -0
- comma_command-0.1.0/src/comma_command/__main__.py +8 -0
- comma_command-0.1.0/src/comma_command/cli.py +451 -0
- comma_command-0.1.0/src/comma_command/config.py +130 -0
- comma_command-0.1.0/src/comma_command/dispatch.py +50 -0
- comma_command-0.1.0/src/comma_command/paths.py +37 -0
- comma_command-0.1.0/tests/conftest.py +95 -0
- comma_command-0.1.0/tests/test_cli.py +122 -0
- comma_command-0.1.0/tests/test_config.py +87 -0
- comma_command-0.1.0/tests/test_dispatch.py +90 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
fail-fast: false
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: ${{ matrix.python-version }}
|
|
20
|
+
- name: install
|
|
21
|
+
run: |
|
|
22
|
+
python -m pip install --upgrade pip
|
|
23
|
+
pip install -e '.[dev]'
|
|
24
|
+
- name: lint
|
|
25
|
+
run: ruff check .
|
|
26
|
+
- name: test
|
|
27
|
+
run: pytest -q
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 hak
|
|
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.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: comma-command
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Run any configured command from any shell as `name, args` — register once, invoke everywhere.
|
|
5
|
+
Project-URL: Homepage, https://github.com/by3hak/comma-command
|
|
6
|
+
Project-URL: Repository, https://github.com/by3hak/comma-command
|
|
7
|
+
Project-URL: Issues, https://github.com/by3hak/comma-command/issues
|
|
8
|
+
Author-email: hak <by3hak@users.noreply.github.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: alias,cli,dispatch,multicall,shell,terminal
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: System :: Shells
|
|
24
|
+
Classifier: Topic :: Utilities
|
|
25
|
+
Requires-Python: >=3.10
|
|
26
|
+
Requires-Dist: tomli>=2.0; python_version < '3.11'
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# comma-command
|
|
33
|
+
|
|
34
|
+
Run any command you have installed from any shell, as if it were a shell builtin:
|
|
35
|
+
|
|
36
|
+
```console
|
|
37
|
+
$ gus, hello world
|
|
38
|
+
# → too talk gus -- hello world
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Register an entry once. From then on, `NAME, any words` is the whole interface — no
|
|
42
|
+
aliases to source, no shell hook, no TUI.
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
```console
|
|
47
|
+
$ uv tool install comma-command # or: pipx install comma-command
|
|
48
|
+
$ comma init --write # puts the shim directory on PATH
|
|
49
|
+
$ exec $SHELL # or open a new terminal
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Quickstart
|
|
53
|
+
|
|
54
|
+
```console
|
|
55
|
+
$ comma add gus -- too talk gus --
|
|
56
|
+
added gus, → too talk gus --
|
|
57
|
+
|
|
58
|
+
$ comma add pyi -- uv run ipython --
|
|
59
|
+
added pyi, → uv run ipython --
|
|
60
|
+
|
|
61
|
+
$ gus, hello world # runs: too talk gus -- hello world
|
|
62
|
+
$ pyi, --pdb script.py # runs: uv run ipython -- --pdb script.py
|
|
63
|
+
$ comma ls
|
|
64
|
+
gus, too talk gus --
|
|
65
|
+
pyi, uv run ipython --
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`comma add` does two things: writes the entry to `~/.config/comma/config.toml` and
|
|
69
|
+
creates an executable named exactly `gus,` in `~/.local/share/comma/bin`.
|
|
70
|
+
|
|
71
|
+
## How it works
|
|
72
|
+
|
|
73
|
+
The shim is a multicall dispatcher — the same trick `busybox` and `git` use for
|
|
74
|
+
subcommands, applied to names:
|
|
75
|
+
|
|
76
|
+
1. `gus,` is a symlink to the `comma` executable.
|
|
77
|
+
2. `comma` looks at `argv[0]`, sees a trailing comma, strips it, and finds `gus` in
|
|
78
|
+
the config.
|
|
79
|
+
3. It calls `os.execvpe("too", ["too", "talk", "gus", "--", "hello", "world"])`.
|
|
80
|
+
|
|
81
|
+
Because the final step *replaces* the process instead of spawning a child, the
|
|
82
|
+
target command inherits the terminal, stdin, signals and job control directly, and
|
|
83
|
+
its exit status reaches your shell unchanged. `comma,` adds no wrapping layer.
|
|
84
|
+
|
|
85
|
+
Why not the alternatives:
|
|
86
|
+
|
|
87
|
+
- **Shell aliases/functions.** `gus,` is not a portable function name in bash or
|
|
88
|
+
fish, and functions only exist in interactive shells you have sourced.
|
|
89
|
+
- **`command_not_found_handle` hooks.** Bash-only, collides with distro handlers
|
|
90
|
+
(Nix, Debian's package suggestion hook), and silently does nothing in
|
|
91
|
+
non-interactive shells, `sh -c`, cron, or most editors' task runners.
|
|
92
|
+
- **Shims on `PATH`.** Work everywhere a real executable works, including
|
|
93
|
+
`xargs`, `find -exec`, CI scripts, Makefiles and shell completion.
|
|
94
|
+
|
|
95
|
+
## Configuration
|
|
96
|
+
|
|
97
|
+
`~/.config/comma/config.toml` — managed by `comma`, but hand-editable:
|
|
98
|
+
|
|
99
|
+
```toml
|
|
100
|
+
[commands.gus]
|
|
101
|
+
cmd = ["too", "talk", "gus", "--"]
|
|
102
|
+
|
|
103
|
+
# shorthand is fine too
|
|
104
|
+
[commands.pyi]
|
|
105
|
+
cmd = "uv run ipython --"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Arguments are appended verbatim, so `--` at the end of `cmd` is the usual way to
|
|
109
|
+
keep flags from being swallowed by the target's own option parser.
|
|
110
|
+
|
|
111
|
+
## Commands
|
|
112
|
+
|
|
113
|
+
| Command | What it does |
|
|
114
|
+
| --- | --- |
|
|
115
|
+
| `comma add NAME -- CMD...` | register a name and create its `NAME,` shim |
|
|
116
|
+
| `comma rm NAME` | unregister a name and remove its shim |
|
|
117
|
+
| `comma ls [--json]` | list registered names |
|
|
118
|
+
| `comma run NAME [--] [ARG...]` | run a name without going through the shim |
|
|
119
|
+
| `comma which NAME` | show the shim path and the command it runs |
|
|
120
|
+
| `comma init [--write] [--shell S]` | print or install PATH + completion setup |
|
|
121
|
+
| `comma doctor` | check config, PATH, shims and targets |
|
|
122
|
+
| `comma completion bash\|zsh\|fish` | print a completion script |
|
|
123
|
+
|
|
124
|
+
Names must be shell-safe words: letters, digits, `.`, `_`, `+`, `-`. The comma is
|
|
125
|
+
added for you, so `comma add gus, -- ...` is rejected rather than silently creating
|
|
126
|
+
`gus,,`.
|
|
127
|
+
|
|
128
|
+
## Limits
|
|
129
|
+
|
|
130
|
+
- POSIX first. Windows needs a `.cmd` shim layer, which is not in 0.1.
|
|
131
|
+
- No per-command `env`/`cwd` yet; use `cmd = ["sh", "-c", "..."]` as an escape hatch.
|
|
132
|
+
- The `comma-command` crate on crates.io is a name reservation for a future native
|
|
133
|
+
binary; the Python implementation is the one to install today.
|
|
134
|
+
|
|
135
|
+
## Development
|
|
136
|
+
|
|
137
|
+
```console
|
|
138
|
+
$ uv venv && uv pip install -e '.[dev]'
|
|
139
|
+
$ uv run pytest
|
|
140
|
+
$ uv run ruff check .
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
MIT licensed.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# comma-command
|
|
2
|
+
|
|
3
|
+
Run any command you have installed from any shell, as if it were a shell builtin:
|
|
4
|
+
|
|
5
|
+
```console
|
|
6
|
+
$ gus, hello world
|
|
7
|
+
# → too talk gus -- hello world
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Register an entry once. From then on, `NAME, any words` is the whole interface — no
|
|
11
|
+
aliases to source, no shell hook, no TUI.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```console
|
|
16
|
+
$ uv tool install comma-command # or: pipx install comma-command
|
|
17
|
+
$ comma init --write # puts the shim directory on PATH
|
|
18
|
+
$ exec $SHELL # or open a new terminal
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quickstart
|
|
22
|
+
|
|
23
|
+
```console
|
|
24
|
+
$ comma add gus -- too talk gus --
|
|
25
|
+
added gus, → too talk gus --
|
|
26
|
+
|
|
27
|
+
$ comma add pyi -- uv run ipython --
|
|
28
|
+
added pyi, → uv run ipython --
|
|
29
|
+
|
|
30
|
+
$ gus, hello world # runs: too talk gus -- hello world
|
|
31
|
+
$ pyi, --pdb script.py # runs: uv run ipython -- --pdb script.py
|
|
32
|
+
$ comma ls
|
|
33
|
+
gus, too talk gus --
|
|
34
|
+
pyi, uv run ipython --
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`comma add` does two things: writes the entry to `~/.config/comma/config.toml` and
|
|
38
|
+
creates an executable named exactly `gus,` in `~/.local/share/comma/bin`.
|
|
39
|
+
|
|
40
|
+
## How it works
|
|
41
|
+
|
|
42
|
+
The shim is a multicall dispatcher — the same trick `busybox` and `git` use for
|
|
43
|
+
subcommands, applied to names:
|
|
44
|
+
|
|
45
|
+
1. `gus,` is a symlink to the `comma` executable.
|
|
46
|
+
2. `comma` looks at `argv[0]`, sees a trailing comma, strips it, and finds `gus` in
|
|
47
|
+
the config.
|
|
48
|
+
3. It calls `os.execvpe("too", ["too", "talk", "gus", "--", "hello", "world"])`.
|
|
49
|
+
|
|
50
|
+
Because the final step *replaces* the process instead of spawning a child, the
|
|
51
|
+
target command inherits the terminal, stdin, signals and job control directly, and
|
|
52
|
+
its exit status reaches your shell unchanged. `comma,` adds no wrapping layer.
|
|
53
|
+
|
|
54
|
+
Why not the alternatives:
|
|
55
|
+
|
|
56
|
+
- **Shell aliases/functions.** `gus,` is not a portable function name in bash or
|
|
57
|
+
fish, and functions only exist in interactive shells you have sourced.
|
|
58
|
+
- **`command_not_found_handle` hooks.** Bash-only, collides with distro handlers
|
|
59
|
+
(Nix, Debian's package suggestion hook), and silently does nothing in
|
|
60
|
+
non-interactive shells, `sh -c`, cron, or most editors' task runners.
|
|
61
|
+
- **Shims on `PATH`.** Work everywhere a real executable works, including
|
|
62
|
+
`xargs`, `find -exec`, CI scripts, Makefiles and shell completion.
|
|
63
|
+
|
|
64
|
+
## Configuration
|
|
65
|
+
|
|
66
|
+
`~/.config/comma/config.toml` — managed by `comma`, but hand-editable:
|
|
67
|
+
|
|
68
|
+
```toml
|
|
69
|
+
[commands.gus]
|
|
70
|
+
cmd = ["too", "talk", "gus", "--"]
|
|
71
|
+
|
|
72
|
+
# shorthand is fine too
|
|
73
|
+
[commands.pyi]
|
|
74
|
+
cmd = "uv run ipython --"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Arguments are appended verbatim, so `--` at the end of `cmd` is the usual way to
|
|
78
|
+
keep flags from being swallowed by the target's own option parser.
|
|
79
|
+
|
|
80
|
+
## Commands
|
|
81
|
+
|
|
82
|
+
| Command | What it does |
|
|
83
|
+
| --- | --- |
|
|
84
|
+
| `comma add NAME -- CMD...` | register a name and create its `NAME,` shim |
|
|
85
|
+
| `comma rm NAME` | unregister a name and remove its shim |
|
|
86
|
+
| `comma ls [--json]` | list registered names |
|
|
87
|
+
| `comma run NAME [--] [ARG...]` | run a name without going through the shim |
|
|
88
|
+
| `comma which NAME` | show the shim path and the command it runs |
|
|
89
|
+
| `comma init [--write] [--shell S]` | print or install PATH + completion setup |
|
|
90
|
+
| `comma doctor` | check config, PATH, shims and targets |
|
|
91
|
+
| `comma completion bash\|zsh\|fish` | print a completion script |
|
|
92
|
+
|
|
93
|
+
Names must be shell-safe words: letters, digits, `.`, `_`, `+`, `-`. The comma is
|
|
94
|
+
added for you, so `comma add gus, -- ...` is rejected rather than silently creating
|
|
95
|
+
`gus,,`.
|
|
96
|
+
|
|
97
|
+
## Limits
|
|
98
|
+
|
|
99
|
+
- POSIX first. Windows needs a `.cmd` shim layer, which is not in 0.1.
|
|
100
|
+
- No per-command `env`/`cwd` yet; use `cmd = ["sh", "-c", "..."]` as an escape hatch.
|
|
101
|
+
- The `comma-command` crate on crates.io is a name reservation for a future native
|
|
102
|
+
binary; the Python implementation is the one to install today.
|
|
103
|
+
|
|
104
|
+
## Development
|
|
105
|
+
|
|
106
|
+
```console
|
|
107
|
+
$ uv venv && uv pip install -e '.[dev]'
|
|
108
|
+
$ uv run pytest
|
|
109
|
+
$ uv run ruff check .
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
MIT licensed.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "comma-command"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Run any configured command from any shell as `name, args` — register once, invoke everywhere."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [{ name = "hak", email = "by3hak@users.noreply.github.com" }]
|
|
13
|
+
keywords = ["cli", "shell", "alias", "dispatch", "multicall", "terminal"]
|
|
14
|
+
dependencies = ['tomli>=2.0; python_version < "3.11"']
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 3 - Alpha",
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Operating System :: MacOS :: MacOS X",
|
|
21
|
+
"Operating System :: POSIX :: Linux",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Topic :: System :: Shells",
|
|
28
|
+
"Topic :: Utilities",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://github.com/by3hak/comma-command"
|
|
33
|
+
Repository = "https://github.com/by3hak/comma-command"
|
|
34
|
+
Issues = "https://github.com/by3hak/comma-command/issues"
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
comma = "comma_command.cli:main"
|
|
38
|
+
|
|
39
|
+
[project.optional-dependencies]
|
|
40
|
+
dev = ["pytest>=8.0", "ruff>=0.6"]
|
|
41
|
+
|
|
42
|
+
[tool.hatch.build.targets.wheel]
|
|
43
|
+
packages = ["src/comma_command"]
|
|
44
|
+
|
|
45
|
+
[tool.ruff]
|
|
46
|
+
line-length = 100
|
|
47
|
+
src = ["src", "tests"]
|
|
48
|
+
target-version = "py310"
|
|
49
|
+
|
|
50
|
+
[tool.ruff.lint]
|
|
51
|
+
select = ["E", "F", "I", "UP", "B"]
|
|
52
|
+
|
|
53
|
+
[tool.pytest.ini_options]
|
|
54
|
+
testpaths = ["tests"]
|
|
55
|
+
addopts = "-q"
|