typefully-cli 0.1.0__tar.gz → 0.2.1__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 (42) hide show
  1. typefully_cli-0.2.1/.github/dependabot.yml +6 -0
  2. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/.github/workflows/ci.yml +2 -2
  3. typefully_cli-0.2.1/.github/workflows/monitor.yml +141 -0
  4. typefully_cli-0.2.1/.github/workflows/publish.yml +28 -0
  5. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/.gitignore +2 -0
  6. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/CHANGELOG.md +15 -0
  7. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/CLAUDE.md +9 -3
  8. typefully_cli-0.2.1/Formula/README.md +40 -0
  9. typefully_cli-0.2.1/Formula/typefully-cli.rb +84 -0
  10. typefully_cli-0.2.1/PKG-INFO +340 -0
  11. typefully_cli-0.2.1/README.md +305 -0
  12. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/TODOS.md +3 -29
  13. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/pyproject.toml +5 -5
  14. typefully_cli-0.2.1/requirements.lock +54 -0
  15. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/src/typefully_cli/__init__.py +1 -1
  16. typefully_cli-0.2.1/src/typefully_cli/cli.py +1548 -0
  17. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/src/typefully_cli/client.py +205 -20
  18. typefully_cli-0.2.1/src/typefully_cli/completions.py +186 -0
  19. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/src/typefully_cli/config.py +66 -4
  20. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/src/typefully_cli/media.py +5 -3
  21. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/src/typefully_cli/output.py +76 -0
  22. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/tests/test_auth.py +17 -0
  23. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/tests/test_cli.py +286 -6
  24. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/tests/test_client.py +35 -0
  25. typefully_cli-0.2.1/tests/test_completions.py +206 -0
  26. typefully_cli-0.1.0/.coverage +0 -0
  27. typefully_cli-0.1.0/PKG-INFO +0 -263
  28. typefully_cli-0.1.0/README.md +0 -228
  29. typefully_cli-0.1.0/src/typefully_cli/cli.py +0 -876
  30. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/CONTRIBUTING.md +0 -0
  31. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/LICENSE +0 -0
  32. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/docs/batch-format.md +0 -0
  33. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/src/typefully_cli/__main__.py +0 -0
  34. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/src/typefully_cli/auth.py +0 -0
  35. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/src/typefully_cli/batch.py +0 -0
  36. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/src/typefully_cli/console.py +0 -0
  37. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/src/typefully_cli/exceptions.py +0 -0
  38. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/tests/__init__.py +0 -0
  39. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/tests/conftest.py +0 -0
  40. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/tests/test_batch.py +0 -0
  41. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/tests/test_media.py +0 -0
  42. {typefully_cli-0.1.0 → typefully_cli-0.2.1}/tests/test_output.py +0 -0
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
@@ -14,10 +14,10 @@ jobs:
14
14
  python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
15
15
 
16
16
  steps:
17
- - uses: actions/checkout@v4
17
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
18
18
 
19
19
  - name: Set up Python ${{ matrix.python-version }}
20
- uses: actions/setup-python@v5
20
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
21
21
  with:
22
22
  python-version: ${{ matrix.python-version }}
23
23
 
@@ -0,0 +1,141 @@
1
+ name: Monitor Typefully API & Competitors
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 8 * * 1,4" # Mon & Thu 8am UTC (1:30pm IST)
6
+ workflow_dispatch: {}
7
+
8
+ permissions:
9
+ issues: write
10
+ contents: read
11
+
12
+ jobs:
13
+ monitor:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
17
+
18
+ - name: Restore cache
19
+ uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
20
+ with:
21
+ path: .monitor-cache
22
+ key: monitor-cache-${{ github.run_id }}
23
+ restore-keys: monitor-cache-
24
+
25
+ - name: Init cache dir
26
+ run: mkdir -p .monitor-cache
27
+
28
+ - name: Fetch OpenAPI spec
29
+ run: |
30
+ curl -sf https://api.typefully.com/ -o .monitor-cache/openapi-new.json || true
31
+ if [ ! -f .monitor-cache/openapi.json ]; then
32
+ cp .monitor-cache/openapi-new.json .monitor-cache/openapi.json 2>/dev/null || true
33
+ fi
34
+
35
+ - name: Fetch agent-skills source
36
+ run: |
37
+ curl -sf https://raw.githubusercontent.com/typefully/agent-skills/main/scripts/typefully.js \
38
+ -o .monitor-cache/agent-skills-new.js || true
39
+ if [ ! -f .monitor-cache/agent-skills.js ]; then
40
+ cp .monitor-cache/agent-skills-new.js .monitor-cache/agent-skills.js 2>/dev/null || true
41
+ fi
42
+
43
+ - name: Fetch MCP tool list
44
+ run: |
45
+ curl -sf -X POST https://mcp.typefully.com/mcp \
46
+ -H "Content-Type: application/json" \
47
+ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
48
+ -o .monitor-cache/mcp-tools-new.json || true
49
+ if [ ! -f .monitor-cache/mcp-tools.json ]; then
50
+ cp .monitor-cache/mcp-tools-new.json .monitor-cache/mcp-tools.json 2>/dev/null || true
51
+ fi
52
+
53
+ - name: Fetch npm package version
54
+ run: |
55
+ npm view @typefully/agent-skills version 2>/dev/null \
56
+ > .monitor-cache/npm-version-new.txt || true
57
+ if [ ! -f .monitor-cache/npm-version.txt ]; then
58
+ cp .monitor-cache/npm-version-new.txt .monitor-cache/npm-version.txt 2>/dev/null || true
59
+ fi
60
+
61
+ - name: Fetch changelog
62
+ run: |
63
+ curl -sf https://typefully.com/blog/changelog \
64
+ | sha256sum | cut -d' ' -f1 > .monitor-cache/changelog-hash-new.txt || true
65
+ if [ ! -f .monitor-cache/changelog-hash.txt ]; then
66
+ cp .monitor-cache/changelog-hash-new.txt .monitor-cache/changelog-hash.txt 2>/dev/null || true
67
+ fi
68
+
69
+ - name: Diff and report
70
+ env:
71
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
72
+ run: |
73
+ changes=""
74
+
75
+ # OpenAPI spec
76
+ if [ -f .monitor-cache/openapi-new.json ] && [ -f .monitor-cache/openapi.json ]; then
77
+ d=$(diff .monitor-cache/openapi.json .monitor-cache/openapi-new.json || true)
78
+ if [ -n "$d" ]; then
79
+ changes="${changes}\n## OpenAPI Spec Changed\n\`\`\`diff\n${d}\n\`\`\`\n"
80
+ fi
81
+ fi
82
+
83
+ # agent-skills source
84
+ if [ -f .monitor-cache/agent-skills-new.js ] && [ -f .monitor-cache/agent-skills.js ]; then
85
+ d=$(diff .monitor-cache/agent-skills.js .monitor-cache/agent-skills-new.js || true)
86
+ if [ -n "$d" ]; then
87
+ changes="${changes}\n## agent-skills (typefully.js) Changed\n\`\`\`diff\n${d}\n\`\`\`\n"
88
+ fi
89
+ fi
90
+
91
+ # MCP tools
92
+ if [ -f .monitor-cache/mcp-tools-new.json ] && [ -f .monitor-cache/mcp-tools.json ]; then
93
+ d=$(diff .monitor-cache/mcp-tools.json .monitor-cache/mcp-tools-new.json || true)
94
+ if [ -n "$d" ]; then
95
+ changes="${changes}\n## MCP Tool List Changed\n\`\`\`diff\n${d}\n\`\`\`\n"
96
+ fi
97
+ fi
98
+
99
+ # npm version
100
+ if [ -f .monitor-cache/npm-version-new.txt ] && [ -f .monitor-cache/npm-version.txt ]; then
101
+ old=$(cat .monitor-cache/npm-version.txt)
102
+ new=$(cat .monitor-cache/npm-version-new.txt)
103
+ if [ "$old" != "$new" ]; then
104
+ changes="${changes}\n## npm Package Version Changed\n- Old: ${old}\n- New: ${new}\n"
105
+ fi
106
+ fi
107
+
108
+ # Changelog hash
109
+ if [ -f .monitor-cache/changelog-hash-new.txt ] && [ -f .monitor-cache/changelog-hash.txt ]; then
110
+ old=$(cat .monitor-cache/changelog-hash.txt)
111
+ new=$(cat .monitor-cache/changelog-hash-new.txt)
112
+ if [ "$old" != "$new" ]; then
113
+ changes="${changes}\n## Changelog Page Updated\nHash changed from \`${old}\` to \`${new}\`.\nCheck: https://typefully.com/blog/changelog\n"
114
+ fi
115
+ fi
116
+
117
+ # Report
118
+ if [ -n "$changes" ]; then
119
+ body=$(printf "Automated monitoring detected changes in Typefully's ecosystem.\n\n${changes}\n\nReview these changes and determine if typefully-cli needs updates.")
120
+ gh issue create \
121
+ --title "Monitor: Typefully API/MCP changes detected $(date +%Y-%m-%d)" \
122
+ --body "$body" \
123
+ --label "monitor"
124
+ echo "Changes detected. Issue created."
125
+ else
126
+ echo "No changes detected."
127
+ fi
128
+
129
+ # Update cache
130
+ for f in openapi agent-skills mcp-tools; do
131
+ [ -f ".monitor-cache/${f}-new.json" ] && cp ".monitor-cache/${f}-new.json" ".monitor-cache/${f}.json"
132
+ [ -f ".monitor-cache/${f}-new.js" ] && cp ".monitor-cache/${f}-new.js" ".monitor-cache/${f}.js"
133
+ done
134
+ [ -f .monitor-cache/npm-version-new.txt ] && cp .monitor-cache/npm-version-new.txt .monitor-cache/npm-version.txt
135
+ [ -f .monitor-cache/changelog-hash-new.txt ] && cp .monitor-cache/changelog-hash-new.txt .monitor-cache/changelog-hash.txt
136
+
137
+ - name: Save cache
138
+ uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
139
+ with:
140
+ path: .monitor-cache
141
+ key: monitor-cache-${{ github.run_id }}
@@ -0,0 +1,28 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ id-token: write # trusted publishing
12
+
13
+ steps:
14
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
15
+
16
+ - name: Set up Python
17
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
18
+ with:
19
+ python-version: "3.12"
20
+
21
+ - name: Install build tools
22
+ run: pip install build
23
+
24
+ - name: Build
25
+ run: python -m build
26
+
27
+ - name: Publish to PyPI
28
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
@@ -10,4 +10,6 @@ venv/
10
10
  .env
11
11
  .ruff_cache/
12
12
  .pytest_cache/
13
+ .coverage
13
14
  .mypy_cache/
15
+ .gstack/
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.1 (2026-08-21)
4
+
5
+ - Fix trusted PyPI publishing workflow action pin.
6
+
7
+ ## 0.2.0 (2026-08-21)
8
+
9
+ Sync with Typefully's official MCP and Agent Skill surface.
10
+
11
+ - Add X follower analytics with `followers`.
12
+ - Add planned drafts with `draft --plan`, `update --plan`, and `plan`.
13
+ - Add review comment threads: list, create, reply, resolve, update, delete.
14
+ - Add comment-marker-safe reads and updates.
15
+ - Add Substack Notes, X Articles, platform selection, link-preview suppression, X disclosures, and official quote-post payload fields.
16
+ - Add multi-platform draft/thread creation through `--platform`.
17
+
3
18
  ## 0.1.0 (2026-03-26)
4
19
 
5
20
  Initial release.
@@ -2,14 +2,15 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- Python CLI wrapping the Typefully API v2. Agent-first design: JSON output by default, structured errors on stderr, deterministic behavior. 17 Click commands for drafts, threads, batch, media, tags, accounts, config.
5
+ Python CLI wrapping the Typefully API v2. Agent-first design: JSON output by default, structured errors on stderr, deterministic behavior. 24 Click commands for drafts, threads, batch, media, analytics, queue, LinkedIn, tags, accounts, config, completions.
6
6
 
7
7
  ## Architecture
8
8
 
9
9
  ```
10
10
  src/typefully_cli/
11
- cli.py -- 17 Click commands, shared options, error handler, payload builder
11
+ cli.py -- 24 Click commands, shared options, error handler, payload builder
12
12
  client.py -- httpx wrapper over Typefully API v2 (rate-limited, account resolution)
13
+ completions.py -- Shell completions install/show (bash/zsh/fish)
13
14
  auth.py -- API key resolution chain: flag > env > config > 1Password
14
15
  config.py -- TOML config at ~/.config/typefully/config.toml
15
16
  console.py -- stderr output (status, warnings, errors) via Rich
@@ -23,9 +24,12 @@ src/typefully_cli/
23
24
 
24
25
  - **Output contract:** Success -> `{"ok": true, "data": ...}` on stdout. Errors -> `{"ok": false, "error": {...}}` on stderr. Exit codes: 0 success, 1 input/auth, 2 API, 3 partial failure.
25
26
  - **Rich markup safety:** All user/API text in output.py is wrapped with `_esc()` (rich.markup.escape) before printing. Never pass raw API content to `_console.print()`.
26
- - **Input validation:** Dates via `_validate_date()`, limits via `_validate_limit()`, both raise `TypefullyError(code="invalid_input")` which exits 1.
27
+ - **Input validation:** Dates via `_validate_date()`, limits via `_validate_limit()`, timezones via `_validate_timezone()`, platforms via `_validate_platforms()`. All raise on invalid input with exit 1.
28
+ - **Default platforms:** Config `default_platforms` (e.g. `x,linkedin`) auto-applied on `draft`/`thread` when no platform flags passed. Explicit flags override defaults.
29
+ - **Timezone conversion:** Config `timezone` (IANA name) converts naive schedule datetimes to UTC before API call. Already-tz-aware values pass through unchanged.
27
30
  - **Partial failure:** Delete and batch loops catch per-item errors. `_handle_multi_result()` handles the 3-branch contract (all succeed / partial / all fail).
28
31
  - **Error sanitization:** `APIError.user_message` property strips raw upstream bodies from stdout payloads. Full details stay on stderr.
32
+ - **API parity:** Tracks all Typefully API v2 endpoints including analytics, queue management, and LinkedIn org resolution.
29
33
 
30
34
  ## Dev setup
31
35
 
@@ -47,6 +51,8 @@ Config at `~/.config/typefully/config.toml`. Test account: BungeeCEO.
47
51
  ```bash
48
52
  typefully config set api_key tf_...
49
53
  typefully config set default_account BungeeCEO
54
+ typefully config set default_platforms x,linkedin
55
+ typefully config set timezone Asia/Kolkata
50
56
  ```
51
57
 
52
58
  ## Conventions
@@ -0,0 +1,40 @@
1
+ # Homebrew Formula for typefully-cli
2
+
3
+ This directory contains the Homebrew formula, staged here before moving to a dedicated tap repo.
4
+
5
+ ## Setup the tap
6
+
7
+ 1. Create a repo named `homebrew-tap` under `dheeraj-shah` (or your preferred GitHub org).
8
+ 2. Copy `Formula/typefully-cli.rb` into that repo at `Formula/typefully-cli.rb`.
9
+ 3. Push to GitHub.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ brew tap dheeraj-shah/tap
15
+ brew install typefully-cli
16
+ ```
17
+
18
+ ## Filling in resource hashes
19
+
20
+ The formula has `TODO` placeholders for sha256 hashes. To fill them in:
21
+
22
+ ```bash
23
+ pip install homebrew-pypi-poet
24
+ poet typefully-cli
25
+ ```
26
+
27
+ Paste the output over the existing resource blocks. Then validate:
28
+
29
+ ```bash
30
+ brew audit --new typefully-cli
31
+ brew install --build-from-source typefully-cli
32
+ brew test typefully-cli
33
+ ```
34
+
35
+ ## Updating to a new version
36
+
37
+ 1. Bump the `url` in the formula to the new PyPI tarball URL.
38
+ 2. Update the top-level `sha256` with the new tarball hash.
39
+ 3. Re-run `poet typefully-cli` to check if any dependency versions changed. Update resource blocks as needed.
40
+ 4. Run `brew audit` and `brew test` to verify.
@@ -0,0 +1,84 @@
1
+ class TypefullyCli < Formula
2
+ include Language::Python::Virtualenv
3
+
4
+ desc "CLI for the Typefully API - draft, schedule, and publish social media posts"
5
+ homepage "https://github.com/nicedevelopers/typefully-cli"
6
+ url "https://files.pythonhosted.org/packages/c3/6d/d96bd1a794e8819c9c048cd1eccb86ba06d361ae5b60c82f3277a737775b/typefully_cli-0.1.0.tar.gz"
7
+ sha256 "c8344f6c527f4e2028604f966409d0368e6f3f626f0fa6cadfce71fbf270ca94"
8
+ license "MIT"
9
+
10
+ depends_on "python@3.13"
11
+
12
+ resource "anyio" do
13
+ url "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz"
14
+ sha256 "334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc"
15
+ end
16
+
17
+ resource "certifi" do
18
+ url "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz"
19
+ sha256 "e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7"
20
+ end
21
+
22
+ resource "click" do
23
+ url "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz"
24
+ sha256 "12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a"
25
+ end
26
+
27
+ resource "h11" do
28
+ url "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz"
29
+ sha256 "4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"
30
+ end
31
+
32
+ resource "httpcore" do
33
+ url "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz"
34
+ sha256 "6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"
35
+ end
36
+
37
+ resource "httpx" do
38
+ url "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz"
39
+ sha256 "75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"
40
+ end
41
+
42
+ resource "idna" do
43
+ url "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz"
44
+ sha256 "795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"
45
+ end
46
+
47
+ resource "markdown-it-py" do
48
+ url "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz"
49
+ sha256 "cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3"
50
+ end
51
+
52
+ resource "mdurl" do
53
+ url "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz"
54
+ sha256 "bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"
55
+ end
56
+
57
+ resource "pygments" do
58
+ url "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea585a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz"
59
+ sha256 "636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"
60
+ end
61
+
62
+ resource "rich" do
63
+ url "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz"
64
+ sha256 "b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b"
65
+ end
66
+
67
+ resource "sniffio" do
68
+ url "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz"
69
+ sha256 "f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"
70
+ end
71
+
72
+ resource "typing-extensions" do
73
+ url "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz"
74
+ sha256 "0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"
75
+ end
76
+
77
+ def install
78
+ virtualenv_install_with_resources
79
+ end
80
+
81
+ test do
82
+ assert_match "typefully, version", shell_output("#{bin}/typefully --version")
83
+ end
84
+ end