@weareikko/code-review 0.8.6 → 0.9.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/dist/{cli-BbR1oftT.js → cli-BGn8g23f.js} +276 -175
- package/dist/cli-BGn8g23f.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/diagnostics.d.ts +11 -1
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/gitlab-review.d.ts +9 -0
- package/dist/gitlab-review.d.ts.map +1 -1
- package/dist/otel.d.ts +20 -4
- package/dist/otel.d.ts.map +1 -1
- package/dist/review.js +1 -1
- package/package.json +1 -1
- package/dist/cli-BbR1oftT.js.map +0 -1
|
@@ -560,7 +560,7 @@ function buildSummaryBody(summary, costFooter, options = {}) {
|
|
|
560
560
|
return `${withFooter}\n\n${buildSummaryHistoryBlock(historyEntries)}`;
|
|
561
561
|
}
|
|
562
562
|
function buildReviewedCommitFooter(commitSha) {
|
|
563
|
-
return `Reviewed by ${PRODUCT_LINK} v0.
|
|
563
|
+
return `Reviewed by ${PRODUCT_LINK} v0.9.1 for commit ${commitSha}.`;
|
|
564
564
|
}
|
|
565
565
|
function extractReviewedCommitSha(body) {
|
|
566
566
|
return REVIEWED_COMMIT_FOOTER_PATTERN.exec(body)?.[1] ?? null;
|
|
@@ -1359,6 +1359,7 @@ function createDiagnosticContext(phase, config, runId, overrides = {}) {
|
|
|
1359
1359
|
project: config.project,
|
|
1360
1360
|
mr: config.mr,
|
|
1361
1361
|
gitlabUrl: config.gitlabUrl,
|
|
1362
|
+
platform: config.platform,
|
|
1362
1363
|
cwd: config.cwd,
|
|
1363
1364
|
model: config.model,
|
|
1364
1365
|
minSeverity: config.minSeverity,
|
|
@@ -4354,54 +4355,59 @@ async function runReview(config, options) {
|
|
|
4354
4355
|
attachTelemetry: options.attachTelemetry,
|
|
4355
4356
|
verifyStaged: diskMode ? retrievableSkipped : void 0
|
|
4356
4357
|
};
|
|
4358
|
+
const buildUsage = () => ({
|
|
4359
|
+
model: config.model,
|
|
4360
|
+
thinkingLevel: config.thinkingLevel,
|
|
4361
|
+
tokens: aggregated.tokens,
|
|
4362
|
+
cost: aggregated.cost,
|
|
4363
|
+
byModel: buildByModelUsage(aggregated),
|
|
4364
|
+
skills: context.skills.map((s) => s.name),
|
|
4365
|
+
sizeNotice
|
|
4366
|
+
});
|
|
4357
4367
|
let outputText;
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
const detachTelemetry = options.attachTelemetry?.(findAgent);
|
|
4370
|
-
let turnCount = 0;
|
|
4371
|
-
let toolCallCount = 0;
|
|
4372
|
-
let finalText;
|
|
4373
|
-
try {
|
|
4374
|
-
finalText = await runAgentToCompletion(findAgent, userPrompt, {
|
|
4375
|
-
timeoutMs,
|
|
4376
|
-
onAssistantMessage: (message) => accumulateUsage(aggregated, message, primary.id),
|
|
4377
|
-
onTurnStart: (turn) => {
|
|
4378
|
-
turnCount = turn;
|
|
4379
|
-
logger.debug(`Turn ${turn} started`);
|
|
4380
|
-
},
|
|
4381
|
-
onToolStart: (toolName, args) => {
|
|
4382
|
-
toolCallCount += 1;
|
|
4383
|
-
logger.debug(` → ${toolName}${formatToolArgs(toolName, args)}`);
|
|
4384
|
-
}
|
|
4368
|
+
try {
|
|
4369
|
+
if (config.reviewDepth === "full") {
|
|
4370
|
+
const { findings, summary } = await runMultiAngleFind(context, minSeverity, userPrompt, deps);
|
|
4371
|
+
outputText = await verifyAndSynthesize(findings, summary, diff, options.commitLog, deps);
|
|
4372
|
+
} else {
|
|
4373
|
+
const findAgent = createAgent({
|
|
4374
|
+
systemPrompt,
|
|
4375
|
+
model: primary.model,
|
|
4376
|
+
tools,
|
|
4377
|
+
thinkingLevel: config.thinkingLevel,
|
|
4378
|
+
getApiKey: primary.getApiKey
|
|
4385
4379
|
});
|
|
4386
|
-
|
|
4387
|
-
|
|
4380
|
+
const detachTelemetry = options.attachTelemetry?.(findAgent);
|
|
4381
|
+
let turnCount = 0;
|
|
4382
|
+
let toolCallCount = 0;
|
|
4383
|
+
let finalText;
|
|
4384
|
+
try {
|
|
4385
|
+
finalText = await runAgentToCompletion(findAgent, userPrompt, {
|
|
4386
|
+
timeoutMs,
|
|
4387
|
+
onAssistantMessage: (message) => accumulateUsage(aggregated, message, primary.id),
|
|
4388
|
+
onTurnStart: (turn) => {
|
|
4389
|
+
turnCount = turn;
|
|
4390
|
+
logger.debug(`Turn ${turn} started`);
|
|
4391
|
+
},
|
|
4392
|
+
onToolStart: (toolName, args) => {
|
|
4393
|
+
toolCallCount += 1;
|
|
4394
|
+
logger.debug(` → ${toolName}${formatToolArgs(toolName, args)}`);
|
|
4395
|
+
}
|
|
4396
|
+
});
|
|
4397
|
+
} finally {
|
|
4398
|
+
detachTelemetry?.();
|
|
4399
|
+
}
|
|
4400
|
+
logger.debug(`Agent finished: ${turnCount} turn(s), ${toolCallCount} tool call(s)`);
|
|
4401
|
+
outputText = config.reviewDepth === "verify" ? await runVerifyStage(finalText, diff, options.commitLog, deps) : finalText;
|
|
4388
4402
|
}
|
|
4389
|
-
|
|
4390
|
-
|
|
4403
|
+
} finally {
|
|
4404
|
+
options.onUsage?.(buildUsage());
|
|
4391
4405
|
}
|
|
4392
4406
|
const reviewPath = resolve(cwd, config.reviewFile);
|
|
4393
4407
|
await mkdir(dirname(reviewPath), { recursive: true });
|
|
4394
4408
|
await writeFile(reviewPath, outputText, "utf8");
|
|
4395
4409
|
if (retrievableSkipped.length > 0) await cleanupSkippedDiffs(cwd);
|
|
4396
|
-
return
|
|
4397
|
-
model: config.model,
|
|
4398
|
-
thinkingLevel: config.thinkingLevel,
|
|
4399
|
-
tokens: aggregated.tokens,
|
|
4400
|
-
cost: aggregated.cost,
|
|
4401
|
-
byModel: buildByModelUsage(aggregated),
|
|
4402
|
-
skills: context.skills.map((s) => s.name),
|
|
4403
|
-
sizeNotice
|
|
4404
|
-
};
|
|
4410
|
+
return buildUsage();
|
|
4405
4411
|
}
|
|
4406
4412
|
/**
|
|
4407
4413
|
* Convert the per-model usage buckets into the public {@link ModelUsage} array,
|
|
@@ -4758,13 +4764,13 @@ async function startOtelBridge(options = {}) {
|
|
|
4758
4764
|
unit: "{token}",
|
|
4759
4765
|
advice: { explicitBucketBoundaries: TOKEN_BUCKETS }
|
|
4760
4766
|
});
|
|
4761
|
-
const operationCost = meter.createHistogram("
|
|
4762
|
-
description: "
|
|
4767
|
+
const operationCost = meter.createHistogram("code_review_llm_cost_usd", {
|
|
4768
|
+
description: "LLM cost in USD per turn, by token type (non-standard extension)",
|
|
4763
4769
|
unit: "{usd}",
|
|
4764
4770
|
advice: { explicitBucketBoundaries: COST_BUCKETS_USD }
|
|
4765
4771
|
});
|
|
4766
|
-
const timeToFirstToken = meter.createHistogram("gen_ai.client.
|
|
4767
|
-
description: "Time to first
|
|
4772
|
+
const timeToFirstToken = meter.createHistogram("gen_ai.client.operation.time_to_first_chunk", {
|
|
4773
|
+
description: "Time to first chunk from the LLM",
|
|
4768
4774
|
unit: "s",
|
|
4769
4775
|
advice: { explicitBucketBoundaries: TTFT_BUCKETS_S }
|
|
4770
4776
|
});
|
|
@@ -4804,6 +4810,9 @@ async function startOtelBridge(options = {}) {
|
|
|
4804
4810
|
ciAttrs,
|
|
4805
4811
|
ciSpanAttrs,
|
|
4806
4812
|
model: ctx.model,
|
|
4813
|
+
dryRun: ctx.dryRun,
|
|
4814
|
+
platform: ctx.platform,
|
|
4815
|
+
serverAddress: hostOf(ctx.gitlabUrl),
|
|
4807
4816
|
rootSpanCtx
|
|
4808
4817
|
});
|
|
4809
4818
|
emitReviewStartedLog(logger, ctx, ciAttrs, ciSpanAttrs, rootSpanCtx);
|
|
@@ -4835,50 +4844,55 @@ async function startOtelBridge(options = {}) {
|
|
|
4835
4844
|
entry.span.end();
|
|
4836
4845
|
entry.closed = true;
|
|
4837
4846
|
const status = resolveRunStatus(ctx, isError);
|
|
4838
|
-
const projectPath = ciAttrs["
|
|
4847
|
+
const projectPath = ciAttrs["vcs.repository.name"] ?? "";
|
|
4848
|
+
const vcs = vcsAttrs(ctx.platform, ctx.gitlabUrl);
|
|
4839
4849
|
if (typeof ctx.durationMs === "number") reviewPhaseDuration.record(ctx.durationMs / 1e3, {
|
|
4840
4850
|
...REVIEW_SERVICE_ATTRS,
|
|
4841
|
-
|
|
4842
|
-
"
|
|
4843
|
-
"
|
|
4851
|
+
...vcs,
|
|
4852
|
+
"vcs.repository.name": projectPath,
|
|
4853
|
+
"code_review.phase": ctx.phase,
|
|
4854
|
+
"code_review.status": status
|
|
4844
4855
|
});
|
|
4845
4856
|
if (ctx.phase === ROOT_PHASE) {
|
|
4846
4857
|
const meta = runMeta.get(ctx.runId);
|
|
4847
|
-
const pipelineSource = ciAttrs["
|
|
4858
|
+
const pipelineSource = ciAttrs["cicd.pipeline.source"] ?? "";
|
|
4848
4859
|
const runMetricBase = {
|
|
4849
4860
|
...REVIEW_SERVICE_ATTRS,
|
|
4850
|
-
|
|
4851
|
-
"
|
|
4861
|
+
...vcs,
|
|
4862
|
+
"vcs.repository.name": projectPath,
|
|
4863
|
+
"code_review.dry_run": ctx.dryRun,
|
|
4864
|
+
...ctx.firstReview !== void 0 ? { "code_review.first_review": ctx.firstReview } : {}
|
|
4852
4865
|
};
|
|
4853
4866
|
const usage = meta?.usage ?? ctx.usage;
|
|
4854
4867
|
const runModelAttrs = genAiModelAttrs(void 0, splitModel(usage?.model ?? "").modelId);
|
|
4855
4868
|
reviewRunsTotal.add(1, {
|
|
4856
4869
|
...runMetricBase,
|
|
4857
|
-
"
|
|
4858
|
-
"
|
|
4870
|
+
"cicd.pipeline.source": pipelineSource,
|
|
4871
|
+
"code_review.status": status
|
|
4859
4872
|
});
|
|
4860
4873
|
if (isError) reviewErrorsTotal.add(1, {
|
|
4861
4874
|
...runMetricBase,
|
|
4862
|
-
"
|
|
4875
|
+
"code_review.status": status,
|
|
4863
4876
|
"error.type": errorTypeOf(ctx)
|
|
4864
4877
|
});
|
|
4865
4878
|
if (typeof ctx.durationMs === "number") reviewRunDuration.record(ctx.durationMs / 1e3, {
|
|
4866
4879
|
...runMetricBase,
|
|
4867
4880
|
...runModelAttrs,
|
|
4868
|
-
"
|
|
4869
|
-
"
|
|
4881
|
+
"cicd.pipeline.source": pipelineSource,
|
|
4882
|
+
"code_review.status": status
|
|
4870
4883
|
});
|
|
4871
4884
|
const totalCostUsd = usage?.cost.total;
|
|
4872
4885
|
if (totalCostUsd !== void 0) reviewTotalCost.record(totalCostUsd, {
|
|
4873
4886
|
...runMetricBase,
|
|
4874
4887
|
...runModelAttrs,
|
|
4875
|
-
"
|
|
4888
|
+
"code_review.status": status
|
|
4876
4889
|
});
|
|
4877
4890
|
if (usage) {
|
|
4878
4891
|
const tokenAttrs = {
|
|
4879
4892
|
...REVIEW_SERVICE_ATTRS,
|
|
4880
4893
|
...runModelAttrs,
|
|
4881
|
-
|
|
4894
|
+
...vcs,
|
|
4895
|
+
"vcs.repository.name": projectPath
|
|
4882
4896
|
};
|
|
4883
4897
|
for (const [field, type] of [
|
|
4884
4898
|
["input", "input"],
|
|
@@ -4894,7 +4908,7 @@ async function startOtelBridge(options = {}) {
|
|
|
4894
4908
|
if (bySeverity) {
|
|
4895
4909
|
for (const [severity, count] of Object.entries(bySeverity)) if (count && count > 0) reviewCommentsTotal.add(count, {
|
|
4896
4910
|
...runMetricBase,
|
|
4897
|
-
"
|
|
4911
|
+
"code_review.comment.severity": severity
|
|
4898
4912
|
});
|
|
4899
4913
|
} else {
|
|
4900
4914
|
const posted = ctx.posted ?? 0;
|
|
@@ -4940,16 +4954,17 @@ async function startOtelBridge(options = {}) {
|
|
|
4940
4954
|
context: meta?.rootSpanCtx,
|
|
4941
4955
|
attributes: {
|
|
4942
4956
|
"service.name": SERVICE_NAME,
|
|
4943
|
-
"event.name": "
|
|
4944
|
-
"
|
|
4945
|
-
"
|
|
4946
|
-
"
|
|
4947
|
-
"
|
|
4948
|
-
"
|
|
4957
|
+
"event.name": "code_review.comment",
|
|
4958
|
+
"code_review.run_id": runId,
|
|
4959
|
+
"code_review.comment.file": comment.file,
|
|
4960
|
+
"code_review.comment.line": comment.line,
|
|
4961
|
+
"code_review.comment.severity": comment.severity,
|
|
4962
|
+
"code_review.comment.is_duplicate": duplicate,
|
|
4949
4963
|
...meta && {
|
|
4950
|
-
"
|
|
4951
|
-
"
|
|
4952
|
-
"
|
|
4964
|
+
"vcs.repository.id": meta.project,
|
|
4965
|
+
"vcs.change.id": meta.mr,
|
|
4966
|
+
...meta.platform ? { "vcs.provider.name": meta.platform } : {},
|
|
4967
|
+
...meta.serverAddress ? { "server.address": meta.serverAddress } : {},
|
|
4953
4968
|
...meta.ciAttrs,
|
|
4954
4969
|
...meta.ciSpanAttrs
|
|
4955
4970
|
}
|
|
@@ -4964,20 +4979,30 @@ async function startOtelBridge(options = {}) {
|
|
|
4964
4979
|
ciAttrs,
|
|
4965
4980
|
runId,
|
|
4966
4981
|
configuredModel: runMeta.get(runId)?.model,
|
|
4982
|
+
dryRun: runMeta.get(runId)?.dryRun,
|
|
4983
|
+
platform: runMeta.get(runId)?.platform,
|
|
4984
|
+
serverAddress: runMeta.get(runId)?.serverAddress,
|
|
4967
4985
|
captureContent
|
|
4968
4986
|
});
|
|
4969
4987
|
}
|
|
4970
4988
|
};
|
|
4971
4989
|
}
|
|
4972
4990
|
/**
|
|
4973
|
-
* Builds the dynamic `gen_ai.
|
|
4974
|
-
* shared by the per-turn and per-phase GenAI metric emitters. Owning
|
|
4975
|
-
* one place keeps the two emission sites from drifting into separate
|
|
4976
|
-
* series (the double-count `recordGenAiMetrics` documents).
|
|
4991
|
+
* Builds the dynamic `gen_ai.provider.name` / `gen_ai.request.model` metric
|
|
4992
|
+
* labels shared by the per-turn and per-phase GenAI metric emitters. Owning
|
|
4993
|
+
* these in one place keeps the two emission sites from drifting into separate
|
|
4994
|
+
* Prometheus series (the double-count `recordGenAiMetrics` documents).
|
|
4995
|
+
*
|
|
4996
|
+
* `gen_ai.provider.name` is the current GenAI-semconv discriminator; the
|
|
4997
|
+
* deprecated `gen_ai.system` is emitted alongside it during the transition so
|
|
4998
|
+
* backends still keyed on the old attribute keep working.
|
|
4977
4999
|
*/
|
|
4978
5000
|
function genAiModelAttrs(provider, modelId) {
|
|
4979
5001
|
return {
|
|
4980
|
-
...provider ? {
|
|
5002
|
+
...provider ? {
|
|
5003
|
+
"gen_ai.provider.name": provider,
|
|
5004
|
+
"gen_ai.system": provider
|
|
5005
|
+
} : {},
|
|
4981
5006
|
...modelId ? { "gen_ai.request.model": modelId } : {}
|
|
4982
5007
|
};
|
|
4983
5008
|
}
|
|
@@ -5033,9 +5058,9 @@ function recordTurnUsage(span, u, metricAttrs, tokenUsage, operationCost) {
|
|
|
5033
5058
|
...metricAttrs,
|
|
5034
5059
|
"gen_ai.token.type": "cache_creation"
|
|
5035
5060
|
});
|
|
5036
|
-
span.setAttribute("
|
|
5037
|
-
span.setAttribute("
|
|
5038
|
-
span.setAttribute("
|
|
5061
|
+
span.setAttribute("code_review.cost.input_usd", u.cost.input);
|
|
5062
|
+
span.setAttribute("code_review.cost.output_usd", u.cost.output);
|
|
5063
|
+
span.setAttribute("code_review.cost.total_usd", u.cost.total);
|
|
5039
5064
|
}
|
|
5040
5065
|
}
|
|
5041
5066
|
/**
|
|
@@ -5099,12 +5124,15 @@ function extractOutputMessages(msg) {
|
|
|
5099
5124
|
}]);
|
|
5100
5125
|
}
|
|
5101
5126
|
function buildAgentSubscriber(tracer, tokenUsage, operationCost, timeToFirstToken, reviewerSpanCtx, options = {}) {
|
|
5102
|
-
const { ciAttrs = {}, runId, configuredModel, captureContent = false } = options;
|
|
5127
|
+
const { ciAttrs = {}, runId, configuredModel, dryRun, platform, serverAddress, captureContent = false } = options;
|
|
5103
5128
|
const configuredProvider = configuredModel ? splitModel(configuredModel).provider : void 0;
|
|
5104
5129
|
const baseMetricAttrs = {
|
|
5105
5130
|
"gen_ai.operation.name": "invoke_agent",
|
|
5106
5131
|
...REVIEW_SERVICE_ATTRS,
|
|
5107
|
-
...ciAttrs
|
|
5132
|
+
...ciAttrs,
|
|
5133
|
+
...dryRun !== void 0 ? { "code_review.dry_run": dryRun } : {},
|
|
5134
|
+
...platform ? { "vcs.provider.name": platform } : {},
|
|
5135
|
+
...serverAddress ? { "server.address": serverAddress } : {}
|
|
5108
5136
|
};
|
|
5109
5137
|
return (agent) => {
|
|
5110
5138
|
let currentTurn;
|
|
@@ -5138,13 +5166,16 @@ function buildAgentSubscriber(tracer, tokenUsage, operationCost, timeToFirstToke
|
|
|
5138
5166
|
...baseMetricAttrs,
|
|
5139
5167
|
...genAiModelAttrs(provider, modelId)
|
|
5140
5168
|
};
|
|
5141
|
-
if (provider)
|
|
5169
|
+
if (provider) {
|
|
5170
|
+
span.setAttribute("gen_ai.provider.name", provider);
|
|
5171
|
+
span.setAttribute("gen_ai.system", provider);
|
|
5172
|
+
}
|
|
5142
5173
|
if (modelId) span.setAttribute("gen_ai.response.model", modelId);
|
|
5143
5174
|
if (msg.stopReason) span.setAttribute("gen_ai.response.stop_reason", msg.stopReason);
|
|
5144
5175
|
if (firstTokenMs !== void 0) {
|
|
5145
5176
|
const ttftS = (firstTokenMs - startMs) / 1e3;
|
|
5146
5177
|
timeToFirstToken.record(ttftS, metricAttrs);
|
|
5147
|
-
span.setAttribute("gen_ai.client.
|
|
5178
|
+
span.setAttribute("gen_ai.client.operation.time_to_first_chunk_s", ttftS);
|
|
5148
5179
|
}
|
|
5149
5180
|
if (msg.usage) recordTurnUsage(span, msg.usage, metricAttrs, tokenUsage, operationCost);
|
|
5150
5181
|
if (captureContent) {
|
|
@@ -5205,6 +5236,26 @@ function buildAgentSubscriber(tracer, tokenUsage, operationCost, timeToFirstToke
|
|
|
5205
5236
|
});
|
|
5206
5237
|
};
|
|
5207
5238
|
}
|
|
5239
|
+
/**
|
|
5240
|
+
* Applies our OTLP exporter env defaults, only when the caller hasn't set them
|
|
5241
|
+
* (explicit choices, including `none`, always win).
|
|
5242
|
+
*
|
|
5243
|
+
* Metrics temporality defaults to **delta** because code-review runs as a
|
|
5244
|
+
* short-lived CI job. With the OTel SDK's default cumulative temporality, each
|
|
5245
|
+
* ephemeral job's metric series starts mid-flight in the backend (its first
|
|
5246
|
+
* export already carries accumulated counts, and per-run histograms are a single
|
|
5247
|
+
* observation), so range aggregation of cost/token totals is unreliable —
|
|
5248
|
+
* `sum_over_time` over-counts and `increase` under-counts or returns nothing.
|
|
5249
|
+
* Delta makes each job's metrics self-contained deltas that sum correctly across
|
|
5250
|
+
* runs. Override with `OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=cumulative`
|
|
5251
|
+
* for long-running hosts, and confirm your backend ingests delta (Grafana
|
|
5252
|
+
* Cloud/Mimir converts to cumulative or stores it natively) before relying on it.
|
|
5253
|
+
*/
|
|
5254
|
+
function applyOtelExporterDefaults(env = process.env) {
|
|
5255
|
+
env.OTEL_METRICS_EXPORTER = env.OTEL_METRICS_EXPORTER ?? "otlp";
|
|
5256
|
+
env.OTEL_LOGS_EXPORTER = env.OTEL_LOGS_EXPORTER ?? "otlp";
|
|
5257
|
+
env.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE = env.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE ?? "delta";
|
|
5258
|
+
}
|
|
5208
5259
|
async function loadDefaultRuntime() {
|
|
5209
5260
|
let modules;
|
|
5210
5261
|
try {
|
|
@@ -5215,10 +5266,9 @@ async function loadDefaultRuntime() {
|
|
|
5215
5266
|
const [sdkNode, resources, semconv] = modules;
|
|
5216
5267
|
const serviceResource = resources.resourceFromAttributes({
|
|
5217
5268
|
[semconv.ATTR_SERVICE_NAME ?? "service.name"]: SERVICE_NAME,
|
|
5218
|
-
[semconv.ATTR_SERVICE_VERSION ?? "service.version"]: "0.
|
|
5269
|
+
[semconv.ATTR_SERVICE_VERSION ?? "service.version"]: "0.9.1"
|
|
5219
5270
|
});
|
|
5220
|
-
process.env
|
|
5221
|
-
process.env.OTEL_LOGS_EXPORTER = process.env.OTEL_LOGS_EXPORTER ?? "otlp";
|
|
5271
|
+
applyOtelExporterDefaults(process.env);
|
|
5222
5272
|
const sdk = new sdkNode.NodeSDK({ resource: resources.defaultResource().merge(serviceResource) });
|
|
5223
5273
|
sdk.start();
|
|
5224
5274
|
return {
|
|
@@ -5237,14 +5287,14 @@ function emitReviewStartedLog(logger, ctx, ciAttrs, ciSpanAttrs, rootSpanCtx) {
|
|
|
5237
5287
|
context: rootSpanCtx,
|
|
5238
5288
|
attributes: {
|
|
5239
5289
|
"service.name": SERVICE_NAME,
|
|
5240
|
-
"event.name": "
|
|
5241
|
-
"
|
|
5242
|
-
"
|
|
5243
|
-
|
|
5290
|
+
"event.name": "code_review.started",
|
|
5291
|
+
"vcs.repository.id": ctx.project,
|
|
5292
|
+
"vcs.change.id": ctx.mr,
|
|
5293
|
+
...vcsAttrs(ctx.platform, ctx.gitlabUrl),
|
|
5244
5294
|
...ciAttrs,
|
|
5245
5295
|
...ciSpanAttrs,
|
|
5246
|
-
"
|
|
5247
|
-
"
|
|
5296
|
+
"code_review.run_id": ctx.runId,
|
|
5297
|
+
"code_review.dry_run": ctx.dryRun,
|
|
5248
5298
|
...modelId !== void 0 && { "gen_ai.request.model": modelId }
|
|
5249
5299
|
}
|
|
5250
5300
|
});
|
|
@@ -5264,10 +5314,10 @@ function emitReviewCompletedLog(logger, ctx, meta, isError) {
|
|
|
5264
5314
|
context: meta?.rootSpanCtx,
|
|
5265
5315
|
attributes: {
|
|
5266
5316
|
"service.name": SERVICE_NAME,
|
|
5267
|
-
"event.name": isError ? "
|
|
5268
|
-
"
|
|
5269
|
-
"
|
|
5270
|
-
|
|
5317
|
+
"event.name": isError ? "code_review.failed" : "code_review.completed",
|
|
5318
|
+
"vcs.repository.id": ctx.project,
|
|
5319
|
+
"vcs.change.id": ctx.mr,
|
|
5320
|
+
...vcsAttrs(ctx.platform, ctx.gitlabUrl),
|
|
5271
5321
|
...meta?.ciAttrs,
|
|
5272
5322
|
...meta?.ciSpanAttrs,
|
|
5273
5323
|
...isError && {
|
|
@@ -5275,15 +5325,15 @@ function emitReviewCompletedLog(logger, ctx, meta, isError) {
|
|
|
5275
5325
|
...ctx.errorInfo && { "error.message": ctx.errorInfo.message },
|
|
5276
5326
|
...typeof ctx.errorInfo?.status === "number" && { "http.response.status_code": ctx.errorInfo.status }
|
|
5277
5327
|
},
|
|
5278
|
-
"
|
|
5279
|
-
"
|
|
5280
|
-
"
|
|
5281
|
-
"
|
|
5282
|
-
"
|
|
5283
|
-
"
|
|
5284
|
-
"
|
|
5328
|
+
"code_review.run_id": ctx.runId,
|
|
5329
|
+
"code_review.duration_ms": ctx.durationMs ?? 0,
|
|
5330
|
+
"code_review.dry_run": ctx.dryRun,
|
|
5331
|
+
"code_review.comments.generated": ctx.generated ?? 0,
|
|
5332
|
+
"code_review.comments.new": ctx.newComments ?? 0,
|
|
5333
|
+
"code_review.comments.duplicate": ctx.duplicateComments ?? 0,
|
|
5334
|
+
"code_review.comments.posted": ctx.posted ?? 0,
|
|
5285
5335
|
...modelId !== void 0 && { "gen_ai.request.model": modelId },
|
|
5286
|
-
...cost !== void 0 && { "
|
|
5336
|
+
...cost !== void 0 && { "code_review.cost.total_usd": cost },
|
|
5287
5337
|
...usage?.tokens.input !== void 0 && { "gen_ai.usage.input_tokens": usage.tokens.input + (usage.tokens.cacheRead ?? 0) },
|
|
5288
5338
|
...usage?.tokens.cacheRead && {
|
|
5289
5339
|
"gen_ai.usage.input_tokens.cached": usage.tokens.cacheRead,
|
|
@@ -5302,39 +5352,39 @@ function spanNameFor(phase) {
|
|
|
5302
5352
|
/** Creates the review-level OTel metric instruments on the given meter. */
|
|
5303
5353
|
function createReviewInstruments(meter) {
|
|
5304
5354
|
return {
|
|
5305
|
-
reviewRunsTotal: meter.createCounter("
|
|
5306
|
-
reviewErrorsTotal: meter.createCounter("
|
|
5355
|
+
reviewRunsTotal: meter.createCounter("code_review_runs_total", { description: "Total number of code-review runs, labelled by terminal status" }),
|
|
5356
|
+
reviewErrorsTotal: meter.createCounter("code_review_errors_total", { description: "Total number of failed code-review runs, labelled by error type" }),
|
|
5307
5357
|
reviewLlmTokens: {
|
|
5308
|
-
input: meter.createCounter("
|
|
5358
|
+
input: meter.createCounter("code_review_llm_input_tokens_total", {
|
|
5309
5359
|
description: "Total non-cached LLM input tokens consumed across code-review runs",
|
|
5310
5360
|
unit: "{token}"
|
|
5311
5361
|
}),
|
|
5312
|
-
output: meter.createCounter("
|
|
5362
|
+
output: meter.createCounter("code_review_llm_output_tokens_total", {
|
|
5313
5363
|
description: "Total LLM output tokens generated across code-review runs",
|
|
5314
5364
|
unit: "{token}"
|
|
5315
5365
|
}),
|
|
5316
|
-
cache_read: meter.createCounter("
|
|
5366
|
+
cache_read: meter.createCounter("code_review_llm_cache_read_tokens_total", {
|
|
5317
5367
|
description: "Total LLM cache-read input tokens across code-review runs",
|
|
5318
5368
|
unit: "{token}"
|
|
5319
5369
|
}),
|
|
5320
|
-
cache_creation: meter.createCounter("
|
|
5370
|
+
cache_creation: meter.createCounter("code_review_llm_cache_creation_tokens_total", {
|
|
5321
5371
|
description: "Total LLM cache-creation input tokens across code-review runs",
|
|
5322
5372
|
unit: "{token}"
|
|
5323
5373
|
})
|
|
5324
5374
|
},
|
|
5325
|
-
reviewRunDuration: meter.createHistogram("
|
|
5375
|
+
reviewRunDuration: meter.createHistogram("code_review_run_duration_seconds", {
|
|
5326
5376
|
description: "Duration of a complete code-review run",
|
|
5327
5377
|
unit: "s",
|
|
5328
5378
|
advice: { explicitBucketBoundaries: REVIEW_RUN_DURATION_BUCKETS_S }
|
|
5329
5379
|
}),
|
|
5330
|
-
reviewTotalCost: meter.createHistogram("
|
|
5380
|
+
reviewTotalCost: meter.createHistogram("code_review_total_cost_usd", {
|
|
5331
5381
|
description: "Total LLM cost in USD for a complete code-review run",
|
|
5332
5382
|
unit: "{usd}",
|
|
5333
5383
|
advice: { explicitBucketBoundaries: REVIEW_TOTAL_COST_BUCKETS_USD }
|
|
5334
5384
|
}),
|
|
5335
|
-
reviewCommentsTotal: meter.createCounter("
|
|
5336
|
-
reviewDraftsPublishedTotal: meter.createCounter("
|
|
5337
|
-
reviewPhaseDuration: meter.createHistogram("
|
|
5385
|
+
reviewCommentsTotal: meter.createCounter("code_review_comments_total", { description: "Total number of MR comments posted by code-review" }),
|
|
5386
|
+
reviewDraftsPublishedTotal: meter.createCounter("code_review_drafts_published_total", { description: "Total number of draft notes published by code-review" }),
|
|
5387
|
+
reviewPhaseDuration: meter.createHistogram("code_review_phase_duration_seconds", {
|
|
5338
5388
|
description: "Duration of individual code-review workflow phases",
|
|
5339
5389
|
unit: "s",
|
|
5340
5390
|
advice: { explicitBucketBoundaries: REVIEW_PHASE_DURATION_BUCKETS_S }
|
|
@@ -5358,7 +5408,7 @@ function errorTypeOf(ctx) {
|
|
|
5358
5408
|
return base;
|
|
5359
5409
|
}
|
|
5360
5410
|
/**
|
|
5361
|
-
* Derives the `
|
|
5411
|
+
* Derives the `code_review.status` label used by review-level OTel metrics.
|
|
5362
5412
|
* Distinguishes timeouts (AbortError / ETIMEDOUT) from generic errors so
|
|
5363
5413
|
* Grafana alerts can treat deadline-exceeded runs separately.
|
|
5364
5414
|
*/
|
|
@@ -5369,55 +5419,91 @@ function resolveRunStatus(ctx, isError) {
|
|
|
5369
5419
|
return "error";
|
|
5370
5420
|
}
|
|
5371
5421
|
/**
|
|
5372
|
-
* Extracts
|
|
5373
|
-
*
|
|
5374
|
-
*
|
|
5422
|
+
* Extracts low-cardinality CI project/pipeline context (repository, owner, base
|
|
5423
|
+
* branch, pipeline trigger) as platform-neutral `vcs.*` / `cicd.*` attributes
|
|
5424
|
+
* added to every metric, span, and log record. Sourced from GitLab CI or GitHub
|
|
5425
|
+
* Actions variables — a run is one or the other, so `??` picks whichever is set;
|
|
5426
|
+
* callers spread the result so missing vars add nothing.
|
|
5375
5427
|
*/
|
|
5376
5428
|
function buildCiAttrs(env) {
|
|
5377
5429
|
const attrs = {};
|
|
5378
|
-
|
|
5379
|
-
if (
|
|
5380
|
-
|
|
5381
|
-
if (
|
|
5430
|
+
const repository = env.CI_PROJECT_PATH ?? env.GITHUB_REPOSITORY;
|
|
5431
|
+
if (repository) attrs["vcs.repository.name"] = repository;
|
|
5432
|
+
const owner = env.CI_PROJECT_NAMESPACE ?? env.GITHUB_REPOSITORY_OWNER;
|
|
5433
|
+
if (owner) attrs["vcs.owner.name"] = owner;
|
|
5434
|
+
const baseRef = env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME ?? env.GITHUB_BASE_REF;
|
|
5435
|
+
if (baseRef) attrs["vcs.ref.base.name"] = baseRef;
|
|
5436
|
+
const pipelineSource = env.CI_PIPELINE_SOURCE ?? env.GITHUB_EVENT_NAME;
|
|
5437
|
+
if (pipelineSource) attrs["cicd.pipeline.source"] = pipelineSource;
|
|
5382
5438
|
return attrs;
|
|
5383
5439
|
}
|
|
5384
5440
|
/**
|
|
5385
|
-
* Extracts high-cardinality
|
|
5386
|
-
*
|
|
5387
|
-
* Prometheus/Mimir).
|
|
5441
|
+
* Extracts high-cardinality CI identifiers that should appear on spans and log
|
|
5442
|
+
* records but NOT on metric data points (to avoid label explosion in
|
|
5443
|
+
* Prometheus/Mimir). Sourced from GitLab CI or GitHub Actions. GitHub exposes no
|
|
5444
|
+
* per-job run id in the environment, so the job's config-key (`GITHUB_JOB`) is
|
|
5445
|
+
* used for the task identifier. Spread via `ciSpanAttrs` stored in RunMeta.
|
|
5388
5446
|
*/
|
|
5389
5447
|
function buildCiSpanAttrs(env) {
|
|
5390
5448
|
const attrs = {};
|
|
5391
|
-
|
|
5392
|
-
if (
|
|
5449
|
+
const taskRunId = env.CI_JOB_ID ?? env.GITHUB_JOB;
|
|
5450
|
+
if (taskRunId) attrs["cicd.pipeline.task.run.id"] = taskRunId;
|
|
5451
|
+
const pipelineRunId = env.CI_PIPELINE_ID ?? env.GITHUB_RUN_ID;
|
|
5452
|
+
if (pipelineRunId) attrs["cicd.pipeline.run.id"] = pipelineRunId;
|
|
5453
|
+
const repositoryUrl = env.CI_PROJECT_URL ?? (env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY ? `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}` : void 0);
|
|
5454
|
+
if (repositoryUrl) attrs["vcs.repository.url.full"] = repositoryUrl;
|
|
5393
5455
|
return attrs;
|
|
5394
5456
|
}
|
|
5457
|
+
/** Host of a server URL, for the low-cardinality `server.address` instance label. */
|
|
5458
|
+
function hostOf(url) {
|
|
5459
|
+
if (!url) return void 0;
|
|
5460
|
+
try {
|
|
5461
|
+
return new URL(url).host;
|
|
5462
|
+
} catch {
|
|
5463
|
+
return;
|
|
5464
|
+
}
|
|
5465
|
+
}
|
|
5466
|
+
/**
|
|
5467
|
+
* Low-cardinality VCS discriminators added to every metric, span, and log:
|
|
5468
|
+
* `vcs.provider.name` (gitlab | github) to filter by platform, and
|
|
5469
|
+
* `server.address` (the instance host) to distinguish multiple GitLab/GitHub
|
|
5470
|
+
* instances (e.g. gitlab.com vs a self-hosted gitlab.example.com).
|
|
5471
|
+
*/
|
|
5472
|
+
function vcsAttrs(platform, serverUrl) {
|
|
5473
|
+
const host = hostOf(serverUrl);
|
|
5474
|
+
return {
|
|
5475
|
+
...platform ? { "vcs.provider.name": platform } : {},
|
|
5476
|
+
...host ? { "server.address": host } : {}
|
|
5477
|
+
};
|
|
5478
|
+
}
|
|
5395
5479
|
function baseAttributes(ctx) {
|
|
5480
|
+
const host = hostOf(ctx.gitlabUrl);
|
|
5396
5481
|
return {
|
|
5397
|
-
"
|
|
5482
|
+
"code_review.run_id": ctx.runId,
|
|
5398
5483
|
"gen_ai.conversation.id": ctx.runId,
|
|
5399
|
-
"
|
|
5400
|
-
"
|
|
5401
|
-
"
|
|
5402
|
-
"
|
|
5403
|
-
"
|
|
5404
|
-
"
|
|
5405
|
-
"
|
|
5484
|
+
"code_review.phase": ctx.phase,
|
|
5485
|
+
"vcs.repository.id": ctx.project,
|
|
5486
|
+
"vcs.change.id": ctx.mr,
|
|
5487
|
+
...ctx.platform ? { "vcs.provider.name": ctx.platform } : {},
|
|
5488
|
+
...host ? { "server.address": host } : {},
|
|
5489
|
+
"code_review.dry_run": ctx.dryRun,
|
|
5490
|
+
"code_review.no_post": ctx.noPost,
|
|
5491
|
+
"code_review.min_severity": ctx.minSeverity
|
|
5406
5492
|
};
|
|
5407
5493
|
}
|
|
5408
5494
|
var NUMERIC_RESULT_ATTRIBUTES = [
|
|
5409
|
-
["durationMs", "
|
|
5410
|
-
["generated", "
|
|
5411
|
-
["newComments", "
|
|
5412
|
-
["duplicateComments", "
|
|
5413
|
-
["posted", "
|
|
5414
|
-
["draftsPublished", "
|
|
5415
|
-
["draftsCreated", "
|
|
5416
|
-
["summaryNoteId", "
|
|
5417
|
-
["warnings", "
|
|
5418
|
-
["draftsAbandoned", "
|
|
5419
|
-
["draftsDeletedPrePublish", "
|
|
5420
|
-
["draftsPublishFailed", "
|
|
5495
|
+
["durationMs", "code_review.duration_ms"],
|
|
5496
|
+
["generated", "code_review.comments.generated"],
|
|
5497
|
+
["newComments", "code_review.comments.new"],
|
|
5498
|
+
["duplicateComments", "code_review.comments.duplicate"],
|
|
5499
|
+
["posted", "code_review.comments.posted"],
|
|
5500
|
+
["draftsPublished", "code_review.drafts.published"],
|
|
5501
|
+
["draftsCreated", "code_review.drafts.created"],
|
|
5502
|
+
["summaryNoteId", "code_review.summary.note_id"],
|
|
5503
|
+
["warnings", "code_review.warnings"],
|
|
5504
|
+
["draftsAbandoned", "code_review.drafts.abandoned"],
|
|
5505
|
+
["draftsDeletedPrePublish", "code_review.drafts.deleted_pre_publish"],
|
|
5506
|
+
["draftsPublishFailed", "code_review.drafts.publish_failed"],
|
|
5421
5507
|
["diffFilesChanged", "diff.files_changed"],
|
|
5422
5508
|
["diffLinesAdded", "diff.lines_added"],
|
|
5423
5509
|
["diffLinesRemoved", "diff.lines_removed"],
|
|
@@ -5425,7 +5511,7 @@ var NUMERIC_RESULT_ATTRIBUTES = [
|
|
|
5425
5511
|
["httpResponseBodySize", "http.response.body.size"]
|
|
5426
5512
|
];
|
|
5427
5513
|
var STRING_RESULT_ATTRIBUTES = [
|
|
5428
|
-
["summaryAction", "
|
|
5514
|
+
["summaryAction", "code_review.summary.action"],
|
|
5429
5515
|
["httpRequestMethod", "http.request.method"],
|
|
5430
5516
|
["httpUrl", "url.full"],
|
|
5431
5517
|
["serverAddress", "server.address"]
|
|
@@ -5442,7 +5528,10 @@ function applyResultAttributes(span, ctx) {
|
|
|
5442
5528
|
}
|
|
5443
5529
|
function applyGenAiAttributes(span, ctx) {
|
|
5444
5530
|
const { provider, modelId } = splitModel(ctx.model ?? "");
|
|
5445
|
-
if (provider)
|
|
5531
|
+
if (provider) {
|
|
5532
|
+
span.setAttribute("gen_ai.provider.name", provider);
|
|
5533
|
+
span.setAttribute("gen_ai.system", provider);
|
|
5534
|
+
}
|
|
5446
5535
|
if (modelId) {
|
|
5447
5536
|
span.setAttribute("gen_ai.request.model", modelId);
|
|
5448
5537
|
span.setAttribute("gen_ai.response.model", modelId);
|
|
@@ -5452,16 +5541,16 @@ function applyGenAiAttributes(span, ctx) {
|
|
|
5452
5541
|
const usage = ctx.usage;
|
|
5453
5542
|
if (!usage) return;
|
|
5454
5543
|
setTokenUsageSpanAttributes(span, usage.tokens);
|
|
5455
|
-
span.setAttribute("
|
|
5456
|
-
span.setAttribute("
|
|
5457
|
-
span.setAttribute("
|
|
5458
|
-
span.setAttribute("
|
|
5459
|
-
span.setAttribute("
|
|
5544
|
+
span.setAttribute("code_review.cost.input_usd", usage.cost.input);
|
|
5545
|
+
span.setAttribute("code_review.cost.output_usd", usage.cost.output);
|
|
5546
|
+
span.setAttribute("code_review.cost.cache_read_usd", usage.cost.cacheRead);
|
|
5547
|
+
span.setAttribute("code_review.cost.cache_creation_usd", usage.cost.cacheWrite);
|
|
5548
|
+
span.setAttribute("code_review.cost.total_usd", usage.cost.total);
|
|
5460
5549
|
}
|
|
5461
5550
|
/**
|
|
5462
5551
|
* Records `gen_ai.client.operation.duration` for the `reviewer.run` phase.
|
|
5463
5552
|
*
|
|
5464
|
-
* Token usage (`gen_ai.client.token.usage`) and cost (`
|
|
5553
|
+
* Token usage (`gen_ai.client.token.usage`) and cost (`code_review_llm_cost_usd`) are
|
|
5465
5554
|
* intentionally NOT recorded here. They are emitted per-turn by
|
|
5466
5555
|
* `buildAgentSubscriber` from the live agent event stream. Keeping a single
|
|
5467
5556
|
* emission point for each metric prevents the double-count that previously
|
|
@@ -5474,7 +5563,9 @@ function recordGenAiMetrics(durationHist, ctx, isError, ciAttrs = {}) {
|
|
|
5474
5563
|
"gen_ai.operation.name": "invoke_agent",
|
|
5475
5564
|
...REVIEW_SERVICE_ATTRS,
|
|
5476
5565
|
...ciAttrs,
|
|
5477
|
-
...
|
|
5566
|
+
...vcsAttrs(ctx.platform, ctx.gitlabUrl),
|
|
5567
|
+
...genAiModelAttrs(provider, modelId),
|
|
5568
|
+
"code_review.dry_run": ctx.dryRun
|
|
5478
5569
|
};
|
|
5479
5570
|
if (isError) attrs["error.type"] = errorTypeOf(ctx);
|
|
5480
5571
|
if (typeof ctx.durationMs === "number") durationHist.record(ctx.durationMs / 1e3, attrs);
|
|
@@ -5647,7 +5738,7 @@ function boldCommentTitle(body) {
|
|
|
5647
5738
|
*/
|
|
5648
5739
|
function buildCommentBody(body, commitSha, confidence) {
|
|
5649
5740
|
const confidenceLine = `_Confidence: ${confidence}._`;
|
|
5650
|
-
const footer = `<sub>Reviewed by ${PRODUCT_LINK} v0.
|
|
5741
|
+
const footer = `<sub>Reviewed by ${PRODUCT_LINK} v0.9.1 for commit ${commitSha}.</sub>`;
|
|
5651
5742
|
return `${boldCommentTitle(body.trim())}\n\n${confidenceLine}\n\n---\n\n${footer}`;
|
|
5652
5743
|
}
|
|
5653
5744
|
function buildPayload(comment, body, refs, resolved) {
|
|
@@ -6442,6 +6533,7 @@ async function run(config, bridges) {
|
|
|
6442
6533
|
const refs = await tracedRead("scm.get_latest_version", () => platform.getRefs());
|
|
6443
6534
|
const initialDiscussions = await tracedRead("scm.get_discussions", () => platform.getDiscussions());
|
|
6444
6535
|
const reviewedCommitSha = findExistingReviewedCommitSha(initialDiscussions);
|
|
6536
|
+
runContext.firstReview = findExistingSummaryNote(initialDiscussions) === null;
|
|
6445
6537
|
if (!config.forceReview && !config.dryRun && !config.noPost && reviewedCommitSha === refs.head_sha) {
|
|
6446
6538
|
const usage = zeroReviewUsage(config.model, config.thinkingLevel);
|
|
6447
6539
|
runContext.usage = usage;
|
|
@@ -6484,27 +6576,36 @@ async function run(config, bridges) {
|
|
|
6484
6576
|
if (priorThreads.length > 0) logger.info(`Found ${priorThreads.length} prior thread(s) with developer replies — including as context.`);
|
|
6485
6577
|
logger.info("Running review...");
|
|
6486
6578
|
let usage;
|
|
6579
|
+
let partialUsage;
|
|
6487
6580
|
try {
|
|
6488
6581
|
usage = await traceDiagnosticPhase("reviewer.run", config, runId, async (context) => {
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6582
|
+
try {
|
|
6583
|
+
const result = await runReview(config, {
|
|
6584
|
+
cwd: config.cwd,
|
|
6585
|
+
diff,
|
|
6586
|
+
commitLog,
|
|
6587
|
+
priorThreads,
|
|
6588
|
+
intent: {
|
|
6589
|
+
title: mr.title,
|
|
6590
|
+
description: mr.description
|
|
6591
|
+
},
|
|
6592
|
+
logger,
|
|
6593
|
+
attachTelemetry: bridges?.otel?.createAgentTelemetry(runId),
|
|
6594
|
+
onUsage: (u) => {
|
|
6595
|
+
partialUsage = u;
|
|
6596
|
+
},
|
|
6597
|
+
sinceRef: config.inputMode === "commits" && reviewedCommitSha && reviewedCommitSha !== refs.head_sha ? reviewedCommitSha : void 0
|
|
6598
|
+
});
|
|
6599
|
+
context.usage = result;
|
|
6600
|
+
return result;
|
|
6601
|
+
} catch (error) {
|
|
6602
|
+
if (partialUsage) context.usage = partialUsage;
|
|
6603
|
+
throw error;
|
|
6604
|
+
}
|
|
6504
6605
|
});
|
|
6505
6606
|
} catch (error) {
|
|
6506
6607
|
if (!isQuotaExceededError(error)) throw error;
|
|
6507
|
-
const skipUsage = zeroReviewUsage(config.model, config.thinkingLevel);
|
|
6608
|
+
const skipUsage = partialUsage ?? zeroReviewUsage(config.model, config.thinkingLevel);
|
|
6508
6609
|
runContext.usage = skipUsage;
|
|
6509
6610
|
runContext.generated = 0;
|
|
6510
6611
|
runContext.newComments = 0;
|
|
@@ -6744,10 +6845,10 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
6744
6845
|
return;
|
|
6745
6846
|
}
|
|
6746
6847
|
if (argv.includes("--version") || argv.includes("-v")) {
|
|
6747
|
-
console.log("0.
|
|
6848
|
+
console.log("0.9.1");
|
|
6748
6849
|
return;
|
|
6749
6850
|
}
|
|
6750
|
-
process.stderr.write(`[code-review] @weareikko/code-review v0.
|
|
6851
|
+
process.stderr.write(`[code-review] @weareikko/code-review v0.9.1\n`);
|
|
6751
6852
|
assertNodeVersion();
|
|
6752
6853
|
applyCodeReviewEnvPrefix();
|
|
6753
6854
|
applyDefaultCacheRetention();
|
|
@@ -6770,4 +6871,4 @@ if (isDirectRun()) main().catch((error) => {
|
|
|
6770
6871
|
//#endregion
|
|
6771
6872
|
export { normalizeBody as $, SUMMARY_HISTORY_END as A, buildSummaryHistoryEntries as B, createDiagnosticContext as C, traceDiagnosticPhase as D, traceDiagnostic as E, SUMMARY_MARKER as F, findExistingSummaryNoteId as G, extractSummaryHistoryEntries as H, buildArchivedSummaryEntry as I, upsertSummaryNote as J, stripSummaryHistory as K, buildReviewedCommitFooter as L, SUMMARY_HISTORY_ENTRY_START as M, SUMMARY_HISTORY_LIMIT as N, normalizeSeverity as O, SUMMARY_HISTORY_START as P, fingerprints as Q, buildSizeNoticeBlock as R, DIAGNOSTIC_CHANNEL_PREFIX as S, diagnosticChannels as T, findExistingReviewedCommitSha as U, extractReviewedCommitSha as V, findExistingSummaryNote as W, extractDiffHunkContext as X, appendFingerprintMarkers as Y, extractExistingFingerprints as Z, resolveNpmSkillDir as _, main as a, parseReviewMarkdownWithWarnings as b, buildGeneratedComments as c, startOtelBridge as d, sha256 as et, filterDiff as f, parseSkillSpec as g, loadNamedSkill as h, formatUsageLine as i, SUMMARY_HISTORY_ENTRY_END as j, toGitLabReviewSeverity as k, buildPayload as l, gitSkillCacheKey as m, formatPerModelUsage as n, run as o, runReview as p, stripSummaryMarker as q, formatSkillsFooter as r, withHttpStamping as s, countPostedBySeverity as t, isOtelEnabled as u, resolveSkillCacheDir as v, createDiagnosticRunId as w, DIAGNOSTIC_CHANNEL_NAMES as x, parseReviewMarkdown as y, buildSummaryBody as z };
|
|
6772
6873
|
|
|
6773
|
-
//# sourceMappingURL=cli-
|
|
6874
|
+
//# sourceMappingURL=cli-BGn8g23f.js.map
|