stage-cli 1.0.0__py3-none-any.whl

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 (170) hide show
  1. stage/__init__.py +1 -0
  2. stage/__main__.py +8 -0
  3. stage/banner.py +32 -0
  4. stage/bootstrap/__init__.py +0 -0
  5. stage/bootstrap/openjobs.py +392 -0
  6. stage/classify/__init__.py +29 -0
  7. stage/classify/eligibility.py +115 -0
  8. stage/classify/internship.py +64 -0
  9. stage/classify/role.py +91 -0
  10. stage/classify/scope.py +47 -0
  11. stage/cli/__init__.py +0 -0
  12. stage/cli/app.py +4 -0
  13. stage/cli/commands/__init__.py +8 -0
  14. stage/cli/commands/discovery.py +294 -0
  15. stage/cli/commands/insight.py +494 -0
  16. stage/cli/commands/pipeline.py +337 -0
  17. stage/cli/commands/postings.py +473 -0
  18. stage/cli/commands/schedule.py +171 -0
  19. stage/cli/housekeeping.py +64 -0
  20. stage/cli/logfile.py +56 -0
  21. stage/cli/notify.py +170 -0
  22. stage/cli/options.py +678 -0
  23. stage/cli/render.py +1398 -0
  24. stage/cli/runlock.py +74 -0
  25. stage/cli/schedule.py +702 -0
  26. stage/cli/schedule_state.py +363 -0
  27. stage/cli/selection.py +83 -0
  28. stage/cli/serialize.py +196 -0
  29. stage/companies.py +542 -0
  30. stage/data/companies/a.yaml +1289 -0
  31. stage/data/companies/b.yaml +900 -0
  32. stage/data/companies/c.yaml +1377 -0
  33. stage/data/companies/d.yaml +497 -0
  34. stage/data/companies/e.yaml +519 -0
  35. stage/data/companies/f.yaml +454 -0
  36. stage/data/companies/g.yaml +601 -0
  37. stage/data/companies/h.yaml +446 -0
  38. stage/data/companies/i.yaml +503 -0
  39. stage/data/companies/j.yaml +138 -0
  40. stage/data/companies/k.yaml +278 -0
  41. stage/data/companies/l.yaml +402 -0
  42. stage/data/companies/m.yaml +937 -0
  43. stage/data/companies/n.yaml +549 -0
  44. stage/data/companies/o.yaml +371 -0
  45. stage/data/companies/other.yaml +58 -0
  46. stage/data/companies/p.yaml +825 -0
  47. stage/data/companies/q.yaml +121 -0
  48. stage/data/companies/r.yaml +583 -0
  49. stage/data/companies/s.yaml +1140 -0
  50. stage/data/companies/t.yaml +817 -0
  51. stage/data/companies/u.yaml +196 -0
  52. stage/data/companies/v.yaml +325 -0
  53. stage/data/companies/w.yaml +353 -0
  54. stage/data/companies/x.yaml +67 -0
  55. stage/data/companies/y.yaml +36 -0
  56. stage/data/companies/z.yaml +146 -0
  57. stage/data/fonts/DejaVuSans.LICENSE.txt +99 -0
  58. stage/data/fonts/DejaVuSans.ttf +0 -0
  59. stage/data/lexicon/company_tokens.yaml +228 -0
  60. stage/data/lexicon/eligibility.yaml +455 -0
  61. stage/data/lexicon/inclusive_suffixes.yaml +37 -0
  62. stage/data/lexicon/internship.yaml +187 -0
  63. stage/data/lexicon/language.yaml +226 -0
  64. stage/data/lexicon/locations.yaml +1159 -0
  65. stage/data/lexicon/roles.yaml +2012 -0
  66. stage/data/lexicon/terms.yaml +76 -0
  67. stage/data/lexicon/workday_facets.yaml +27 -0
  68. stage/data/seed_companies.yaml +198 -0
  69. stage/dedup/__init__.py +19 -0
  70. stage/dedup/identity.py +113 -0
  71. stage/dedup/resolve.py +97 -0
  72. stage/domain/__init__.py +244 -0
  73. stage/domain/company.py +49 -0
  74. stage/domain/coverage.py +86 -0
  75. stage/domain/custom_board.py +92 -0
  76. stage/domain/discovery.py +94 -0
  77. stage/domain/enums.py +114 -0
  78. stage/domain/events.py +204 -0
  79. stage/domain/filters.py +27 -0
  80. stage/domain/health.py +169 -0
  81. stage/domain/ids.py +48 -0
  82. stage/domain/job.py +47 -0
  83. stage/domain/matching.py +15 -0
  84. stage/domain/priority.py +34 -0
  85. stage/domain/quarantine.py +39 -0
  86. stage/domain/rate_state.py +78 -0
  87. stage/domain/retention.py +20 -0
  88. stage/domain/rotation.py +46 -0
  89. stage/domain/signals.py +12 -0
  90. stage/domain/sync_run.py +35 -0
  91. stage/domain/text.py +113 -0
  92. stage/domain/validator.py +14 -0
  93. stage/domain/visits.py +60 -0
  94. stage/domain/workday.py +38 -0
  95. stage/http/__init__.py +58 -0
  96. stage/http/breaker.py +53 -0
  97. stage/http/cache.py +44 -0
  98. stage/http/client.py +725 -0
  99. stage/http/profiles.py +101 -0
  100. stage/lexicon.py +370 -0
  101. stage/normalize/__init__.py +16 -0
  102. stage/normalize/language.py +47 -0
  103. stage/normalize/location.py +271 -0
  104. stage/normalize/terms.py +153 -0
  105. stage/normalize/urls.py +122 -0
  106. stage/paths.py +86 -0
  107. stage/py.typed +0 -0
  108. stage/services/__init__.py +0 -0
  109. stage/services/canary.py +120 -0
  110. stage/services/coverage.py +231 -0
  111. stage/services/discover.py +747 -0
  112. stage/services/export.py +274 -0
  113. stage/services/health.py +237 -0
  114. stage/services/maintenance.py +225 -0
  115. stage/services/quarantine.py +20 -0
  116. stage/services/query.py +86 -0
  117. stage/services/sync.py +1257 -0
  118. stage/sources/__init__.py +82 -0
  119. stage/sources/_text.py +79 -0
  120. stage/sources/ashby.py +93 -0
  121. stage/sources/bamboohr.py +80 -0
  122. stage/sources/base.py +225 -0
  123. stage/sources/breezy.py +90 -0
  124. stage/sources/collage.py +60 -0
  125. stage/sources/community_feeds.py +142 -0
  126. stage/sources/curated_markdown.py +289 -0
  127. stage/sources/custom_json.py +610 -0
  128. stage/sources/espresso.py +154 -0
  129. stage/sources/feed.py +44 -0
  130. stage/sources/greenhouse.py +104 -0
  131. stage/sources/jobbank.py +147 -0
  132. stage/sources/jobvite.py +133 -0
  133. stage/sources/lever.py +76 -0
  134. stage/sources/oracle_cloud.py +187 -0
  135. stage/sources/platforms.py +609 -0
  136. stage/sources/quebec_emploi.py +146 -0
  137. stage/sources/recruitee.py +96 -0
  138. stage/sources/simplify.py +110 -0
  139. stage/sources/smartrecruiters.py +216 -0
  140. stage/sources/speedyapply.py +200 -0
  141. stage/sources/themuse.py +157 -0
  142. stage/sources/workable.py +83 -0
  143. stage/sources/workday.py +524 -0
  144. stage/sources/zshah.py +99 -0
  145. stage/storage/__init__.py +29 -0
  146. stage/storage/migrations/0001_initial.sql +239 -0
  147. stage/storage/migrations/__init__.py +135 -0
  148. stage/storage/repository.py +213 -0
  149. stage/storage/search.py +28 -0
  150. stage/storage/sqlite_repo.py +1586 -0
  151. stage/storage/writer.py +249 -0
  152. stage/tui/__init__.py +0 -0
  153. stage/tui/app.py +82 -0
  154. stage/tui/help.py +26 -0
  155. stage/tui/safe.py +21 -0
  156. stage/tui/screens/__init__.py +0 -0
  157. stage/tui/screens/boards.py +186 -0
  158. stage/tui/screens/postings.py +509 -0
  159. stage/tui/screens/review.py +209 -0
  160. stage/tui/screens/splash.py +37 -0
  161. stage/tui/screens/stats.py +124 -0
  162. stage/tui/screens/sync.py +194 -0
  163. stage/tui/state.py +160 -0
  164. stage/tui/theme.tcss +205 -0
  165. stage/tui/widgets/__init__.py +0 -0
  166. stage_cli-1.0.0.dist-info/METADATA +379 -0
  167. stage_cli-1.0.0.dist-info/RECORD +170 -0
  168. stage_cli-1.0.0.dist-info/WHEEL +4 -0
  169. stage_cli-1.0.0.dist-info/entry_points.txt +2 -0
  170. stage_cli-1.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,379 @@
1
+ Metadata-Version: 2.5
2
+ Name: stage-cli
3
+ Version: 1.0.0
4
+ Summary: Aggregates CS internship postings (Canada/US, EN + FR) into a local SQLite database
5
+ Project-URL: Homepage, https://github.com/NicholasXydis/Stage
6
+ Project-URL: Repository, https://github.com/NicholasXydis/Stage
7
+ Project-URL: Issues, https://github.com/NicholasXydis/Stage/issues
8
+ Project-URL: Changelog, https://github.com/NicholasXydis/Stage/blob/main/CHANGELOG.md
9
+ Author-email: Nicholas Xydis <NicholasXydis@outlook.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: cli,co-op,internship,python,stage,student,tui
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: End Users/Desktop
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: MacOS
18
+ Classifier: Operating System :: Microsoft :: Windows
19
+ Classifier: Operating System :: POSIX :: Linux
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
25
+ Classifier: Topic :: Utilities
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: <3.15,>=3.12
28
+ Requires-Dist: beautifulsoup4>=4.15.0
29
+ Requires-Dist: fpdf2>=2.8.4
30
+ Requires-Dist: httpx>=0.28.1
31
+ Requires-Dist: platformdirs>=4.3.6
32
+ Requires-Dist: pydantic>=2.10.0
33
+ Requires-Dist: pyyaml>=6.0.2
34
+ Requires-Dist: rich>=13.9.4
35
+ Requires-Dist: tenacity>=9.1.4
36
+ Requires-Dist: textual>=8.2.8
37
+ Requires-Dist: typer<0.28,>=0.27.1
38
+ Description-Content-Type: text/markdown
39
+
40
+ <div align="center">
41
+ <table><tr><td>
42
+ <pre>
43
+ ____ _
44
+ / ___|| |_ __ _ __ _ ___
45
+ &#92;___ &#92;| __| / _&#96; | / _&#96; | / _ &#92;
46
+ ___) | |_ | (_| || (_| || __/
47
+ |____/ &#92;__| &#92;__,_| &#92;__, | &#92;___|
48
+ |___/
49
+ </pre>
50
+ </td></tr></table>
51
+
52
+ ### One command. Thousands of internships.
53
+
54
+ **Every CS internship you can actually apply to, in one place.**
55
+
56
+ Free and open source. No account, no server, no telemetry.
57
+
58
+ <br>
59
+
60
+ ![python](https://img.shields.io/static/v1?label=python&message=3.12%20%7C%203.13%20%7C%203.14&color=4a9eff&logo=python&logoColor=white)
61
+
62
+ ![tests](https://img.shields.io/static/v1?label=tests&message=2%2C375&color=44bb00) ![coverage](https://img.shields.io/static/v1?label=coverage&message=89%25&color=44bb00) [![ci](https://img.shields.io/github/actions/workflow/status/NicholasXydis/Stage/ci.yml?branch=main&label=ci&logo=githubactions&logoColor=white)](https://github.com/NicholasXydis/Stage/actions/workflows/ci.yml)
63
+
64
+ <br>
65
+
66
+ <p align="center"><sub><b>Made with</b></sub></p>
67
+
68
+ <p align="center">
69
+ <img src="https://cdn.jsdelivr.net/gh/devicons/devicon@v2.16.0/icons/python/python-original.svg" alt="Python" width="46" height="46">
70
+ &nbsp;&nbsp;&nbsp;
71
+ <img src="https://cdn.jsdelivr.net/gh/devicons/devicon@v2.16.0/icons/sqlite/sqlite-original.svg" alt="SQLite" width="46" height="46">
72
+ &nbsp;&nbsp;&nbsp;
73
+ <img src="https://avatars.githubusercontent.com/u/93378883?s=200" alt="Textual" width="46" height="46">
74
+ </p>
75
+
76
+ <p align="center"><sub><b>Works on</b></sub></p>
77
+
78
+ <p align="center">
79
+ <img src="https://cdn.jsdelivr.net/gh/devicons/devicon@v2.16.0/icons/windows8/windows8-original.svg" alt="Windows" width="46" height="46">
80
+ &nbsp;&nbsp;&nbsp;
81
+ <img src="https://cdn.jsdelivr.net/gh/devicons/devicon@v2.16.0/icons/linux/linux-original.svg" alt="Linux" width="46" height="46">
82
+ &nbsp;&nbsp;&nbsp;
83
+ <img src="https://cdn.jsdelivr.net/gh/devicons/devicon@v2.16.0/icons/apple/apple-original.svg" alt="macOS" width="46" height="46">
84
+ </p>
85
+
86
+ </div>
87
+
88
+ ## Why
89
+ Internships disappear fast. By the time you find the right posting, hundreds of students may already be ahead of you. Most job boards make it worse by burying relevant roles under senior positions, research jobs, and listings nowhere near you.
90
+
91
+ Stage scans 1,450+ employer career boards and finds internships CS undergrads in Canada and the U.S. can actually apply to. Every rejected posting is logged with the exact reason it was filtered out.
92
+
93
+ It has kept **4,165** postings out of **138,533** screened so far.
94
+
95
+ ## A look at it
96
+
97
+ <div align="center">
98
+ <img src="assets/tui.png" alt="The Stage TUI listing internship postings, with columns for age, company, title and location, a search bar, and the full description of the highlighted posting below" width="100%">
99
+ <br><sub><b>stage tui</b> — browse everything, filter with <b>f</b>, open with <b>o</b></sub>
100
+ </div>
101
+
102
+ <br>
103
+
104
+ <div align="center">
105
+ <img src="assets/cli.png" alt="The stage command line help, showing commands grouped into Everyday, Keeping current, Registry and maintenance, and Health" width="100%">
106
+ <br><sub><b>stage --help</b> — commands grouped by what you are doing</sub>
107
+ </div>
108
+
109
+ ## Install
110
+
111
+ ```bash
112
+ uv tool install stage-cli
113
+ ```
114
+
115
+ <details>
116
+ <summary><b>Don't have uv?</b> Install it first, then reopen your terminal.</summary>
117
+
118
+ <br>
119
+
120
+ If you already have Python, this works everywhere:
121
+
122
+ ```bash
123
+ pip install uv
124
+ ```
125
+
126
+ Or use your usual package manager — `brew install uv` on macOS, `winget install
127
+ astral-sh.uv` on Windows. More options at
128
+ [docs.astral.sh/uv](https://docs.astral.sh/uv/getting-started/installation/).
129
+
130
+ </details>
131
+
132
+ <details>
133
+ <summary><b>Other ways to install</b></summary>
134
+
135
+ <br>
136
+
137
+ ```bash
138
+ pipx install stage-cli # isolates the tool, like uv
139
+ pip install stage-cli # installs into the active environment
140
+ ```
141
+
142
+ `uv tool install` and `pipx` both keep Stage away from your system Python, which
143
+ is what you want for a command line tool.
144
+
145
+ </details>
146
+
147
+ Needs Python 3.12, 3.13, or 3.14. Nothing else to set up — no database to
148
+ configure, no API key, no config file.
149
+
150
+ ### First run
151
+
152
+ ```bash
153
+ stage sync # fetch every board once (grab a coffee)
154
+ stage tui # browse what came back
155
+ ```
156
+
157
+ The first sync visits every board and takes a few minutes. Later ones are much
158
+ quicker, since Stage remembers what it already has and only asks each board for
159
+ what changed.
160
+
161
+ ```bash
162
+ stage --install-completion # tab-complete commands and filters
163
+ ```
164
+
165
+ Completion needs a fresh terminal. After that, `stage <TAB>` lists commands and
166
+ `stage list --<TAB>` lists filters.
167
+
168
+ ## The basics
169
+
170
+ ```bash
171
+ stage sync # fetch the latest postings
172
+ stage list # what is new, newest first
173
+ stage search "machine learning" # search titles, employers, descriptions
174
+ stage tui # browse it all in a full screen
175
+ ```
176
+
177
+ Rows are numbered, so you can act on what you just saw:
178
+
179
+ ```bash
180
+ stage list --role swe --location montreal
181
+ stage show 3 # read the third row in full
182
+ stage open 3 5 9 # open those three in your browser
183
+ ```
184
+
185
+ Filters work the same on `list`, `search`, and `export`:
186
+
187
+ | Filter | What it takes |
188
+ | --- | --- |
189
+ | `--role` | swe, security, data, ml-ai, quant, infra, embedded, general-cs |
190
+ | `--location` | montreal, canada, usa, unknown |
191
+ | `--term` | summer-2027, fall-2026, winter-2027, and so on |
192
+ | `--lang` | en, fr, bilingual |
193
+ | `--source` | greenhouse, lever, ashby, workday, and more |
194
+ | `--company` | one exact employer |
195
+ | `--all` | every match, not just the first page |
196
+ | `--last N` | look back N days instead of the default 14; `--last 0` removes the limit. On `search`, which already covers every row, it narrows instead |
197
+
198
+ Mistype one and Stage tells you what it accepts, rather than showing you an
199
+ empty list.
200
+
201
+ ## The full-screen browser
202
+
203
+ ```bash
204
+ stage tui
205
+ ```
206
+
207
+ Press `/` to search and `f` for filters — arrows move, enter picks, escape
208
+ closes. Role, location, language, how far back to look, new-since-last-sync and
209
+ the employer you are sitting on all live in that one panel.
210
+ `space` marks rows and `o` opens every one you marked. `w` expands the full
211
+ description, `e` exports what you are looking at, and `ctrl+t` changes the theme.
212
+ Press `?` for the full key list.
213
+
214
+ Same database as the CLI. The panel covers role, location, language, the date
215
+ window and new-since-last-sync; `--term` and `--source` stay CLI-only. Row
216
+ numbers are a CLI idea — in the TUI you move a cursor instead.
217
+
218
+ ## Keeping it fresh
219
+
220
+ ```bash
221
+ stage schedule enable # sync quietly in the background
222
+ stage schedule status # check on it
223
+ ```
224
+
225
+ Opt-in, and it uses whatever scheduler your system already has: launchd,
226
+ systemd, or Task Scheduler. Nothing runs until you turn it on.
227
+
228
+ Want to hear about new postings without checking? Point Stage at a Discord
229
+ channel you manage:
230
+
231
+ ```bash
232
+ stage schedule notify https://discord.com/api/webhooks/...
233
+ stage schedule test-notify # make sure it works
234
+ ```
235
+
236
+ Create a Discord webhook in the channel you want Stage to post to. It is just a URL Stage uses to send new internships.
237
+
238
+ Notifications only follow scheduled syncs, not stage sync. Your machine also needs to be awake. If it misses runs, Stage catches up once when it can run again.
239
+
240
+ <details>
241
+ <summary><b>Want notifications around the clock?</b></summary>
242
+
243
+ <br>
244
+
245
+ Put Stage on something that stays on — a VPS, a Raspberry Pi, an old laptop:
246
+
247
+ ```bash
248
+ uv tool install stage-cli
249
+ stage sync # first sync, a few minutes
250
+ stage schedule notify <webhook>
251
+ stage schedule enable # systemd, launchd, or Task Scheduler
252
+ ```
253
+
254
+ That machine keeps its own database and posts to Discord on its own schedule.
255
+ Yours stays free for browsing.
256
+
257
+ </details>
258
+
259
+ ## Architecture
260
+
261
+ ```text
262
+ Stage/
263
+ ├─ src/stage/
264
+ │ ├─ cli/ Typer commands, Rich rendering, scheduling, notify
265
+ │ ├─ tui/ Textual screens over the same services; safe.py escapes output
266
+ │ ├─ domain/ the types every layer speaks: jobs, filters, enums, events
267
+ │ ├─ sources/ 13 ATS adapters + 11 curated feeds
268
+ │ ├─ services/ sync, discover, query, export, quarantine, health
269
+ │ ├─ classify/ role, internship scope, degree eligibility, location
270
+ │ ├─ normalize/ location, term, language, apply-url canonicalisation
271
+ │ ├─ dedup/ cross-source duplicate resolution
272
+ │ ├─ http/ rate posture, circuit breaker, validator cache
273
+ │ ├─ storage/ SQLite repository, migrations, FTS
274
+ │ └─ data/ packaged registry (a directory) and lexicons
275
+ ├─ tests/ 2,375 tests, 89% branch coverage
276
+ └─ .github/workflows/ CI, CodeQL, scheduled canary, release
277
+ ```
278
+
279
+ <div align="center">
280
+ <pre>
281
+ ┌──────────────────────────────────────────────────────────────┐
282
+ │ 1,450+ employer boards │
283
+ │ Greenhouse · Lever · Ashby · Workday · SmartRecruiters │
284
+ │ + 11 curated internship feeds │
285
+ └───────────────────────────┬──────────────────────────────────┘
286
+ │ rate-limited, cached, backed off
287
+ ▼
288
+ ┌──────────────────────────────────────────────────────────────┐
289
+ │ normalize │
290
+ │ location · term · language · canonical apply URL │
291
+ └───────────────────────────┬──────────────────────────────────┘
292
+ ▼
293
+ ┌──────────────────────────────────────────────────────────────┐
294
+ │ screen │
295
+ │ internship? · CS role? · degree scope? · Canada or US? │
296
+ │ every rejection keeps the rule that caught it │
297
+ └──────────────┬───────────────────────────────┬───────────────┘
298
+ │ kept │ rejected
299
+ ▼ ▼
300
+ ┌─────────────┐ ┌─────────────┐
301
+ │ jobs │ │ quarantine │
302
+ │ 4,165 │ │ 134,368 │
303
+ └──────┬──────┘ └─────────────┘
304
+ │ dedup collapses the same posting across sources
305
+ ▼
306
+ ┌───────────────────────┐
307
+ │ SQLite + FTS5 │
308
+ │ on your machine │
309
+ └──────┬────────┬───────┘
310
+ ▼ ▼
311
+ stage list stage tui
312
+ search full-screen browser
313
+ export Discord on a schedule
314
+ </pre>
315
+ </div>
316
+
317
+ ## CI
318
+
319
+ | Workflow | File | Purpose |
320
+ | --- | --- | --- |
321
+ | CI | `.github/workflows/ci.yml` | Ruff, format, mypy strict, 2,375 tests, coverage floor, badge drift |
322
+ | Supported Pythons | `.github/workflows/ci.yml` | The full suite again on 3.13 and 3.14 |
323
+ | Wheel | `.github/workflows/ci.yml` | Builds and smoke-tests the wheel on Ubuntu, Windows and macOS |
324
+ | CodeQL | `.github/workflows/codeql.yml` | Static analysis for Python and the workflows themselves |
325
+ | Canary | `.github/workflows/canary.yml` | Probes one live board per platform and opens an issue on drift |
326
+ | Release | `.github/workflows/release.yml` | Re-runs every gate plus pip-audit, then publishes from a `v*` tag |
327
+
328
+ <div align="center">
329
+ <img src="assets/ci-flow.svg" alt="Quality checks on Python 3.12, then the full suite on 3.13 and 3.14, a wheel smoke test on three operating systems, and CodeQL. All gates must pass for CI to pass" width="100%">
330
+ </div>
331
+
332
+ Any failing gate blocks the merge. The canary runs weekly and opens an issue
333
+ when a board changes shape, so parser drift surfaces before a sync does.
334
+
335
+ Every run also builds the wheel and installs it into a clean environment outside
336
+ the checkout on Ubuntu, Windows and macOS, checks the registry, lexicons and font
337
+ resolve from inside the installed package, then runs `help`, `list`, `search`,
338
+ `doctor`, `coverage`, `stats`, a dry-run sync and all four export formats against
339
+ it. What ships is what gets tested.
340
+
341
+ ## Good to know
342
+
343
+ - Everything sits in one SQLite file you own. Open it with any SQLite client,
344
+ back it up, or delete it.
345
+ - The only network traffic is Stage reading public job boards. No account, no
346
+ telemetry.
347
+ - Requests are rate limited per host, cached, and retried with backoff, so it
348
+ does not hammer anyone's site.
349
+ - Four in five postings arrive with no description at all. Stage marks those
350
+ fields `unknown` instead of guessing.
351
+ - Missing something you expected? `stage quarantine` shows which rule caught it.
352
+
353
+ ## Learn more
354
+
355
+ `stage help` walks through the common workflows with real examples.
356
+ `stage help COMMAND` explains one command; `stage --help` lists them all.
357
+
358
+ [CHANGELOG.md](CHANGELOG.md) lists what changed in each release.
359
+
360
+ ## Found a bug?
361
+
362
+ Open an issue, especially if a job board stopped working, since those break
363
+ without warning and I cannot watch all of them myself. I read everything.
364
+
365
+ ## Security
366
+
367
+ Stage reads public job boards and writes to a local file. It never asks for
368
+ credentials. Found a security issue? Open a
369
+ [security advisory](https://github.com/NicholasXydis/Stage/security/advisories/new)
370
+ instead of a public issue.
371
+
372
+ ## License
373
+
374
+ MIT. See [LICENSE](LICENSE).
375
+
376
+ <div align="center">
377
+ <br>
378
+ <sub>Built for students who would rather be studying than refreshing career pages.</sub>
379
+ </div>
@@ -0,0 +1,170 @@
1
+ stage/__init__.py,sha256=J-j-u0itpEFT6irdmWmixQqYMadNl1X91TxUmoiLHMI,22
2
+ stage/__main__.py,sha256=vMLJHIuZfQz7KDs5ismZ5I5TYCoFu_45f1hLrnL84zQ,123
3
+ stage/banner.py,sha256=jq7qsyfnXlycEZRB6IAiOJ1DFQr6pHioYgQDcvunHlM,670
4
+ stage/companies.py,sha256=ZqhKz2EU8rD3gr0GVilSZ0lfIF6F5LoeBcXFHDYqHiI,20765
5
+ stage/lexicon.py,sha256=DHTDLdeyIarLaxau5yjEqhbGywr7Dxh2-0f3VsavXhQ,13757
6
+ stage/paths.py,sha256=gU2pMcnwc3f2vRIgrtsn__6mxyk3Be9B6Dms0L7Shk4,2553
7
+ stage/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ stage/bootstrap/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ stage/bootstrap/openjobs.py,sha256=keQjRD_9sR8Wzm9jSuiFNlX5b143Cb9rmCkoMcR-AbY,14578
10
+ stage/classify/__init__.py,sha256=FyDaO8269XWSi2a_iHb_mVk4DEs0ut90NPr4bHuLzZw,693
11
+ stage/classify/eligibility.py,sha256=-6oR3Z8x8hH2dNG_hIe-01HTCsRyvbddz1hzvNEzlws,3941
12
+ stage/classify/internship.py,sha256=3joTRKbKPpGnB6wYTidSFbYpTzmOElxEX4cUeHM61QU,2397
13
+ stage/classify/role.py,sha256=2SmvA5IHC0X0fgSku8f5xFdruXuqBqDSUXvg6U90ipo,3786
14
+ stage/classify/scope.py,sha256=mAcKC2kiMAX_w-D3w3i1mXWoRZd6_Xo5yeuXeNGv7x4,1456
15
+ stage/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ stage/cli/app.py,sha256=66Lv7Yjq5zF9sHTTSmfXsL5UOxQ8r3m9zbXa3Gf05s0,158
17
+ stage/cli/housekeeping.py,sha256=i_Rh-dBSwQpOYHv0K-lWKwSDJQ6UWbF8l1CpCHWjhgs,1801
18
+ stage/cli/logfile.py,sha256=6UMZsM_1JwSnu4rxc0bdTHIiuOENSeBdcBvZUhey4gc,1825
19
+ stage/cli/notify.py,sha256=uJa6uqXmoZoJ3c5sp4hdlB-V4jkjPNOT1eU_7uOnVMI,5006
20
+ stage/cli/options.py,sha256=zz7guIon4y302AoSSLT4_VddHcMBGc_Y7eBr6zCeYyM,23376
21
+ stage/cli/render.py,sha256=1FCG8V9WNwu3YlZg0_q9eyBjQRZK-rORrwgJFeISjKc,53419
22
+ stage/cli/runlock.py,sha256=00sOEQC9uxhJLD0IIGXaPTX0E0DMPCWbeT5aMHHG8Wo,2158
23
+ stage/cli/schedule.py,sha256=y4SSsqqjfpM3zZdXgjhhTR_2x_Xkf1KyA1QJWNCSa_c,24461
24
+ stage/cli/schedule_state.py,sha256=UvCJChvAegH1yBuJGhJcMAZq2kIkrhLMruzsSHogEp0,12647
25
+ stage/cli/selection.py,sha256=JF18SapaAj3r5AiFUIIvn7yn7VlqbkLk4o3WAJHo1OU,2246
26
+ stage/cli/serialize.py,sha256=s-pH-ktGpc4gPImXCOqLPMI-UBoDQ7Gv70kT9jrHsyQ,6336
27
+ stage/cli/commands/__init__.py,sha256=6Aka0Lz9bsScDgqgRoDfr8Fx2iWx_eY8yXL96EuX8dU,185
28
+ stage/cli/commands/discovery.py,sha256=qdFzo1GPuZF6Zn47NWKFuzgiHBWpzE4O8xHX-3KPbL0,10172
29
+ stage/cli/commands/insight.py,sha256=netydEoDKz61duSwfYTWEss2NIApgCRDijjqt3srn2c,16142
30
+ stage/cli/commands/pipeline.py,sha256=dBz_qFZPpOHKHk-5z24v_VAoDBGHNFlL9jOrktKb9iw,11747
31
+ stage/cli/commands/postings.py,sha256=nRgZrb5r4oe4clvJauc3vG2_yanajp4CdOqc9JYy0Ao,14762
32
+ stage/cli/commands/schedule.py,sha256=GJVuJehQcSW7V_3vTDZDP-xsXK5LEzr_Xmx74iX5T5U,5264
33
+ stage/data/seed_companies.yaml,sha256=xQF5ojHVaQDGL-Uz0I_mtbp5AcLdJJc49CfjTgJxqkI,11526
34
+ stage/data/companies/a.yaml,sha256=kFwefx11QCYYhoT29HcMpR080JaG28q-L48YIKgkn6g,42944
35
+ stage/data/companies/b.yaml,sha256=fG_pXmEOhL7m5P1YKDzde56hU_3Ba6AZlf_SM1moWUU,28984
36
+ stage/data/companies/c.yaml,sha256=jiQmUvSkOhwXC_u9V2FoOfXpU7z-7wc_AxOvIlsYGlQ,44037
37
+ stage/data/companies/d.yaml,sha256=rIR02dSPsnOS272z0DOFu687qvxAHhLmUqxJDpqAMFk,16190
38
+ stage/data/companies/e.yaml,sha256=fbVVkJmxH6DkUeeg6vJlrrFr4zOvlI9YCXRBijun-rg,17589
39
+ stage/data/companies/f.yaml,sha256=B-KQjofOnt7IR0GwqOldcat-1n2vJ3lr12LdUN3IdhM,15792
40
+ stage/data/companies/g.yaml,sha256=bG_hXuVJ6fatxnP7kUT_N5R0jkq6mwStX7AqpA1rN-g,20158
41
+ stage/data/companies/h.yaml,sha256=Bc02UWiaanbyO4pW03hKc_C9vjeJNipX5CAmAgAMF7E,15353
42
+ stage/data/companies/i.yaml,sha256=i-i1SjudsqtZT8xZ0DH7lMKH5QDpwG3LGOALWhMPwtE,15656
43
+ stage/data/companies/j.yaml,sha256=60qsJ6zAN_cHHV6YTpbRsB7nAtctueOkQBy2vROCVWw,4460
44
+ stage/data/companies/k.yaml,sha256=dmdF0Xca4VaD6xKn8prRbWS917sr5DXuy4Su6gYBzM8,9739
45
+ stage/data/companies/l.yaml,sha256=6Hirw9UPuet5ykdW3YwtOJEfzSvzOh6JwGvkLkobhNg,13695
46
+ stage/data/companies/m.yaml,sha256=61n1pbrJ1QAAmWiC03aeBtGYBm22cwUs2dG1yQCI0vc,31160
47
+ stage/data/companies/n.yaml,sha256=6Qqv82NfPwrIM4tXsu_JEqrTRj1pEVokCRF3px276A0,18420
48
+ stage/data/companies/o.yaml,sha256=zOA6-_KkngitmGRfE0vdzuqv5_eD40A5xahNsjz66i4,11641
49
+ stage/data/companies/other.yaml,sha256=3TW_I8Kfu_btkbQ3-LvOk7B2iNL_CM_wt7r96FTOvKA,2151
50
+ stage/data/companies/p.yaml,sha256=L9UQx7LSjhAxJ2VYrdWLhkg12_OX8zG1PXN9WePMTMg,27636
51
+ stage/data/companies/q.yaml,sha256=WUUoD9Yb2NB0WBSQqDB5Q4n3LtWHlo2giAXzkXdz4L0,4018
52
+ stage/data/companies/r.yaml,sha256=RADUcTwsLT0qolquRVqoCGIgQZxZurOrR5ITNq0VTmA,19942
53
+ stage/data/companies/s.yaml,sha256=-w_gnWtrdOcC_pUzP36204kMGfJd4SbtvIE1isQJoX4,37555
54
+ stage/data/companies/t.yaml,sha256=vYmpKWthr2opXjyUw-7rd_lu6G8DNzTvx89elOZ_z8c,27859
55
+ stage/data/companies/u.yaml,sha256=8l7d7CEjJK2wZg1Wrv7NJF36yLlC8k25syZXhTmhP6U,6545
56
+ stage/data/companies/v.yaml,sha256=YjpcmjauRAy-ROuNlAyVW4AUj3l4fTl_tM3FLcVB0v4,11343
57
+ stage/data/companies/w.yaml,sha256=lg6rOmf7Q-c_O4EIbuLI3ZqVLYRduQEhyFOD9D4u7uY,11968
58
+ stage/data/companies/x.yaml,sha256=gfEivYFvIa6Uo8nsXZ70uTWGobhvn8jO-hFkNre0IO8,2081
59
+ stage/data/companies/y.yaml,sha256=ZH8IJ1nazGr_D9oi8o8PCNkk3zWf5Q9nVUtog0HBOLA,1396
60
+ stage/data/companies/z.yaml,sha256=tJXSTx5-Nkqrfk3wYHIOhKuEhFZnFQc4yVP_TszbmZE,5155
61
+ stage/data/fonts/DejaVuSans.LICENSE.txt,sha256=11k43sCY8G8Kw8AIUwZdlPAgvhw8Yu8dwpdboVtNmw4,4816
62
+ stage/data/fonts/DejaVuSans.ttf,sha256=P99pyr8GBJ6nCgC1kZNA4s4ebQKwzDxLRPtoAb0eDSI,756072
63
+ stage/data/lexicon/company_tokens.yaml,sha256=XhSyJBLAmQ-nczuHgnw5Q8yo_0R4I85PVJJ9jeHFkY8,2747
64
+ stage/data/lexicon/eligibility.yaml,sha256=EVsRGS5TK2E3DdaSTyAGkJ-L-jALhDRChR1pktYR53U,10208
65
+ stage/data/lexicon/inclusive_suffixes.yaml,sha256=gemDFTYAwstybo9GryG0H3wt3wFSTKgFIloxA4w0Vgg,335
66
+ stage/data/lexicon/internship.yaml,sha256=mcPNw2cNwvr1Rz8ng6Bhh0C_jAbMda3VaoRzYowsV0w,3606
67
+ stage/data/lexicon/language.yaml,sha256=fkbhVITovWUNBJ8jHKIs3kB08FDFuYRqBSY0myduvYY,2636
68
+ stage/data/lexicon/locations.yaml,sha256=RxBh7uqxvnyDxEGlX2UbqQx8Z8N6GA1ruid1w4Yo1jU,15754
69
+ stage/data/lexicon/roles.yaml,sha256=1tEWosEd4CXWH7qcc6if9FwykmRvQkS3P3qfpC_rrSo,54491
70
+ stage/data/lexicon/terms.yaml,sha256=HcM463UEpg-2bgZKYEbFdN4ehsve8XWmf46Zgie2tjg,1020
71
+ stage/data/lexicon/workday_facets.yaml,sha256=NxOCgHZVo6TpYwWLIEImTnSMyl0JG0DSfvEHHhw1_6o,404
72
+ stage/dedup/__init__.py,sha256=3siSI7YV_TPBpRXiB5dJFeOESpo5nWThv9K7O91XlEU,375
73
+ stage/dedup/identity.py,sha256=665tnXwmAbxikOL2uG0Hl0Yz9KH5KikgkdGpyfrHVnY,3290
74
+ stage/dedup/resolve.py,sha256=VmG5C-0KLPlD5CgotEnpuop2xZuGLx4WVQrM2kaEI7g,3347
75
+ stage/domain/__init__.py,sha256=UmBEbENVfmhiyTmtZ1LUbxVFhCER11xCDysHepyto1w,5206
76
+ stage/domain/company.py,sha256=SJUBxXVId1mUMwctZwnJfZ0AaRnQPF3Pj3Q8tmkF2sk,1494
77
+ stage/domain/coverage.py,sha256=qQfClfnhczSrfaes2eMJdhhtucdj4OYVWVWADXt0s_M,2010
78
+ stage/domain/custom_board.py,sha256=SjNcqR87oaChfdw0lbS_wzqQa7o42-DUKJCIGGeRBf0,2365
79
+ stage/domain/discovery.py,sha256=_3ogh8Wx1V_D5ClVnF_Onh1etpPXuf2om-g_MX8SGSI,2273
80
+ stage/domain/enums.py,sha256=cYd0dtBzN_3XbOqqmAkrjgsAryexEobE9ePCnB60rzk,2123
81
+ stage/domain/events.py,sha256=HkxqpCyl3crgRIoPi78jqJ6qSBvTYQ5ijYouWXVF4dU,3708
82
+ stage/domain/filters.py,sha256=eV2G92XhQ1BsHCxCWLE65Hq4mMxB3W3ZrCKpJ_483mg,670
83
+ stage/domain/health.py,sha256=PFAHRXzzqiV1khAXxS_YQU9kOunWLJMw48wB4Kb4JUo,4343
84
+ stage/domain/ids.py,sha256=iShfIaqBvbUzCPwGLfWyGykztJbHwJ36chho-8s3X64,1415
85
+ stage/domain/job.py,sha256=lo1b4JR2iMTc2MPs3GYuupR-qv_4EQ4N6BtLXvjEfLM,1246
86
+ stage/domain/matching.py,sha256=M48iK9BZHm3SQ37Ie-BHDfkj7zgkRUMcSkXWtfZM8b4,495
87
+ stage/domain/priority.py,sha256=Md50LQ2Uynuy95mPHTopTJSKMPJRUlcXHzYnbTFCHvY,655
88
+ stage/domain/quarantine.py,sha256=q3JeYvCMyxkFlIko90xAUxBdGPygZt2eVMulqLkPPGI,1032
89
+ stage/domain/rate_state.py,sha256=8wXRsODRGBqAulpg9ykEtq4r7rMAc3jDxEr8fzEEWyI,2361
90
+ stage/domain/retention.py,sha256=_szVT-GJ0C7yI9eZHuu3KOOYxAf078t6rynG2jVPu8E,371
91
+ stage/domain/rotation.py,sha256=tnlL-jZJwhRwC104yCzJMUUSAOXXHTsENB_6_diM7so,1300
92
+ stage/domain/signals.py,sha256=quX6eK5VMnRZ4qr7J1kRZtgedcaOPmUJg3fFEbQsH0c,319
93
+ stage/domain/sync_run.py,sha256=La8xy0AwROnavweMx1pbegrToK3f9AOuv-TOfzggAWo,838
94
+ stage/domain/text.py,sha256=HRDGb4qcV1IVsGk0HLfU7ySjSzgrUFqsZz5RYw2AZEw,3005
95
+ stage/domain/validator.py,sha256=Lefn_oNmz8vgfn7MUpYM7huv_E4et110-2MRSBx0e_8,338
96
+ stage/domain/visits.py,sha256=YZIR2tNnsL2Kd_m73xLuVOlyPXKM9n0bWryKdC5uy7Q,1374
97
+ stage/domain/workday.py,sha256=ZZtem_SqyAxdJGFo-4pj69HuetzUVyzcVznz4WG8wUw,859
98
+ stage/http/__init__.py,sha256=jMQ1zJxNhIQR4N4JtKe3fYxrDC6NaFQqHwL-fDNFKX0,1243
99
+ stage/http/breaker.py,sha256=SJQ8h0iPYS-MnaFx2SeLtTWkDCYRCrHp211AI-KX-qk,1684
100
+ stage/http/cache.py,sha256=zX-uapUc3rcS98y4aXmEEAsYGD_rI5tlz8HDNR1Mqhs,1469
101
+ stage/http/client.py,sha256=8PS-z8feXd_q6Q-4QP0WSP-vakypvZ9T9WXMc3bh4IA,25984
102
+ stage/http/profiles.py,sha256=wj9RQYrmQVjpC9AxHt3rhzzQwcVN4QxJTGJOapJxxD0,3176
103
+ stage/normalize/__init__.py,sha256=xqUc5t-5z7cJkcM1JRmxe5ew0L9hDX2ADf4DanyigFs,512
104
+ stage/normalize/language.py,sha256=CATWmNxaHiBeIhqwg5douvU3ovMk0HdsVH1WPDwaQd8,1756
105
+ stage/normalize/location.py,sha256=5lObNeuKnf6nmNN8prCWU4t1mref-tYy32d_6fyxL-s,9067
106
+ stage/normalize/terms.py,sha256=1C_gp5DjfjMn2R0wA8ieiFgYY7C5RVK9i3KyBXsN6d8,4912
107
+ stage/normalize/urls.py,sha256=ifExzEiO6F38NImbdcsgWLDYuv0IQbgysDw4GQWu-nw,2973
108
+ stage/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
109
+ stage/services/canary.py,sha256=8Tlug81QrcDcCOZNDPK5euCWSmf2saNY4Agv2Ot_k-k,3713
110
+ stage/services/coverage.py,sha256=23xmp92ol-FWeLBYXNK-Yv3YxcPTIwhsz_7DITeRiw8,7736
111
+ stage/services/discover.py,sha256=YYRR2U6KapA8-k4QWu3zB6o__QcRj0LFXuRCzPxAKFg,26102
112
+ stage/services/export.py,sha256=ObNLEWOboSCPSKLZToPv3XZROEIXko9ilSKGAd59vFk,8357
113
+ stage/services/health.py,sha256=MdbJPD8ZJXWoXa5a1TTKKHu1KQRv1v3WD7q5GUS84oo,7712
114
+ stage/services/maintenance.py,sha256=CiHHFtEOr_oYW2LlgjI9xwRP9rZ2qPBcfivbD_5PB8Q,7763
115
+ stage/services/quarantine.py,sha256=1skjpsiZ6tAXoCEOGwDO_-5-O9iwX4IC2RUYCbd9Ork,678
116
+ stage/services/query.py,sha256=20CxMYZP2DHF1I-KlEv5d1EPiawzDLu2R811vpsK0PU,2591
117
+ stage/services/sync.py,sha256=If-9ssUp__frIwMu_BMf2Gt3VWRIez0EOtVwA-OeW_U,42850
118
+ stage/sources/__init__.py,sha256=APZKBTLH9EnNXWW-mQm_pRP0iLx-N6Qwx5DafnJ-gxE,1956
119
+ stage/sources/_text.py,sha256=8nT6HDi3d4jy9oIPHpxRWX-nqkQ0YQ9pcU5mtDEHbuw,2539
120
+ stage/sources/ashby.py,sha256=8AmUOcy0IH3cB553QrvxUXPcBQVOO5TWMxySk24JcRo,3073
121
+ stage/sources/bamboohr.py,sha256=ebqcctlgNBUJnPbZNtBhdtWxHwjFF_z73ZJuTQWne_Y,2503
122
+ stage/sources/base.py,sha256=Df5yLQ9OSNW7gjgJ60q754pLULMUF9JXuc18ZYS6L34,7732
123
+ stage/sources/breezy.py,sha256=uAsXmHA3ZRr2yvfpvchG2CNef2NL9a1oSpQbVnCl1rQ,2635
124
+ stage/sources/collage.py,sha256=5Nf_MrtXkXChiU3_cs6BZJoEEDZTF7UNx-0f7aPYoSs,1966
125
+ stage/sources/community_feeds.py,sha256=1S4NMXp2SqhUfS_3rg0L-jL6KdveyPQ7seI2PsUtFYk,4998
126
+ stage/sources/curated_markdown.py,sha256=sdCiYVRMUN_tZCINh8DNoeTSr5wGAeTFjfWbnPyrtNM,10731
127
+ stage/sources/custom_json.py,sha256=JEENp141S4k3hK2FZUgwxG21vbUao1c8I4t301Wgl_w,21305
128
+ stage/sources/espresso.py,sha256=yx5nuiURHzS_NfouUKUKWhTmnX7G-J714PVApcYwLzc,5563
129
+ stage/sources/feed.py,sha256=UxSMi-xqNLVfPq2O4N3easYy-ywNjYypOHmpSX_HpEA,1178
130
+ stage/sources/greenhouse.py,sha256=R8vu-jyouMQFcigkQi9XOrMltsIKZbjtgv_8D3N76ng,3620
131
+ stage/sources/jobbank.py,sha256=a39tB9yKooX0Xme5YpRmC5dXhoZsBXSHf72uoeAvvHg,5220
132
+ stage/sources/jobvite.py,sha256=GTRdrJyn4i5NqLZT7z0Y6_gqqh-zLRGH4dnnyRJqj0Q,4559
133
+ stage/sources/lever.py,sha256=a_Zvj3iD9yyenx4-KWhHIIzVqIyetx5k7ND5DWtjgwg,2568
134
+ stage/sources/oracle_cloud.py,sha256=my7VqLHi3vrMOHmLNZTBGloSe9VEYoeltvlx03hI4fE,7034
135
+ stage/sources/platforms.py,sha256=-Gpk4ujkSaQHG0uIPBk6rn3aEsPi5PaoOt3ZGzcxGoM,19322
136
+ stage/sources/quebec_emploi.py,sha256=4me_B6lGx9Kl94HxiNKvepeUeDobHK_su7qRQKNOnuo,4854
137
+ stage/sources/recruitee.py,sha256=j8mCfC2oCGbpdX9V_-Agk5_-PNWS0ABPqVTyfION8g4,3175
138
+ stage/sources/simplify.py,sha256=X_LFdXQMKulVeDRhUp8t7I3fge4bKJI-mu3ZDX38k9g,3902
139
+ stage/sources/smartrecruiters.py,sha256=7E1EenyCzoZUOMgTHQF4M7ffWYUAqFi3SoKvdkVSiL4,7809
140
+ stage/sources/speedyapply.py,sha256=BSo6_cnJZJVVCsjMtTwM7LPalRRpER37-0E-7CldUww,7796
141
+ stage/sources/themuse.py,sha256=N9-EmD_eswRN0Q80VrApwyA1oDaWW9fsJndeZ7CaKVM,4998
142
+ stage/sources/workable.py,sha256=YbEPqTmU0wYYhOxdIqIY4qJD2W1-3FaNBVYC9ccrQ2I,2835
143
+ stage/sources/workday.py,sha256=yw92bp-IweQcNFkGChDk540XWcenmCScRQZ-RCzO2x8,19663
144
+ stage/sources/zshah.py,sha256=Qe0o4DWxMcxwEb8gC2i37T-vDCh4_M265rAJbOzd-Vs,3459
145
+ stage/storage/__init__.py,sha256=D7oXRVEktHNdQn4c718K1oVPh1Lops_r6ofCUfrXp70,784
146
+ stage/storage/repository.py,sha256=NWHzvkNHadHpuvTA5dst4Ogb_UYO0l3yvRXMctDunhM,5670
147
+ stage/storage/search.py,sha256=I5p8aRRUSK83wvxArFDfqZ2LbySZm-aoCq-hL9oFd4c,583
148
+ stage/storage/sqlite_repo.py,sha256=YQY6mb7EQS-440cweMpkU3wMNjyBnUcfa7lZiBHJP-c,64813
149
+ stage/storage/writer.py,sha256=qeNY6EtsF1AONzPlDGYYm2oepTxaFDiQL4o_BFxK2tM,10554
150
+ stage/storage/migrations/0001_initial.sql,sha256=xR4Xa2z_zuiWTJA_OJtDaUBnfM9hPvWLo-4-yTvz33c,8454
151
+ stage/storage/migrations/__init__.py,sha256=gDdaozUAIbwGFuyefH8Jb0z1rXDLvc6P2BN7QUFh0uw,4347
152
+ stage/tui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
153
+ stage/tui/app.py,sha256=fWp8u5sw-I1i_FlcGyOY3JV27lbFTEYe7b6q7_t01fE,2639
154
+ stage/tui/help.py,sha256=bKSoqD4krt-gwHPOH46aERiSROB8ki25grjH3X80uRc,702
155
+ stage/tui/safe.py,sha256=oa_urNPAqnHOygBSFLtgMHrSNm6dG3L2GeE-lobF5hM,589
156
+ stage/tui/state.py,sha256=oJpmwF74h0ODb_ToUjAlh7zB66qRjG3fM-9wiuKQ1tU,4826
157
+ stage/tui/theme.tcss,sha256=2tjFElsksY78-QXu_l5p3Cf1w3L7LO9ILfCCwzmsjIQ,2729
158
+ stage/tui/screens/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
159
+ stage/tui/screens/boards.py,sha256=XOEqzHv3wJpaQgqhELzLl0Q5fiOnjJ6eQxMowhNzEzU,6282
160
+ stage/tui/screens/postings.py,sha256=EutNbk17SlDG-7oMsqp5TVaTST7UeU4Aw8ZgMflJ6i0,18022
161
+ stage/tui/screens/review.py,sha256=XxBlIy7lKk7MvaDUSiuhDeRPWnGhDOQgOpfWlym_zOs,7591
162
+ stage/tui/screens/splash.py,sha256=-gjpQVzQmIl669eWxsNQPOsLzikPSDNY8P9nwaqOlwU,1239
163
+ stage/tui/screens/stats.py,sha256=gx-bBphdgnN0-1cvAdpmZuq4Oo25JBHKvmMkW9Rj8f0,4128
164
+ stage/tui/screens/sync.py,sha256=P8OJUWZVcugU-ZCWzjSOJ254n4o04IhoX7fXDnTgY8w,7019
165
+ stage/tui/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
166
+ stage_cli-1.0.0.dist-info/METADATA,sha256=gMmYLhdwG5MQDaV7qj-XgjJsH7vz5LQHT0L1OJ92i0o,16127
167
+ stage_cli-1.0.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
168
+ stage_cli-1.0.0.dist-info/entry_points.txt,sha256=N3GAgSJ5CsTOtu1rIPFV_Pp_Ay7Vw2sZZhy6UOeDbb4,45
169
+ stage_cli-1.0.0.dist-info/licenses/LICENSE,sha256=7h-7XM1TFJfQW75cOFA435MEJQtoHfUJipxzbdojZ-c,1071
170
+ stage_cli-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ stage = stage.cli.app:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nicholas Xydis
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.