appmates 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.
Files changed (192) hide show
  1. appmates-0.1.0/.claude/launch.json +17 -0
  2. appmates-0.1.0/.env.example +13 -0
  3. appmates-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +30 -0
  4. appmates-0.1.0/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
  5. appmates-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +13 -0
  6. appmates-0.1.0/.github/dependabot.yml +25 -0
  7. appmates-0.1.0/.github/workflows/ci.yml +151 -0
  8. appmates-0.1.0/.github/workflows/codeql.yml +66 -0
  9. appmates-0.1.0/.github/workflows/release.yml +44 -0
  10. appmates-0.1.0/.gitignore +51 -0
  11. appmates-0.1.0/.python-version +1 -0
  12. appmates-0.1.0/CODE_OF_CONDUCT.md +67 -0
  13. appmates-0.1.0/CONTRIBUTING.md +50 -0
  14. appmates-0.1.0/LAUNCH_READINESS.md +196 -0
  15. appmates-0.1.0/LICENSE +21 -0
  16. appmates-0.1.0/PKG-INFO +766 -0
  17. appmates-0.1.0/README.md +730 -0
  18. appmates-0.1.0/SECURITY.md +58 -0
  19. appmates-0.1.0/pyproject.toml +100 -0
  20. appmates-0.1.0/scripts/deploy-web.sh +9 -0
  21. appmates-0.1.0/scripts/export_conformance.py +796 -0
  22. appmates-0.1.0/scripts/export_parser_fixtures.py +171 -0
  23. appmates-0.1.0/scripts/export_specs.py +120 -0
  24. appmates-0.1.0/src/appmates/__init__.py +3 -0
  25. appmates-0.1.0/src/appmates/cli/__init__.py +0 -0
  26. appmates-0.1.0/src/appmates/cli/commands/__init__.py +0 -0
  27. appmates-0.1.0/src/appmates/cli/commands/app.py +174 -0
  28. appmates-0.1.0/src/appmates/cli/commands/appstore_connect.py +231 -0
  29. appmates-0.1.0/src/appmates/cli/commands/competitors.py +389 -0
  30. appmates-0.1.0/src/appmates/cli/commands/keywords.py +191 -0
  31. appmates-0.1.0/src/appmates/cli/commands/markets.py +181 -0
  32. appmates-0.1.0/src/appmates/cli/commands/metadata.py +69 -0
  33. appmates-0.1.0/src/appmates/cli/commands/niche.py +202 -0
  34. appmates-0.1.0/src/appmates/cli/commands/pricing.py +54 -0
  35. appmates-0.1.0/src/appmates/cli/commands/screenshots.py +162 -0
  36. appmates-0.1.0/src/appmates/cli/commands/specs.py +35 -0
  37. appmates-0.1.0/src/appmates/cli/commands/submission.py +82 -0
  38. appmates-0.1.0/src/appmates/cli/commands/tester.py +108 -0
  39. appmates-0.1.0/src/appmates/cli/console.py +57 -0
  40. appmates-0.1.0/src/appmates/cli/main.py +82 -0
  41. appmates-0.1.0/src/appmates/core/__init__.py +0 -0
  42. appmates-0.1.0/src/appmates/core/clients/__init__.py +0 -0
  43. appmates-0.1.0/src/appmates/core/clients/appstore_connect.py +358 -0
  44. appmates-0.1.0/src/appmates/core/clients/itunes.py +288 -0
  45. appmates-0.1.0/src/appmates/core/config.py +58 -0
  46. appmates-0.1.0/src/appmates/core/errors.py +47 -0
  47. appmates-0.1.0/src/appmates/core/models/__init__.py +0 -0
  48. appmates-0.1.0/src/appmates/core/models/app_metadata.py +65 -0
  49. appmates-0.1.0/src/appmates/core/models/app_profile.py +177 -0
  50. appmates-0.1.0/src/appmates/core/models/competitors.py +261 -0
  51. appmates-0.1.0/src/appmates/core/models/keywords.py +85 -0
  52. appmates-0.1.0/src/appmates/core/models/market.py +161 -0
  53. appmates-0.1.0/src/appmates/core/models/report.py +156 -0
  54. appmates-0.1.0/src/appmates/core/models/testing.py +61 -0
  55. appmates-0.1.0/src/appmates/core/services/__init__.py +0 -0
  56. appmates-0.1.0/src/appmates/core/services/app_profile.py +329 -0
  57. appmates-0.1.0/src/appmates/core/services/asc_sync.py +255 -0
  58. appmates-0.1.0/src/appmates/core/services/competitor_analyzer.py +439 -0
  59. appmates-0.1.0/src/appmates/core/services/google_play.py +271 -0
  60. appmates-0.1.0/src/appmates/core/services/image_fixer.py +246 -0
  61. appmates-0.1.0/src/appmates/core/services/image_validator.py +411 -0
  62. appmates-0.1.0/src/appmates/core/services/keyword_builder.py +325 -0
  63. appmates-0.1.0/src/appmates/core/services/market_analyzer.py +274 -0
  64. appmates-0.1.0/src/appmates/core/services/market_scanner.py +209 -0
  65. appmates-0.1.0/src/appmates/core/services/metadata_validator.py +195 -0
  66. appmates-0.1.0/src/appmates/core/services/pricing_calculator.py +73 -0
  67. appmates-0.1.0/src/appmates/core/services/reporting.py +447 -0
  68. appmates-0.1.0/src/appmates/core/services/submission_checker.py +129 -0
  69. appmates-0.1.0/src/appmates/core/specs/__init__.py +19 -0
  70. appmates-0.1.0/src/appmates/core/specs/app_health.yaml +65 -0
  71. appmates-0.1.0/src/appmates/core/specs/apple.yaml +117 -0
  72. appmates-0.1.0/src/appmates/core/specs/aso.yaml +241 -0
  73. appmates-0.1.0/src/appmates/core/specs/google_play.yaml +74 -0
  74. appmates-0.1.0/src/appmates/core/specs/market.yaml +171 -0
  75. appmates-0.1.0/src/appmates/core/specs/pricing.yaml +45 -0
  76. appmates-0.1.0/src/appmates/core/specs/registry.py +274 -0
  77. appmates-0.1.0/src/appmates/py.typed +0 -0
  78. appmates-0.1.0/tests/__init__.py +0 -0
  79. appmates-0.1.0/tests/conftest.py +110 -0
  80. appmates-0.1.0/tests/fixtures/itunes_competitors.json +254 -0
  81. appmates-0.1.0/tests/fixtures/itunes_habit_tracker.json +213 -0
  82. appmates-0.1.0/tests/test_app_profile.py +258 -0
  83. appmates-0.1.0/tests/test_appstore_connect_client.py +339 -0
  84. appmates-0.1.0/tests/test_asc_sync.py +312 -0
  85. appmates-0.1.0/tests/test_cli.py +1234 -0
  86. appmates-0.1.0/tests/test_competitor_analyzer.py +550 -0
  87. appmates-0.1.0/tests/test_config_and_reporting.py +289 -0
  88. appmates-0.1.0/tests/test_google_play.py +249 -0
  89. appmates-0.1.0/tests/test_image_fixer.py +234 -0
  90. appmates-0.1.0/tests/test_image_validator.py +290 -0
  91. appmates-0.1.0/tests/test_itunes_client.py +439 -0
  92. appmates-0.1.0/tests/test_keyword_builder.py +291 -0
  93. appmates-0.1.0/tests/test_market_analyzer.py +438 -0
  94. appmates-0.1.0/tests/test_market_scanner.py +157 -0
  95. appmates-0.1.0/tests/test_metadata_validator.py +199 -0
  96. appmates-0.1.0/tests/test_pricing_calculator.py +45 -0
  97. appmates-0.1.0/tests/test_specs.py +120 -0
  98. appmates-0.1.0/tests/test_submission_checker.py +74 -0
  99. appmates-0.1.0/uv.lock +1122 -0
  100. appmates-0.1.0/web/.well-known/security.txt +5 -0
  101. appmates-0.1.0/web/404.html +47 -0
  102. appmates-0.1.0/web/README.md +146 -0
  103. appmates-0.1.0/web/_headers +23 -0
  104. appmates-0.1.0/web/app.html +679 -0
  105. appmates-0.1.0/web/app.js +251 -0
  106. appmates-0.1.0/web/assets/app-store.png +0 -0
  107. appmates-0.1.0/web/assets/darkHighFive.png +0 -0
  108. appmates-0.1.0/web/assets/google-play.png +0 -0
  109. appmates-0.1.0/web/assets/icon.svg +14 -0
  110. appmates-0.1.0/web/assets/lightHighFive.png +0 -0
  111. appmates-0.1.0/web/browse-view.js +332 -0
  112. appmates-0.1.0/web/index.html +592 -0
  113. appmates-0.1.0/web/landing-demo.js +115 -0
  114. appmates-0.1.0/web/landing.css +1724 -0
  115. appmates-0.1.0/web/landing.js +795 -0
  116. appmates-0.1.0/web/legal-notice.html +65 -0
  117. appmates-0.1.0/web/legal.css +55 -0
  118. appmates-0.1.0/web/lib/app-profile.js +355 -0
  119. appmates-0.1.0/web/lib/community.js +405 -0
  120. appmates-0.1.0/web/lib/competitors.js +360 -0
  121. appmates-0.1.0/web/lib/favorites.js +74 -0
  122. appmates-0.1.0/web/lib/fixer.js +150 -0
  123. appmates-0.1.0/web/lib/globe-centroids.js +97 -0
  124. appmates-0.1.0/web/lib/globe-land.js +157 -0
  125. appmates-0.1.0/web/lib/globe.js +505 -0
  126. appmates-0.1.0/web/lib/image-facts.js +161 -0
  127. appmates-0.1.0/web/lib/itunes.js +342 -0
  128. appmates-0.1.0/web/lib/keywords.js +305 -0
  129. appmates-0.1.0/web/lib/market.js +313 -0
  130. appmates-0.1.0/web/lib/metadata.js +146 -0
  131. appmates-0.1.0/web/lib/platform-badge.js +41 -0
  132. appmates-0.1.0/web/lib/presence.js +44 -0
  133. appmates-0.1.0/web/lib/pricing.js +92 -0
  134. appmates-0.1.0/web/lib/promo-colors.js +25 -0
  135. appmates-0.1.0/web/lib/promo-form.js +329 -0
  136. appmates-0.1.0/web/lib/push.js +107 -0
  137. appmates-0.1.0/web/lib/shot-store.js +44 -0
  138. appmates-0.1.0/web/lib/specs.json +905 -0
  139. appmates-0.1.0/web/lib/sponsor-tape.js +273 -0
  140. appmates-0.1.0/web/lib/testers.js +195 -0
  141. appmates-0.1.0/web/lib/tests-store.js +56 -0
  142. appmates-0.1.0/web/lib/validator.js +419 -0
  143. appmates-0.1.0/web/lib/zip.js +190 -0
  144. appmates-0.1.0/web/privacy.html +172 -0
  145. appmates-0.1.0/web/push-sw.js +60 -0
  146. appmates-0.1.0/web/sponsor-view.js +338 -0
  147. appmates-0.1.0/web/styles.css +1780 -0
  148. appmates-0.1.0/web/terms.html +118 -0
  149. appmates-0.1.0/web/test/conformance-cases.json +23951 -0
  150. appmates-0.1.0/web/test/conformance.test.js +498 -0
  151. appmates-0.1.0/web/test/favorites.test.js +103 -0
  152. appmates-0.1.0/web/test/fixtures/cmyk.jpg +0 -0
  153. appmates-0.1.0/web/test/fixtures/fixtures.json +104 -0
  154. appmates-0.1.0/web/test/fixtures/greyscale-alpha.png +0 -0
  155. appmates-0.1.0/web/test/fixtures/greyscale.jpg +0 -0
  156. appmates-0.1.0/web/test/fixtures/greyscale.png +0 -0
  157. appmates-0.1.0/web/test/fixtures/palette-trns.png +0 -0
  158. appmates-0.1.0/web/test/fixtures/palette.png +0 -0
  159. appmates-0.1.0/web/test/fixtures/rgb-with-text.png +0 -0
  160. appmates-0.1.0/web/test/fixtures/rgb.jpg +0 -0
  161. appmates-0.1.0/web/test/fixtures/rgb.png +0 -0
  162. appmates-0.1.0/web/test/fixtures/rgba.png +0 -0
  163. appmates-0.1.0/web/test/fixtures/wide.jpg +0 -0
  164. appmates-0.1.0/web/test/itunes.test.js +203 -0
  165. appmates-0.1.0/web/test/parser.test.js +81 -0
  166. appmates-0.1.0/web/test/zip.test.js +132 -0
  167. appmates-0.1.0/web/views/admin.js +380 -0
  168. appmates-0.1.0/web/views/be-tester.js +1175 -0
  169. appmates-0.1.0/web/views/community.js +1117 -0
  170. appmates-0.1.0/web/views/competitors.js +175 -0
  171. appmates-0.1.0/web/views/favorites-tray.js +85 -0
  172. appmates-0.1.0/web/views/inbox.js +756 -0
  173. appmates-0.1.0/web/views/keywords.js +89 -0
  174. appmates-0.1.0/web/views/launch.js +196 -0
  175. appmates-0.1.0/web/views/markets.js +102 -0
  176. appmates-0.1.0/web/views/metadata.js +206 -0
  177. appmates-0.1.0/web/views/niche.js +97 -0
  178. appmates-0.1.0/web/views/onboard.js +214 -0
  179. appmates-0.1.0/web/views/overview.js +448 -0
  180. appmates-0.1.0/web/views/pricing.js +77 -0
  181. appmates-0.1.0/web/views/rank.js +148 -0
  182. appmates-0.1.0/web/views/readiness.js +161 -0
  183. appmates-0.1.0/web/views/screenshots.js +434 -0
  184. appmates-0.1.0/web/views/shared.js +291 -0
  185. appmates-0.1.0/web/views/specs.js +63 -0
  186. appmates-0.1.0/web/views/testers.js +409 -0
  187. appmates-0.1.0/worker/README.md +59 -0
  188. appmates-0.1.0/worker/package-lock.json +1537 -0
  189. appmates-0.1.0/worker/package.json +12 -0
  190. appmates-0.1.0/worker/src/index.js +176 -0
  191. appmates-0.1.0/worker/test/rate-limit.test.js +66 -0
  192. appmates-0.1.0/worker/wrangler.jsonc +23 -0
@@ -0,0 +1,17 @@
1
+ {
2
+ "version": "0.0.1",
3
+ "configurations": [
4
+ {
5
+ "name": "appmates-web",
6
+ "runtimeExecutable": "python3",
7
+ "runtimeArgs": [
8
+ "-m",
9
+ "http.server",
10
+ "8123",
11
+ "--directory",
12
+ "web"
13
+ ],
14
+ "port": 8123
15
+ }
16
+ ]
17
+ }
@@ -0,0 +1,13 @@
1
+ # Copy to .env and fill in — never commit the real file (.env is gitignored).
2
+
3
+ # --- App Store Connect (optional, only for `appmates asc ...`) -------------
4
+ #
5
+ # Generate a key at:
6
+ # https://appstoreconnect.apple.com/access/integrations/api
7
+ #
8
+ # The private key file itself never leaves your machine — see
9
+ # core/clients/appstore_connect.py for exactly what that means. chmod 600
10
+ # the .p8 file; `appmates asc status` warns if it is more open than that.
11
+ LAUNCHPILOT_APP_STORE_KEY_ID=
12
+ LAUNCHPILOT_APP_STORE_ISSUER_ID=
13
+ LAUNCHPILOT_APP_STORE_PRIVATE_KEY_PATH=
@@ -0,0 +1,30 @@
1
+ ---
2
+ name: Bug report
3
+ about: Something in AppMates isn't working as expected
4
+ title: ""
5
+ labels: bug
6
+ assignees: ""
7
+ ---
8
+
9
+ **What happened**
10
+ A clear description of the bug.
11
+
12
+ **What you expected**
13
+ What you expected to happen instead.
14
+
15
+ **How to reproduce**
16
+
17
+ ```bash
18
+ appmates <command that triggers it>
19
+ ```
20
+
21
+ Attach a minimal example file (screenshot, listing text, spec) if the bug is
22
+ data-dependent — strip anything sensitive first.
23
+
24
+ **Environment**
25
+ - AppMates version: `appmates --version`
26
+ - OS:
27
+ - Python version:
28
+
29
+ **Additional context**
30
+ Anything else relevant (store, storefront, error traceback, etc).
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an idea or a store rule AppMates should know about
4
+ title: ""
5
+ labels: enhancement
6
+ assignees: ""
7
+ ---
8
+
9
+ **What's the problem**
10
+ What's missing or annoying today. If this is a store rule change, link the
11
+ source (App Store Connect / Play Console docs, changelog, etc).
12
+
13
+ **What you'd like instead**
14
+ What you want AppMates to do.
15
+
16
+ **Alternatives considered**
17
+ Any workaround you're using today, if any.
@@ -0,0 +1,13 @@
1
+ ## What this does
2
+
3
+ <!-- One or two sentences. -->
4
+
5
+ ## Why
6
+
7
+ <!-- The problem this solves, or the source URL if this is a store rule change. -->
8
+
9
+ ## Checklist
10
+
11
+ - [ ] `uv run ruff check . && uv run ruff format --check . && uv run mypy && uv run pytest` all pass
12
+ - [ ] `node --test "web/test/*.test.js"` passes (if `web/` changed)
13
+ - [ ] Scope is one change — unrelated cleanup is in a separate PR
@@ -0,0 +1,25 @@
1
+ version: 2
2
+ updates:
3
+ # CLI + core engines (pyproject.toml)
4
+ - package-ecosystem: "pip"
5
+ directory: "/"
6
+ schedule:
7
+ interval: "weekly"
8
+ groups:
9
+ python-dependencies:
10
+ patterns: ["*"]
11
+
12
+ # Screenshot relay Worker
13
+ - package-ecosystem: "npm"
14
+ directory: "/worker"
15
+ schedule:
16
+ interval: "weekly"
17
+ groups:
18
+ npm-dependencies:
19
+ patterns: ["*"]
20
+
21
+ # Action versions pinned in .github/workflows/*.yml
22
+ - package-ecosystem: "github-actions"
23
+ directory: "/"
24
+ schedule:
25
+ interval: "weekly"
@@ -0,0 +1,151 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ env:
14
+ FORCE_COLOR: "1"
15
+
16
+ jobs:
17
+ lint:
18
+ name: Lint & types
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - name: Install uv
24
+ uses: astral-sh/setup-uv@v5
25
+ with:
26
+ enable-cache: true
27
+
28
+ - name: Set up Python
29
+ run: uv python install 3.11
30
+
31
+ - name: Install
32
+ run: uv sync --extra dev
33
+
34
+ - run: uv run ruff check .
35
+ - run: uv run ruff format --check .
36
+ - run: uv run mypy
37
+
38
+ test:
39
+ name: Tests · Python ${{ matrix.python-version }}
40
+ runs-on: ${{ matrix.os }}
41
+ strategy:
42
+ fail-fast: false
43
+ matrix:
44
+ python-version: ["3.11", "3.12", "3.13"]
45
+ os: [ubuntu-latest]
46
+ # Pillow behaves differently enough across platforms to be worth one
47
+ # non-Linux run; a full matrix would be wasteful for a pure-Python tool.
48
+ include:
49
+ - python-version: "3.12"
50
+ os: macos-latest
51
+
52
+ # Set for the whole job rather than passed to `uv sync` alone: a --python
53
+ # flag on sync does not carry over to `uv run`, which then falls back to the
54
+ # .python-version file, resolves a different interpreter, and cannot find
55
+ # pytest. UV_PYTHON keeps every uv invocation on the same interpreter.
56
+ env:
57
+ UV_PYTHON: ${{ matrix.python-version }}
58
+
59
+ steps:
60
+ - uses: actions/checkout@v4
61
+
62
+ - name: Install uv
63
+ uses: astral-sh/setup-uv@v5
64
+ with:
65
+ enable-cache: true
66
+
67
+ - name: Set up Python ${{ matrix.python-version }}
68
+ run: uv python install ${{ matrix.python-version }}
69
+
70
+ - name: Install
71
+ run: uv sync --extra dev
72
+
73
+ - name: Verify the interpreter matches the matrix
74
+ run: uv run python -c "import sys; assert sys.version.startswith('${{ matrix.python-version }}'), sys.version"
75
+
76
+ - name: Run tests
77
+ run: uv run pytest
78
+
79
+ - name: Upload coverage
80
+ if: matrix.python-version == '3.12' && matrix.os == 'ubuntu-latest'
81
+ uses: codecov/codecov-action@v5
82
+ with:
83
+ files: ./coverage.xml
84
+ fail_ci_if_error: false
85
+ env:
86
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
87
+
88
+ web:
89
+ name: Web checker
90
+ runs-on: ubuntu-latest
91
+ steps:
92
+ - uses: actions/checkout@v4
93
+
94
+ - name: Install uv
95
+ uses: astral-sh/setup-uv@v5
96
+ with:
97
+ enable-cache: true
98
+
99
+ - uses: actions/setup-node@v4
100
+ with:
101
+ node-version: "22"
102
+
103
+ - name: Install
104
+ run: uv sync --extra dev
105
+
106
+ # The browser engine reads generated copies of the Python-side data.
107
+ # If someone edits a spec YAML without regenerating, the web page would
108
+ # quietly apply different rules from the CLI, so treat staleness as a
109
+ # build failure rather than a nightly surprise.
110
+ - name: Generated artefacts are current
111
+ run: |
112
+ uv run python scripts/export_specs.py --check
113
+ uv run python scripts/export_conformance.py --check
114
+ uv run python scripts/export_parser_fixtures.py --check
115
+
116
+ - name: Conformance and unit tests
117
+ run: node --test "web/test/*.test.js" | tee /tmp/node-test.log
118
+
119
+ # Our own assertions check the bytes we meant to write; this checks that a
120
+ # real ZIP implementation accepts them.
121
+ - name: Archive opens with a real unzip
122
+ run: |
123
+ ZIP=$(grep -o 'ZIP_FIXTURE=.*' /tmp/node-test.log | head -1 | cut -d= -f2)
124
+ test -n "$ZIP" || { echo "::error::zip fixture path not emitted"; exit 1; }
125
+ unzip -t "$ZIP"
126
+ unzip -o "$ZIP" -d /tmp/zipcheck
127
+ test -f /tmp/zipcheck/locale/en-US/screen-02.jpg
128
+
129
+ smoke:
130
+ name: CLI smoke test
131
+ runs-on: ubuntu-latest
132
+ steps:
133
+ - uses: actions/checkout@v4
134
+
135
+ - name: Install uv
136
+ uses: astral-sh/setup-uv@v5
137
+
138
+ - name: Install
139
+ run: uv sync --extra dev
140
+
141
+ # The commands must actually run end to end, not merely import.
142
+ - name: Exercise the CLI
143
+ run: |
144
+ uv run appmates --version
145
+ uv run appmates specs --json > /dev/null
146
+ uv run appmates check-testers -d 14 -t 12
147
+ # Exit code 1 is the documented "findings" contract; assert it holds.
148
+ if uv run appmates check-testers -d 3 -t 12; then
149
+ echo "::error::expected exit code 1 for an incomplete test period"
150
+ exit 1
151
+ fi
@@ -0,0 +1,66 @@
1
+ name: CodeQL
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ schedule:
9
+ # Catches newly-published CodeQL query rules against unchanged code —
10
+ # a Monday morning UTC run, off the hour to avoid the top-of-hour spike
11
+ # every other repo's cron also fires at.
12
+ - cron: "17 6 * * 1"
13
+
14
+ jobs:
15
+ analyze:
16
+ name: Analyze (${{ matrix.language }})
17
+ runs-on: ubuntu-latest
18
+ permissions:
19
+ security-events: write
20
+ contents: read
21
+ # codeql-action/analyze calls the Actions API for its own run
22
+ # metadata (unrelated to the SARIF upload below) — without this, that
23
+ # call comes back "Resource not accessible by integration" and the
24
+ # step gets marked failed on the error annotation alone, even though
25
+ # the process catches it, logs a warning, and exits 0. Found by
26
+ # reading the actual failure log rather than guessing: `upload:
27
+ # false` on its own did not fix this, because it was never the
28
+ # upload that was failing.
29
+ actions: read
30
+
31
+ strategy:
32
+ fail-fast: false
33
+ matrix:
34
+ # javascript-typescript covers web/, worker/ in one pass.
35
+ # python covers src/appmates.
36
+ language: ["javascript-typescript", "python"]
37
+
38
+ steps:
39
+ - uses: actions/checkout@v4
40
+
41
+ - uses: github/codeql-action/init@v4
42
+ with:
43
+ languages: ${{ matrix.language }}
44
+
45
+ # `upload: false` here, not the action's own default upload: on a
46
+ # *private* repo, pushing results to the code-scanning API needs
47
+ # GitHub Advanced Security, which this repo doesn't have. That push
48
+ # would fail once the fix above (actions: read) is in place, so this
49
+ # keeps analyze itself green regardless — the separate
50
+ # `continue-on-error` upload below is what actually tries it, and it
51
+ # starts succeeding on its own the moment this repo goes public (code
52
+ # scanning is free for public repos) or GHAS gets turned on, with no
53
+ # flag to remember to flip back.
54
+ - uses: github/codeql-action/analyze@v4
55
+ with:
56
+ category: "/language:${{ matrix.language }}"
57
+ upload: false
58
+ output: sarif-results
59
+
60
+ - name: Upload SARIF (works once the repo is public, or with GitHub Advanced Security)
61
+ uses: github/codeql-action/upload-sarif@v4
62
+ if: always()
63
+ continue-on-error: true
64
+ with:
65
+ sarif_file: sarif-results
66
+ category: "/language:${{ matrix.language }}"
@@ -0,0 +1,44 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build:
9
+ name: Build distribution
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - name: Install uv
15
+ uses: astral-sh/setup-uv@v5
16
+
17
+ - name: Build sdist + wheel
18
+ run: uv build
19
+
20
+ - uses: actions/upload-artifact@v4
21
+ with:
22
+ name: dist
23
+ path: dist/
24
+
25
+ publish:
26
+ name: Publish to PyPI
27
+ needs: build
28
+ runs-on: ubuntu-latest
29
+ # Matches the GitHub Actions environment named on PyPI's trusted-publisher
30
+ # form — not required for OIDC to work, but scopes the id-token
31
+ # permission below to only run under this environment's protection
32
+ # rules, if any get added later.
33
+ environment: pypi
34
+ permissions:
35
+ # Trusted publishing (OIDC) needs this — it's how the job proves its
36
+ # identity to PyPI instead of a stored API token.
37
+ id-token: write
38
+ steps:
39
+ - uses: actions/download-artifact@v4
40
+ with:
41
+ name: dist
42
+ path: dist/
43
+
44
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,51 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ build/
5
+ dist/
6
+ .venv/
7
+ venv/
8
+
9
+ .pytest_cache/
10
+ .mypy_cache/
11
+ .ruff_cache/
12
+ .coverage
13
+ coverage.xml
14
+ htmlcov/
15
+
16
+ .DS_Store
17
+ .idea/
18
+ .vscode/
19
+
20
+ # Local project config may hold store credentials
21
+ .env
22
+ .env.*
23
+ !.env.example
24
+ appmates.local.toml
25
+
26
+ # Real listing text pulled from App Store Connect via `appmates asc pull`
27
+ # — not secret, but real business data with no reason to sit in git.
28
+ # Both names: `pulled*.json` from earlier docs, `listing.json` from the
29
+ # README/dashboard's own example command.
30
+ pulled*.json
31
+ /listing.json
32
+
33
+ # Local scratch for browser-driven checks
34
+ web/.fixtures/
35
+
36
+ # Cloudflare Pages deploy state — `/.wrangler/` when deployed as
37
+ # `wrangler pages deploy web` from the repo root, `web/.wrangler/` when run
38
+ # as `wrangler pages deploy .` from inside web/ (both invocations have been
39
+ # used; either leaves state in a different place).
40
+ /.wrangler/
41
+ web/.wrangler/
42
+
43
+ # Worker: installed deps and local dev state, neither of which is source
44
+ worker/node_modules/
45
+ worker/.wrangler/
46
+
47
+ # community/ moved to its own private repo (appmates-community) — this
48
+ # local copy is a leftover, not part of the repo at all anymore. Ignored
49
+ # wholesale rather than deleted, since it still holds local dev state
50
+ # (.dev.vars, .wrangler) not worth losing by hand.
51
+ /community/
@@ -0,0 +1 @@
1
+ 3.11
@@ -0,0 +1,67 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics,
8
+ gender identity and expression, level of experience, education,
9
+ socio-economic status, nationality, personal appearance, race, religion, or
10
+ sexual identity and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment:
18
+
19
+ - Demonstrating empathy and kindness toward other people
20
+ - Being respectful of differing opinions, viewpoints, and experiences
21
+ - Giving and gracefully accepting constructive feedback
22
+ - Accepting responsibility and apologizing to those affected by our
23
+ mistakes, and learning from the experience
24
+ - Focusing on what is best not just for us as individuals, but for the
25
+ overall community
26
+
27
+ Examples of unacceptable behavior:
28
+
29
+ - The use of sexualized language or imagery, and sexual attention or
30
+ advances of any kind
31
+ - Trolling, insulting or derogatory comments, and personal or political
32
+ attacks
33
+ - Public or private harassment
34
+ - Publishing others' private information, such as a physical or email
35
+ address, without their explicit permission
36
+ - Other conduct which could reasonably be considered inappropriate in a
37
+ professional setting
38
+
39
+ ## Enforcement Responsibilities
40
+
41
+ Project maintainers are responsible for clarifying and enforcing standards
42
+ of acceptable behavior and will take appropriate and fair corrective action
43
+ in response to any behavior deemed inappropriate, threatening, offensive, or
44
+ harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies within all community spaces, and also applies
49
+ when an individual is officially representing the community in public
50
+ spaces.
51
+
52
+ ## Enforcement
53
+
54
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
55
+ reported to appmates.contact@gmail.com. All complaints will be reviewed and
56
+ investigated promptly and fairly.
57
+
58
+ All community leaders are obligated to respect the privacy and security of
59
+ the reporter of any incident.
60
+
61
+ ## Attribution
62
+
63
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
64
+ version 2.1, available at
65
+ https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
66
+
67
+ [homepage]: https://www.contributor-covenant.org
@@ -0,0 +1,50 @@
1
+ # Contributing to AppMates
2
+
3
+ Issues and PRs welcome.
4
+
5
+ ## Dev setup
6
+
7
+ ```bash
8
+ git clone https://github.com/pP4010/appmates.git
9
+ cd appmates
10
+ uv sync --extra dev
11
+ ```
12
+
13
+ Runs on Python 3.11+, managed with [uv](https://docs.astral.sh/uv/). The web
14
+ frontend (`web/`) is vanilla JS with no build step — edit and reload.
15
+
16
+ ## Before opening a PR
17
+
18
+ ```bash
19
+ uv run ruff check .
20
+ uv run ruff format --check .
21
+ uv run mypy
22
+ uv run pytest
23
+ ```
24
+
25
+ All four must pass; CI (`.github/workflows/ci.yml`) runs the same checks
26
+ plus a web conformance suite and a CLI smoke test. If you touch
27
+ `web/`, also run the JS tests:
28
+
29
+ ```bash
30
+ node --test "web/test/*.test.js"
31
+ ```
32
+
33
+ ## Store rule changes
34
+
35
+ When a store changes a rule, the fix is usually a one-line edit to
36
+ `src/appmates/core/specs/*.yaml` plus a bump of `last_verified` — please
37
+ include the source URL in your PR description.
38
+
39
+ ## Code style
40
+
41
+ - Python: `ruff` (lint + format) and `mypy --strict` — both enforced in CI,
42
+ no separate style guide beyond what they check.
43
+ - JS (`web/`): match the existing file's style; no framework/bundler, keep
44
+ it that way unless discussed first in an issue.
45
+ - Keep PRs scoped to one change. Unrelated cleanup belongs in its own PR.
46
+
47
+ ## Reporting a security issue
48
+
49
+ Do not open a public issue for security vulnerabilities — see
50
+ [SECURITY.md](SECURITY.md) for the disclosure process.