@weareikko/code-review 0.0.1 → 0.8.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/LICENSE +105 -0
- package/README.md +221 -0
- package/bin/code-review.js +7 -0
- package/dist/cli-7RGxyNy6.js +6375 -0
- package/dist/cli-7RGxyNy6.js.map +1 -0
- package/dist/cli.d.ts +56 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +2 -0
- package/dist/config.d.ts +205 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/diagnostics.d.ts +118 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diff-lines.d.ts +48 -0
- package/dist/diff-lines.d.ts.map +1 -0
- package/dist/errors.d.ts +69 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/fingerprints.d.ts +22 -0
- package/dist/fingerprints.d.ts.map +1 -0
- package/dist/git.d.ts +50 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/github.d.ts +119 -0
- package/dist/github.d.ts.map +1 -0
- package/dist/gitlab-review.d.ts +210 -0
- package/dist/gitlab-review.d.ts.map +1 -0
- package/dist/gitlab.d.ts +98 -0
- package/dist/gitlab.d.ts.map +1 -0
- package/dist/logger.d.ts +10 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/otel.d.ts +111 -0
- package/dist/otel.d.ts.map +1 -0
- package/dist/parser.d.ts +27 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/payloads.d.ts +30 -0
- package/dist/payloads.d.ts.map +1 -0
- package/dist/platform.d.ts +71 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platforms/github.d.ts +115 -0
- package/dist/platforms/github.d.ts.map +1 -0
- package/dist/platforms/gitlab.d.ts +26 -0
- package/dist/platforms/gitlab.d.ts.map +1 -0
- package/dist/posting.d.ts +108 -0
- package/dist/posting.d.ts.map +1 -0
- package/dist/prior-threads.d.ts +40 -0
- package/dist/prior-threads.d.ts.map +1 -0
- package/dist/product.d.ts +17 -0
- package/dist/product.d.ts.map +1 -0
- package/dist/review.d.ts +18 -0
- package/dist/review.d.ts.map +1 -0
- package/dist/review.js +2 -0
- package/dist/skills.d.ts +92 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/skipped-retrieval.d.ts +26 -0
- package/dist/skipped-retrieval.d.ts.map +1 -0
- package/dist/summary-carryover.d.ts +48 -0
- package/dist/summary-carryover.d.ts.map +1 -0
- package/dist/triage.d.ts +37 -0
- package/dist/triage.d.ts.map +1 -0
- package/dist/types.d.ts +95 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/verify.d.ts +74 -0
- package/dist/verify.d.ts.map +1 -0
- package/package.json +90 -2
- package/skills/code-review/SKILL.md +112 -0
- package/skills/code-review/references/javascript-typescript.md +50 -0
- package/skills/code-review/references/php.md +46 -0
- package/skills/test-integrity/SKILL.md +76 -0
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Config } from './config.js';
|
|
2
|
+
import { type DiagnosticContext } from './diagnostics.js';
|
|
3
|
+
import type { ReviewUsage } from './gitlab-review.js';
|
|
4
|
+
import type { OtelBridge } from './otel.js';
|
|
5
|
+
import { type ScmResponseInfo } from './platform.js';
|
|
6
|
+
import type { SummaryResult } from './posting.js';
|
|
7
|
+
import type { GeneratedComment, Severity } from './types.js';
|
|
8
|
+
export type { DiagnosticContext, DiagnosticError, DiagnosticPhase, DiagnosticUsage, DiagnosticUsageBreakdown, } from './diagnostics.js';
|
|
9
|
+
export { DIAGNOSTIC_CHANNEL_NAMES, DIAGNOSTIC_CHANNEL_PREFIX, createDiagnosticContext, createDiagnosticRunId, diagnosticChannels, traceDiagnostic, traceDiagnosticPhase, } from './diagnostics.js';
|
|
10
|
+
export type { OtelBridge, OtelBridgeOptions, OtelRuntime } from './otel.js';
|
|
11
|
+
export { isOtelEnabled, startOtelBridge } from './otel.js';
|
|
12
|
+
export interface RunResult {
|
|
13
|
+
generated: GeneratedComment[];
|
|
14
|
+
posted: number;
|
|
15
|
+
usage: ReviewUsage;
|
|
16
|
+
summary: SummaryResult | null;
|
|
17
|
+
skipped?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface RunBridges {
|
|
20
|
+
/** Pre-started OTel bridge for per-turn and per-tool-call agent telemetry. */
|
|
21
|
+
otel?: OtelBridge;
|
|
22
|
+
}
|
|
23
|
+
export declare function run(config: Config, bridges?: RunBridges): Promise<RunResult>;
|
|
24
|
+
export declare function formatSkillsFooter(skills: string[]): string | undefined;
|
|
25
|
+
export declare function formatUsageLine(usage: ReviewUsage): string;
|
|
26
|
+
/**
|
|
27
|
+
* Render the per-model usage breakdown for heterogeneous `full`-depth runs: one
|
|
28
|
+
* indented line per pool member with its billable input / output tokens and
|
|
29
|
+
* cost. Returns `undefined` when there is no breakdown (single-model runs), so
|
|
30
|
+
* the caller prints nothing extra. Surfaces model ids and numbers only — never
|
|
31
|
+
* any key or secret.
|
|
32
|
+
*/
|
|
33
|
+
export declare function formatPerModelUsage(usage: ReviewUsage): string | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Wraps a phase operation so the phase context gets HTTP semantic-convention
|
|
36
|
+
* attributes stamped from the most recent platform response — on both success
|
|
37
|
+
* and error paths. `readLastHttp` returns the platform's latest response holder;
|
|
38
|
+
* the wrapper snapshots it before the operation and only stamps when the
|
|
39
|
+
* operation's own request produced a *new* response, so a phase that threw
|
|
40
|
+
* before any HTTP call never inherits a previous phase's URL/status.
|
|
41
|
+
*
|
|
42
|
+
* Used by every traced platform phase, including the write phases
|
|
43
|
+
* (`scm.post_comments`, `scm.upsert_summary`) so a failure like a 500 on
|
|
44
|
+
* `bulk_publish` carries http.response.status_code / url.full / server.address.
|
|
45
|
+
*/
|
|
46
|
+
export declare function withHttpStamping<T>(readLastHttp: () => ScmResponseInfo | undefined, operation: (context: DiagnosticContext) => Promise<T>): (context: DiagnosticContext) => Promise<T>;
|
|
47
|
+
/**
|
|
48
|
+
* Count the comments posted to the MR, grouped by severity. Duplicates are
|
|
49
|
+
* excluded since they are never posted. The total equals the new-comment count;
|
|
50
|
+
* in `draft` mode a concurrent run can race-delete some drafts before publish,
|
|
51
|
+
* so the breakdown reflects posted intent and may slightly exceed the published
|
|
52
|
+
* count in that rare case.
|
|
53
|
+
*/
|
|
54
|
+
export declare function countPostedBySeverity(generated: GeneratedComment[]): Partial<Record<Severity, number>>;
|
|
55
|
+
export declare function main(argv?: string[]): Promise<void>;
|
|
56
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAO1C,OAAO,EAGL,KAAK,iBAAiB,EAEvB,MAAM,kBAAkB,CAAC;AAI1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAG5C,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAIlD,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAiB,MAAM,YAAY,CAAC;AAE5E,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,eAAe,EACf,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,wBAAwB,EACxB,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,EACrB,kBAAkB,EAClB,eAAe,EACf,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAuE3D,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAiBD,MAAM,WAAW,UAAU;IACzB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAuBD,wBAAsB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CA0SlF;AAaD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAGvE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAoB1D;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAW1E;AAQD;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,YAAY,EAAE,MAAM,eAAe,GAAG,SAAS,EAC/C,SAAS,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC,GACpD,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC,CAU5C;AAsBD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,gBAAgB,EAAE,GAC5B,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAQnC;AAED,wBAAsB,IAAI,CAAC,IAAI,WAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BtE"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { C as createDiagnosticContext, D as traceDiagnosticPhase, E as traceDiagnostic, S as DIAGNOSTIC_CHANNEL_PREFIX, T as diagnosticChannels, a as main, d as startOtelBridge, i as formatUsageLine, n as formatPerModelUsage, o as run, r as formatSkillsFooter, s as withHttpStamping, t as countPostedBySeverity, u as isOtelEnabled, w as createDiagnosticRunId, x as DIAGNOSTIC_CHANNEL_NAMES } from "./cli-7RGxyNy6.js";
|
|
2
|
+
export { DIAGNOSTIC_CHANNEL_NAMES, DIAGNOSTIC_CHANNEL_PREFIX, countPostedBySeverity, createDiagnosticContext, createDiagnosticRunId, diagnosticChannels, formatPerModelUsage, formatSkillsFooter, formatUsageLine, isOtelEnabled, main, run, startOtelBridge, traceDiagnostic, traceDiagnosticPhase, withHttpStamping };
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { type PostingMode } from './posting.js';
|
|
2
|
+
import { type ReviewDepth, type Severity, type ThinkingLevel } from './types.js';
|
|
3
|
+
export type GitLabAuthHeader = 'PRIVATE-TOKEN' | 'JOB-TOKEN';
|
|
4
|
+
/** Source-control backends the reviewer can target. */
|
|
5
|
+
export declare const PLATFORMS: readonly ["gitlab", "github"];
|
|
6
|
+
export type Platform = (typeof PLATFORMS)[number];
|
|
7
|
+
/** Default GitHub server (web) URL, honoring `GITHUB_SERVER_URL` on Enterprise. */
|
|
8
|
+
export declare const DEFAULT_GITHUB_SERVER_URL = "https://github.com";
|
|
9
|
+
/**
|
|
10
|
+
* The single source of truth for the tool's own `CODE_REVIEW_*` settings.
|
|
11
|
+
*
|
|
12
|
+
* Each entry is the suffix after the `CODE_REVIEW_` prefix (e.g. `MODEL` for
|
|
13
|
+
* `CODE_REVIEW_MODEL`). These are read directly across `config.ts`/`otel.ts`
|
|
14
|
+
* and must NEVER be de-prefixed by {@link applyCodeReviewEnvPrefix}.
|
|
15
|
+
*
|
|
16
|
+
* Note: `API_KEY` is reserved. `CODE_REVIEW_API_KEY` was intentionally retired
|
|
17
|
+
* as the AI provider key and must not be revived as one.
|
|
18
|
+
*/
|
|
19
|
+
export declare const RESERVED_ENV_SUFFIXES: readonly ["API_KEY", "BASE_URL", "DECOMPOSE_HINT_LINES", "MAX_DIFF_CHARS", "MAX_TOKENS", "MIN_SEVERITY", "MODEL", "MODEL_POOL", "PLATFORM", "OTEL", "OTEL_CAPTURE_CONTENT", "POSTING_MODE", "POST_SUMMARY", "FORCE_REVIEW", "VERBOSE", "SKILLS", "REFRESH_SKILLS", "THINKING_LEVEL"];
|
|
20
|
+
/**
|
|
21
|
+
* Optional namespacing shim for provider/infra environment variables.
|
|
22
|
+
*
|
|
23
|
+
* For each `CODE_REVIEW_<NAME>` variable whose `<NAME>` is not a reserved tool
|
|
24
|
+
* setting (see {@link RESERVED_ENV_SUFFIXES}), this exposes `<NAME>` in the same
|
|
25
|
+
* env object. The prefixed value wins when both `CODE_REVIEW_<NAME>` and a
|
|
26
|
+
* plain `<NAME>` are set — the tool's scoped value should override an unrelated
|
|
27
|
+
* CI-wide variable of the same name.
|
|
28
|
+
*
|
|
29
|
+
* This lets credentials and infra vars that `@earendil-works/pi-ai` reads
|
|
30
|
+
* (`ANTHROPIC_API_KEY`, `CLOUDFLARE_API_KEY`, `CLOUDFLARE_ACCOUNT_ID`,
|
|
31
|
+
* `OLLAMA_HOST`, ambient AWS/Vertex creds, …) — and the GitLab tokens — be
|
|
32
|
+
* scoped under `CODE_REVIEW_` in shared CI without enumerating pi-ai's
|
|
33
|
+
* provider list.
|
|
34
|
+
*
|
|
35
|
+
* Must run once at startup BEFORE config/key resolution: `getEnvApiKey` and
|
|
36
|
+
* pi-ai's request-time reads both read `process.env` directly, so mutating it
|
|
37
|
+
* in-process is what makes those reads pick up the de-prefixed values.
|
|
38
|
+
*
|
|
39
|
+
* Empty prefixed values are ignored (treated as unset). Double-prefixed names
|
|
40
|
+
* (e.g. `CODE_REVIEW_CODE_REVIEW_MODEL`) are also skipped so a de-prefixed
|
|
41
|
+
* suffix can never clobber the tool's own reserved `CODE_REVIEW_*` settings.
|
|
42
|
+
*
|
|
43
|
+
* @returns the same `env` object it was given, mutated in place.
|
|
44
|
+
*/
|
|
45
|
+
export declare function applyCodeReviewEnvPrefix(env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
46
|
+
/**
|
|
47
|
+
* Default pi-ai's prompt-cache retention to `long` when the caller has not set
|
|
48
|
+
* it. pi-ai reads `PI_CACHE_RETENTION` from `process.env` at request time; `long`
|
|
49
|
+
* asks providers that support it (e.g. OpenAI's `openai-responses` API, including
|
|
50
|
+
* via the Cloudflare AI Gateway) to keep the cached system-prompt prefix for up
|
|
51
|
+
* to 24h so reviews spaced hours apart still reuse it. It is a safe no-op for
|
|
52
|
+
* providers/models without long-retention support (e.g. Anthropic), where it
|
|
53
|
+
* behaves exactly like the default `short`.
|
|
54
|
+
*
|
|
55
|
+
* Overridable: an explicit `PI_CACHE_RETENTION` (or `CODE_REVIEW_PI_CACHE_RETENTION`,
|
|
56
|
+
* mapped by {@link applyCodeReviewEnvPrefix} first) is left untouched.
|
|
57
|
+
*/
|
|
58
|
+
export declare function applyDefaultCacheRetention(env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
59
|
+
export interface Config {
|
|
60
|
+
/**
|
|
61
|
+
* The source-control backend to review against. Auto-detected from the
|
|
62
|
+
* environment by default (see {@link detectPlatform}); `--platform` /
|
|
63
|
+
* `CODE_REVIEW_PLATFORM` is an explicit override that always wins.
|
|
64
|
+
*/
|
|
65
|
+
platform: Platform;
|
|
66
|
+
project: string;
|
|
67
|
+
mr: string;
|
|
68
|
+
gitlabUrl: string;
|
|
69
|
+
gitlabToken: string;
|
|
70
|
+
gitlabAuthHeader: GitLabAuthHeader;
|
|
71
|
+
/** `owner/repo` slug of the GitHub repository (`GITHUB_REPOSITORY`). */
|
|
72
|
+
githubRepository: string;
|
|
73
|
+
/** Pull-request number as a string, mirroring {@link Config.mr}. */
|
|
74
|
+
githubPr: string;
|
|
75
|
+
/** Token used for the GitHub REST API (`GITHUB_TOKEN` / `--github-token`). */
|
|
76
|
+
githubToken: string;
|
|
77
|
+
/** GitHub REST API base; defaults to {@link DEFAULT_GITHUB_API_URL}. */
|
|
78
|
+
githubApiUrl: string;
|
|
79
|
+
/** GitHub server (web) URL; defaults to {@link DEFAULT_GITHUB_SERVER_URL}. */
|
|
80
|
+
githubServerUrl: string;
|
|
81
|
+
model: string;
|
|
82
|
+
/**
|
|
83
|
+
* Optional pool of `provider/modelId` models for heterogeneous `full`-depth
|
|
84
|
+
* review. When non-empty, multi-angle Find maps each angle to a pool member and
|
|
85
|
+
* the adversarial verifier prefers a member other than the one that authored a
|
|
86
|
+
* finding. Empty (the default) means the effective pool is just `[model]`, which
|
|
87
|
+
* reproduces single-model behaviour byte-for-byte. Sourced from `--model-pool`
|
|
88
|
+
* or `CODE_REVIEW_MODEL_POOL` (comma-separated).
|
|
89
|
+
*/
|
|
90
|
+
modelPool: string[];
|
|
91
|
+
minSeverity: Severity;
|
|
92
|
+
thinkingLevel: ThinkingLevel;
|
|
93
|
+
/**
|
|
94
|
+
* How many stages of the review pipeline run. `single` keeps the legacy
|
|
95
|
+
* single-pass behaviour; `verify` adds an adversarial Verify + Synthesize pass.
|
|
96
|
+
*/
|
|
97
|
+
reviewDepth: ReviewDepth;
|
|
98
|
+
/**
|
|
99
|
+
* Optional `provider/modelId` for the Verify stage (`verify`/`full` depth). When
|
|
100
|
+
* set, every adversarial verifier runs on this model instead of the pool's
|
|
101
|
+
* cross-family pick — pairing a cheap, high-recall Find model with a strong,
|
|
102
|
+
* high-precision verifier. Empty (default) keeps the pool-based selection.
|
|
103
|
+
* Sourced from `--verify-model` or `CODE_REVIEW_VERIFY_MODEL`.
|
|
104
|
+
*/
|
|
105
|
+
verifyModel: string;
|
|
106
|
+
postingMode: PostingMode;
|
|
107
|
+
apiKey: string;
|
|
108
|
+
/** Custom base URL for the AI provider API (e.g. Ollama or other OpenAI-compatible endpoints). */
|
|
109
|
+
baseUrl: string;
|
|
110
|
+
/** Maximum output tokens to request from the model. 0 uses the model's default. */
|
|
111
|
+
maxTokens: number;
|
|
112
|
+
/**
|
|
113
|
+
* Maximum cumulative diff characters sent to the reviewer. Files past this
|
|
114
|
+
* budget are dropped and surfaced as a size-skip callout. Defaults to 100_000.
|
|
115
|
+
*/
|
|
116
|
+
maxDiffChars: number;
|
|
117
|
+
/**
|
|
118
|
+
* When > 0, an MR whose reviewed diff changes more lines than this threshold
|
|
119
|
+
* gets a "consider decomposing this MR" hint in the summary. 0 = off (default).
|
|
120
|
+
*/
|
|
121
|
+
decomposeHintLines: number;
|
|
122
|
+
/**
|
|
123
|
+
* Lines of surrounding context per diff hunk (`git diff --unified`). More
|
|
124
|
+
* context helps the model reason about each change but inflates tokens and
|
|
125
|
+
* fits fewer files in the char budget; less context fits more files. 0 uses
|
|
126
|
+
* the built-in default. Sourced from `--diff-context` / `CODE_REVIEW_DIFF_CONTEXT`.
|
|
127
|
+
*/
|
|
128
|
+
diffContext: number;
|
|
129
|
+
/**
|
|
130
|
+
* When true, diffs for files dropped by the char budget are staged on disk so
|
|
131
|
+
* the reviewer can read them on demand instead of losing them (retrieval mode).
|
|
132
|
+
* Default false. Sourced from `--retrieve-skipped` / `CODE_REVIEW_RETRIEVE_SKIPPED`.
|
|
133
|
+
*/
|
|
134
|
+
retrieveSkipped: boolean;
|
|
135
|
+
reviewFile: string;
|
|
136
|
+
output: string;
|
|
137
|
+
dryRun: boolean;
|
|
138
|
+
noPost: boolean;
|
|
139
|
+
postSummary: boolean;
|
|
140
|
+
forceReview: boolean;
|
|
141
|
+
verbose: boolean;
|
|
142
|
+
cwd: string;
|
|
143
|
+
skills: string[];
|
|
144
|
+
/** Re-clone `git:` / `git+ssh:` skills, bypassing the on-disk clone cache. */
|
|
145
|
+
refreshGitSkills: boolean;
|
|
146
|
+
}
|
|
147
|
+
export type ParsedArgs = Record<string, string | boolean | string[]>;
|
|
148
|
+
export declare function parseArgs(argv: string[]): ParsedArgs;
|
|
149
|
+
/**
|
|
150
|
+
* Extract the provider name from a `"provider/modelId"` model string.
|
|
151
|
+
* Returns an empty string when the model string contains no slash.
|
|
152
|
+
*/
|
|
153
|
+
export declare function parseModelProvider(model: string): string;
|
|
154
|
+
/**
|
|
155
|
+
* Resolve the API key for the given model's provider, delegating entirely to
|
|
156
|
+
* `@earendil-works/pi-ai`'s `getEnvApiKey`. That helper reads the provider's
|
|
157
|
+
* standard environment variable (e.g. `ANTHROPIC_API_KEY` / `ANTHROPIC_OAUTH_TOKEN`,
|
|
158
|
+
* `OPENAI_API_KEY`, `GEMINI_API_KEY`, `OPENROUTER_API_KEY`, …) and resolves
|
|
159
|
+
* ambient credentials (Amazon Bedrock, Google Vertex ADC). The key is therefore
|
|
160
|
+
* always provider-specific — a key for provider X is never used for provider Y.
|
|
161
|
+
*
|
|
162
|
+
* Ollama is a local OpenAI-compatible endpoint that needs no key, so a
|
|
163
|
+
* placeholder is returned. The `--api-key` flag takes precedence in
|
|
164
|
+
* `resolveConfig`.
|
|
165
|
+
*
|
|
166
|
+
* NOTE: `getEnvApiKey` reads `process.env` directly (not a passed-in env), so
|
|
167
|
+
* tests stub `process.env` or pass `--api-key` to control the resolved key.
|
|
168
|
+
*/
|
|
169
|
+
export declare function resolveProviderApiKey(model: string): string;
|
|
170
|
+
/**
|
|
171
|
+
* Extract a pull-request number from a GitHub Actions event payload JSON string
|
|
172
|
+
* (the file `GITHUB_EVENT_PATH` points at). Prefers `.pull_request.number`, then
|
|
173
|
+
* the top-level `.number` (present on `issue_comment` events). Returns `''` when
|
|
174
|
+
* the JSON is unparsable or carries no number.
|
|
175
|
+
*/
|
|
176
|
+
export declare function parsePrNumberFromEvent(json: string): string;
|
|
177
|
+
/**
|
|
178
|
+
* Extract a pull-request number from a `GITHUB_REF` of the form
|
|
179
|
+
* `refs/pull/<N>/merge` (or `/head`). Returns `''` for any other ref shape.
|
|
180
|
+
*/
|
|
181
|
+
export declare function parsePrNumberFromRef(ref: string | undefined): string;
|
|
182
|
+
/**
|
|
183
|
+
* Resolve the GitHub pull-request number, in priority order: `--pr` flag, then
|
|
184
|
+
* the `GITHUB_EVENT_PATH` payload (`.pull_request.number` ?? `.number`), then a
|
|
185
|
+
* `refs/pull/<N>/merge` `GITHUB_REF`. Returns `''` when none apply.
|
|
186
|
+
*/
|
|
187
|
+
export declare function resolveGitHubPr(args: ParsedArgs, env: NodeJS.ProcessEnv, readEventFile?: (path: string) => string | undefined): string;
|
|
188
|
+
/**
|
|
189
|
+
* Determine the review platform for this run.
|
|
190
|
+
*
|
|
191
|
+
* Precedence:
|
|
192
|
+
* 1. Explicit `--platform` / `CODE_REVIEW_PLATFORM` (throws on an unknown value).
|
|
193
|
+
* 2. CI markers: `GITHUB_ACTIONS === 'true'` → github; `GITLAB_CI === 'true'`
|
|
194
|
+
* or a present `CI_PROJECT_ID` / `CI_SERVER_URL` → gitlab.
|
|
195
|
+
* 3. Inference from which platform's required identifiers are present
|
|
196
|
+
* (`GITHUB_REPOSITORY` + a PR number vs. `CI_PROJECT_ID` + `CI_MERGE_REQUEST_IID`).
|
|
197
|
+
*
|
|
198
|
+
* Throws a {@link ConfigError} when both platforms' identifiers are present
|
|
199
|
+
* (ambiguous) or neither is (undetectable), with a hint to set `--platform`.
|
|
200
|
+
*/
|
|
201
|
+
export declare function detectPlatform(args: ParsedArgs, env: NodeJS.ProcessEnv, readEventFile?: (path: string) => string | undefined): Platform;
|
|
202
|
+
export declare function resolveConfig(argv?: string[], env?: NodeJS.ProcessEnv): Config;
|
|
203
|
+
export declare function validateConfig(config: Config): void;
|
|
204
|
+
export { type Severity, type ThinkingLevel };
|
|
205
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { type TracingChannel } from 'node:diagnostics_channel';
|
|
2
|
+
import type { Config } from './config.js';
|
|
3
|
+
import type { Severity } from './types.js';
|
|
4
|
+
export type DiagnosticPhase = 'run' | 'scm.get_merge_request' | 'scm.get_latest_version' | 'git.prepare_history' | 'git.get_merge_diff' | 'git.get_commit_log' | 'reviewer.run' | 'review.parse' | 'scm.get_discussions' | 'comments.build' | 'artifact.write_output' | 'scm.post_comments' | 'scm.upsert_summary';
|
|
5
|
+
export interface DiagnosticError {
|
|
6
|
+
name?: string;
|
|
7
|
+
message: string;
|
|
8
|
+
code?: string;
|
|
9
|
+
/** True when the failure was a deadline/abort, so the bridge can label it `timeout`. */
|
|
10
|
+
timeout?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* HTTP status code when the failure came from a GitLab API response (e.g. a
|
|
13
|
+
* 500 on `bulk_publish`). Propagates up the phase chain so the OTel bridge can
|
|
14
|
+
* refine `error.type` and label the error counter with the status.
|
|
15
|
+
*/
|
|
16
|
+
status?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Value-based secret redaction: removes the *known* secret values this run holds
|
|
20
|
+
* (the GitLab token and the provider API key) from a string, in every encoding
|
|
21
|
+
* they might appear under. Unlike pattern matching it cannot over-redact ordinary
|
|
22
|
+
* text, cannot miss a token because of its format, and uses literal replacement
|
|
23
|
+
* (no regex), so there is no catastrophic-backtracking risk on large messages.
|
|
24
|
+
*/
|
|
25
|
+
export declare function scrubSecrets(input: string, secretValues: readonly string[]): string;
|
|
26
|
+
/** Collects the run's secret values (non-empty) for {@link scrubSecrets}. */
|
|
27
|
+
export declare function collectSecrets(config: Config): string[];
|
|
28
|
+
export interface DiagnosticUsageBreakdown {
|
|
29
|
+
input: number;
|
|
30
|
+
output: number;
|
|
31
|
+
cacheRead: number;
|
|
32
|
+
cacheWrite: number;
|
|
33
|
+
total: number;
|
|
34
|
+
}
|
|
35
|
+
export interface DiagnosticUsage {
|
|
36
|
+
model: string;
|
|
37
|
+
tokens: DiagnosticUsageBreakdown;
|
|
38
|
+
cost: DiagnosticUsageBreakdown;
|
|
39
|
+
}
|
|
40
|
+
export interface DiagnosticContext {
|
|
41
|
+
version: 1;
|
|
42
|
+
runId: string;
|
|
43
|
+
phase: DiagnosticPhase;
|
|
44
|
+
project: string;
|
|
45
|
+
mr: string;
|
|
46
|
+
gitlabUrl: string;
|
|
47
|
+
cwd: string;
|
|
48
|
+
model: string;
|
|
49
|
+
minSeverity: string;
|
|
50
|
+
dryRun: boolean;
|
|
51
|
+
noPost: boolean;
|
|
52
|
+
startedAt: string;
|
|
53
|
+
completedAt?: string;
|
|
54
|
+
durationMs?: number;
|
|
55
|
+
generated?: number;
|
|
56
|
+
newComments?: number;
|
|
57
|
+
duplicateComments?: number;
|
|
58
|
+
posted?: number;
|
|
59
|
+
/**
|
|
60
|
+
* Breakdown of posted comments by severity, populated on the `run` context so
|
|
61
|
+
* the OTel bridge can split `gitlab_review_comments_total` by severity. Counts
|
|
62
|
+
* the non-duplicate (posted-intent) comments; absent on dry-run/skip paths.
|
|
63
|
+
*/
|
|
64
|
+
postedBySeverity?: Partial<Record<Severity, number>>;
|
|
65
|
+
warnings?: number;
|
|
66
|
+
/** Why the reviewer JSON could not be parsed, on the `review.parse` phase when it fails. */
|
|
67
|
+
malformedReason?: string;
|
|
68
|
+
reviewFile?: string;
|
|
69
|
+
output?: string;
|
|
70
|
+
/** Number of files in the merge diff (set on the `git.get_merge_diff` phase). */
|
|
71
|
+
diffFilesChanged?: number;
|
|
72
|
+
/** Added content lines in the merge diff. */
|
|
73
|
+
diffLinesAdded?: number;
|
|
74
|
+
/** Removed content lines in the merge diff. */
|
|
75
|
+
diffLinesRemoved?: number;
|
|
76
|
+
/** HTTP method of the GitLab API call traced by this phase. */
|
|
77
|
+
httpRequestMethod?: string;
|
|
78
|
+
/** Full URL of the (last) GitLab API request in this phase; carries no secrets. */
|
|
79
|
+
httpUrl?: string;
|
|
80
|
+
/** HTTP status code of the (last) GitLab API response in this phase. */
|
|
81
|
+
httpStatusCode?: number;
|
|
82
|
+
/** Response Content-Length in bytes, when present. */
|
|
83
|
+
httpResponseBodySize?: number;
|
|
84
|
+
/** Host of the GitLab server the request targeted. */
|
|
85
|
+
serverAddress?: string;
|
|
86
|
+
draftsAbandoned?: number;
|
|
87
|
+
draftsCreated?: number;
|
|
88
|
+
draftsDeletedPrePublish?: number;
|
|
89
|
+
draftsPublished?: number;
|
|
90
|
+
/** Drafts that could not be published on the per-draft fallback path (silent comment drops). */
|
|
91
|
+
draftsPublishFailed?: number;
|
|
92
|
+
summaryAction?: 'created' | 'updated' | 'skipped';
|
|
93
|
+
summaryNoteId?: number;
|
|
94
|
+
usage?: DiagnosticUsage;
|
|
95
|
+
errorInfo?: DiagnosticError;
|
|
96
|
+
}
|
|
97
|
+
export declare const DIAGNOSTIC_CHANNEL_PREFIX = "@weareikko/code-review";
|
|
98
|
+
export declare const DIAGNOSTIC_CHANNEL_NAMES: {
|
|
99
|
+
readonly run: "@weareikko/code-review:run";
|
|
100
|
+
readonly getMergeRequest: "@weareikko/code-review:scm.get_merge_request";
|
|
101
|
+
readonly getLatestVersion: "@weareikko/code-review:scm.get_latest_version";
|
|
102
|
+
readonly prepareGitHistory: "@weareikko/code-review:git.prepare_history";
|
|
103
|
+
readonly getMergeDiff: "@weareikko/code-review:git.get_merge_diff";
|
|
104
|
+
readonly getCommitLog: "@weareikko/code-review:git.get_commit_log";
|
|
105
|
+
readonly runReviewer: "@weareikko/code-review:reviewer.run";
|
|
106
|
+
readonly parseReview: "@weareikko/code-review:review.parse";
|
|
107
|
+
readonly getDiscussions: "@weareikko/code-review:scm.get_discussions";
|
|
108
|
+
readonly buildComments: "@weareikko/code-review:comments.build";
|
|
109
|
+
readonly writeOutput: "@weareikko/code-review:artifact.write_output";
|
|
110
|
+
readonly postComments: "@weareikko/code-review:scm.post_comments";
|
|
111
|
+
readonly upsertSummary: "@weareikko/code-review:scm.upsert_summary";
|
|
112
|
+
};
|
|
113
|
+
export declare const diagnosticChannels: Record<"buildComments" | "getCommitLog" | "getDiscussions" | "getLatestVersion" | "getMergeDiff" | "getMergeRequest" | "parseReview" | "postComments" | "prepareGitHistory" | "run" | "runReviewer" | "upsertSummary" | "writeOutput", TracingChannel<DiagnosticContext, DiagnosticContext>>;
|
|
114
|
+
export declare function createDiagnosticRunId(): string;
|
|
115
|
+
export declare function createDiagnosticContext(phase: DiagnosticPhase, config: Config, runId: string, overrides?: Partial<DiagnosticContext>): DiagnosticContext;
|
|
116
|
+
export declare function traceDiagnostic<T>(channel: TracingChannel<DiagnosticContext>, context: DiagnosticContext, operation: (context: DiagnosticContext) => Promise<T>, secretValues?: readonly string[]): Promise<T>;
|
|
117
|
+
export declare function traceDiagnosticPhase<T>(phase: DiagnosticPhase, config: Config, runId: string, operation: (context: DiagnosticContext) => Promise<T>, overrides?: Partial<DiagnosticContext>): Promise<T>;
|
|
118
|
+
//# sourceMappingURL=diagnostics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Side } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* A diff line resolved to the old/new line numbers it maps to. GitLab consumes
|
|
4
|
+
* both (`old_line`/`new_line`); GitHub consumes one plus a `side`. Shared by both
|
|
5
|
+
* platforms so line resolution lives in one place.
|
|
6
|
+
*/
|
|
7
|
+
export interface ResolvedDiffLine {
|
|
8
|
+
newLine?: number;
|
|
9
|
+
oldLine?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Classify a target line in a unified diff into the old/new line numbers it maps
|
|
13
|
+
* to, tracking which side(s) apply:
|
|
14
|
+
* - an **added** line resolves to `newLine` only,
|
|
15
|
+
* - a **removed** line resolves to `oldLine` only,
|
|
16
|
+
* - an **unchanged (context)** line resolves to BOTH `oldLine` and `newLine`.
|
|
17
|
+
*
|
|
18
|
+
* GitLab needs both sides for context lines: a one-sided position is accepted by
|
|
19
|
+
* the draft-notes API but makes `bulk_publish` return 500 (GitLab skips position
|
|
20
|
+
* validation on draft creation — gitlab-org/gitlab#579609). GitHub uses a single
|
|
21
|
+
* `line` + `side`, taking `newLine`/`RIGHT` or `oldLine`/`LEFT`. We feed the
|
|
22
|
+
* reviewer ±20 lines of context, so it routinely anchors comments on unchanged
|
|
23
|
+
* lines; resolving them here is what lets both platforms place the comment.
|
|
24
|
+
*
|
|
25
|
+
* Returns `null` when the line is not part of the diff for `file`, so the caller
|
|
26
|
+
* can fall back (GitLab) or drop the comment (GitHub avoids a 422 on off-diff
|
|
27
|
+
* lines) rather than emit a position the platform cannot place.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveDiffLine(diff: string, file: string, target: number, side: Side): ResolvedDiffLine | null;
|
|
30
|
+
/** Context lines GitHub renders around each hunk change in a PR diff by default. */
|
|
31
|
+
export declare const GITHUB_DIFF_CONTEXT = 3;
|
|
32
|
+
/**
|
|
33
|
+
* True when the context line `target` (on `side`) is within `maxDistance` rows
|
|
34
|
+
* of the nearest added/removed line in its hunk.
|
|
35
|
+
*
|
|
36
|
+
* The reviewer runs against our LOCAL merge diff, generated with a wide context
|
|
37
|
+
* (`--unified=20`, see `git.ts`), so it routinely anchors findings on unchanged
|
|
38
|
+
* lines up to 20 rows from a change. GitHub's PR diff, however, shows only 3
|
|
39
|
+
* context lines: a review comment on a line outside GitHub's diff gets a 422,
|
|
40
|
+
* and because the review is posted as one atomic batch, a single 422 sinks every
|
|
41
|
+
* inline comment. This lets the GitHub payload builder drop such an off-diff
|
|
42
|
+
* context line (returning `null`) instead of 422-ing the whole review.
|
|
43
|
+
*
|
|
44
|
+
* Only meaningful for context lines (added/removed lines are always inside
|
|
45
|
+
* GitHub's diff); the caller checks that before calling.
|
|
46
|
+
*/
|
|
47
|
+
export declare function contextLineWithinGitHubDiff(diff: string, file: string, target: number, side: Side, maxDistance?: number): boolean;
|
|
48
|
+
//# sourceMappingURL=diff-lines.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-lines.d.ts","sourceRoot":"","sources":["../src/diff-lines.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAoBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,IAAI,GACT,gBAAgB,GAAG,IAAI,CAyCzB;AAED,oFAAoF;AACpF,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,IAAI,EACV,WAAW,SAAsB,GAChC,OAAO,CAqDT"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export type ErrorCode = 'CONFIG_ERROR' | 'GITLAB_API_ERROR' | 'GITHUB_API_ERROR' | 'GIT_ERROR' | 'REVIEWER_ERROR' | 'PARSE_ERROR' | 'RUNTIME_ERROR';
|
|
2
|
+
export interface GitlabReviewErrorOptions extends ErrorOptions {
|
|
3
|
+
code: ErrorCode;
|
|
4
|
+
hint?: string;
|
|
5
|
+
/**
|
|
6
|
+
* Marks a deadline-exceeded failure. The CLI's `code` taxonomy stays coarse
|
|
7
|
+
* (one code per subsystem), so timeouts are flagged here rather than via a
|
|
8
|
+
* separate code; the OTel bridge reads it to label runs `status=timeout`.
|
|
9
|
+
*/
|
|
10
|
+
timeout?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Marks a provider credit/quota-exhaustion failure (e.g. HTTP 402). The review
|
|
13
|
+
* could not run for reasons outside the MR's control, so the CLI treats it as
|
|
14
|
+
* a non-fatal skip (warn, exit 0) rather than failing the pipeline.
|
|
15
|
+
*/
|
|
16
|
+
quotaExceeded?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare class GitlabReviewError extends Error {
|
|
19
|
+
readonly code: ErrorCode;
|
|
20
|
+
readonly hint?: string;
|
|
21
|
+
readonly timeout: boolean;
|
|
22
|
+
readonly quotaExceeded: boolean;
|
|
23
|
+
constructor(message: string, options: GitlabReviewErrorOptions);
|
|
24
|
+
}
|
|
25
|
+
/** True when `message` looks like a provider credit/quota-exhaustion error. */
|
|
26
|
+
export declare function isQuotaExceededMessage(message: string | undefined): boolean;
|
|
27
|
+
/** True when `error` is (or reports) a provider credit/quota-exhaustion failure. */
|
|
28
|
+
export declare function isQuotaExceededError(error: unknown): boolean;
|
|
29
|
+
export declare class ConfigError extends GitlabReviewError {
|
|
30
|
+
constructor(message: string, options?: Omit<GitlabReviewErrorOptions, 'code'>);
|
|
31
|
+
}
|
|
32
|
+
export declare class GitLabApiError extends GitlabReviewError {
|
|
33
|
+
readonly method: string;
|
|
34
|
+
readonly path: string;
|
|
35
|
+
readonly status?: number;
|
|
36
|
+
readonly responseBody?: string;
|
|
37
|
+
constructor(message: string, options: Omit<GitlabReviewErrorOptions, 'code'> & {
|
|
38
|
+
method: string;
|
|
39
|
+
path: string;
|
|
40
|
+
status?: number;
|
|
41
|
+
responseBody?: string;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
export declare class GitHubApiError extends GitlabReviewError {
|
|
45
|
+
readonly method: string;
|
|
46
|
+
readonly path: string;
|
|
47
|
+
readonly status?: number;
|
|
48
|
+
readonly responseBody?: string;
|
|
49
|
+
constructor(message: string, options: Omit<GitlabReviewErrorOptions, 'code'> & {
|
|
50
|
+
method: string;
|
|
51
|
+
path: string;
|
|
52
|
+
status?: number;
|
|
53
|
+
responseBody?: string;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
export declare class GitError extends GitlabReviewError {
|
|
57
|
+
constructor(message: string, options?: Omit<GitlabReviewErrorOptions, 'code'>);
|
|
58
|
+
}
|
|
59
|
+
export declare class ReviewerError extends GitlabReviewError {
|
|
60
|
+
constructor(message: string, options?: Omit<GitlabReviewErrorOptions, 'code'>);
|
|
61
|
+
}
|
|
62
|
+
export declare class ParseError extends GitlabReviewError {
|
|
63
|
+
constructor(message: string, options?: Omit<GitlabReviewErrorOptions, 'code'>);
|
|
64
|
+
}
|
|
65
|
+
export declare class RuntimeError extends GitlabReviewError {
|
|
66
|
+
constructor(message: string, options?: Omit<GitlabReviewErrorOptions, 'code'>);
|
|
67
|
+
}
|
|
68
|
+
export declare function formatError(error: unknown): string;
|
|
69
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Discussion } from './gitlab.js';
|
|
2
|
+
import type { Fingerprints, ReviewComment, Side } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Pattern source for the hidden fingerprint marker, capturing the hash group.
|
|
5
|
+
* Shared with the parser and prior-thread detection so the marker format is
|
|
6
|
+
* defined in one place; each call site builds its own RegExp with the flags it
|
|
7
|
+
* needs (the capture group is harmless when only stripping or testing). This is
|
|
8
|
+
* a stable wire contract — see CLAUDE.md before changing it.
|
|
9
|
+
*
|
|
10
|
+
* Reads match BOTH the current `code-review:` prefix and the legacy
|
|
11
|
+
* `gitlab-review:` prefix so findings posted under the old product identity are
|
|
12
|
+
* still recognised and deduplicated after the rename. Writes emit the current
|
|
13
|
+
* prefix (see {@link appendFingerprintMarkers}).
|
|
14
|
+
*/
|
|
15
|
+
export declare const FINGERPRINT_MARKER_PATTERN: string;
|
|
16
|
+
export declare function sha256(input: string): string;
|
|
17
|
+
export declare function normalizeBody(body: string): string;
|
|
18
|
+
export declare function extractDiffHunkContext(diff: string, file: string, line: number, side: Side): string;
|
|
19
|
+
export declare function fingerprints(comment: ReviewComment, hunkContext: string): Fingerprints;
|
|
20
|
+
export declare function appendFingerprintMarkers(body: string, fp: Fingerprints): string;
|
|
21
|
+
export declare function extractExistingFingerprints(discussions: Discussion[]): Set<string>;
|
|
22
|
+
//# sourceMappingURL=fingerprints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fingerprints.d.ts","sourceRoot":"","sources":["../src/fingerprints.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,QAAuG,CAAC;AAI/I,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAsCD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,IAAI,GACT,MAAM,CAqCR;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,GAAG,YAAY,CAetF;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,YAAY,GAAG,MAAM,CAE/E;AAED,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAUlF"}
|
package/dist/git.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export interface GitOptions {
|
|
2
|
+
cwd?: string;
|
|
3
|
+
}
|
|
4
|
+
export interface PrepareGitHistoryOptions extends GitOptions {
|
|
5
|
+
remote?: string;
|
|
6
|
+
codeQualityArtifacts?: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function git(args: string[], options?: GitOptions): Promise<string>;
|
|
9
|
+
export declare function getMergeDiffArguments(targetBranch: string, options?: {
|
|
10
|
+
remote?: string;
|
|
11
|
+
context?: number;
|
|
12
|
+
}): string[];
|
|
13
|
+
/**
|
|
14
|
+
* Full git argv for the merge diff. `-c core.quotepath=false` keeps non-ASCII
|
|
15
|
+
* paths literal instead of git's default octal-escaped + double-quoted form
|
|
16
|
+
* (`"a/caf\303\251.ts"`), which the comment-position parser cannot match —
|
|
17
|
+
* leaving such comments with invalid one-sided positions that 500 on
|
|
18
|
+
* `bulk_publish`. Diffing literally also gives the reviewer readable paths.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getMergeDiffCommand(targetBranch: string, options?: {
|
|
21
|
+
remote?: string;
|
|
22
|
+
context?: number;
|
|
23
|
+
}): string[];
|
|
24
|
+
export declare function removeGeneratedCodeQualityArtifacts(paths?: string[], options?: GitOptions): Promise<string[]>;
|
|
25
|
+
export declare function prepareGitHistory(sourceBranch: string, targetBranch: string, options?: PrepareGitHistoryOptions): Promise<void>;
|
|
26
|
+
export declare function getMergeDiff(targetBranch: string, options?: GitOptions & {
|
|
27
|
+
remote?: string;
|
|
28
|
+
context?: number;
|
|
29
|
+
}): Promise<string>;
|
|
30
|
+
export declare function getMergeCommitLogArguments(targetBranch: string, options?: {
|
|
31
|
+
remote?: string;
|
|
32
|
+
}): string[];
|
|
33
|
+
export declare function getMergeCommitLog(targetBranch: string, options?: GitOptions & {
|
|
34
|
+
remote?: string;
|
|
35
|
+
}): Promise<string>;
|
|
36
|
+
export interface DiffSummary {
|
|
37
|
+
filesChanged: number;
|
|
38
|
+
linesAdded: number;
|
|
39
|
+
linesRemoved: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Summarize a unified diff into file/line counts for telemetry. Counts one file
|
|
43
|
+
* per `diff --git` header and counts `+`/`-` lines only inside a hunk (after a
|
|
44
|
+
* `@@` header), so the `--- a/file` / `+++ b/file` header lines are excluded and
|
|
45
|
+
* a genuine content line whose text starts with `++`/`--` is still counted. Pure
|
|
46
|
+
* and allocation-light so it can run on the full merge diff without an extra git
|
|
47
|
+
* invocation.
|
|
48
|
+
*/
|
|
49
|
+
export declare function summarizeDiff(diff: string): DiffSummary;
|
|
50
|
+
//# sourceMappingURL=git.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,wBAAyB,SAAQ,UAAU;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAgBD,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAanF;AAMD,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAClD,MAAM,EAAE,CAIV;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAClD,MAAM,EAAE,CAEV;AAkBD,wBAAsB,mCAAmC,CACvD,KAAK,WAAgC,EACrC,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC,CAanB;AAED,wBAAsB,iBAAiB,CACrC,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CAoCf;AAED,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,UAAU,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/D,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAChC,MAAM,EAAE,CAQV;AAED,wBAAsB,iBAAiB,CACrC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,UAAU,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7C,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAkBvD"}
|