secondpair 0.1.0 → 0.1.1

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.
package/README.md CHANGED
@@ -1,119 +1,119 @@
1
- # secondpair — the second pair of eyes
2
-
3
- LLM-powered PR reviewer with whole-repo context. Reviews a diff (local,
4
- staged, or a GitHub/GitLab/Bitbucket PR), posts inline comments, gates CI
5
- on severity. Uses sibling package [`codengram`](../codengram/README.md) as
6
- its repo memory so review isn't diff-blind — it sees callers, related
7
- files, and project context, not just the patch.
8
-
9
- ## Install
10
-
11
- ```bash
12
- npm install --save-dev secondpair
13
- ```
14
-
15
- Needs an LLM API key (same resolution as `codengram` — set one):
16
-
17
- ```bash
18
- export ANTHROPIC_API_KEY=sk-ant-... # default, recommended
19
- # or: OPENAI_API_KEY / OPENROUTER_API_KEY / CODENGRAM_API_KEY+CODENGRAM_BASE_URL+CODENGRAM_MODEL
20
- ```
21
-
22
- ## Quick start
23
-
24
- ```bash
25
- cd your-repo
26
- npx codengram init # one-time: builds repo memory, installs git hooks
27
- npx secondpair review --staged # review staged changes, print report
28
- npx secondpair review --base main # review branch vs main
29
- ```
30
-
31
- Nothing to configure to get useful output — defaults are sane
32
- (`fail_on: high`, `min_confidence: 0.5`). Add `.pr-review.yml` only when you
33
- want to change them (see [Config](#config)).
34
-
35
- ## Reviewing a real PR (posting comments + CI gate)
36
-
37
- Pick your platform, set its token, run with `--post`:
38
-
39
- **GitHub** (GitHub Actions: `GITHUB_TOKEN` is provided automatically)
40
- ```bash
41
- export GITHUB_TOKEN=ghp_...
42
- npx secondpair review --pr 123 --repo owner/name --post --fail-on high
43
- ```
44
-
45
- **GitLab** (in GitLab CI, `CI_SERVER_URL`/`CI_PROJECT_ID`/`CI_MERGE_REQUEST_IID`
46
- are auto-detected; set a token as `GITLAB_TOKEN` or `GL_TOKEN`)
47
- ```bash
48
- export GITLAB_TOKEN=glpat-...
49
- npx secondpair review --post --fail-on high # host auto-detected via GITLAB_CI env
50
- ```
51
-
52
- **Bitbucket** (`BITBUCKET_WORKSPACE`/`BITBUCKET_PR_ID` auto-detected in
53
- Bitbucket Pipelines; auth via token or app password)
54
- ```bash
55
- export BITBUCKET_TOKEN=... # or BITBUCKET_USERNAME + BITBUCKET_APP_PASSWORD
56
- npx secondpair review --post --fail-on high
57
- ```
58
-
59
- `--host` overrides auto-detection if you're running somewhere the CI env
60
- vars aren't set. Exit code is 1 when any active finding is at/above
61
- `fail_on` — wire that into your pipeline as the merge gate.
62
-
63
- ### Example: GitHub Actions
64
-
65
- ```yaml
66
- - run: npx secondpair review --pr ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --post
67
- env:
68
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
69
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
70
- ```
71
-
72
- Re-running on the same PR (new commit, or CI re-triggered) never
73
- double-posts — each platform re-checks live existing comment ids right
74
- before posting, on top of run-to-run fingerprint reconciliation.
75
-
76
- ## Config (`.pr-review.yml`, optional)
77
-
78
- ```yaml
79
- fail_on: high # critical|high|medium|low|info — CI exit-1 threshold
80
- min_confidence: 0.5
81
- ignore: ["**/*.generated.ts", "vendor/**"]
82
- context_token_budget: 8000 # codengram context injected per chunk
83
- context_snippets: 3
84
- categories: # turn any off
85
- bug: true
86
- security: true
87
- missing-tests: true
88
- naming: true
89
- complexity: true
90
- custom: true
91
- limits:
92
- max_findings_per_file: 5
93
- max_total: 30
94
- self_critique: false # extra LLM pass that only drops findings, never adds
95
- redact_secrets: true # strip secrets from diff/context before they reach the LLM
96
- redact_patterns: [] # extra regexes, on top of built-in AWS/GitHub-token/PEM/etc
97
- write_suppressions: false # persist "won't fix" replies to .pr-review-suppressions.yml
98
- custom_instructions: ""
99
- ```
100
-
101
- Suppress a finding permanently: reply "won't fix" (or react 👎) on its PR
102
- comment, or hand-edit `.pr-review-suppressions.yml` with the finding id
103
- from the report.
104
-
105
- ## `secondpair index`
106
-
107
- Alias for `codengram index` — kept so a repo can adopt `secondpair` without
108
- also depending on `codengram` directly for this one command. Same
109
- incremental behavior; see [codengram's README](../codengram/README.md#staying-in-sync-after-code-changes)
110
- for exactly when/how re-indexing happens and why it's cheap on repeated
111
- runs — short version: git-hook-triggered, hash-incremental, never a full
112
- rebuild unless you pass `--full`.
113
-
114
- ## More detail
115
-
116
- - Agent-oriented internals reference (pipeline, invariants to preserve when
117
- editing): [`AGENTS.md`](./AGENTS.md)
118
- - Architecture review, requirements scorecard, known gaps:
119
- [`docs/architecture-review.md`](./docs/architecture-review.md)
1
+ # secondpair — the second pair of eyes
2
+
3
+ LLM-powered PR reviewer with whole-repo context. Reviews a diff (local,
4
+ staged, or a GitHub/GitLab/Bitbucket PR), posts inline comments, gates CI
5
+ on severity. Uses sibling package [`repocairn`](../repocairn/README.md) as
6
+ its repo memory so review isn't diff-blind — it sees callers, related
7
+ files, and project context, not just the patch.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install --save-dev secondpair
13
+ ```
14
+
15
+ Needs an LLM API key (same resolution as `repocairn` — set one):
16
+
17
+ ```bash
18
+ export ANTHROPIC_API_KEY=sk-ant-... # default, recommended
19
+ # or: OPENAI_API_KEY / OPENROUTER_API_KEY / REPOCAIRN_API_KEY+REPOCAIRN_BASE_URL+REPOCAIRN_MODEL
20
+ ```
21
+
22
+ ## Quick start
23
+
24
+ ```bash
25
+ cd your-repo
26
+ npx repocairn init # one-time: builds repo memory, installs git hooks
27
+ npx secondpair review --staged # review staged changes, print report
28
+ npx secondpair review --base main # review branch vs main
29
+ ```
30
+
31
+ Nothing to configure to get useful output — defaults are sane
32
+ (`fail_on: high`, `min_confidence: 0.5`). Add `.pr-review.yml` only when you
33
+ want to change them (see [Config](#config)).
34
+
35
+ ## Reviewing a real PR (posting comments + CI gate)
36
+
37
+ Pick your platform, set its token, run with `--post`:
38
+
39
+ **GitHub** (GitHub Actions: `GITHUB_TOKEN` is provided automatically)
40
+ ```bash
41
+ export GITHUB_TOKEN=ghp_...
42
+ npx secondpair review --pr 123 --repo owner/name --post --fail-on high
43
+ ```
44
+
45
+ **GitLab** (in GitLab CI, `CI_SERVER_URL`/`CI_PROJECT_ID`/`CI_MERGE_REQUEST_IID`
46
+ are auto-detected; set a token as `GITLAB_TOKEN` or `GL_TOKEN`)
47
+ ```bash
48
+ export GITLAB_TOKEN=glpat-...
49
+ npx secondpair review --post --fail-on high # host auto-detected via GITLAB_CI env
50
+ ```
51
+
52
+ **Bitbucket** (`BITBUCKET_WORKSPACE`/`BITBUCKET_PR_ID` auto-detected in
53
+ Bitbucket Pipelines; auth via token or app password)
54
+ ```bash
55
+ export BITBUCKET_TOKEN=... # or BITBUCKET_USERNAME + BITBUCKET_APP_PASSWORD
56
+ npx secondpair review --post --fail-on high
57
+ ```
58
+
59
+ `--host` overrides auto-detection if you're running somewhere the CI env
60
+ vars aren't set. Exit code is 1 when any active finding is at/above
61
+ `fail_on` — wire that into your pipeline as the merge gate.
62
+
63
+ ### Example: GitHub Actions
64
+
65
+ ```yaml
66
+ - run: npx secondpair review --pr ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --post
67
+ env:
68
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
69
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
70
+ ```
71
+
72
+ Re-running on the same PR (new commit, or CI re-triggered) never
73
+ double-posts — each platform re-checks live existing comment ids right
74
+ before posting, on top of run-to-run fingerprint reconciliation.
75
+
76
+ ## Config (`.pr-review.yml`, optional)
77
+
78
+ ```yaml
79
+ fail_on: high # critical|high|medium|low|info — CI exit-1 threshold
80
+ min_confidence: 0.5
81
+ ignore: ["**/*.generated.ts", "vendor/**"]
82
+ context_token_budget: 8000 # repocairn context injected per chunk
83
+ context_snippets: 3
84
+ categories: # turn any off
85
+ bug: true
86
+ security: true
87
+ missing-tests: true
88
+ naming: true
89
+ complexity: true
90
+ custom: true
91
+ limits:
92
+ max_findings_per_file: 5
93
+ max_total: 30
94
+ self_critique: false # extra LLM pass that only drops findings, never adds
95
+ redact_secrets: true # strip secrets from diff/context before they reach the LLM
96
+ redact_patterns: [] # extra regexes, on top of built-in AWS/GitHub-token/PEM/etc
97
+ write_suppressions: false # persist "won't fix" replies to .pr-review-suppressions.yml
98
+ custom_instructions: ""
99
+ ```
100
+
101
+ Suppress a finding permanently: reply "won't fix" (or react 👎) on its PR
102
+ comment, or hand-edit `.pr-review-suppressions.yml` with the finding id
103
+ from the report.
104
+
105
+ ## `secondpair index`
106
+
107
+ Alias for `repocairn index` — kept so a repo can adopt `secondpair` without
108
+ also depending on `repocairn` directly for this one command. Same
109
+ incremental behavior; see [repocairn's README](../repocairn/README.md#staying-in-sync-after-code-changes)
110
+ for exactly when/how re-indexing happens and why it's cheap on repeated
111
+ runs — short version: git-hook-triggered, hash-incremental, never a full
112
+ rebuild unless you pass `--full`.
113
+
114
+ ## More detail
115
+
116
+ - Agent-oriented internals reference (pipeline, invariants to preserve when
117
+ editing): [`AGENTS.md`](./AGENTS.md)
118
+ - Architecture review, requirements scorecard, known gaps:
119
+ [`docs/architecture-review.md`](./docs/architecture-review.md)
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { Command } from "commander";
3
3
  import path from "node:path";
4
4
  import pc from "picocolors";
5
- import { getModel, runIndex } from "codengram";
5
+ import { getModel, runIndex } from "repocairn";
6
6
  import { getBbPrDiff, listBbFindingIds, listBbWontFixFindingIds, postBbReview, resolveBbRef, } from "./bitbucket/comments.js";
7
7
  import { getGlMrDiff, listGlFindingIds, listGlWontFixFindingIds, postGlReview, resolveGlRef, } from "./gitlab/comments.js";
8
8
  import { loadConfig } from "./config.js";
@@ -18,11 +18,11 @@ const program = new Command();
18
18
  const log = (msg) => console.error(pc.dim(msg));
19
19
  program
20
20
  .name("secondpair")
21
- .description("secondpair — the second pair of eyes: LLM PR reviewer with a persistent repo memory (codengram) for whole-project context")
21
+ .description("secondpair — the second pair of eyes: LLM PR reviewer with a persistent repo memory (repocairn) for whole-project context")
22
22
  .version("0.1.0");
23
23
  program
24
24
  .command("index")
25
- .description("Build or incrementally update the repo memory (.codengram/index.json)")
25
+ .description("Build or incrementally update the repo memory (.repocairn/index.json)")
26
26
  .option("--full", "re-index every file regardless of content hash", false)
27
27
  .option("--no-llm", "skip LLM summaries (symbols + import graph only; no API key needed)")
28
28
  .option("--dir <path>", "repository root", process.cwd())
package/dist/config.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { matchesGlob } from "codengram";
2
+ import { matchesGlob } from "repocairn";
3
3
  import { type ReviewConfig } from "./types.js";
4
4
  export { matchesGlob };
5
5
  export declare const DEFAULT_CONFIG: ReviewConfig;
@@ -29,5 +29,5 @@ export declare const CONFIG_FILENAME = ".pr-review.yml";
29
29
  /** Load .pr-review.yml from the repo root, merged over defaults. */
30
30
  export declare function loadConfig(cwd: string, configPath?: string): Promise<ReviewConfig>;
31
31
  export declare function mergeConfig(partial: z.infer<typeof configSchema>): ReviewConfig;
32
- /** True when the path matches codengram's built-in ignores or this config's patterns. */
32
+ /** True when the path matches repocairn's built-in ignores or this config's patterns. */
33
33
  export declare function isIgnored(filePath: string, config: ReviewConfig): boolean;
package/dist/config.js CHANGED
@@ -3,7 +3,7 @@ import { existsSync } from "node:fs";
3
3
  import path from "node:path";
4
4
  import YAML from "yaml";
5
5
  import { z } from "zod";
6
- import { isIgnored as matchesIgnorePatterns, matchesGlob } from "codengram";
6
+ import { isIgnored as matchesIgnorePatterns, matchesGlob } from "repocairn";
7
7
  import { compileRedactPatterns } from "./redact.js";
8
8
  import { CATEGORIES, SEVERITIES } from "./types.js";
9
9
  export { matchesGlob };
@@ -80,7 +80,7 @@ export function mergeConfig(partial) {
80
80
  write_suppressions: partial.write_suppressions ?? DEFAULT_CONFIG.write_suppressions,
81
81
  };
82
82
  }
83
- /** True when the path matches codengram's built-in ignores or this config's patterns. */
83
+ /** True when the path matches repocairn's built-in ignores or this config's patterns. */
84
84
  export function isIgnored(filePath, config) {
85
85
  return matchesIgnorePatterns(filePath, config.ignore);
86
86
  }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { runReview } from "./review.js";
2
- export { runIndex, selectContext, loadIndex } from "codengram";
2
+ export { runIndex, selectContext, loadIndex } from "repocairn";
3
3
  export { loadConfig, DEFAULT_CONFIG } from "./config.js";
4
4
  export { parseDiff, renderDiffForPrompt } from "./diff/parse.js";
5
5
  export { validateFindings, reviewOutputSchema, findingSchema } from "./llm/schema.js";
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { runReview } from "./review.js";
2
- export { runIndex, selectContext, loadIndex } from "codengram";
2
+ export { runIndex, selectContext, loadIndex } from "repocairn";
3
3
  export { loadConfig, DEFAULT_CONFIG } from "./config.js";
4
4
  export { parseDiff, renderDiffForPrompt } from "./diff/parse.js";
5
5
  export { validateFindings, reviewOutputSchema, findingSchema } from "./llm/schema.js";
package/dist/review.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { z } from "zod";
4
- import { estimateTokens, getModel, loadIndex, selectContext, structuredCall } from "codengram";
4
+ import { estimateTokens, getModel, loadIndex, selectContext, structuredCall } from "repocairn";
5
5
  import { isIgnored } from "./config.js";
6
6
  import { parseDiff } from "./diff/parse.js";
7
7
  import { withFindingId } from "./finding-id.js";
@@ -66,7 +66,7 @@ export async function runReview(opts) {
66
66
  log(`Injecting context from ${selection.entries.length} codemap entries.`);
67
67
  }
68
68
  else {
69
- log("No codengram index found (.codengram/index.json) — reviewing diff-only. Run `codengram init` (or `codengram index`) and commit the index for whole-repo context.");
69
+ log("No repocairn index found (.repocairn/index.json) — reviewing diff-only. Run `repocairn init` (or `repocairn index`) and commit the index for whole-repo context.");
70
70
  }
71
71
  }
72
72
  context = maybeRedact(context);
package/package.json CHANGED
@@ -1,49 +1,49 @@
1
- {
2
- "name": "secondpair",
3
- "version": "0.1.0",
4
- "description": "LLM-powered pull request reviewer with whole-repo context from a persistent codengram codemap",
5
- "type": "module",
6
- "bin": {
7
- "secondpair": "./dist/cli.js",
8
- "pr-review": "./dist/cli.js"
9
- },
10
- "main": "./dist/index.js",
11
- "types": "./dist/index.d.ts",
12
- "license": "MIT",
13
- "author": "rv-ranbir",
14
- "repository": {
15
- "type": "git",
16
- "url": "git+https://github.com/rv-ranbir/ai-tools.git",
17
- "directory": "packages/secondpair"
18
- },
19
- "homepage": "https://github.com/rv-ranbir/ai-tools/tree/main/packages/secondpair#readme",
20
- "bugs": "https://github.com/rv-ranbir/ai-tools/issues",
21
- "keywords": [
22
- "ai",
23
- "llm",
24
- "pr-review",
25
- "code-review",
26
- "github-actions",
27
- "gitlab-ci",
28
- "bitbucket",
29
- "claude"
30
- ],
31
- "files": [
32
- "dist"
33
- ],
34
- "scripts": {
35
- "build": "tsc -b",
36
- "dev": "tsx src/cli.ts"
37
- },
38
- "engines": {
39
- "node": ">=20"
40
- },
41
- "dependencies": {
42
- "@octokit/rest": "^21.0.0",
43
- "commander": "^12.1.0",
44
- "picocolors": "^1.1.0",
45
- "codengram": "^0.1.0",
46
- "yaml": "^2.5.0",
47
- "zod": "^4.4.3"
48
- }
49
- }
1
+ {
2
+ "name": "secondpair",
3
+ "version": "0.1.1",
4
+ "description": "LLM-powered pull request reviewer with whole-repo context from a persistent repocairn codemap",
5
+ "type": "module",
6
+ "bin": {
7
+ "secondpair": "./dist/cli.js",
8
+ "pr-review": "./dist/cli.js"
9
+ },
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "license": "MIT",
13
+ "author": "rv-ranbir",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/rv-ranbir/ai-tools.git",
17
+ "directory": "packages/secondpair"
18
+ },
19
+ "homepage": "https://github.com/rv-ranbir/ai-tools/tree/main/packages/secondpair#readme",
20
+ "bugs": "https://github.com/rv-ranbir/ai-tools/issues",
21
+ "keywords": [
22
+ "ai",
23
+ "llm",
24
+ "pr-review",
25
+ "code-review",
26
+ "github-actions",
27
+ "gitlab-ci",
28
+ "bitbucket",
29
+ "claude"
30
+ ],
31
+ "files": [
32
+ "dist"
33
+ ],
34
+ "scripts": {
35
+ "build": "tsc -b",
36
+ "dev": "tsx src/cli.ts"
37
+ },
38
+ "engines": {
39
+ "node": ">=20"
40
+ },
41
+ "dependencies": {
42
+ "@octokit/rest": "^21.0.0",
43
+ "commander": "^12.1.0",
44
+ "picocolors": "^1.1.0",
45
+ "repocairn": "^0.1.1",
46
+ "yaml": "^2.5.0",
47
+ "zod": "^4.4.3"
48
+ }
49
+ }