blumkin 0.2.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.
- blumkin-0.2.0/.cursor/rules/git-commit-identity.mdc +156 -0
- blumkin-0.2.0/.cursor/rules/lexicographic-code-organization.mdc +95 -0
- blumkin-0.2.0/.cursor/rules/local-live-graph-tests.mdc +33 -0
- blumkin-0.2.0/.cursor/rules/main-worktree-off-limits.mdc +38 -0
- blumkin-0.2.0/.cursor/rules/no-secret-exposure.mdc +46 -0
- blumkin-0.2.0/.cursor/rules/no-third-party-side-effects.mdc +71 -0
- blumkin-0.2.0/.cursor/rules/pr-ship-and-review.mdc +125 -0
- blumkin-0.2.0/.cursor/rules/pre-pr-checks.mdc +67 -0
- blumkin-0.2.0/.cursor/rules/read-agents-and-rules.mdc +21 -0
- blumkin-0.2.0/.cursor/rules/remote-timeouts-retries.mdc +66 -0
- blumkin-0.2.0/.cursor/rules/repo-practices-after-config-change.mdc +59 -0
- blumkin-0.2.0/.cursor/rules/stacking-tool.mdc +56 -0
- blumkin-0.2.0/.cursor/skills/blumkin/SKILL.md +241 -0
- blumkin-0.2.0/.github/CODEOWNERS +7 -0
- blumkin-0.2.0/.github/ci/assert-uv-lock-version +54 -0
- blumkin-0.2.0/.github/ci/pytest-hermetic +6 -0
- blumkin-0.2.0/.github/ci/python-static +11 -0
- blumkin-0.2.0/.github/ci/secret-scan +212 -0
- blumkin-0.2.0/.github/ci/setup-python +10 -0
- blumkin-0.2.0/.github/ci/shellcheck +37 -0
- blumkin-0.2.0/.github/copilot-instructions.md +10 -0
- blumkin-0.2.0/.github/dependabot.yml +24 -0
- blumkin-0.2.0/.github/secret-audit.json +1 -0
- blumkin-0.2.0/.github/stacking-tool +1 -0
- blumkin-0.2.0/.github/workflows/ci.yml +215 -0
- blumkin-0.2.0/.github/workflows/cleanup-branch-on-merge.yml +25 -0
- blumkin-0.2.0/.github/workflows/cleanup-merged-branches.yml +109 -0
- blumkin-0.2.0/.github/workflows/cve-check.yml +195 -0
- blumkin-0.2.0/.github/workflows/dependabot-auto-merge.yml +25 -0
- blumkin-0.2.0/.github/workflows/merged-pr-closer.yml +135 -0
- blumkin-0.2.0/.github/workflows/release-please.yml +216 -0
- blumkin-0.2.0/.gitignore +16 -0
- blumkin-0.2.0/.python-version +1 -0
- blumkin-0.2.0/.release-please-manifest.json +3 -0
- blumkin-0.2.0/AGENTS.md +172 -0
- blumkin-0.2.0/CHANGELOG.md +85 -0
- blumkin-0.2.0/CLAUDE.md +9 -0
- blumkin-0.2.0/HANDOFF.md +114 -0
- blumkin-0.2.0/LICENSE +21 -0
- blumkin-0.2.0/PKG-INFO +235 -0
- blumkin-0.2.0/PLAN.md +552 -0
- blumkin-0.2.0/README.md +201 -0
- blumkin-0.2.0/RETROSPECTIVE-M1.md +79 -0
- blumkin-0.2.0/docs/RELEASING.md +67 -0
- blumkin-0.2.0/docs/agent-integration.md +409 -0
- blumkin-0.2.0/docs/google-setup.md +293 -0
- blumkin-0.2.0/pyproject.toml +85 -0
- blumkin-0.2.0/release-please-config.json +17 -0
- blumkin-0.2.0/scripts/embed_build_metadata +78 -0
- blumkin-0.2.0/scripts/verify-pypi-release +110 -0
- blumkin-0.2.0/src/blumkin/__init__.py +9 -0
- blumkin-0.2.0/src/blumkin/__main__.py +8 -0
- blumkin-0.2.0/src/blumkin/_build_metadata.py +6 -0
- blumkin-0.2.0/src/blumkin/attachments.py +98 -0
- blumkin-0.2.0/src/blumkin/auth.py +373 -0
- blumkin-0.2.0/src/blumkin/cli.py +2737 -0
- blumkin-0.2.0/src/blumkin/config.py +592 -0
- blumkin-0.2.0/src/blumkin/exit_codes.py +10 -0
- blumkin-0.2.0/src/blumkin/graph.py +50 -0
- blumkin-0.2.0/src/blumkin/help_text.py +722 -0
- blumkin-0.2.0/src/blumkin/output.py +53 -0
- blumkin-0.2.0/src/blumkin/pipx_install.py +64 -0
- blumkin-0.2.0/src/blumkin/providers/__init__.py +56 -0
- blumkin-0.2.0/src/blumkin/providers/google/__init__.py +1 -0
- blumkin-0.2.0/src/blumkin/providers/google/calendar.py +540 -0
- blumkin-0.2.0/src/blumkin/providers/google/chat.py +584 -0
- blumkin-0.2.0/src/blumkin/providers/google/mail.py +640 -0
- blumkin-0.2.0/src/blumkin/providers/google/mail_writes.py +717 -0
- blumkin-0.2.0/src/blumkin/providers/google/people.py +248 -0
- blumkin-0.2.0/src/blumkin/providers/google_auth.py +312 -0
- blumkin-0.2.0/src/blumkin/providers/google_http.py +72 -0
- blumkin-0.2.0/src/blumkin/providers/google_provider.py +445 -0
- blumkin-0.2.0/src/blumkin/providers/kind.py +29 -0
- blumkin-0.2.0/src/blumkin/providers/microsoft.py +468 -0
- blumkin-0.2.0/src/blumkin/providers/protocol.py +258 -0
- blumkin-0.2.0/src/blumkin/skills/__init__.py +882 -0
- blumkin-0.2.0/src/blumkin/skills/calendar.py +708 -0
- blumkin-0.2.0/src/blumkin/skills/calendar_writes.py +248 -0
- blumkin-0.2.0/src/blumkin/skills/chat.py +826 -0
- blumkin-0.2.0/src/blumkin/skills/freebusy_suggest.py +58 -0
- blumkin-0.2.0/src/blumkin/skills/mail.py +1961 -0
- blumkin-0.2.0/src/blumkin/skills/meeting.py +135 -0
- blumkin-0.2.0/src/blumkin/skills/people.py +171 -0
- blumkin-0.2.0/src/blumkin/version.py +158 -0
- blumkin-0.2.0/test_packaging +104 -0
- blumkin-0.2.0/tests/conftest.py +26 -0
- blumkin-0.2.0/tests/test_auth_refresh_unit.py +167 -0
- blumkin-0.2.0/tests/test_auth_scopes.py +81 -0
- blumkin-0.2.0/tests/test_auth_secret_perms_unit.py +136 -0
- blumkin-0.2.0/tests/test_auth_status.py +32 -0
- blumkin-0.2.0/tests/test_calendar_suggest_unit.py +403 -0
- blumkin-0.2.0/tests/test_calendar_timezone_unit.py +127 -0
- blumkin-0.2.0/tests/test_calendar_today_unit.py +49 -0
- blumkin-0.2.0/tests/test_chat_attachments_unit.py +491 -0
- blumkin-0.2.0/tests/test_cli_completion_unit.py +43 -0
- blumkin-0.2.0/tests/test_cli_help.py +153 -0
- blumkin-0.2.0/tests/test_cli_usage.py +1598 -0
- blumkin-0.2.0/tests/test_config.py +368 -0
- blumkin-0.2.0/tests/test_error_hints_unit.py +173 -0
- blumkin-0.2.0/tests/test_google_calendar_writes_unit.py +479 -0
- blumkin-0.2.0/tests/test_google_chat_reads_unit.py +315 -0
- blumkin-0.2.0/tests/test_google_chat_writes_unit.py +426 -0
- blumkin-0.2.0/tests/test_google_http_unit.py +72 -0
- blumkin-0.2.0/tests/test_google_mail_reads_unit.py +371 -0
- blumkin-0.2.0/tests/test_google_mail_writes_unit.py +828 -0
- blumkin-0.2.0/tests/test_google_people_unit.py +266 -0
- blumkin-0.2.0/tests/test_google_provider_unit.py +831 -0
- blumkin-0.2.0/tests/test_graph_request_config_unit.py +32 -0
- blumkin-0.2.0/tests/test_graph_timeout_unit.py +41 -0
- blumkin-0.2.0/tests/test_json_envelope_unit.py +98 -0
- blumkin-0.2.0/tests/test_live_reads.py +86 -0
- blumkin-0.2.0/tests/test_logout_cache.py +36 -0
- blumkin-0.2.0/tests/test_mail_attach_unit.py +356 -0
- blumkin-0.2.0/tests/test_mail_attachments_unit.py +651 -0
- blumkin-0.2.0/tests/test_mail_filters_unit.py +716 -0
- blumkin-0.2.0/tests/test_mail_folders_unit.py +476 -0
- blumkin-0.2.0/tests/test_mail_get_unit.py +258 -0
- blumkin-0.2.0/tests/test_mail_recipients_unit.py +205 -0
- blumkin-0.2.0/tests/test_mail_reply_unit.py +475 -0
- blumkin-0.2.0/tests/test_mail_signature_reapply_unit.py +159 -0
- blumkin-0.2.0/tests/test_mail_signature_unit.py +160 -0
- blumkin-0.2.0/tests/test_people_resolve_unit.py +494 -0
- blumkin-0.2.0/tests/test_phase2_reads_unit.py +762 -0
- blumkin-0.2.0/tests/test_phase3_writes_unit.py +1130 -0
- blumkin-0.2.0/tests/test_phase4_writes_unit.py +362 -0
- blumkin-0.2.0/tests/test_profile_email_unit.py +361 -0
- blumkin-0.2.0/tests/test_providers_unit.py +127 -0
- blumkin-0.2.0/tests/test_release_config_unit.py +37 -0
- blumkin-0.2.0/tests/test_skills_catalog.py +28 -0
- blumkin-0.2.0/tests/test_skills_schema.py +408 -0
- blumkin-0.2.0/tests/test_upgrade_unit.py +263 -0
- blumkin-0.2.0/tests/test_version_unit.py +119 -0
- blumkin-0.2.0/uv.lock +1217 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Commits and PRs attribute only the committer — no agent or machine co-authors
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Git commit identity
|
|
7
|
+
|
|
8
|
+
Commits and pull requests must attribute **only** whoever is making the commit —
|
|
9
|
+
their configured git `user.name` and `user.email`. Do not leak hostnames, Cursor,
|
|
10
|
+
or other co-authors.
|
|
11
|
+
|
|
12
|
+
## Commits
|
|
13
|
+
|
|
14
|
+
- Use plain `git commit -m "…"` or a HEREDOC with **subject and body only**.
|
|
15
|
+
- Do **not** add `Co-authored-by`, `Made-with: Cursor`, or any `--trailer` flags.
|
|
16
|
+
- Do **not** append attribution lines to commit messages, even if Cursor defaults
|
|
17
|
+
would add them.
|
|
18
|
+
- Do **not** pass `--no-gpg-sign` (or otherwise skip signing) when `commit.gpgsign`
|
|
19
|
+
is enabled.
|
|
20
|
+
- After any commit (hooks / tooling may rewrite the message), inspect
|
|
21
|
+
`git show -s --format=%B HEAD` before push. If it contains `Co-authored-by:` or
|
|
22
|
+
`Made-with:`, **stop**, fix the message, and do not push until clean.
|
|
23
|
+
- Prefer `git verify-commit HEAD` after signing commits; confirm GitHub shows the
|
|
24
|
+
commit as Verified once pushed.
|
|
25
|
+
|
|
26
|
+
## Pull requests
|
|
27
|
+
|
|
28
|
+
- Do **not** add `Co-authored-by` or `Made-with: Cursor` to `gh pr create --body`
|
|
29
|
+
or `gh pr edit --body`.
|
|
30
|
+
|
|
31
|
+
## Git identity
|
|
32
|
+
|
|
33
|
+
- Rely on git's configured author for the current committer (`git config user.name`
|
|
34
|
+
and `git config user.email`). Do not hardcode a specific name or email.
|
|
35
|
+
- If `user.email` is unset, stop and ask the committer to configure git before
|
|
36
|
+
committing (avoid hostname fallback addresses like `user@machine.local`).
|
|
37
|
+
- Also survey **effective** identity (env overrides beat config): compare
|
|
38
|
+
`git var GIT_AUTHOR_IDENT` and `git var GIT_COMMITTER_IDENT` to the approved
|
|
39
|
+
GitHub name/email. Reject machine-local addresses (e.g. `*.local`) and stop if
|
|
40
|
+
`GIT_AUTHOR_*`, `GIT_COMMITTER_*`, `EMAIL`, or `git commit --author` would produce
|
|
41
|
+
a different identity than configured.
|
|
42
|
+
|
|
43
|
+
## Commit signing (GPG / SSH)
|
|
44
|
+
|
|
45
|
+
At the **start of any session where the agent may commit**, survey whether commit
|
|
46
|
+
signing is set up for the committer:
|
|
47
|
+
|
|
48
|
+
1. `git config --get commit.gpgsign` should be `true` (global or local, as they intend).
|
|
49
|
+
2. `git config --get user.signingkey` should be set (GPG key id, or SSH public key
|
|
50
|
+
path when `gpg.format` is `ssh`).
|
|
51
|
+
3. Check `git config --get gpg.format` (and any repo-local override). For GPG
|
|
52
|
+
signing, prefer `openpgp` (or unset). If a leftover `gpg.format=ssh` is set
|
|
53
|
+
while `user.signingkey` is a GPG key id, Git will mis-treat the key — set
|
|
54
|
+
`gpg.format` to `openpgp` (or unset ssh) before committing.
|
|
55
|
+
4. If `gpg.format` is `ssh`, confirm the public key path exists **and** the matching
|
|
56
|
+
private key is loaded (`ssh-add -L` should list it), or run a real signed-commit
|
|
57
|
+
probe. Otherwise confirm `gpg --list-secret-keys --keyid-format=long <signingkey>`
|
|
58
|
+
succeeds (secret present on **this** host).
|
|
59
|
+
5. On Darwin (GPG): `pinentry-program` in `~/.gnupg/gpg-agent.conf` should point at an
|
|
60
|
+
existing binary (prefer `pinentry-mac` from Homebrew).
|
|
61
|
+
6. Optional one-shot probe: `echo test | gpg --clearsign -u <KEYID>`. If it hangs or
|
|
62
|
+
fails in the agent TTY, tell the operator to unlock via GUI pinentry or finish the
|
|
63
|
+
commit in Terminal.app — agent terminals often cannot drive curses pinentry.
|
|
64
|
+
7. GitHub Verified checks depend on signing format:
|
|
65
|
+
- **OpenPGP** (`gpg.format` is `openpgp` or unset): the **committer email** must
|
|
66
|
+
appear on the GPG key UID and be a **verified** email on the GitHub account
|
|
67
|
+
(same value as `git config user.email`). Optional list check:
|
|
68
|
+
`gh api user/gpg_keys` (needs `read:gpg_key`; `admin:gpg_key` also works). If the
|
|
69
|
+
API is unavailable, guide manual paste of `gpg --armor --export <KEYID>`.
|
|
70
|
+
- **SSH** (`gpg.format=ssh`): UID / `user/gpg_keys` do **not** apply. Confirm the
|
|
71
|
+
configured public key is registered on GitHub as a **Signing Key** (not only
|
|
72
|
+
Authentication) and that `ssh-add -L` lists the matching private key.
|
|
73
|
+
|
|
74
|
+
If signing is missing or incomplete, **alert the committer** and surface setup
|
|
75
|
+
instructions before committing (unless they explicitly opt out for a one-off).
|
|
76
|
+
|
|
77
|
+
### Per-machine / personal vs work keys
|
|
78
|
+
|
|
79
|
+
- Prefer a **separate signing key per machine** (or at least personal vs work). Do
|
|
80
|
+
**not** export a personal laptop’s secret key onto a corporate device.
|
|
81
|
+
- Match `user.name` / `user.email` to the GitHub identity. For OpenPGP, put that same
|
|
82
|
+
verified email in the GPG UID; upload **that** public key to GitHub → Settings →
|
|
83
|
+
SSH and GPG keys. For SSH signing, upload the public key as a Signing Key.
|
|
84
|
+
- When a work machine is retired, revoke/rotate that machine’s key on GitHub and
|
|
85
|
+
remove the local secret.
|
|
86
|
+
|
|
87
|
+
### Passphrase
|
|
88
|
+
|
|
89
|
+
- **Recommend using a passphrase** on the signing key (protects the secret at rest;
|
|
90
|
+
`gpg-agent` can cache it with `default-cache-ttl` / `max-cache-ttl`).
|
|
91
|
+
- Do **not** suggest empty-passphrase keys “for agent convenience.”
|
|
92
|
+
- Agent / non-TTY sessions usually cannot drive curses pinentry — use GUI
|
|
93
|
+
`pinentry-mac` (macOS) or commit from Terminal.app after unlocking once.
|
|
94
|
+
|
|
95
|
+
### GPG key (macOS / Homebrew)
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
brew install gnupg pinentry-mac
|
|
99
|
+
# If brew cannot link into /opt/homebrew/bin (ownership / permissions), fix Homebrew
|
|
100
|
+
# ownership for that prefix or use the full $(brew --prefix)/bin path below.
|
|
101
|
+
|
|
102
|
+
mkdir -p ~/.gnupg
|
|
103
|
+
chmod 700 ~/.gnupg
|
|
104
|
+
echo "pinentry-program $(brew --prefix)/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf
|
|
105
|
+
# optional passphrase cache (seconds), so you are not prompted every commit:
|
|
106
|
+
# echo "default-cache-ttl 28800" >> ~/.gnupg/gpg-agent.conf
|
|
107
|
+
# echo "max-cache-ttl 86400" >> ~/.gnupg/gpg-agent.conf
|
|
108
|
+
gpgconf --kill gpg-agent
|
|
109
|
+
|
|
110
|
+
gpg --full-generate-key
|
|
111
|
+
# Choose RSA (or default), key size ≥ 3072, set an expiration, and use a passphrase.
|
|
112
|
+
# UID email must be a GitHub-verified address matching git config user.email.
|
|
113
|
+
gpg --list-secret-keys --keyid-format=long
|
|
114
|
+
git config --global gpg.format openpgp
|
|
115
|
+
git config --global user.signingkey <KEYID>
|
|
116
|
+
git config --global commit.gpgsign true
|
|
117
|
+
# Clear a leftover repo-local ssh signing override if present:
|
|
118
|
+
# git config --unset gpg.format # run inside the repo if it forced ssh
|
|
119
|
+
gpg --armor --export <KEYID>
|
|
120
|
+
# Upload the armored public key: GitHub → Settings → SSH and GPG keys → New GPG key
|
|
121
|
+
|
|
122
|
+
# Sanity check (GUI pinentry should appear if the agent needs the passphrase):
|
|
123
|
+
echo test | gpg --clearsign -u <KEYID>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### SSH signing (alternative)
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
git config --global gpg.format ssh
|
|
130
|
+
git config --global user.signingkey ~/.ssh/id_ed25519.pub
|
|
131
|
+
git config --global commit.gpgsign true
|
|
132
|
+
ssh-add -L # private key must be available via ssh-agent
|
|
133
|
+
# Add the same public key on GitHub as a Signing Key (not only Authentication)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Cursor CLI attribution (per machine)
|
|
137
|
+
|
|
138
|
+
At the **start of any session where the agent may commit or open PRs**, read
|
|
139
|
+
`~/.cursor/cli-config.json` (if present) and verify attribution is disabled:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
"attribution": {
|
|
143
|
+
"attributeCommitsToAgent": false,
|
|
144
|
+
"attributePRsToAgent": false
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
If the file is missing, unreadable, or either flag is not `false`, **alert the
|
|
149
|
+
committer** before committing and surface setup instructions — explain that Cursor
|
|
150
|
+
will inject co-author trailers unless they fix their local config. Provide the
|
|
151
|
+
exact keys to set (or create the file with the block above). Also remind them to
|
|
152
|
+
disable **Settings → Git & PRs → Attribution** in the Cursor IDE (IDE and CLI
|
|
153
|
+
settings are separate).
|
|
154
|
+
|
|
155
|
+
Do not commit on their behalf until they acknowledge or fix the config (unless
|
|
156
|
+
they explicitly opt out for a one-off commit).
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Lexicographic code organization — public then private; sorted closed sets
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Lexicographic code organization
|
|
7
|
+
|
|
8
|
+
**Default:** sort **ASCII lexicographically by name** whenever possible. **Insert** new
|
|
9
|
+
definitions and closed-set members in sorted position — do not append at the bottom of a
|
|
10
|
+
block.
|
|
11
|
+
|
|
12
|
+
Keep language-standard import / `from … import` blocks at the top of the module (e.g. PEP 8
|
|
13
|
+
for Python); they are not part of the public/private sorts below.
|
|
14
|
+
|
|
15
|
+
## Module level
|
|
16
|
+
|
|
17
|
+
Two blocks, in order:
|
|
18
|
+
|
|
19
|
+
1. **Public** — module-level names **without** a leading `_`: constants (`ALL_CAPS`),
|
|
20
|
+
classes, module-level functions (`def` / `async def`), and other public bindings. Sort
|
|
21
|
+
**within this block** by name (ASCII).
|
|
22
|
+
2. **Private** — module-level names **with** a leading `_` (helpers, module-private
|
|
23
|
+
constants, etc.). Sort **within this block** by name (ASCII).
|
|
24
|
+
|
|
25
|
+
Public names are **not** interleaved with private names by strict global ASCII
|
|
26
|
+
(`build_foo` stays in the public block even though `_` sorts before `b`).
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
# public block (sorted)
|
|
30
|
+
DEFAULT_TIMEOUT_S = 30
|
|
31
|
+
class Widget: ...
|
|
32
|
+
def build_status() -> None: ...
|
|
33
|
+
|
|
34
|
+
# private block (sorted)
|
|
35
|
+
def _epoch_to_iso_z(epoch: float) -> str: ...
|
|
36
|
+
def _format_label(dt: datetime) -> str: ...
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
When adding a new `_helper`, insert it among the other `_` names — not after the public
|
|
40
|
+
APIs and not at the end of the file unless it sorts last in the private block.
|
|
41
|
+
|
|
42
|
+
## Inside a `class`
|
|
43
|
+
|
|
44
|
+
Two blocks, in order:
|
|
45
|
+
|
|
46
|
+
1. **Public** — class-level members whose names do **not** start with `_`, including
|
|
47
|
+
methods, `@property` getters, constants, nested classes, and other bindings. Treat
|
|
48
|
+
`async def` like `def`. Dunder methods (`__init__`, `__str__`, …) live in this block and
|
|
49
|
+
participate in the same lexicographic sort.
|
|
50
|
+
2. **Private** — class-level members whose names start with `_` (single leading underscore),
|
|
51
|
+
including methods, properties, constants, nested classes, and other bindings. Sort
|
|
52
|
+
lexicographically within this block.
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
class Example:
|
|
56
|
+
def __init__(self) -> None: ...
|
|
57
|
+
def __str__(self) -> str: ...
|
|
58
|
+
def close(self) -> None: ...
|
|
59
|
+
def fetch(self) -> None: ...
|
|
60
|
+
|
|
61
|
+
def _validate(self) -> None: ...
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Closed-set literals
|
|
65
|
+
|
|
66
|
+
For **unordered** closed name sets, keep members in **ASCII lexicographic order** and insert
|
|
67
|
+
new members in sorted position (do not append):
|
|
68
|
+
|
|
69
|
+
- `frozenset({...})` / `set` literals of names
|
|
70
|
+
|
|
71
|
+
For **order-sensitive** declarations, preserve declaration order when it is part of the
|
|
72
|
+
contract (enum auto-values, iteration/serialization order, or user-visible sequencing). Sort
|
|
73
|
+
lexicographically only when order is not significant:
|
|
74
|
+
|
|
75
|
+
- Enum members — sort when values/iteration order are not contractual; otherwise keep
|
|
76
|
+
declaration order
|
|
77
|
+
- Tuple / list constants of identifier-like strings — sort when order is not observable
|
|
78
|
+
externally; otherwise keep declaration order
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
# good — unordered name set
|
|
82
|
+
ALLOWED = frozenset({"alpha", "beta", "gamma"})
|
|
83
|
+
|
|
84
|
+
# bad — unsorted / append-only unordered set
|
|
85
|
+
ALLOWED = frozenset({"gamma", "alpha", "beta"})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Other languages
|
|
89
|
+
|
|
90
|
+
Apply the same **public-then-private, lexicographic within each block** idea elsewhere when
|
|
91
|
+
organizing code (e.g. grouped `const` / `enum` members in TypeScript, export blocks in TS
|
|
92
|
+
modules) unless a file already documents a different stable layout.
|
|
93
|
+
|
|
94
|
+
Whole-file reorders of legacy modules are optional drive-by refactors; **new and moved APIs
|
|
95
|
+
must follow this rule in the block they belong to.**
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Run live Graph/auth tests locally (CI mocks only)
|
|
3
|
+
globs: src/blumkin/auth.py,src/blumkin/graph.py,src/blumkin/skills/**/*.py,tests/test_auth*.py,tests/test_live*.py
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Local live Graph / auth tests
|
|
8
|
+
|
|
9
|
+
CI runs **mocked** unit tests only (`pytest -m 'not live'`). Silent refresh and real Graph reads are validated **on this machine**.
|
|
10
|
+
|
|
11
|
+
Live means **real**: never verify with a skill that notifies others (no invites,
|
|
12
|
+
sends, or chats). See `.cursor/rules/no-third-party-side-effects.mdc`.
|
|
13
|
+
|
|
14
|
+
When changing auth, Graph client, calendar/mail/chat skills, or live/auth tests:
|
|
15
|
+
|
|
16
|
+
1. Unit (same as CI):
|
|
17
|
+
```bash
|
|
18
|
+
uv run pytest -m 'not live'
|
|
19
|
+
```
|
|
20
|
+
2. Live reads + forced access-token expiry → silent refresh:
|
|
21
|
+
```bash
|
|
22
|
+
BLUMKIN_LIVE=1 uv run pytest -m live
|
|
23
|
+
```
|
|
24
|
+
Requires config + token cache + auth record with a refresh token under
|
|
25
|
+
`~/.config/blumkin/` (or `BLUMKIN_CONFIG_DIR`). Do not commit those files.
|
|
26
|
+
|
|
27
|
+
3. Smoke CLI after live green:
|
|
28
|
+
```bash
|
|
29
|
+
blumkin auth status
|
|
30
|
+
blumkin calendar today --json
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Do not skip step 2 for auth/token-cache changes: the live test force-expires the cached access token and asserts Graph still works and `auth status` shows a future expiry.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Never modify the primary (main) git worktree unless the user explicitly authorizes it
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Main worktree is off-limits
|
|
7
|
+
|
|
8
|
+
The **primary clone** at the repo root (first line of `git worktree list`) is the **main worktree**. Do **not** modify it unless the user explicitly authorizes that in the current conversation.
|
|
9
|
+
|
|
10
|
+
## Do all work in a stack worktree
|
|
11
|
+
|
|
12
|
+
1. Run `~/work/ai/repository-helpers/scripts/dev/start-development --worktree <stack-name> --no-interactive`.
|
|
13
|
+
2. `cd` into `.worktrees/<stack-name>-wt` before any implementation, tests, or git writes.
|
|
14
|
+
3. Point tools at the stack worktree (`--dir`, working directory, file paths).
|
|
15
|
+
|
|
16
|
+
## Forbidden on the main worktree (without explicit user authorization)
|
|
17
|
+
|
|
18
|
+
- File edits, dependency installs, tests, builds, linters, formatters
|
|
19
|
+
- `dep-updater --dir <repo-root>` (fast-forwards the primary clone and changes git state)
|
|
20
|
+
- `gh stack …` / commits / checkouts / other git write operations
|
|
21
|
+
- Leaving uncommitted changes or stray branches
|
|
22
|
+
|
|
23
|
+
## Read-only on main is OK
|
|
24
|
+
|
|
25
|
+
`git log`, `git show`, `gh pr view`, and reading files without writing are fine on the main worktree.
|
|
26
|
+
|
|
27
|
+
## Investigating without polluting main
|
|
28
|
+
|
|
29
|
+
Use a detached temporary worktree, not the primary clone:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
git worktree add --detach /tmp/repo-inspect-<id> origin/main
|
|
33
|
+
# ... read-only or isolated experiments ...
|
|
34
|
+
git worktree remove --force /tmp/repo-inspect-<id>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`start-development` may sync the main worktree for environment setup; that does **not** grant permission to implement or run mutating commands there.
|
|
38
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Never expose secrets in logs, PRs, tool output, or the repo
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# No secret exposure (logs, PRs, repo)
|
|
7
|
+
|
|
8
|
+
Coding agents must not leak secrets into **any** channel: shell/tool output,
|
|
9
|
+
transcripts, PR/issue text, review replies, commits, fixtures, or docs.
|
|
10
|
+
|
|
11
|
+
This complements CI secret-scan (detection after the fact). Prefer prevention.
|
|
12
|
+
|
|
13
|
+
Org tracking / template sync: [repository-helpers#566](https://github.com/the-hcma/repository-helpers/issues/566).
|
|
14
|
+
|
|
15
|
+
## Never print or paste
|
|
16
|
+
|
|
17
|
+
- Client secrets, passwords, API keys, PATs, webhook secrets
|
|
18
|
+
- Access / refresh tokens, MSAL / auth record JSON, private keys
|
|
19
|
+
- Full contents of `~/.config/blumkin/config.toml`, `.env`, or token-cache files
|
|
20
|
+
- Raw `Authorization` headers or Graph/MSAL error bodies that embed tokens
|
|
21
|
+
|
|
22
|
+
## When inspecting local config
|
|
23
|
+
|
|
24
|
+
- Prefer **allowlisted non-secret keys** only (`tenant_id`, `default_tz`,
|
|
25
|
+
`provider`, `wo1162425_scopes`, path existence flags).
|
|
26
|
+
- Redact values that might be sensitive: `client_id = "(redacted)"`.
|
|
27
|
+
- Do **not** `cat` / `type` whole config or env dumps “for debugging.”
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# bad — may dump client_secret / tokens into the transcript
|
|
31
|
+
cat ~/.config/blumkin/config.toml
|
|
32
|
+
|
|
33
|
+
# good — keys only, redact known secret-ish values
|
|
34
|
+
rg -n '^[a-z_]+' ~/.config/blumkin/config.toml | sed -E 's/(client_id|client_secret|google_oauth_client_file|.*token.*)\s*=.*/\1 = "(redacted)"/I'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Repo / PR hygiene
|
|
38
|
+
|
|
39
|
+
- Never commit secrets, `.msal_token_cache.json`, `.auth_record.json`, `.env`.
|
|
40
|
+
- Never put secret values in PR titles, bodies, comments, or review replies.
|
|
41
|
+
- Test fixtures use obvious fakes (`test-client`, `not-a-secret`).
|
|
42
|
+
|
|
43
|
+
## If something already leaked
|
|
44
|
+
|
|
45
|
+
Tell the operator to **rotate** the credential. Do **not** repeat the secret
|
|
46
|
+
value in chat, logs, or GitHub.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Never let local verification reach other people (no invites, mail, or chats)
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Local verification must not reach other people
|
|
7
|
+
|
|
8
|
+
blumkin acts as the operator against their real mailbox, calendar, and Teams. A
|
|
9
|
+
verification run is not a sandbox: anything it sends is indistinguishable from the
|
|
10
|
+
operator doing it by hand, lands in someone else's inbox or calendar, and cannot be
|
|
11
|
+
recalled.
|
|
12
|
+
|
|
13
|
+
**Never invoke a skill that notifies others in order to test, verify, demo, or
|
|
14
|
+
reproduce something.** Do it only when the operator asks for that specific action
|
|
15
|
+
in the current conversation, on the real recipients they named.
|
|
16
|
+
|
|
17
|
+
## The trip-wire
|
|
18
|
+
|
|
19
|
+
`blumkin skills list --json` marks every skill with `notifies_others`. Treat
|
|
20
|
+
`notifies_others: true` as off-limits for verification. **The flag is
|
|
21
|
+
authoritative** — the list below is a snapshot, so re-read the catalog rather
|
|
22
|
+
than trusting it to stay complete. At the time of writing:
|
|
23
|
+
|
|
24
|
+
- `calendar.accept` — sends a response to the organizer
|
|
25
|
+
- `calendar.cancel` — sends cancellations to every attendee
|
|
26
|
+
- `calendar.create` — invites attendees
|
|
27
|
+
- `chat.delete` — every participant sees the message vanish
|
|
28
|
+
- `chat.edit` — rewrites a message other people already read
|
|
29
|
+
- `chat.send` — messages a person
|
|
30
|
+
- `mail.send-draft` — sends mail
|
|
31
|
+
|
|
32
|
+
To check the current set without trusting this list:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
blumkin skills list --json | jq -r '.skills[] | select(.notifies_others) | .id'
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Absence of the flag is not a blank cheque: `mail.draft`, `mail.update-draft`, and
|
|
39
|
+
`mail.delete-draft` are safe because they stay in the operator's own mailbox, and
|
|
40
|
+
that is the actual test — *does this reach anyone else?*
|
|
41
|
+
|
|
42
|
+
## Verify with reads instead
|
|
43
|
+
|
|
44
|
+
Reads cover most behavior, cost nothing, and reach no one:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
blumkin calendar today --json
|
|
48
|
+
blumkin calendar view --from YYYY-MM-DD --to YYYY-MM-DD --json
|
|
49
|
+
blumkin mail list --folder sentitems --top 5 --json
|
|
50
|
+
blumkin mail folders --json
|
|
51
|
+
blumkin chat find --with "Name" --json
|
|
52
|
+
blumkin chat last --with "Name" --n 3 --json
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
To exercise a write path, prefer one that is self-contained and reversible:
|
|
56
|
+
create a draft, inspect it, delete it. Never promote that to a send.
|
|
57
|
+
|
|
58
|
+
For anything genuinely unreachable without notifying someone, verify with mocked
|
|
59
|
+
unit tests and say plainly that the live path was not exercised. An honest gap
|
|
60
|
+
beats a real invitation.
|
|
61
|
+
|
|
62
|
+
## If a notifying action is explicitly requested
|
|
63
|
+
|
|
64
|
+
Confirm the recipients and the exact payload before running it, pass `--yes`
|
|
65
|
+
knowingly rather than reflexively, and never widen the recipient list to make a
|
|
66
|
+
test more convincing.
|
|
67
|
+
|
|
68
|
+
## Free/busy and other people's data
|
|
69
|
+
|
|
70
|
+
`calendar.freebusy` reads other people's availability. It notifies no one, so it
|
|
71
|
+
is fine — but do not spray it across colleagues to generate test fixtures.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Ship a PR end-to-end — local gates, submit, agent review loop, operator email
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PR ship, agent review, and operator email
|
|
7
|
+
|
|
8
|
+
When the user asks to **ship**, **submit**, **open a PR**, or **follow the flow**, run this
|
|
9
|
+
sequence in a **stack worktree** (never the primary clone). Read `.github/stacking-tool` and
|
|
10
|
+
`.cursor/rules/stacking-tool.mdc` before creating branches or submitting.
|
|
11
|
+
|
|
12
|
+
Helper scripts live in **repository-helpers** (canonical agent review loop):
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
rh="${REPOSITORY_HELPERS_DIR:-$HOME/work/ai/repository-helpers}"
|
|
16
|
+
"${rh}/scripts/wait-for-agent-review" …
|
|
17
|
+
"${rh}/scripts/trigger-agent-review" …
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Configure `~/.config/agent-review.env` from `${rh}/etc/agent-review.env.example` (`AGENT_REVIEW_REPORT_TO`, SMTP).
|
|
21
|
+
|
|
22
|
+
<!-- pr-ship-canonical-skill: https://github.com/the-hcma/repository-helpers/blob/main/.cursor/skills/ship-and-review/SKILL.md -->
|
|
23
|
+
<!-- pr-ship-canonical-rule: https://github.com/the-hcma/repository-helpers/blob/main/.cursor/rules/pr-ship-and-review.mdc -->
|
|
24
|
+
|
|
25
|
+
**Canonical playbook (read first):** This file is a consumer summary. Exit codes,
|
|
26
|
+
early-complete semantics, quota chains, and triage details are maintained in
|
|
27
|
+
repository-helpers and may change between releases.
|
|
28
|
+
|
|
29
|
+
Agents **must** read the canonical Skill before running the agent review loop:
|
|
30
|
+
|
|
31
|
+
- **GitHub (`main`):** https://github.com/the-hcma/repository-helpers/blob/main/.cursor/skills/ship-and-review/SKILL.md
|
|
32
|
+
- **Local clone (when `${rh}` is synced to `main`):** `${rh}/.cursor/skills/ship-and-review/SKILL.md`
|
|
33
|
+
|
|
34
|
+
When this summary and the canonical Skill disagree, follow the canonical Skill.
|
|
35
|
+
|
|
36
|
+
## 1. Local quality gates (all must pass before submit)
|
|
37
|
+
|
|
38
|
+
Run this repository's quality gates from the stack worktree (tests, linters, etc.).
|
|
39
|
+
|
|
40
|
+
## 2. Commit and submit
|
|
41
|
+
|
|
42
|
+
Only after §1 quality gates pass. **Read** `.github/stacking-tool` (`graphite` or `gh-stack`)
|
|
43
|
+
and follow `.cursor/rules/stacking-tool.mdc` — do not mix backends on the same stack.
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# When marker is graphite (apply-fix comments the inactive backend):
|
|
47
|
+
# gt create <stack>/<topic> -m 'feat: …' # or gt modify -m '…'
|
|
48
|
+
# gt submit --publish --no-interactive
|
|
49
|
+
|
|
50
|
+
# When marker is gh-stack:
|
|
51
|
+
gh stack init <stack>/<topic> # or gh stack add for a higher layer
|
|
52
|
+
git add -A && git commit -m 'feat: …'
|
|
53
|
+
gh stack submit --auto --open --remote origin
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Wait for CI:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
"${rh}/scripts/dev/post-pr-submission-checks" --pr <n>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
If stderr shows `NOTE: GITHUB_RATE_LIMIT_*`, the helpers are waiting on GitHub API
|
|
63
|
+
quota reset — let them finish (do not treat as a hard local failure mid-wait).
|
|
64
|
+
|
|
65
|
+
Patch title/body if stale: `gh pr edit <n> --title … --body …`
|
|
66
|
+
|
|
67
|
+
## 3. Agent review loop
|
|
68
|
+
|
|
69
|
+
> **Reply before resolve (required):** For every valid agent review thread (Copilot, Bugbot, CodeRabbit, …), post an **on-thread human reply** as the authenticated operator **before** resolving. Exit code **3** means threads **lack a human reply** — resolving without replying is non-compliant.
|
|
70
|
+
|
|
71
|
+
**Prerequisites:** `gh auth` must be set up for the operator running the loop. Copy
|
|
72
|
+
`${rh}/etc/agent-review.env.example` to `~/.config/agent-review.env` with
|
|
73
|
+
`AGENT_REVIEW_REPORT_TO` and SMTP before `complete`. `complete_ready: true` is
|
|
74
|
+
reported by `"${rh}/scripts/wait-for-agent-review" check --pr <n>` (or `status`)
|
|
75
|
+
JSON when CI is green and agent review threads are clear.
|
|
76
|
+
|
|
77
|
+
Prefer the built-in loop:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
"${rh}/scripts/wait-for-agent-review" loop --pr <n>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Early complete:** when all threads are addressed, CI is green, there is **no** pending requested
|
|
84
|
+
Copilot/Bugbot review, and CodeRabbit’s workflow is **not** running, the loop finishes — no
|
|
85
|
+
mandatory idle dwell. **12h PR cap** (`AGENT_REVIEW_PR_TIMEOUT`) when review cycles never
|
|
86
|
+
converge (exit **6** give-up). Per-agent quota caches skip exhausted agents (CodeRabbit, Copilot,
|
|
87
|
+
Bugbot).
|
|
88
|
+
|
|
89
|
+
**CodeRabbit is on_push:** a new push starts CodeRabbit — never post `@coderabbitai review`.
|
|
90
|
+
If quota-limited, wait the cooldown with feedback polls (issue #369; default poll **60s**) +
|
|
91
|
+
grace (default **60s**); only then, if still no real review on head, the loop may post a
|
|
92
|
+
one-shot `@coderabbitai full review`. When CodeRabbit says wait, do not re-ask until
|
|
93
|
+
`retry_after`. Rate-limit stubs are not reviews. Mid-cooldown pending
|
|
94
|
+
feedback wakes the loop (exit **3**).
|
|
95
|
+
|
|
96
|
+
When `loop` exits **3**, triage each unaddressed agent thread:
|
|
97
|
+
|
|
98
|
+
1. Fix in the worktree when actionable (or skip with a brief on-thread reason).
|
|
99
|
+
2. **Reply on-thread** as the authenticated human:
|
|
100
|
+
```bash
|
|
101
|
+
"${rh}/scripts/wait-for-agent-review" reply-thread --thread-id <PRRT_…> --body 'Fixed in abc1234: …'
|
|
102
|
+
```
|
|
103
|
+
3. **Resolve only after step 2:**
|
|
104
|
+
```bash
|
|
105
|
+
"${rh}/scripts/wait-for-agent-review" resolve-thread --thread-id <PRRT_…>
|
|
106
|
+
```
|
|
107
|
+
Or batch: `"${rh}/scripts/wait-for-agent-review" resolve-addressed --pr <n>` (requires an existing human reply per thread).
|
|
108
|
+
|
|
109
|
+
**Never** resolve via raw GraphQL/API without an on-thread human reply first.
|
|
110
|
+
|
|
111
|
+
Then push fixes, re-run `"${rh}/scripts/dev/post-pr-submission-checks" --pr <n>`, and start the next loop iteration.
|
|
112
|
+
|
|
113
|
+
When `check` reports `complete_ready: true`:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
"${rh}/scripts/wait-for-agent-review" complete --pr <n>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`complete_ready` requires an agent sign-off on the current head (not a bare CodeRabbit
|
|
120
|
+
commit status / rate-limit stub). This emails `AGENT_REVIEW_REPORT_TO`. It does **not**
|
|
121
|
+
run `gh pr review --approve` (self-approve is skipped; merge stays an explicit operator step).
|
|
122
|
+
|
|
123
|
+
Do **not** add `merge-it` unless the user explicitly confirms. Org merge path is
|
|
124
|
+
GitHub auto-merge (`gh pr merge --auto --squash` / Enable auto-merge) when the
|
|
125
|
+
operator asks to merge.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Block PR submit until pre-pr-checks pass; format before check; no truncated output
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Pre-PR checks (required)
|
|
7
|
+
|
|
8
|
+
`pre-pr-checks` lives in **repository-helpers**, not in this repo. Resolve the
|
|
9
|
+
clone once:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
rh="${REPOSITORY_HELPERS_DIR:-$HOME/work/ai/repository-helpers}"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`pre-pr-checks` resolves its target from `$PWD`, so it audits **this** repo when
|
|
16
|
+
run from a feature worktree here. The `submit-stack` wrapper does **not** — it
|
|
17
|
+
resolves the repo from its own path and would submit the repository-helpers
|
|
18
|
+
clone, so consumers submit with a bare `gh stack submit` / `gt submit`.
|
|
19
|
+
|
|
20
|
+
Before submitting a PR:
|
|
21
|
+
|
|
22
|
+
1. Run **`"${rh}/scripts/dev/pre-pr-checks"`** from this repo's feature worktree
|
|
23
|
+
(must exit 0), then submit with bare **`gh stack submit --auto`** or
|
|
24
|
+
**`gt submit`** per this repo's `.github/stacking-tool` marker, from the same
|
|
25
|
+
worktree. Do **not** use `"${rh}/scripts/dev/submit-stack"` from here.
|
|
26
|
+
|
|
27
|
+
2. Do **not** submit if pre-pr-checks failed or was skipped. A skipped job is
|
|
28
|
+
allowed **only** when the user has approved it for this PR: pass
|
|
29
|
+
`PRE_PR_CHECKS_SKIP=job1,job2` (never a silent skip) and record the skipped
|
|
30
|
+
jobs and the reason in the PR **Test plan**.
|
|
31
|
+
|
|
32
|
+
3. In the PR **Test plan**, note that `"${rh}/scripts/dev/pre-pr-checks"` passed
|
|
33
|
+
(paste the final `==> pre-pr-checks passed` line from the full run).
|
|
34
|
+
|
|
35
|
+
4. Scripts must not leave changes on the **primary (main) worktree**.
|
|
36
|
+
|
|
37
|
+
## Apply formatters before check (required)
|
|
38
|
+
|
|
39
|
+
`pre-pr-checks` is **check-only** by default (e.g. `ruff format --check`, `cargo fmt -- --check`).
|
|
40
|
+
After review-fix edits — especially string literals — **apply** formatters first, then run the gate:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Python (match CI paths; adjust for the repo)
|
|
44
|
+
uv run ruff format .
|
|
45
|
+
# Rust
|
|
46
|
+
cargo fmt --all
|
|
47
|
+
# Then the gate
|
|
48
|
+
"${rh}/scripts/dev/pre-pr-checks"
|
|
49
|
+
# Or apply + check in one shot (mutates the worktree):
|
|
50
|
+
"${rh}/scripts/dev/pre-pr-checks" --fix
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Commit any format-only diff before submit. Do **not** treat a green `pytest` / `ruff check` /
|
|
54
|
+
partial job as a pre-PR pass.
|
|
55
|
+
|
|
56
|
+
## No truncated pre-PR output
|
|
57
|
+
|
|
58
|
+
Do **not** pipe `pre-pr-checks` to `tail` / `head`. Require exit **0** and the final
|
|
59
|
+
`==> pre-pr-checks passed` line from the full run.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# ❌ Truncated — hides failures above the last few lines
|
|
63
|
+
"${rh}/scripts/dev/pre-pr-checks" 2>&1 | tail -8
|
|
64
|
+
|
|
65
|
+
# ✅ Full output + exit status
|
|
66
|
+
"${rh}/scripts/dev/pre-pr-checks"
|
|
67
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: On every new agent session, read AGENTS.md and .cursor/rules before acting
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Session start: read AGENTS.md and project rules
|
|
7
|
+
|
|
8
|
+
At the **start of every new agent session** (before implementing, editing, or
|
|
9
|
+
answering from assumed conventions), actively load project guidance:
|
|
10
|
+
|
|
11
|
+
1. **Read** `AGENTS.md` at the repository root when it exists (use the Read tool;
|
|
12
|
+
do not rely only on auto-injected snippets).
|
|
13
|
+
2. **List** `.cursor/rules/*.mdc` and **read** each rule that applies to this
|
|
14
|
+
session — at minimum every `alwaysApply: true` rule, plus any glob-matched
|
|
15
|
+
rules for files you will touch.
|
|
16
|
+
|
|
17
|
+
Do this on the first turn of a new conversation even if some guidance already
|
|
18
|
+
appears in context — confirm the on-disk files are what you follow.
|
|
19
|
+
|
|
20
|
+
If `AGENTS.md` is missing, note that and continue with `.cursor/rules/` only.
|
|
21
|
+
Do not invent org conventions that are not in those files.
|