typefully-cli 0.1.0__tar.gz → 0.3.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.
Files changed (51) hide show
  1. typefully_cli-0.3.0/.github/dependabot.yml +6 -0
  2. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/.github/workflows/ci.yml +4 -4
  3. typefully_cli-0.3.0/.github/workflows/monitor.yml +72 -0
  4. typefully_cli-0.3.0/.github/workflows/publish.yml +28 -0
  5. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/.gitignore +2 -0
  6. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/CHANGELOG.md +26 -0
  7. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/CLAUDE.md +14 -10
  8. typefully_cli-0.3.0/Formula/README.md +40 -0
  9. typefully_cli-0.3.0/Formula/typefully-cli.rb +84 -0
  10. typefully_cli-0.3.0/PKG-INFO +378 -0
  11. typefully_cli-0.3.0/README.md +343 -0
  12. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/TODOS.md +3 -29
  13. typefully_cli-0.3.0/docs/quote-parity.md +79 -0
  14. typefully_cli-0.3.0/docs/upstream-parity.md +133 -0
  15. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/pyproject.toml +5 -5
  16. typefully_cli-0.3.0/requirements.lock +54 -0
  17. typefully_cli-0.3.0/scripts/monitor.py +147 -0
  18. typefully_cli-0.3.0/skills/typefully-cli/SKILL.md +76 -0
  19. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/src/typefully_cli/__init__.py +1 -1
  20. typefully_cli-0.3.0/src/typefully_cli/cli.py +1805 -0
  21. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/src/typefully_cli/client.py +230 -24
  22. typefully_cli-0.3.0/src/typefully_cli/completions.py +186 -0
  23. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/src/typefully_cli/config.py +66 -4
  24. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/src/typefully_cli/media.py +7 -4
  25. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/src/typefully_cli/output.py +76 -0
  26. typefully_cli-0.3.0/src/typefully_cli/payloads.py +195 -0
  27. typefully_cli-0.3.0/src/typefully_cli/request-schemas.json +1220 -0
  28. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/tests/test_auth.py +17 -0
  29. typefully_cli-0.3.0/tests/test_cli.py +1191 -0
  30. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/tests/test_client.py +35 -0
  31. typefully_cli-0.3.0/tests/test_completions.py +207 -0
  32. typefully_cli-0.3.0/tests/test_monitor.py +69 -0
  33. typefully_cli-0.3.0/tests/test_payloads.py +216 -0
  34. typefully_cli-0.1.0/.coverage +0 -0
  35. typefully_cli-0.1.0/PKG-INFO +0 -263
  36. typefully_cli-0.1.0/README.md +0 -228
  37. typefully_cli-0.1.0/src/typefully_cli/cli.py +0 -876
  38. typefully_cli-0.1.0/tests/test_cli.py +0 -573
  39. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/CONTRIBUTING.md +0 -0
  40. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/LICENSE +0 -0
  41. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/docs/batch-format.md +0 -0
  42. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/src/typefully_cli/__main__.py +0 -0
  43. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/src/typefully_cli/auth.py +0 -0
  44. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/src/typefully_cli/batch.py +0 -0
  45. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/src/typefully_cli/console.py +0 -0
  46. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/src/typefully_cli/exceptions.py +0 -0
  47. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/tests/__init__.py +0 -0
  48. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/tests/conftest.py +0 -0
  49. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/tests/test_batch.py +0 -0
  50. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/tests/test_media.py +0 -0
  51. {typefully_cli-0.1.0 → typefully_cli-0.3.0}/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"
@@ -8,16 +8,16 @@ on:
8
8
 
9
9
  jobs:
10
10
  test:
11
- runs-on: ubuntu-latest
11
+ runs-on: ubuntu-22.04 # Python 3.9 remains supported; avoid ubuntu-latest image drift.
12
12
  strategy:
13
13
  matrix:
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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
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
 
@@ -25,7 +25,7 @@ jobs:
25
25
  run: pip install -e ".[dev]"
26
26
 
27
27
  - name: Lint
28
- run: ruff check src/ tests/
28
+ run: ruff check --isolated --select E4,E7,E9,F --target-version py39 --line-length 100 src/ tests/ scripts/
29
29
 
30
30
  - name: Test
31
31
  run: python -m pytest tests/ -v
@@ -0,0 +1,72 @@
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
+ concurrency:
9
+ group: typefully-upstream-monitor
10
+ cancel-in-progress: false
11
+
12
+ permissions:
13
+ issues: write
14
+ contents: read
15
+
16
+ jobs:
17
+ monitor:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
21
+
22
+ - name: Restore cache
23
+ uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
24
+ with:
25
+ path: .monitor-cache
26
+ key: monitor-cache-${{ github.run_id }}
27
+ restore-keys: monitor-cache-
28
+
29
+ - name: Fetch and validate public upstream sources
30
+ run: python3 scripts/monitor.py
31
+
32
+ - name: Report changes or degraded monitoring
33
+ env:
34
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
35
+ run: |
36
+ python3 - <<'PYTHON'
37
+ import json
38
+ import subprocess
39
+ from pathlib import Path
40
+
41
+ cache = Path(".monitor-cache")
42
+ result = json.loads((cache / "result.json").read_text())
43
+ if result["report_needed"]:
44
+ # A stable title deduplicates the same unresolved change/failure.
45
+ issues = json.loads(subprocess.check_output([
46
+ "gh", "issue", "list", "--state", "open", "--search",
47
+ result["fingerprint"] + " in:title",
48
+ "--json", "title", "--limit", "100",
49
+ ], text=True))
50
+ if not any(issue["title"] == result["title"] for issue in issues):
51
+ subprocess.run([
52
+ "gh", "issue", "create", "--title", result["title"],
53
+ "--body-file", str(cache / "report.md"),
54
+ ], check=True)
55
+ subprocess.run(["python3", "scripts/monitor.py", "--commit"], check=True)
56
+ PYTHON
57
+
58
+ - name: Save cache
59
+ uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
60
+ with:
61
+ path: .monitor-cache
62
+ key: monitor-cache-${{ github.run_id }}
63
+
64
+ - name: Fail visibly on degraded monitoring
65
+ run: |
66
+ python3 - <<'PYTHON'
67
+ import json
68
+ from pathlib import Path
69
+ result = json.loads(Path(".monitor-cache/result.json").read_text())
70
+ if result["failed"]:
71
+ raise SystemExit("Upstream fetch failed; see monitoring issue and result.json")
72
+ PYTHON
@@ -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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
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,31 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0 (2026-10-29)
4
+
5
+ - Add schema-backed `draft-payload` request-file input with offline validation, per-post fields and null/false clearing; keep `--json` as output-only.
6
+ - Add X reply/subscriber/community flags, LinkedIn first-comment/reshare fields, upload alt text and media metadata updates.
7
+ - Follow social-set pagination, accept repeated tag filters and reject negative offsets; document every public API operation and unverified MCP/product-only boundaries.
8
+
9
+
10
+ - Repair upstream monitoring: validate official public sources, expose fetch failures, deduplicate reports, and advance baselines only after successful reporting.
11
+ - Pin CI to Ubuntu 22.04 to retain Python 3.9 compatibility; isolate Fish completion tests from the real home directory.
12
+ - Extend `--quote-post-url` / `--qrt` to the documented Threads, Bluesky, Mastodon and Substack quote targets.
13
+
14
+ ## 0.2.1 (2026-08-21)
15
+
16
+ - Fix trusted PyPI publishing workflow action pin.
17
+
18
+ ## 0.2.0 (2026-08-21)
19
+
20
+ Sync with Typefully's official MCP and Agent Skill surface.
21
+
22
+ - Add X follower analytics with `followers`.
23
+ - Add planned drafts with `draft --plan`, `update --plan`, and `plan`.
24
+ - Add review comment threads: list, create, reply, resolve, update, delete.
25
+ - Add comment-marker-safe reads and updates.
26
+ - Add Substack Notes, X Articles, platform selection, link-preview suppression, X disclosures, and official quote-post payload fields.
27
+ - Add multi-platform draft/thread creation through `--platform`.
28
+
3
29
  ## 0.1.0 (2026-03-26)
4
30
 
5
31
  Initial release.
@@ -2,14 +2,17 @@
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-friendly structured JSON output with `--json`, structured errors on stderr, and configurable text output. See `skills/typefully-cli/SKILL.md` for current agent usage and `docs/upstream-parity.md` for evidence and limitations.
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 -- Click commands, shared options, error handler, payload builder
12
+ payloads.py -- Explicit JSON request input, local schema validation, media metadata
13
+ request-schemas.json -- Reviewed public create/update schema snapshot
12
14
  client.py -- httpx wrapper over Typefully API v2 (rate-limited, account resolution)
15
+ completions.py -- Shell completions install/show (bash/zsh/fish)
13
16
  auth.py -- API key resolution chain: flag > env > config > 1Password
14
17
  config.py -- TOML config at ~/.config/typefully/config.toml
15
18
  console.py -- stderr output (status, warnings, errors) via Rich
@@ -23,9 +26,12 @@ src/typefully_cli/
23
26
 
24
27
  - **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
28
  - **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.
29
+ - **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.
30
+ - **Default platforms:** Config `default_platforms` (e.g. `x,linkedin`) auto-applied on `draft`/`thread` when no platform flags passed. Explicit flags override defaults.
31
+ - **Timezone conversion:** Config `timezone` (IANA name) converts naive schedule datetimes to UTC before API call. Already-tz-aware values pass through unchanged.
27
32
  - **Partial failure:** Delete and batch loops catch per-item errors. `_handle_multi_result()` handles the 3-branch contract (all succeed / partial / all fail).
28
33
  - **Error sanitization:** `APIError.user_message` property strips raw upstream bodies from stdout payloads. Full details stay on stderr.
34
+ - **API parity:** Map each public operation in docs/upstream-parity.md. Do not claim exhaustive MCP parity; analytics and legacy convenience fields are not verified by the current public schema.
29
35
 
30
36
  ## Dev setup
31
37
 
@@ -37,17 +43,15 @@ pip install -e ".[dev]"
37
43
 
38
44
  ```bash
39
45
  python3 -m pytest tests/ -v
40
- ruff check src/ tests/
46
+ ruff check --isolated --select E4,E7,E9,F --target-version py39 --line-length 100 src/ tests/ scripts/
41
47
  ```
42
48
 
43
49
  ## Auth for live testing
44
50
 
45
- Config at `~/.config/typefully/config.toml`. Test account: BungeeCEO.
46
-
47
- ```bash
48
- typefully config set api_key tf_...
49
- typefully config set default_account BungeeCEO
50
- ```
51
+ Use existing authorized access from environment/config; never assume an account
52
+ named in documentation is a sandbox. No cloud credential is bundled with this repo.
53
+ Use local `--validate-only` and mocked tests first. Live test writes need explicit
54
+ scope and a verified social set; never publish as part of maintenance tests.
51
55
 
52
56
  ## Conventions
53
57
 
@@ -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