diff --git a/.gitignore b/.gitignore index af8ea34..785f4b4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,9 @@ dist/ # this repo's own dogfooding digests — end-user repos should commit these docs/promote/digests/ +# internal-only product spec — not for npm or public history +docs/prd.md + # claude code .claude/ diff --git a/README.md b/README.md index e8846a1..12ee4cc 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,18 @@

Turn repeated AI review comments into durable repository memory.

+ Audience · Why · How · Quick start · Features · + Examples · + Privacy +

+

Cost · CLI · + FAQ · Roadmap

@@ -25,7 +31,18 @@
-CodeRabbit, Copilot, and Claude review your PRs — and the same suggestions keep coming back. **promote-cli** mines repeated review comments across your PR history, clusters them into patterns, and helps you promote each into a rule your AI tools will read on the next review. +CodeRabbit, Copilot, Claude, Cursor, and other AI reviewers can be useful, but the same suggestions often come back across PRs. + +**promote-cli** scans your PR review history, clusters repeated comments, and helps you promote those patterns into durable repo memory: + +- `CLAUDE.md` / `AGENTS.md` +- GitHub Copilot instructions +- Cursor / Windsurf / Gemini rules +- path-scoped rules +- ADRs +- test recommendations + +It runs locally, uses your own LLM API key, and asks for human approval before writing.
@@ -46,6 +63,19 @@ promote scan --since 30d
+## Who this is for + +promote-cli is for teams that: + +- use AI reviewers such as CodeRabbit, Copilot, Claude, Cursor, Greptile, Qodo, Devin, or Sourcery +- keep repo instructions in `CLAUDE.md`, `AGENTS.md`, `.github/copilot-instructions.md`, `.cursor/rules/`, or similar files +- see the same review comments repeated across PRs +- want a human-approved way to turn repeated review feedback into durable rules, ADRs, or tests + +It is probably not useful if your repo does not use PR review comments or coding-agent instruction files. + +
+ ## Why promote-cli AI review tools leave comments on PRs. Developers resolve them and move on. The decision disappears into a closed PR thread. @@ -56,7 +86,7 @@ If the same comment appears next week, the team pays the same review cost again. > *"The human reviewer's role is no longer to trace code details, but to measure the distance between decisions and implementation."* -The name *promote* reflects that shift: review comments aren't disposable noise — they're **knowledge waiting to be elevated** into your repo's durable memory. The decision still yours is *where* it belongs. +The name *promote* reflects that shift: review comments aren't disposable noise — they're **knowledge waiting to be elevated** into your repo's durable memory. The decision is still yours: whether and where each pattern belongs. | | Without any tool | Hand-writing AGENTS.md | With promote-cli | | ---------------------------- | ------------------------- | -------------------------- | ------------------------------- | @@ -107,7 +137,7 @@ promote init promote scan --since 30d ``` -**3. Review.** Walk through each candidate — promote or skip per item. Approved ones land in your chosen target file immediately. +**3. Review.** Walk through each candidate — promote or skip per item. Approved ones land in your chosen target file immediately. See [Examples](#examples) for what a real digest and patch look like. ``` ─── Candidate 1/7 ─── @@ -173,15 +203,43 @@ Output is localized per `language.preferredOutput` in `.promote.yml` (en / ko /
+## Examples + +Want to see representative output from real scans before installing? + +- [Sample quick digest (trpc/trpc, OpenAI `quick`)](examples/digests/sample-quick.md) +- [Sample broad digest (trpc/trpc, Anthropic `broad`)](examples/digests/sample-broad.md) +- [`CLAUDE.md` patch example](examples/patches/claude-rule.patch) +- [Cursor rule patch example](examples/patches/cursor-rule.patch) + +Both digests come from real `promote scan` runs against the public [`trpc/trpc`](https://github.com/trpc/trpc) repository. + +
+ +## Privacy & security + +promote-cli is designed as a local BYOK tool. + +- **No hosted backend.** Your comments are never proxied through a promote server. +- **Your provider key.** LLM calls go directly from your machine or CI runner to OpenAI, Anthropic, or Google. +- **Secret redaction.** Tokens, AWS keys, JWTs, and similar secrets are stripped before any LLM call (`privacy.redactSecrets: true` by default). +- **No diff hunks by default.** `privacy.sendDiffHunksToLLM` defaults to `false` — comments are analyzed without sending the surrounding code diff. +- **Human approval.** In interactive mode, every candidate is reviewed before anything is written. +- **CI guardrail.** Headless mode can open a PR, but candidates flagged `needs_human_decision` are never auto-applied. + +See [`SECURITY.md`](SECURITY.md) for how to report a vulnerability. + +
+ ## Cost & mode trade-off Measured on trpc/trpc, 120-day window, 380 actionable AI comments: -| Mode + provider | Candidates | Cost | Wall time | Output style | -| -------------------------------------- | ---------- | ------- | --------- | --------------------------------------------- | -| OpenAI `quick` (gpt-4.1-mini + nano) | **24** | $0.07 | 2m 14s | Narrow, file-specific | -| OpenAI `broad` (gpt-4.1-mini cluster) | 8 | $0.10 | 2m 39s | Core conventions only — subset of Anthropic | -| **Anthropic `broad` (Haiku 4.5)** | **21** | $0.47 | 8m 17s | **Convention / principle / ADR mix** | +| Mode + provider | Candidates | Cost | Wall time | Output style | +| --------------------------------- | ---------- | ----- | --------- | ------------------------------------ | +| OpenAI `quick` | **24** | $0.07 | 2m 14s | Narrow, file-specific | +| OpenAI `broad` | 8 | $0.10 | 2m 39s | Core conventions only | +| **Anthropic `broad` (Haiku 4.5)** | **17** | $0.45 | 4m 55s | Convention / principle / ADR mix | Picking a mode by cadence: @@ -191,7 +249,7 @@ Picking a mode by cadence: | **Monthly** | Anthropic `broad` | Higher cost but extracts conventions worth memorializing | | **Quarterly / sprint-end** | Anthropic `broad` + optional `--mode quick` follow-up | Combined coverage: principles from broad, code-level from quick | -No Anthropic key? OpenAI `broad` is the "budget" alternative — reliably catches the 6–8 core repo-wide conventions at ~5× lower cost than Anthropic broad, though without the full depth (20+ conventions including ADR-worthy decisions). +No Anthropic key? OpenAI `broad` is the "budget" alternative — reliably catches the 6–8 core repo-wide conventions at ~5× lower cost than Anthropic broad, though without the same depth of convention / principle / ADR-style candidates. Full breakdown with examples from each mode → [docs/clustering.md](docs/clustering.md). @@ -292,6 +350,34 @@ promote scan \
+## FAQ + +### Does promote-cli replace code review? + +No. It does not review new code. It mines review history and proposes durable memory updates for patterns that already appeared in PR comments. + +### Does it write to my repo automatically? + +Interactive mode asks for approval per candidate. Headless CI mode can open a single bundled PR, but candidates that require human judgment (`needs_human_decision`) are never auto-applied — they stay in the digest for local review with `promote review`. + +### Does it send my source code to an LLM? + +By default, promote-cli analyzes review comments without sending the surrounding diff hunks (`privacy.sendDiffHunksToLLM: false`). You can opt into sending diff context if your team wants higher classification accuracy. + +### Does it work with private repositories? + +Yes, as long as your GitHub token can read the repository's PR review comments. The tool itself is local-first and never sends comments to a promote-hosted server. + +### Which AI tools does it support? + +It can write to memory targets used by Claude Code, OpenAI Codex, GitHub Copilot, Cursor, Windsurf, and Gemini CLI. See [`docs/config.md`](docs/config.md) for the full targets matrix. + +### Is this a hosted service? + +No. promote-cli runs entirely on your machine or your own CI runner. LLM calls go from your environment to your configured provider using your key. + +
+ ## Roadmap **Shipping today** — Personal CLI, multi-tool routing, hybrid clustering, human reply/reaction signal, filter transparency, stable IDs, secret redaction, i18n digest (en / ko / ja), atomic headless `--create-pr` flow (cuts from base, rollback on failure, LLM-filled PR template, gh/octokit dual transport), GitHub Action template for scheduled weekly digest PRs. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..8bd8ebb --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,30 @@ +# Security Policy + +## Supported versions + +| Version | Supported | +| ------- | --------- | +| 0.7.x | ✅ | +| < 0.7 | ❌ | + +## Reporting a vulnerability + +Please report security issues privately through GitHub Security Advisories +rather than a public issue: + + + +We aim to acknowledge reports within 7 days. + +## Scope + +promote-cli is a local CLI that calls third-party LLM providers with your own +API key. Reports that affect installed users or CI consumers are in scope: + +- Issues that could exfiltrate API keys, repository tokens, or PR content +- Bypasses of secret redaction (`privacy.redactSecrets`) +- Issues that cause unintended writes to your repository +- Supply-chain issues in the published npm package + +Issues in the third-party services we call (OpenAI, Anthropic, Google, +GitHub) should be reported to those providers directly. diff --git a/docs/clustering.md b/docs/clustering.md index 17e161d..1012ad8 100644 --- a/docs/clustering.md +++ b/docs/clustering.md @@ -25,7 +25,7 @@ Two paths for grouping repeated comments, with very different output character. - "Internal implementation details must not be imported from `src/`; use public unstable API exports" - "Cache invalidation must include generator/tsconfig/artifact existence checks" - "SSE retry budget must not be consumed on initial connection; exclude AbortError" -- **Cost / time**: ~$0.47 / ~8 min on 380 comments (Anthropic, concurrency=1) +- **Cost / time**: ~$0.45 / ~5 min on 380 comments (Anthropic, concurrency=1) - **Provider recommendation: Anthropic Claude.** OpenAI broad on tier-1 keys hits rate limits on the larger models (gpt-4.1, gpt-4o) and the mini variants don't produce reliable semantic groupings; Anthropic Haiku 4.5 handles both depth and reliability in one tier. ## Picking a mode @@ -52,6 +52,6 @@ trpc/trpc, 120d window, 380 actionable AI comments: | OpenAI quick (gpt-4.1-mini + nano) | **24** | $0.07 | 2m 14s | Narrow, file-specific | | OpenAI broad (gpt-4.1-mini cluster) | 8 | $0.10 | 2m 39s | Core conventions only — agents-level subset | | OpenAI broad (gpt-4.1 full cluster) | — | — | — | Needs OpenAI tier 2+; tier 1 hits rate limits | -| **Anthropic broad (Haiku 4.5)** | **21** | $0.47 | 8m 17s | **Convention / principle / ADR mix — recommended depth** | +| **Anthropic broad (Haiku 4.5)** | **17** | $0.45 | 4m 55s | **Convention / principle / ADR mix — recommended depth** | -OpenAI broad is positioned as a "no-Anthropic-key" budget alternative — it reliably catches the 6–8 core repo-wide conventions (non-null assertion bans, function-param destructure rules, test-utility imports, CLI version pinning, etc.) at 5× lower cost than Anthropic broad. For full depth (20+ conventions including ADR-worthy decisions) use Anthropic broad. +OpenAI broad is positioned as a "no-Anthropic-key" budget alternative — it reliably catches the 6–8 core repo-wide conventions (non-null assertion bans, function-param destructure rules, test-utility imports, CLI version pinning, etc.) at ~5× lower cost than Anthropic broad. For the same depth of convention / principle / ADR-style candidates, use Anthropic broad. diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..52a809d --- /dev/null +++ b/examples/README.md @@ -0,0 +1,30 @@ +# Examples + +Real output and ready-to-use templates for `promote-cli`. + +## What's here + +| Folder | What it shows | +| --- | --- | +| [`digests/`](./digests/) | Sample markdown digests from real `promote scan` runs against [`trpc/trpc`](https://github.com/trpc/trpc) | +| [`patches/`](./patches/) | Illustrative diffs of what `promote` writes to your memory files | +| [`github-actions/`](./github-actions/) | A weekly scheduled workflow that opens a bundled memory PR | + +## Suggested reading order + +1. **[`digests/sample-quick.md`](./digests/sample-quick.md)** — what a fast scan ($0.07, 2m) looks like. Three representative candidates from a 24-candidate run. +2. **[`digests/sample-broad.md`](./digests/sample-broad.md)** — what a deeper scan ($0.45, 5m) looks like. Same repo, different mode; surfaces convention-level patterns. +3. **[`patches/claude-rule.patch`](./patches/claude-rule.patch)** and **[`patches/cursor-rule.patch`](./patches/cursor-rule.patch)** — what gets written when you `Promote` a candidate. +4. **[`github-actions/weekly-digest.yml`](./github-actions/weekly-digest.yml)** — drop-in workflow for running the whole flow on a schedule. + +## Generating your own + +To produce a digest like these against your own repository: + +```bash +npm i -g promote-cli +promote init +promote scan --since 60d --mode quick --out my-digest.md # or --mode broad +``` + +The digest will land at `my-digest.md` (or `docs/promote/digests/{date}.md` if you skip `--out`). It carries the same structure as the samples above — candidates, evidence trails to source PR comments, suggested patches, and a `Filtered out` appendix for clusters the classifier dropped. diff --git a/examples/digests/sample-broad.md b/examples/digests/sample-broad.md new file mode 100644 index 0000000..1a0c0cb --- /dev/null +++ b/examples/digests/sample-broad.md @@ -0,0 +1,160 @@ +# promote digest — sample (broad mode) + +> A snapshot of a real `promote scan` run. Three representative candidates are shown — the full run produced 17. + +- **Repo:** [`trpc/trpc`](https://github.com/trpc/trpc) +- **Generated:** 2026-05-22 +- **Mode:** `broad` — LLM-direct semantic clustering (no embedding API) +- **Provider:** Anthropic (`claude-haiku-4-5` classify, cluster, draft) +- **Window:** 120 days (overridden via `--since`) +- **Privacy:** `redactSecrets=true`, `sendDiffHunksToLLM=false` + +## Summary + +- Scanned: **454** review comments across **72** PRs +- AI reviewer comments: **384** +- Clusters: **117** (83 repeated → 17 promotion candidates) +- Cost: **$0.45** +- Wall time: **4m 55s** + +## Reproduce + +```bash +promote scan --repo trpc/trpc --since 120d --mode broad +``` + +--- + +## Candidate 1 — Standardize test setup with `testServerAndClientResource` + `await using` + +- **Target:** `path_scoped_rule` → `.claude/rules/test-setup.instructions.md` +- **Confidence:** 0.85 +- **Scope:** cross-PR (4 PRs) +- **Occurrences:** 4 comments +- **Path scope:** `**/*.test.ts` +- **Human signal:** 1 reviewer agreed (`@rbxict`) + +### Why this was promoted + +The same convention shows up across four PRs: tests should call +`testServerAndClientResource` directly (with `await using`) and use the +`client` callback config pattern, rather than wrapping with `run(...)` +or `konn(...)`. A maintainer also followed up agreeing this is the +preferred direction — broad mode picked up on that human signal. + +### Evidence + +- PR [#7262](https://github.com/trpc/trpc/pull/7262#discussion_r2948708218) — `packages/tests/server/regression/batchStreamErrorCallIndex.test.ts` +- PR [#7207](https://github.com/trpc/trpc/pull/7207#discussion_r2879708223) — `packages/tests/server/httpSubscriptionLink.test.ts` +- PR [#7304](https://github.com/trpc/trpc/pull/7304#discussion_r3012813221) — `packages/tests/server/httpSubscriptionLink.fetch.test.ts` +- PR [#7231](https://github.com/trpc/trpc/pull/7231#discussion_r2902034597) — `packages/openapi/test/generate.test.ts` + +### Suggested rule + +```md +--- +applyTo: "**/*.test.ts" +--- +# Test setup + +- Call `testServerAndClientResource` directly with `await using` — both + server and client lifecycles are managed in one place. +- Use the `client` callback config pattern instead of passing `clientLink` + directly. Keeps setup consistent across the suite. +- Do not wrap the helper in `run(...)` or `konn(...)`. +- `await using` ensures resources are released on test exit even on throw. +``` + +--- + +## Candidate 2 — `bin.intent` points to a non-existent directory across packages + +- **Target:** `path_scoped_rule` → `.claude/rules/package-bin.instructions.md` +- **Confidence:** 0.90 +- **Scope:** cross-PR (3 PRs) +- **Occurrences:** 6 comments +- **Path scope:** `packages/**/package.json` +- **Human signal:** 1 reviewer agreed (`@orbisai0security`) + +### Why this was promoted + +Several `@trpc/*` packages declare `bin.intent`, but the referenced files +either don't exist or were never added to `files`. Installations create +broken executables. The cluster crosses three PRs (#7252, #7371, …) and +has explicit reviewer agreement. + +### Evidence (selected) + +- PR [#7371](https://github.com/trpc/trpc/pull/7371#discussion_r3195158582) — `packages/tests/package.json` +- PR [#7252](https://github.com/trpc/trpc/pull/7252#discussion_r2937362632) — `packages/openapi/package.json` +- PR [#7252](https://github.com/trpc/trpc/pull/7252#discussion_r2937362635) — `packages/tanstack-react-query/package.json` +- PR [#7252](https://github.com/trpc/trpc/pull/7252#discussion_r2937362630) — `packages/next/package.json` +- (2 more occurrences across the same set of PRs) + +### Suggested rule + +```md +--- +applyTo: "packages/**/package.json" +--- +# `bin` entry hygiene + +- Every `bin` entry must point to a file that actually ships in the + published tarball — verify with `npm pack` locally. +- Include the `bin/` directory in `files` whenever you add a `bin` entry. +- When multiple `@trpc/*` packages share the same binary name, scope it + (e.g. `@trpc-intent`) to avoid `node_modules/.bin` collisions. +- If a binary depends on an external package, declare it in `dependencies` + or `peerDependencies` rather than relying on transitive resolution. +``` + +--- + +## Candidate 3 — Import from public entrypoints, not `src/internals/` + +- **Target:** `path_scoped_rule` → `.claude/rules/internal-api-boundaries.instructions.md` +- **Confidence:** 0.85 +- **Scope:** cross-PR (2 PRs) +- **Occurrences:** 2 comments +- **Path scope:** `packages/*/src/**` +- **Human signal:** 1 reviewer agreed (`@rbxict`) + +### Why this was promoted + +Two PRs across different packages reached for internal implementation +paths (`src/internals/…`) instead of the published `unstable-*` or `public` +entrypoints. The pattern is repo-wide architectural intent and a +maintainer agreed in the follow-up review. + +### Evidence + +- PR [#7304](https://github.com/trpc/trpc/pull/7304#discussion_r3006306706) — `packages/tests/server/httpSubscriptionLink.fetch.test.ts` +- PR [#7228](https://github.com/trpc/trpc/pull/7228#discussion_r2901567590) — `packages/tanstack-react-query/src/createOptionsProxy.ts` + +### Suggested rule + +```md +--- +applyTo: "packages/*/src/**" +--- +# Internal API boundaries + +- Do not import from `src/internals/**` directly. +- Use the public entrypoints (`unstable-internals`, `public`, or + `src/index.ts`) so the surface stays controlled. +- For cross-package imports, route through each package's public exports + rather than relative paths into another package's internals. +- New internal capability needed externally? Expose it through a public + entrypoint first. +``` + +--- + +## Filtered out (excerpt) + +The classifier dropped 19 clusters with explicit reasons. Examples: + +- *"Address minor typo in JSDoc"* — dropped (`not_promotable`): one-off, no policy implication. +- *"Consider TanStack Query v5 migration"* — dropped (`already_handled`): tracked in a separate roadmap issue. + +The full digest carries the complete `Filtered out` appendix. diff --git a/examples/digests/sample-quick.md b/examples/digests/sample-quick.md new file mode 100644 index 0000000..075ee1e --- /dev/null +++ b/examples/digests/sample-quick.md @@ -0,0 +1,142 @@ +# promote digest — sample (quick mode) + +> A snapshot of a real `promote scan` run. Three representative candidates are shown — the full run produced 24. + +- **Repo:** [`trpc/trpc`](https://github.com/trpc/trpc) +- **Generated:** 2026-05-22 +- **Mode:** `quick` — embedding + HAC + `llmRefine` +- **Provider:** OpenAI (`gpt-4.1-mini` classify, `gpt-4.1-nano` draft, `text-embedding-3-small` embed) +- **Window:** 120 days (overridden via `--since`) +- **Privacy:** `redactSecrets=true`, `sendDiffHunksToLLM=false` + +## Summary + +- Scanned: **454** review comments across **72** PRs +- AI reviewer comments: **384** +- Clusters: **295** (47 repeated → 24 promotion candidates) +- Cost: **$0.07** +- Wall time: **2m 14s** + +## Reproduce + +```bash +promote scan --repo trpc/trpc --since 120d --mode quick +``` + +--- + +## Candidate 1 — Standardize integration test setup on `testServerAndClientResource` + +- **Target:** `agents` → `AGENTS.md` +- **Confidence:** 0.90 +- **Scope:** cross-PR (3 PRs) +- **Occurrences:** 3 comments + +### Why this was promoted + +Three independent PRs flagged the same pattern: integration tests should +use the `testServerAndClientResource` helper with `await using` rather +than bespoke wrappers (`run(...)`, `konn(...)`). This is a repeated +repo-wide test convention, not a single-PR cleanup. + +### Evidence + +- PR [#7231](https://github.com/trpc/trpc/pull/7231#discussion_r2902034597) — `packages/openapi/test/generate.test.ts` +- PR [#7207](https://github.com/trpc/trpc/pull/7207#discussion_r2879708223) — `packages/tests/server/httpSubscriptionLink.test.ts` +- PR [#7304](https://github.com/trpc/trpc/pull/7304#discussion_r3012813221) — `packages/tests/server/httpSubscriptionLink.fetch.test.ts` + +### Suggested instruction + +```md +## Integration test setup + +- Use the `testServerAndClientResource` helper with `await using` for any + test that needs both a server and a client. +- Do not wrap the server lifecycle in `run(...)` or `konn(...)` — call + the standard helper directly. +- `await using` guarantees the resource is released even if the test throws. +``` + +--- + +## Candidate 2 — Include `bin/` in `package.json#files` for binary entries + +- **Target:** `agents` → `AGENTS.md` +- **Confidence:** 0.95 +- **Scope:** within-PR (1 PR, multi-package) +- **Occurrences:** 10 comments across 5 packages + +> `within-PR` candidates are shown separately from `cross-PR` candidates because some repeated patterns are broad within a single large change, but may not yet justify a repo-wide rule. + +### Why this was promoted + +A single PR (#7252) added a `bin.intent` entry across multiple packages, +but the `files` allowlist in each `package.json` was not updated — the +binary would be missing from the published tarball. The same comment +fired in every affected package, indicating a recurring oversight worth +codifying. + +### Evidence (selected) + +- PR [#7252](https://github.com/trpc/trpc/pull/7252#discussion_r2968125965) — `packages/server/package.json` +- PR [#7252](https://github.com/trpc/trpc/pull/7252#discussion_r2968125922) — `packages/tanstack-react-query/package.json` +- PR [#7252](https://github.com/trpc/trpc/pull/7252#discussion_r2968125972) — `packages/client/package.json` +- (7 more occurrences in the same PR) + +### Suggested instruction + +```md +## Publishing binaries + +- When adding a `bin` entry to `package.json`, also add the `bin/` + directory to the `files` allowlist — otherwise the binary is omitted + from the published tarball. +- Verify locally with `npm pack` before publishing. +``` + +--- + +## Candidate 3 — Remove non-null assertions in `www/scripts/check-twoslash.ts` + +- **Target:** `path_scoped_rule` → `.claude/rules/check-twoslash.instructions.md` +- **Confidence:** 0.95 +- **Scope:** cross-PR (3 PRs) +- **Occurrences:** 3 comments +- **Path scope:** `www/scripts/**` + +### Why this was promoted + +Three separate PRs flagged non-null assertion (`!`) usage on indexed and +RegExp capture access within the same file. The matches are not +statically known to be non-null at runtime. This is a path-scoped style +issue, not a repo-wide policy. + +### Evidence + +- PR [#7196](https://github.com/trpc/trpc/pull/7196#discussion_r2869759038) +- PR [#7176](https://github.com/trpc/trpc/pull/7176#discussion_r2876202469) +- PR [#7195](https://github.com/trpc/trpc/pull/7195#discussion_r2869717508) + +### Suggested rule + +```md +--- +applyTo: "www/scripts/**" +--- +# www/scripts/check-twoslash.ts + +- Replace non-null assertions (`!`) on indexed or RegExp-capture access + with explicit null checks or optional chaining. +- Match results are not statically guaranteed to be present at runtime. +``` + +--- + +## Filtered out (excerpt) + +The classifier also dropped 12 clusters from the candidate set with explicit reasons. Examples: + +- *"Add tests for edge cases in error handling"* — dropped (`not_promotable`): too generic, no specific invariant to enforce. +- *"Consider extracting this into a helper"* — dropped (`low_confidence`): single occurrence, refactor suggestion rather than policy. + +The full digest carries the complete `Filtered out` appendix and a `Skipped during review` section for anything deferred in interactive mode. diff --git a/examples/github-actions/README.md b/examples/github-actions/README.md index 1ce986a..9ad2d3f 100644 --- a/examples/github-actions/README.md +++ b/examples/github-actions/README.md @@ -64,6 +64,7 @@ the Octokit REST API using `GITHUB_TOKEN`, so no extra setup is needed. ## Cost control `promote-cli` only calls the LLM for repeated clusters (≥ `minOccurrences` -members). For a mid-size repo with ~200 PR review comments over 60 days, -expect a handful of dollars per scan on default Claude models. See -[`docs/clustering.md`](../../docs/clustering.md) for the cost breakdown. +members). For a mid-size repo, expect costs to range from cents to low +dollars per scan depending on provider, mode, review volume, and whether +diff context is enabled. See [`docs/clustering.md`](../../docs/clustering.md) +for the measured breakdown. diff --git a/examples/patches/claude-rule.patch b/examples/patches/claude-rule.patch new file mode 100644 index 0000000..6cb9746 --- /dev/null +++ b/examples/patches/claude-rule.patch @@ -0,0 +1,20 @@ +diff --git a/CLAUDE.md b/CLAUDE.md +index 11a22bb..33c44dd 100644 +--- a/CLAUDE.md ++++ b/CLAUDE.md +@@ -12,3 +12,15 @@ + ## Testing + + - Run unit tests before changing shared utilities. ++ ++## Internal API boundaries ++ ++- Do not import from `src/internals/**` directly. ++- Use the public entrypoints (`unstable-internals`, `public`, or `src/index.ts`) ++ so the surface stays controlled. ++- For cross-package imports, route through each package's public exports ++ rather than relative paths into another package's internals. ++- If a new internal capability is needed externally, expose it through a ++ public entrypoint first. ++ ++ diff --git a/examples/patches/cursor-rule.patch b/examples/patches/cursor-rule.patch new file mode 100644 index 0000000..5803ff0 --- /dev/null +++ b/examples/patches/cursor-rule.patch @@ -0,0 +1,20 @@ +diff --git a/.cursor/rules/react-imports.mdc b/.cursor/rules/react-imports.mdc +new file mode 100644 +index 0000000..1234567 +--- /dev/null ++++ b/.cursor/rules/react-imports.mdc +@@ -0,0 +1,14 @@ ++--- ++description: React import conventions in test files ++globs: ++ - "packages/tanstack-react-query/test/**/*.test.tsx" ++--- ++ ++# React import conventions ++ ++- Use the namespace form: `import * as React from 'react'`. ++- Do not use individual named imports (`import { useState } from 'react'`) ++ in TanStack React Query test files. ++- Reference React explicitly (`React.createElement`, `React.useState`). ++ ++ diff --git a/package.json b/package.json index 9f3b8dd..9245f5a 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,10 @@ "promote-cli": "dist/index.js" }, "files": [ - "dist" + "dist", + "docs", + "examples", + "SECURITY.md" ], "repository": { "type": "git", @@ -30,10 +33,19 @@ "keywords": [ "ai", "code-review", + "ai-review", + "github", + "github-actions", + "pull-request", "agents-md", "claude-md", + "claude-code", + "copilot-instructions", + "cursor", + "adr", "repository-memory", - "developer-tools" + "developer-tools", + "cli" ], "license": "MIT", "dependencies": {