makememe 0.1.1__tar.gz → 0.1.2__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.
- {makememe-0.1.1 → makememe-0.1.2}/PKG-INFO +28 -17
- {makememe-0.1.1 → makememe-0.1.2}/README.md +27 -16
- {makememe-0.1.1 → makememe-0.1.2}/pyproject.toml +1 -1
- {makememe-0.1.1/skill/meme → makememe-0.1.2/src/memecli}/SKILL.md +2 -2
- {makememe-0.1.1 → makememe-0.1.2}/src/memecli/__init__.py +2 -2
- {makememe-0.1.1 → makememe-0.1.2}/src/memecli/cli.py +44 -0
- {makememe-0.1.1 → makememe-0.1.2}/tests/test_cli.py +25 -0
- {makememe-0.1.1 → makememe-0.1.2}/.github/workflows/publish.yml +0 -0
- {makememe-0.1.1 → makememe-0.1.2}/.github/workflows/tests.yml +0 -0
- {makememe-0.1.1 → makememe-0.1.2}/.gitignore +0 -0
- {makememe-0.1.1 → makememe-0.1.2}/LICENSE +0 -0
- {makememe-0.1.1 → makememe-0.1.2}/src/memecli/__main__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: makememe
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: A tiny zero-dependency CLI for generating memes via the free memegen.link API. Agent-friendly.
|
|
5
5
|
Project-URL: Homepage, https://pypi.org/project/makememe/
|
|
6
6
|
Project-URL: memegen.link API, https://api.memegen.link
|
|
@@ -32,20 +32,33 @@ meme drake "not reading docs" "reading docs" -o out.png
|
|
|
32
32
|
|
|
33
33
|
## Install
|
|
34
34
|
|
|
35
|
-
Requires Python 3.8+.
|
|
35
|
+
Requires Python 3.8+. Easiest is [uv](https://docs.astral.sh/uv/) (installs
|
|
36
|
+
the `meme` command in its own isolated environment):
|
|
36
37
|
|
|
37
38
|
```bash
|
|
38
|
-
|
|
39
|
-
# or, as an isolated tool:
|
|
40
|
-
uv tool install makememe # or: pipx install makememe
|
|
39
|
+
uv tool install makememe # or: pipx install makememe
|
|
41
40
|
```
|
|
42
41
|
|
|
43
|
-
|
|
42
|
+
Update later with:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
uv tool upgrade makememe
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Run once without installing anything:
|
|
44
49
|
|
|
45
50
|
```bash
|
|
46
51
|
uvx --from makememe meme drake "a" "b"
|
|
47
52
|
```
|
|
48
53
|
|
|
54
|
+
(If you specifically want pip: `python3 -m pip install makememe`.)
|
|
55
|
+
|
|
56
|
+
Check the version anytime:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
meme --version
|
|
60
|
+
```
|
|
61
|
+
|
|
49
62
|
## Usage
|
|
50
63
|
|
|
51
64
|
```bash
|
|
@@ -109,21 +122,19 @@ meme drake "old way" "new way" --json # generate, capture the path
|
|
|
109
122
|
|
|
110
123
|
### Claude Code skill
|
|
111
124
|
|
|
112
|
-
|
|
113
|
-
Claude Code auto-
|
|
125
|
+
The package bundles a Claude Code skill. After installing, run one command to
|
|
126
|
+
make Claude Code auto-discover the tool:
|
|
114
127
|
|
|
115
128
|
```bash
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
cp -r skill/meme ~/.claude/skills/meme
|
|
119
|
-
|
|
120
|
-
# or project-level
|
|
121
|
-
mkdir -p .claude/skills
|
|
122
|
-
cp -r skill/meme .claude/skills/meme
|
|
129
|
+
meme --install-skill # installs into ~/.claude/skills/meme/ (all projects)
|
|
130
|
+
meme --install-skill --project # or into ./.claude/skills/meme/ (this repo only)
|
|
123
131
|
```
|
|
124
132
|
|
|
125
|
-
|
|
126
|
-
and it will call `meme` for you.
|
|
133
|
+
Restart Claude Code, then just ask things like *"make a drake meme about
|
|
134
|
+
writing tests"* and it will call `meme` for you.
|
|
135
|
+
|
|
136
|
+
(Other agents like Codex don't use this skill format — they discover everything
|
|
137
|
+
through `meme --help` and `meme --list`, which already works out of the box.)
|
|
127
138
|
|
|
128
139
|
## Robustness
|
|
129
140
|
|
|
@@ -13,20 +13,33 @@ meme drake "not reading docs" "reading docs" -o out.png
|
|
|
13
13
|
|
|
14
14
|
## Install
|
|
15
15
|
|
|
16
|
-
Requires Python 3.8+.
|
|
16
|
+
Requires Python 3.8+. Easiest is [uv](https://docs.astral.sh/uv/) (installs
|
|
17
|
+
the `meme` command in its own isolated environment):
|
|
17
18
|
|
|
18
19
|
```bash
|
|
19
|
-
|
|
20
|
-
# or, as an isolated tool:
|
|
21
|
-
uv tool install makememe # or: pipx install makememe
|
|
20
|
+
uv tool install makememe # or: pipx install makememe
|
|
22
21
|
```
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
Update later with:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
uv tool upgrade makememe
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Run once without installing anything:
|
|
25
30
|
|
|
26
31
|
```bash
|
|
27
32
|
uvx --from makememe meme drake "a" "b"
|
|
28
33
|
```
|
|
29
34
|
|
|
35
|
+
(If you specifically want pip: `python3 -m pip install makememe`.)
|
|
36
|
+
|
|
37
|
+
Check the version anytime:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
meme --version
|
|
41
|
+
```
|
|
42
|
+
|
|
30
43
|
## Usage
|
|
31
44
|
|
|
32
45
|
```bash
|
|
@@ -90,21 +103,19 @@ meme drake "old way" "new way" --json # generate, capture the path
|
|
|
90
103
|
|
|
91
104
|
### Claude Code skill
|
|
92
105
|
|
|
93
|
-
|
|
94
|
-
Claude Code auto-
|
|
106
|
+
The package bundles a Claude Code skill. After installing, run one command to
|
|
107
|
+
make Claude Code auto-discover the tool:
|
|
95
108
|
|
|
96
109
|
```bash
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
cp -r skill/meme ~/.claude/skills/meme
|
|
100
|
-
|
|
101
|
-
# or project-level
|
|
102
|
-
mkdir -p .claude/skills
|
|
103
|
-
cp -r skill/meme .claude/skills/meme
|
|
110
|
+
meme --install-skill # installs into ~/.claude/skills/meme/ (all projects)
|
|
111
|
+
meme --install-skill --project # or into ./.claude/skills/meme/ (this repo only)
|
|
104
112
|
```
|
|
105
113
|
|
|
106
|
-
|
|
107
|
-
and it will call `meme` for you.
|
|
114
|
+
Restart Claude Code, then just ask things like *"make a drake meme about
|
|
115
|
+
writing tests"* and it will call `meme` for you.
|
|
116
|
+
|
|
117
|
+
(Other agents like Codex don't use this skill format — they discover everything
|
|
118
|
+
through `meme --help` and `meme --list`, which already works out of the box.)
|
|
108
119
|
|
|
109
120
|
## Robustness
|
|
110
121
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "makememe"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.2"
|
|
8
8
|
description = "A tiny zero-dependency CLI for generating memes via the free memegen.link API. Agent-friendly."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""meme - a tiny zero-dependency CLI over the free memegen.link API."""
|
|
2
2
|
|
|
3
|
-
from .cli import build_url, download, escape, get_templates, main
|
|
3
|
+
from .cli import build_url, download, escape, get_templates, get_version, main
|
|
4
4
|
|
|
5
|
-
__version__ =
|
|
5
|
+
__version__ = get_version()
|
|
6
6
|
__all__ = ["main", "build_url", "escape", "download", "get_templates", "__version__"]
|
|
@@ -29,6 +29,35 @@ import urllib.request
|
|
|
29
29
|
API = "https://api.memegen.link"
|
|
30
30
|
|
|
31
31
|
|
|
32
|
+
def get_version():
|
|
33
|
+
"""Read the installed package version; fall back gracefully from source."""
|
|
34
|
+
try:
|
|
35
|
+
from importlib.metadata import version
|
|
36
|
+
return version("makememe")
|
|
37
|
+
except Exception:
|
|
38
|
+
return "0.0.0+source"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def install_skill(project=False):
|
|
42
|
+
"""Copy the bundled Claude Code skill into ~/.claude/skills/meme/ (or ./.claude
|
|
43
|
+
with project=True). Returns the path written."""
|
|
44
|
+
try:
|
|
45
|
+
from importlib.resources import files
|
|
46
|
+
content = files("memecli").joinpath("SKILL.md").read_text(encoding="utf-8")
|
|
47
|
+
except Exception:
|
|
48
|
+
# running from a source checkout without installed metadata
|
|
49
|
+
here = os.path.dirname(os.path.abspath(__file__))
|
|
50
|
+
with open(os.path.join(here, "SKILL.md"), encoding="utf-8") as f:
|
|
51
|
+
content = f.read()
|
|
52
|
+
base = os.getcwd() if project else os.path.expanduser("~")
|
|
53
|
+
dest_dir = os.path.join(base, ".claude", "skills", "meme")
|
|
54
|
+
os.makedirs(dest_dir, exist_ok=True)
|
|
55
|
+
dest = os.path.join(dest_dir, "SKILL.md")
|
|
56
|
+
with open(dest, "w", encoding="utf-8") as f:
|
|
57
|
+
f.write(content)
|
|
58
|
+
return dest
|
|
59
|
+
|
|
60
|
+
|
|
32
61
|
# memegen path-segment escaping. Order matters: escape the escape chars first.
|
|
33
62
|
# Confirmed from the API: space->_, _->__, -->--, ?->~q, newline->~n, "->''
|
|
34
63
|
# Others use memegen's documented tilde codes; verify with --print-url if unsure.
|
|
@@ -96,6 +125,12 @@ def build_parser():
|
|
|
96
125
|
"before your lines so it isn't read as a flag:\n"
|
|
97
126
|
" meme regret --json -- \"-26%\" \"WHY\"",
|
|
98
127
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
128
|
+
ap.add_argument("--version", action="version",
|
|
129
|
+
version=f"%(prog)s {get_version()}")
|
|
130
|
+
ap.add_argument("--install-skill", action="store_true",
|
|
131
|
+
help="install the Claude Code skill into ~/.claude/skills/meme/ and exit")
|
|
132
|
+
ap.add_argument("--project", action="store_true",
|
|
133
|
+
help="with --install-skill: install into ./.claude/skills/ instead of your home dir")
|
|
99
134
|
ap.add_argument("template", nargs="?",
|
|
100
135
|
help="template id (see --list), or any id when using --bg")
|
|
101
136
|
ap.add_argument("lines", nargs="*", help="text lines, in order")
|
|
@@ -119,6 +154,15 @@ def _run(argv=None):
|
|
|
119
154
|
ap = build_parser()
|
|
120
155
|
args = ap.parse_args(argv)
|
|
121
156
|
|
|
157
|
+
if args.install_skill:
|
|
158
|
+
try:
|
|
159
|
+
dest = install_skill(project=args.project)
|
|
160
|
+
except Exception as e:
|
|
161
|
+
sys.exit(f"could not install skill: {e}")
|
|
162
|
+
print(dest)
|
|
163
|
+
print("Skill installed. Restart Claude Code to pick it up.", file=sys.stderr)
|
|
164
|
+
return
|
|
165
|
+
|
|
122
166
|
if args.list:
|
|
123
167
|
try:
|
|
124
168
|
list_templates(as_json=args.json)
|
|
@@ -5,6 +5,7 @@ No network access required (network paths are covered by --print-url style asser
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import io
|
|
8
|
+
import os
|
|
8
9
|
import unittest
|
|
9
10
|
from contextlib import redirect_stderr, redirect_stdout
|
|
10
11
|
|
|
@@ -102,5 +103,29 @@ class TestCrashSafety(unittest.TestCase):
|
|
|
102
103
|
cli.download = orig
|
|
103
104
|
|
|
104
105
|
|
|
106
|
+
class TestNewCommands(unittest.TestCase):
|
|
107
|
+
def test_version_flag_prints_and_exits(self):
|
|
108
|
+
buf = io.StringIO()
|
|
109
|
+
with self.assertRaises(SystemExit) as ctx, redirect_stdout(buf):
|
|
110
|
+
cli.main(["--version"])
|
|
111
|
+
self.assertEqual(ctx.exception.code, 0)
|
|
112
|
+
self.assertIn("meme", buf.getvalue())
|
|
113
|
+
|
|
114
|
+
def test_install_skill_writes_file(self):
|
|
115
|
+
import tempfile
|
|
116
|
+
with tempfile.TemporaryDirectory() as d:
|
|
117
|
+
old = os.environ.get("HOME")
|
|
118
|
+
os.environ["HOME"] = d
|
|
119
|
+
try:
|
|
120
|
+
with redirect_stdout(io.StringIO()), redirect_stderr(io.StringIO()):
|
|
121
|
+
cli.main(["--install-skill"])
|
|
122
|
+
dest = os.path.join(d, ".claude", "skills", "meme", "SKILL.md")
|
|
123
|
+
self.assertTrue(os.path.exists(dest))
|
|
124
|
+
self.assertIn("name: meme", open(dest).read())
|
|
125
|
+
finally:
|
|
126
|
+
if old is not None:
|
|
127
|
+
os.environ["HOME"] = old
|
|
128
|
+
|
|
129
|
+
|
|
105
130
|
if __name__ == "__main__":
|
|
106
131
|
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|