careerrag 1.0.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.
- careerrag-1.0.0/.github/workflows/dryclean.yml +63 -0
- careerrag-1.0.0/.github/workflows/publish.yml +57 -0
- careerrag-1.0.0/.gitignore +14 -0
- careerrag-1.0.0/CHANGELOG.md +22 -0
- careerrag-1.0.0/CLAUDE.md +433 -0
- careerrag-1.0.0/LICENSE +21 -0
- careerrag-1.0.0/Makefile +22 -0
- careerrag-1.0.0/PKG-INFO +210 -0
- careerrag-1.0.0/README.md +182 -0
- careerrag-1.0.0/pyproject.toml +47 -0
- careerrag-1.0.0/src/careerrag/__init__.py +1 -0
- careerrag-1.0.0/src/careerrag/__main__.py +93 -0
- careerrag-1.0.0/src/careerrag/config.py +37 -0
- careerrag-1.0.0/src/careerrag/frontend/static/css/chat.css +443 -0
- careerrag-1.0.0/src/careerrag/frontend/static/js/initialize-chat.js +320 -0
- careerrag-1.0.0/src/careerrag/frontend/templates/chat.html +105 -0
- careerrag-1.0.0/src/careerrag/rag/__init__.py +1 -0
- careerrag-1.0.0/src/careerrag/rag/chunker.py +144 -0
- careerrag-1.0.0/src/careerrag/rag/fusion.py +30 -0
- careerrag-1.0.0/src/careerrag/rag/generator.py +67 -0
- careerrag-1.0.0/src/careerrag/rag/indexer.py +47 -0
- careerrag-1.0.0/src/careerrag/rag/keyword.py +35 -0
- careerrag-1.0.0/src/careerrag/rag/loader.py +75 -0
- careerrag-1.0.0/src/careerrag/rag/pipeline.py +46 -0
- careerrag-1.0.0/src/careerrag/rag/prompt.py +50 -0
- careerrag-1.0.0/src/careerrag/rag/reranker.py +26 -0
- careerrag-1.0.0/src/careerrag/rag/retriever.py +73 -0
- careerrag-1.0.0/src/careerrag/rag/selector.py +59 -0
- careerrag-1.0.0/src/careerrag/rag/util.py +62 -0
- careerrag-1.0.0/src/careerrag/rag/vector.py +29 -0
- careerrag-1.0.0/src/careerrag/server/__init__.py +1 -0
- careerrag-1.0.0/src/careerrag/server/app.py +68 -0
- careerrag-1.0.0/tests/__init__.py +1 -0
- careerrag-1.0.0/tests/fixtures/sample-resume.docx +0 -0
- careerrag-1.0.0/tests/fixtures/sample-resume.pdf +0 -0
- careerrag-1.0.0/tests/test_pipeline.py +125 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: dryclean CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
types: [opened, synchronize, reopened, ready_for_review]
|
|
8
|
+
branches: [main]
|
|
9
|
+
issue_comment:
|
|
10
|
+
types: [created]
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
quality:
|
|
14
|
+
name: dryclean Quality Checks
|
|
15
|
+
if: github.event_name != 'issue_comment'
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout repository
|
|
19
|
+
uses: actions/checkout@v6
|
|
20
|
+
- name: Run quality checks
|
|
21
|
+
uses: arup-kumar-maiti/dryclean/ci@v1
|
|
22
|
+
|
|
23
|
+
review:
|
|
24
|
+
name: dryclean PR Review
|
|
25
|
+
if: github.event_name == 'pull_request'
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
permissions:
|
|
28
|
+
actions: read
|
|
29
|
+
contents: read
|
|
30
|
+
id-token: write
|
|
31
|
+
issues: write
|
|
32
|
+
pull-requests: write
|
|
33
|
+
steps:
|
|
34
|
+
- name: Checkout repository
|
|
35
|
+
uses: actions/checkout@v6
|
|
36
|
+
with:
|
|
37
|
+
fetch-depth: 0
|
|
38
|
+
- name: Run Claude PR review
|
|
39
|
+
uses: arup-kumar-maiti/dryclean/review@v1
|
|
40
|
+
with:
|
|
41
|
+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
42
|
+
|
|
43
|
+
describe:
|
|
44
|
+
name: dryclean PR Description
|
|
45
|
+
if: |
|
|
46
|
+
(github.event_name == 'pull_request' && github.event.action == 'opened' && (github.event.pull_request.body == null || github.event.pull_request.body == '')) ||
|
|
47
|
+
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude describe'))
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
permissions:
|
|
50
|
+
actions: read
|
|
51
|
+
contents: read
|
|
52
|
+
id-token: write
|
|
53
|
+
issues: write
|
|
54
|
+
pull-requests: write
|
|
55
|
+
steps:
|
|
56
|
+
- name: Checkout repository
|
|
57
|
+
uses: actions/checkout@v6
|
|
58
|
+
with:
|
|
59
|
+
fetch-depth: 0
|
|
60
|
+
- name: Run Claude PR description
|
|
61
|
+
uses: arup-kumar-maiti/dryclean/describe@v1
|
|
62
|
+
with:
|
|
63
|
+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v[0-9]+.[0-9]+.[0-9]+'
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
name: Build and Publish
|
|
11
|
+
if: github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/v')
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
environment: pypi
|
|
14
|
+
permissions:
|
|
15
|
+
contents: write
|
|
16
|
+
id-token: write
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout repository
|
|
19
|
+
uses: actions/checkout@v6
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0
|
|
22
|
+
|
|
23
|
+
- name: Verify tag is on main
|
|
24
|
+
shell: bash
|
|
25
|
+
run: |
|
|
26
|
+
tag_commit=$(git rev-list -n 1 "${{ github.ref_name }}")
|
|
27
|
+
main_commits=$(git rev-list origin/main)
|
|
28
|
+
if ! echo "$main_commits" | grep -q "$tag_commit"; then
|
|
29
|
+
echo "::error::Tag ${{ github.ref_name }} is not on main branch"
|
|
30
|
+
exit 1
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
- name: Set up Python
|
|
34
|
+
uses: actions/setup-python@v6
|
|
35
|
+
with:
|
|
36
|
+
python-version: '3.11'
|
|
37
|
+
|
|
38
|
+
- name: Install build tools
|
|
39
|
+
shell: bash
|
|
40
|
+
run: pip install build
|
|
41
|
+
|
|
42
|
+
- name: Build package
|
|
43
|
+
shell: bash
|
|
44
|
+
run: python -m build
|
|
45
|
+
|
|
46
|
+
- name: Publish to PyPI
|
|
47
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
48
|
+
|
|
49
|
+
- name: Create GitHub release
|
|
50
|
+
shell: bash
|
|
51
|
+
env:
|
|
52
|
+
GH_TOKEN: ${{ github.token }}
|
|
53
|
+
run: |
|
|
54
|
+
version="${{ github.ref_name }}"
|
|
55
|
+
[ -f CHANGELOG.md ] || { echo "CHANGELOG.md not found."; exit 1; }
|
|
56
|
+
notes=$(awk "/^## \[${version#v}\]/{found=1; next} /^## \[/{found=0} found" CHANGELOG.md)
|
|
57
|
+
gh release create "$version" --title "$version" --notes "$notes"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
4
|
+
Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
5
|
+
|
|
6
|
+
## [1.0.0] - 2026-05-04
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- Chat web UI with FastAPI, SSE streaming, and markdown rendering.
|
|
11
|
+
- ChromaDB vector store with auto-embeddings via sentence-transformers.
|
|
12
|
+
- CLI with init, index, query, and serve commands.
|
|
13
|
+
- Cross-encoder reranking for precise relevance judgments.
|
|
14
|
+
- Document loading via Docling for PDF, DOCX, Markdown, and plain text.
|
|
15
|
+
- Hybrid retrieval with vector search and BM25 keyword search.
|
|
16
|
+
- LLM streaming via Ollama and Claude.
|
|
17
|
+
- MMR diversity selection across overlapping documents.
|
|
18
|
+
- Reciprocal rank fusion of ranked results.
|
|
19
|
+
- Secret management via environment variables.
|
|
20
|
+
- Section-aware chunker with paragraph merging, sentence-level splitting, and overlap.
|
|
21
|
+
- System prompt with career-specific guardrails.
|
|
22
|
+
- YAML configuration file with auto-defaults.
|
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
Non-negotiable rules for this repo. Language-specific details are in `docs/<language>/CODE_GUIDELINES.md` and `docs/<language>/COMMENTING_GUIDELINES.md`.
|
|
4
|
+
|
|
5
|
+
- `[CI]` — build fails automatically. No way to merge a violation.
|
|
6
|
+
- `[Review]` — self-enforce first. Caught by the automated Claude PR reviewer and human review as backup.
|
|
7
|
+
- `[CI · Review]` — mixed section: each bullet inside carries its own per-rule tag.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Quick reference
|
|
12
|
+
|
|
13
|
+
| Convention | CSS | HTML | JavaScript | Python | Shell |
|
|
14
|
+
|-------------------|----------------------|--------------------|----------------------|--------------------|--------------------------------|
|
|
15
|
+
| File naming | `kebab-case` | `kebab-case` | `kebab-case` | `snake_case` | `kebab-case` |
|
|
16
|
+
| Variable naming | — | — | `camelCase` | `snake_case` | `lower_snake` / `UPPER_SNAKE` |
|
|
17
|
+
| Function naming | — | — | `camelCase` | `snake_case` | — |
|
|
18
|
+
| Constant naming | — | — | `UPPER_SNAKE_CASE` | `UPPER_SNAKE_CASE` | `UPPER_SNAKE_CASE` |
|
|
19
|
+
| Class naming | `kebab-case` | — | — | `PascalCase` | — |
|
|
20
|
+
| Custom properties | `--kebab-case` | — | — | — | — |
|
|
21
|
+
| Data attributes | — | `data-kebab-case` | — | — | — |
|
|
22
|
+
| Quotes | Double | Double | Single | Double | — |
|
|
23
|
+
| Imports | — | — | built-in → 3rd → int | stdlib → 3rd → int | — |
|
|
24
|
+
| Formatter | prettier | prettier | prettier | ruff | — |
|
|
25
|
+
| Linter | stylelint | htmlhint | eslint | ruff | shellcheck |
|
|
26
|
+
| Type checker | — | — | — | mypy (strict) | — |
|
|
27
|
+
| Docstrings | — | — | JSDoc | Docstrings | — |
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Universal rules (all languages)
|
|
32
|
+
|
|
33
|
+
### Pre-edit checklist
|
|
34
|
+
|
|
35
|
+
Before writing or modifying any source file:
|
|
36
|
+
|
|
37
|
+
- [ ] Filename follows the language convention (see quick reference)
|
|
38
|
+
- [ ] Every function: ≤ 30 lines, ≤ 4 args, one responsibility
|
|
39
|
+
- [ ] No magic numbers / strings — extract to a module-top constant
|
|
40
|
+
- [ ] Imports grouped with one blank line between groups
|
|
41
|
+
- [ ] Comments only for *why*, on the line **above**, never inline, ≤ 15% density
|
|
42
|
+
- [ ] No trailing whitespace, newline at EOF
|
|
43
|
+
- [ ] All non-code text follows Tone rules
|
|
44
|
+
- [ ] Ordering follows Ordering rules
|
|
45
|
+
|
|
46
|
+
### Naming `[CI · Review]`
|
|
47
|
+
|
|
48
|
+
- Full words — abbreviations only if more recognizable than the full form (e.g. `api`, `db`, `id`, `ip`, `url`), never lazy shorthand (e.g. `btn`, `cfg`, `ctx`, `err`, `msg`, `req`, `res`, `usr`). External API field names are fine if documented with a comment. `[Review]`
|
|
49
|
+
- Unclear name? **Rename first, before doing anything else.** `[Review]`
|
|
50
|
+
|
|
51
|
+
### Constants `[CI · Review]`
|
|
52
|
+
|
|
53
|
+
- No magic numbers or strings anywhere. Extract every literal to a named constant. `[Review]`
|
|
54
|
+
- In comparisons. `[Review]`
|
|
55
|
+
- In defaults and format strings. Inline strings in error messages are fine. `[Review]`
|
|
56
|
+
- **Local** to one module → top of that module. `[CI]`
|
|
57
|
+
|
|
58
|
+
### Functions `[CI · Review]`
|
|
59
|
+
|
|
60
|
+
- **≤ 4 arguments.** `[CI]`
|
|
61
|
+
- **≤ 30 lines.** `[CI]`
|
|
62
|
+
- **One responsibility per function.** `[Review]`
|
|
63
|
+
- **Never return both `None`/`undefined` and a value** from the same function. `[Review]` (`[CI]` in JS via `consistent-return`)
|
|
64
|
+
|
|
65
|
+
### Error handling `[Review]`
|
|
66
|
+
|
|
67
|
+
- Raise / throw **specific** errors, not generic `Exception` or `Error`.
|
|
68
|
+
- Never swallow silently.
|
|
69
|
+
- Language-specific CI rules are in each language section below.
|
|
70
|
+
|
|
71
|
+
### Tone `[Review]`
|
|
72
|
+
|
|
73
|
+
All non-code text uses **imperative voice, present tense**. No gerunds, no passive, no third-person.
|
|
74
|
+
|
|
75
|
+
- Docstrings → imperative verb, one sentence, trailing period → `Return the contents of a template file.`, not `Returns the contents…` or `Gets the contents…`.
|
|
76
|
+
- Names and labels (e.g. workflow steps, action descriptions, CLI help) → imperative verb + object, no period → `Run quality checks`, not `Runs quality checks` or `Running quality checks`.
|
|
77
|
+
- User-facing messages (error, info, warning) → full sentence, sentence case, trailing period → `Pre-commit not found. Skipping.`, not `pre-commit not found`.
|
|
78
|
+
- Changelog entries under Added / Removed → noun phrase, no verb → `CLI with init and run commands.`, not `Add CLI with…`.
|
|
79
|
+
- Changelog entries under Fixed / Changed → imperative verb → `Restrict trigger to semver tags.`, not `Trigger restricted to…`.
|
|
80
|
+
- No filler, no hedging ("might", "could", "please"), no meta-commentary ("This will…", "Let's…").
|
|
81
|
+
|
|
82
|
+
### Comment rules `[CI · Review]`
|
|
83
|
+
|
|
84
|
+
**Comment on _why_. Never on _what_.** `[Review]`
|
|
85
|
+
|
|
86
|
+
Comment ONLY for one of these five reasons:
|
|
87
|
+
1. Non-obvious behavior
|
|
88
|
+
2. External constraints / API quirks
|
|
89
|
+
3. Deliberate non-obvious decisions / tradeoffs
|
|
90
|
+
4. Known limitations accepted for now
|
|
91
|
+
5. Regex or genuinely complex expressions
|
|
92
|
+
|
|
93
|
+
NEVER comment to:
|
|
94
|
+
- Restate what the code does `[Review]`
|
|
95
|
+
- Restate type information `[Review]`
|
|
96
|
+
- Add section dividers `[CI]`
|
|
97
|
+
|
|
98
|
+
Comment format:
|
|
99
|
+
- Full sentences, capital first letter. `[Review]`
|
|
100
|
+
- Single-line: no trailing period. Multi-line: period on each line. `[CI]`
|
|
101
|
+
- Comment goes on the line **above** the code. **Never inline.** `[CI]`
|
|
102
|
+
- Max 15% comment-to-code ratio per file. `[CI]`
|
|
103
|
+
|
|
104
|
+
### Formatting `[CI]`
|
|
105
|
+
|
|
106
|
+
- No trailing whitespace.
|
|
107
|
+
- Newline at end of every file.
|
|
108
|
+
- The language linter is the source of truth — **never** hand-tweak its output.
|
|
109
|
+
|
|
110
|
+
### Ordering `[Review]`
|
|
111
|
+
|
|
112
|
+
**Alphabetical** unless a stronger ordering exists:
|
|
113
|
+
|
|
114
|
+
- Config and declaration keys → alphabetical.
|
|
115
|
+
- Lists with no natural order → alphabetical.
|
|
116
|
+
- Imports have their own rule (see language sections) — that takes precedence.
|
|
117
|
+
|
|
118
|
+
**Code guidelines** (sections, bullets, sub-bullets) → natural reading order, not alphabetical. Order by what you encounter or do first when reading or writing a file.
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
Sections: Stack → Naming → Imports → Constants → … → Comments → Formatting
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Functions in a module** → callees before callers (leaf-first), grouped by call chain:
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
_parse() ← called by validate
|
|
128
|
+
validate() ← called by main (1st)
|
|
129
|
+
_format() ← called by render
|
|
130
|
+
render() ← called by main (2nd)
|
|
131
|
+
main() ← entry point, always last
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Git
|
|
135
|
+
|
|
136
|
+
- **Never commit to `main`.** Branch first.
|
|
137
|
+
- Commit prefix: `ci`, `docs`, `feat`, `fix`, `init`, `refactor`, `test`.
|
|
138
|
+
- `git commit --no-verify` exists for emergencies but **CI re-runs every check**. Don't use it to dodge a real failure.
|
|
139
|
+
|
|
140
|
+
### Changelog `[Review]`
|
|
141
|
+
|
|
142
|
+
Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Update `CHANGELOG.md` before every version tag.
|
|
143
|
+
|
|
144
|
+
- Categories in this order: **Added**, **Changed**, **Removed**, **Fixed** — include only what applies.
|
|
145
|
+
- Entry tone rules are in the Tone section above.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## CSS rules
|
|
150
|
+
|
|
151
|
+
Apply these when editing `.css` files, in addition to universal rules.
|
|
152
|
+
|
|
153
|
+
### Anti-patterns — DON'T
|
|
154
|
+
|
|
155
|
+
- Deep nesting (> 3 levels) → flatten selectors.
|
|
156
|
+
- ID selectors for styling → use class selectors.
|
|
157
|
+
- Magic numbers (`padding: 37px`) → use custom properties.
|
|
158
|
+
- Qualified selectors (`div.class`) → use class alone.
|
|
159
|
+
- Using `!important` → fix specificity instead.
|
|
160
|
+
|
|
161
|
+
### Naming `[CI · Review]`
|
|
162
|
+
|
|
163
|
+
- Files: `kebab-case`, singular noun. `[Review]`
|
|
164
|
+
- Classes: `kebab-case`. `[CI]`
|
|
165
|
+
- Custom properties: `--kebab-case`. `[CI]`
|
|
166
|
+
|
|
167
|
+
### Custom properties `[CI · Review]`
|
|
168
|
+
|
|
169
|
+
- Local → narrowest applicable scope. `[Review]`
|
|
170
|
+
- Shared → `:root`. `[Review]`
|
|
171
|
+
|
|
172
|
+
### Selectors `[CI · Review]`
|
|
173
|
+
|
|
174
|
+
- Prefer class selectors over element selectors. `[Review]`
|
|
175
|
+
- No ID selectors for styling — use classes instead. `[CI]`
|
|
176
|
+
- No qualified selectors unless specificity requires it. `[CI]`
|
|
177
|
+
- Max 3 levels of nesting. `[CI]`
|
|
178
|
+
- No `!important` — fix specificity instead. `[CI]`
|
|
179
|
+
|
|
180
|
+
### Formatting `[CI]`
|
|
181
|
+
|
|
182
|
+
- One declaration per line.
|
|
183
|
+
- **Double quotes**.
|
|
184
|
+
- `prettier` formats, `stylelint` lints — no manual overrides.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## HTML rules
|
|
189
|
+
|
|
190
|
+
Apply these when editing `.html` files, in addition to universal rules.
|
|
191
|
+
|
|
192
|
+
### Anti-patterns — DON'T
|
|
193
|
+
|
|
194
|
+
- Deprecated elements (`<center>`, `<font>`) → use CSS.
|
|
195
|
+
- `disabled="true"` → just `disabled` (boolean attribute).
|
|
196
|
+
- Generic `<div>` and `<span>` for everything → use semantic elements.
|
|
197
|
+
- Inline event handlers (`onclick`, `onload`) → use JavaScript event listeners.
|
|
198
|
+
- Inline styles → use CSS.
|
|
199
|
+
- Missing `alt` on `<img>` → always provide alt text.
|
|
200
|
+
|
|
201
|
+
### Naming `[CI · Review]`
|
|
202
|
+
|
|
203
|
+
- Files: `kebab-case`, singular noun. `[Review]`
|
|
204
|
+
- Data attributes: `data-kebab-case`. `[CI]`
|
|
205
|
+
|
|
206
|
+
### Elements `[CI · Review]`
|
|
207
|
+
|
|
208
|
+
- Semantic elements over generic `<div>` and `<span>`. `[Review]`
|
|
209
|
+
- No deprecated elements. `[CI]`
|
|
210
|
+
- Alt text on all `<img>` elements. `[CI]`
|
|
211
|
+
- No inline styles. `[CI]`
|
|
212
|
+
- No inline event handlers. `[CI]`
|
|
213
|
+
|
|
214
|
+
### Formatting `[CI]`
|
|
215
|
+
|
|
216
|
+
- Boolean attributes: no value (`disabled`, not `disabled="true"`).
|
|
217
|
+
- Double quotes.
|
|
218
|
+
- `prettier` formats, `htmlhint` lints — no manual overrides.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## JavaScript rules
|
|
223
|
+
|
|
224
|
+
Apply these when editing `.js` files, in addition to universal rules.
|
|
225
|
+
|
|
226
|
+
### Anti-patterns — DON'T
|
|
227
|
+
|
|
228
|
+
- Adding a 5th parameter → wrap in an options object.
|
|
229
|
+
- Double quotes (`"foo"`) → always single.
|
|
230
|
+
- Empty `catch` blocks → re-throw or log.
|
|
231
|
+
- Returning `undefined` from one branch and a value from another → pick one shape.
|
|
232
|
+
- Using `console.log` → use `process.stdout.write` / `process.stderr.write`.
|
|
233
|
+
- Using ESM `import` → use `require` (CommonJS).
|
|
234
|
+
|
|
235
|
+
### Naming `[CI · Review]`
|
|
236
|
+
|
|
237
|
+
- Files: `kebab-case`. Components: singular noun. Scripts: verb phrase. `[Review]`
|
|
238
|
+
- Variables: `camelCase`. `[CI]`
|
|
239
|
+
- Constants: `UPPER_SNAKE_CASE`. `[Review]`
|
|
240
|
+
- Functions: `camelCase`, verb or verb phrase. `[Review]`
|
|
241
|
+
|
|
242
|
+
### Imports `[CI]`
|
|
243
|
+
|
|
244
|
+
- Order: **built-in → third-party → internal**.
|
|
245
|
+
- `require` only, no ESM `import`.
|
|
246
|
+
- No duplicate imports. No unused imports.
|
|
247
|
+
|
|
248
|
+
### Constants `[CI · Review]`
|
|
249
|
+
|
|
250
|
+
- In comparisons. `[CI]`
|
|
251
|
+
|
|
252
|
+
### Functions `[CI · Review]`
|
|
253
|
+
|
|
254
|
+
- 5+ args → use an **options object**. `[Review]`
|
|
255
|
+
|
|
256
|
+
### Error handling `[CI · Review]`
|
|
257
|
+
|
|
258
|
+
- No empty `catch` blocks without re-throwing or logging. `[CI]`
|
|
259
|
+
|
|
260
|
+
### Output `[CI]`
|
|
261
|
+
|
|
262
|
+
- `process.stdout.write` / `process.stderr.write`, not `console.log`.
|
|
263
|
+
|
|
264
|
+
### Formatting `[CI]`
|
|
265
|
+
|
|
266
|
+
- **Single quotes** for all strings.
|
|
267
|
+
- `prettier` formats, `eslint` lints — no manual overrides.
|
|
268
|
+
|
|
269
|
+
### JSDoc `[Review]`
|
|
270
|
+
|
|
271
|
+
- Public functions: one-line JSDoc.
|
|
272
|
+
- Internal functions: no JSDoc.
|
|
273
|
+
|
|
274
|
+
```javascript
|
|
275
|
+
// Public
|
|
276
|
+
/** Return the parsed config from the given file path. */
|
|
277
|
+
function readConfig(configPath) {
|
|
278
|
+
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Internal
|
|
282
|
+
function buildDefaultConfig() {
|
|
283
|
+
return { version: 1, enabled: true };
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Python rules
|
|
290
|
+
|
|
291
|
+
Apply these when editing `.py` files, in addition to universal rules.
|
|
292
|
+
|
|
293
|
+
### Anti-patterns — DON'T
|
|
294
|
+
|
|
295
|
+
- `# noqa` / `# type: ignore` → fix the code, don't suppress.
|
|
296
|
+
- Adding `Args:` / `Returns:` / `Raises:` blocks to docstrings → annotations cover it.
|
|
297
|
+
- Adding a 5th parameter → wrap in a dataclass / Pydantic model.
|
|
298
|
+
- Defining a custom exception outside `exception.py` → all exceptions live there.
|
|
299
|
+
- `from foo import *` or unused imports → both fail CI.
|
|
300
|
+
- Returning `User | None` from one branch and `User` from another → pick one shape.
|
|
301
|
+
- Single quotes (`'foo'`) → always double.
|
|
302
|
+
- Splitting a long function with `# region` / `# step 1` → extract real helpers.
|
|
303
|
+
- `try: ... except Exception: pass` → raise specific, don't swallow.
|
|
304
|
+
|
|
305
|
+
### Naming `[CI · Review]`
|
|
306
|
+
|
|
307
|
+
- Files: `snake_case`, singular noun. `[Review]`
|
|
308
|
+
- Variables: `snake_case`. `[CI]`
|
|
309
|
+
- Constants: `UPPER_SNAKE_CASE`. `[CI]`
|
|
310
|
+
- Classes: `PascalCase`, noun or noun phrase. `[Review]`
|
|
311
|
+
- Functions: `snake_case`, verb or verb phrase. `[Review]`
|
|
312
|
+
|
|
313
|
+
### Imports `[CI]`
|
|
314
|
+
|
|
315
|
+
- Order: **stdlib → third-party → internal**.
|
|
316
|
+
- No wildcard imports. No duplicate imports. No unused imports.
|
|
317
|
+
|
|
318
|
+
### Constants `[CI · Review]`
|
|
319
|
+
|
|
320
|
+
- Shared constants → `constant.py`. `[Review]`
|
|
321
|
+
|
|
322
|
+
### Types `[CI · Review]`
|
|
323
|
+
|
|
324
|
+
- Every function signature fully annotated, **including return type**. `[CI]`
|
|
325
|
+
- Boundary data (API / service / config) → **Pydantic model**. `[Review]`
|
|
326
|
+
- Internal data structures → **dataclass**. `[Review]`
|
|
327
|
+
- `mypy --strict` must pass. `[CI]`
|
|
328
|
+
|
|
329
|
+
### Functions `[CI · Review]`
|
|
330
|
+
|
|
331
|
+
- Return type **always annotated**. `[CI]`
|
|
332
|
+
- 5+ args → wrap in a **dataclass or Pydantic model**. `[Review]`
|
|
333
|
+
|
|
334
|
+
```python
|
|
335
|
+
# Wrong: 5 args
|
|
336
|
+
def send_email(recipient, subject, body, cc, priority):
|
|
337
|
+
...
|
|
338
|
+
|
|
339
|
+
# Right: model
|
|
340
|
+
@dataclass
|
|
341
|
+
class EmailRequest:
|
|
342
|
+
recipient: str
|
|
343
|
+
subject: str
|
|
344
|
+
body: str
|
|
345
|
+
cc: str
|
|
346
|
+
priority: int
|
|
347
|
+
|
|
348
|
+
def send_email(request: EmailRequest) -> bool:
|
|
349
|
+
...
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Error handling `[CI · Review]`
|
|
353
|
+
|
|
354
|
+
- No bare `except:` / `except Exception:` unless you re-raise or log. `[CI]`
|
|
355
|
+
- **Every custom exception class** lives in `exception.py`. `[CI]`
|
|
356
|
+
|
|
357
|
+
```python
|
|
358
|
+
# Wrong
|
|
359
|
+
try:
|
|
360
|
+
response = client.get(url)
|
|
361
|
+
except Exception:
|
|
362
|
+
return None
|
|
363
|
+
|
|
364
|
+
# Right
|
|
365
|
+
try:
|
|
366
|
+
response = client.get(url)
|
|
367
|
+
except TimeoutError as exc:
|
|
368
|
+
raise ServiceTimeout(url) from exc
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Formatting `[CI]`
|
|
372
|
+
|
|
373
|
+
- **One** blank line between methods inside a class.
|
|
374
|
+
- **Two** blank lines between top-level definitions.
|
|
375
|
+
- **Double quotes** for all strings.
|
|
376
|
+
- `ruff format` is final.
|
|
377
|
+
|
|
378
|
+
### Docstrings `[CI · Review]`
|
|
379
|
+
|
|
380
|
+
- **Public functions** → exactly **one line**. `[Review]`
|
|
381
|
+
- **Internal helpers** (`_` prefix) → **no docstring at all**. `[CI]`
|
|
382
|
+
- **No `Args:`, `Returns:`, `Raises:` blocks. Ever.** `[CI]`
|
|
383
|
+
|
|
384
|
+
```python
|
|
385
|
+
# Public
|
|
386
|
+
def find_user(user_id: str) -> User:
|
|
387
|
+
"""Return the user matching the given ID."""
|
|
388
|
+
|
|
389
|
+
# Internal
|
|
390
|
+
def _normalize_email(email: str) -> str:
|
|
391
|
+
return email.strip().lower()
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## Shell rules
|
|
397
|
+
|
|
398
|
+
Apply these when editing `.sh` files, in addition to universal rules.
|
|
399
|
+
|
|
400
|
+
### Anti-patterns — DON'T
|
|
401
|
+
|
|
402
|
+
- Missing `set -e` → every shell file must fail on first error.
|
|
403
|
+
- Missing executable permission → `.sh` files must have `+x`.
|
|
404
|
+
- Silent `exit 1` without a message → print what went wrong first.
|
|
405
|
+
- Unquoted variable expansions (`$VAR` instead of `"$VAR"`) → word splitting bugs.
|
|
406
|
+
- Using `eval` with dynamic input → command injection risk.
|
|
407
|
+
|
|
408
|
+
### Naming `[CI · Review]`
|
|
409
|
+
|
|
410
|
+
- Files: `kebab-case`, verb or verb phrase. `[Review]`
|
|
411
|
+
- Local variables: `lower_snake_case`. `[Review]`
|
|
412
|
+
- Exported/environment variables: `UPPER_SNAKE_CASE`. `[Review]`
|
|
413
|
+
|
|
414
|
+
### Shebangs `[CI]`
|
|
415
|
+
|
|
416
|
+
- `#!/bin/bash` on line 1.
|
|
417
|
+
- `set -e` immediately after.
|
|
418
|
+
|
|
419
|
+
### Constants `[Review]`
|
|
420
|
+
|
|
421
|
+
- No magic numbers or strings. Use named variables.
|
|
422
|
+
|
|
423
|
+
### Error handling `[CI · Review]`
|
|
424
|
+
|
|
425
|
+
- No `eval` with dynamic input. `[CI]`
|
|
426
|
+
- Check file/dir existence before operations. `[Review]`
|
|
427
|
+
- Print a descriptive error message before exiting on failure. `[Review]`
|
|
428
|
+
|
|
429
|
+
### Formatting `[CI]`
|
|
430
|
+
|
|
431
|
+
- Executable permission on all `.sh` files.
|
|
432
|
+
- Quote all variable expansions (`"$VAR"`, not `$VAR`).
|
|
433
|
+
- `shellcheck` is final.
|
careerrag-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Arup Kumar Maiti
|
|
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.
|
careerrag-1.0.0/Makefile
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
.PHONY: setup install check test clean
|
|
2
|
+
|
|
3
|
+
PYTHON := $(shell command -v python3 || command -v python)
|
|
4
|
+
|
|
5
|
+
setup:
|
|
6
|
+
$(PYTHON) -m venv .venv
|
|
7
|
+
.venv/bin/pip install dryclean
|
|
8
|
+
.venv/bin/pip install -e ".[dev]"
|
|
9
|
+
.venv/bin/dryclean init
|
|
10
|
+
@echo "Run 'source .venv/bin/activate' to activate the environment"
|
|
11
|
+
|
|
12
|
+
install:
|
|
13
|
+
.venv/bin/pip install -e ".[dev]"
|
|
14
|
+
|
|
15
|
+
check:
|
|
16
|
+
.venv/bin/dryclean run
|
|
17
|
+
|
|
18
|
+
test:
|
|
19
|
+
.venv/bin/pytest tests/
|
|
20
|
+
|
|
21
|
+
clean:
|
|
22
|
+
rm -rf *.egg-info/ .careerrag/ .mypy_cache/ .pytest_cache/ .ruff_cache/ build/ dist/
|