@lcv-ideas-software/cross-review 4.0.0
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/CHANGELOG.md +2568 -0
- package/LICENSE +201 -0
- package/NOTICE +26 -0
- package/README.md +208 -0
- package/SECURITY.md +52 -0
- package/dist/scripts/api-streaming-smoke.d.ts +1 -0
- package/dist/scripts/api-streaming-smoke.js +78 -0
- package/dist/scripts/api-streaming-smoke.js.map +1 -0
- package/dist/scripts/runtime-default-smoke.d.ts +1 -0
- package/dist/scripts/runtime-default-smoke.js +88 -0
- package/dist/scripts/runtime-default-smoke.js.map +1 -0
- package/dist/scripts/runtime-smoke.d.ts +1 -0
- package/dist/scripts/runtime-smoke.js +148 -0
- package/dist/scripts/runtime-smoke.js.map +1 -0
- package/dist/scripts/smoke.d.ts +1 -0
- package/dist/scripts/smoke.js +6156 -0
- package/dist/scripts/smoke.js.map +1 -0
- package/dist/src/core/cache-manifest.d.ts +22 -0
- package/dist/src/core/cache-manifest.js +133 -0
- package/dist/src/core/cache-manifest.js.map +1 -0
- package/dist/src/core/caller-tokens.d.ts +32 -0
- package/dist/src/core/caller-tokens.js +240 -0
- package/dist/src/core/caller-tokens.js.map +1 -0
- package/dist/src/core/config.d.ts +9 -0
- package/dist/src/core/config.js +643 -0
- package/dist/src/core/config.js.map +1 -0
- package/dist/src/core/convergence.d.ts +5 -0
- package/dist/src/core/convergence.js +186 -0
- package/dist/src/core/convergence.js.map +1 -0
- package/dist/src/core/cost.d.ts +59 -0
- package/dist/src/core/cost.js +359 -0
- package/dist/src/core/cost.js.map +1 -0
- package/dist/src/core/file-config.d.ts +316 -0
- package/dist/src/core/file-config.js +490 -0
- package/dist/src/core/file-config.js.map +1 -0
- package/dist/src/core/orchestrator.d.ts +199 -0
- package/dist/src/core/orchestrator.js +3430 -0
- package/dist/src/core/orchestrator.js.map +1 -0
- package/dist/src/core/prompt-parts.d.ts +58 -0
- package/dist/src/core/prompt-parts.js +122 -0
- package/dist/src/core/prompt-parts.js.map +1 -0
- package/dist/src/core/relator-lottery.d.ts +23 -0
- package/dist/src/core/relator-lottery.js +112 -0
- package/dist/src/core/relator-lottery.js.map +1 -0
- package/dist/src/core/reports.d.ts +2 -0
- package/dist/src/core/reports.js +82 -0
- package/dist/src/core/reports.js.map +1 -0
- package/dist/src/core/session-store.d.ts +149 -0
- package/dist/src/core/session-store.js +1923 -0
- package/dist/src/core/session-store.js.map +1 -0
- package/dist/src/core/status.d.ts +61 -0
- package/dist/src/core/status.js +249 -0
- package/dist/src/core/status.js.map +1 -0
- package/dist/src/core/timeouts.d.ts +2 -0
- package/dist/src/core/timeouts.js +3 -0
- package/dist/src/core/timeouts.js.map +1 -0
- package/dist/src/core/types.d.ts +604 -0
- package/dist/src/core/types.js +36 -0
- package/dist/src/core/types.js.map +1 -0
- package/dist/src/dashboard/server.d.ts +2 -0
- package/dist/src/dashboard/server.js +339 -0
- package/dist/src/dashboard/server.js.map +1 -0
- package/dist/src/mcp/server.d.ts +54 -0
- package/dist/src/mcp/server.js +1584 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/observability/logger.d.ts +9 -0
- package/dist/src/observability/logger.js +24 -0
- package/dist/src/observability/logger.js.map +1 -0
- package/dist/src/peers/anthropic.d.ts +14 -0
- package/dist/src/peers/anthropic.js +290 -0
- package/dist/src/peers/anthropic.js.map +1 -0
- package/dist/src/peers/base.d.ts +72 -0
- package/dist/src/peers/base.js +416 -0
- package/dist/src/peers/base.js.map +1 -0
- package/dist/src/peers/deepseek.d.ts +12 -0
- package/dist/src/peers/deepseek.js +246 -0
- package/dist/src/peers/deepseek.js.map +1 -0
- package/dist/src/peers/errors.d.ts +2 -0
- package/dist/src/peers/errors.js +185 -0
- package/dist/src/peers/errors.js.map +1 -0
- package/dist/src/peers/gemini.d.ts +13 -0
- package/dist/src/peers/gemini.js +215 -0
- package/dist/src/peers/gemini.js.map +1 -0
- package/dist/src/peers/grok.d.ts +17 -0
- package/dist/src/peers/grok.js +346 -0
- package/dist/src/peers/grok.js.map +1 -0
- package/dist/src/peers/model-selection.d.ts +4 -0
- package/dist/src/peers/model-selection.js +260 -0
- package/dist/src/peers/model-selection.js.map +1 -0
- package/dist/src/peers/openai.d.ts +14 -0
- package/dist/src/peers/openai.js +299 -0
- package/dist/src/peers/openai.js.map +1 -0
- package/dist/src/peers/perplexity.d.ts +18 -0
- package/dist/src/peers/perplexity.js +375 -0
- package/dist/src/peers/perplexity.js.map +1 -0
- package/dist/src/peers/registry.d.ts +3 -0
- package/dist/src/peers/registry.js +77 -0
- package/dist/src/peers/registry.js.map +1 -0
- package/dist/src/peers/retry.d.ts +2 -0
- package/dist/src/peers/retry.js +36 -0
- package/dist/src/peers/retry.js.map +1 -0
- package/dist/src/peers/stub.d.ts +13 -0
- package/dist/src/peers/stub.js +344 -0
- package/dist/src/peers/stub.js.map +1 -0
- package/dist/src/peers/text.d.ts +18 -0
- package/dist/src/peers/text.js +39 -0
- package/dist/src/peers/text.js.map +1 -0
- package/dist/src/security/redact.d.ts +2 -0
- package/dist/src/security/redact.js +128 -0
- package/dist/src/security/redact.js.map +1 -0
- package/docs/api-keys.md +34 -0
- package/docs/architecture.md +118 -0
- package/docs/caching.md +135 -0
- package/docs/costs.md +40 -0
- package/docs/evidence-preflight.md +88 -0
- package/docs/github-security-baseline.md +32 -0
- package/docs/model-selection.md +105 -0
- package/docs/reports/cross-review-v2-api-capability-smoke-2026-04-30.md +354 -0
- package/docs/reports/cross-review-v2-format-recovery-findings-2026-04-28.md +223 -0
- package/docs/reports/cross-review-v2-official-provider-docs-refresh-2026-05-05.md +60 -0
- package/docs/reports/cross-review-v2-token-streaming-smoke-2026-04-30.md +119 -0
- package/package.json +88 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { BasePeerAdapter } from "./base.js";
|
|
2
|
+
const PROVIDERS = {
|
|
3
|
+
codex: "stub-openai",
|
|
4
|
+
claude: "stub-anthropic",
|
|
5
|
+
gemini: "stub-google",
|
|
6
|
+
deepseek: "stub-deepseek",
|
|
7
|
+
// v2.14.0: stub provider id for the Grok adapter so smoke runs
|
|
8
|
+
// without the real xAI API key.
|
|
9
|
+
grok: "stub-xai",
|
|
10
|
+
// v3.0.0: stub provider id for the Perplexity adapter so smoke runs
|
|
11
|
+
// without the real Sonar API key.
|
|
12
|
+
perplexity: "stub-perplexity",
|
|
13
|
+
};
|
|
14
|
+
// v2.5.0 fix (Codex audit P1, 2026-05-03): stub adapters must NEVER attribute
|
|
15
|
+
// real currency to a session. Pre-v2.5.0, the stub passed prompt/text
|
|
16
|
+
// character counts as `usage.input_tokens`/`usage.output_tokens`, which
|
|
17
|
+
// `estimateCost` then multiplied by the configured cost-rate-per-million,
|
|
18
|
+
// producing tens of dollars of phantom spend in `meta.json` and
|
|
19
|
+
// `totals.cost.total_cost`. The fix overrides the cost field on every
|
|
20
|
+
// stub-emitted PeerResult / GenerationResult to a canonical zero-cost
|
|
21
|
+
// estimate tagged `source: "stub"` so downstream FinOps tooling can both
|
|
22
|
+
// (a) ignore the row and (b) audit that no paid provider call ever ran.
|
|
23
|
+
// The token usage shape stays intact so smoke tests that check
|
|
24
|
+
// `usage.total_tokens > 0` continue to pass.
|
|
25
|
+
//
|
|
26
|
+
// Test-only escape hatch: `CROSS_REVIEW_STUB_FORCE_REAL_COST=1` lets
|
|
27
|
+
// the smoke suite exercise budget_exceeded enforcement (which is
|
|
28
|
+
// arithmetically driven by `cost.total_cost`). It MUST NOT be set in
|
|
29
|
+
// any production-like environment; the env-confirmation gate that
|
|
30
|
+
// `CROSS_REVIEW_STUB` already enforces is the upstream guard.
|
|
31
|
+
function shouldForceRealStubCost() {
|
|
32
|
+
return process.env.CROSS_REVIEW_STUB_FORCE_REAL_COST === "1";
|
|
33
|
+
}
|
|
34
|
+
function stubZeroCost() {
|
|
35
|
+
return {
|
|
36
|
+
currency: "USD",
|
|
37
|
+
input_cost: 0,
|
|
38
|
+
output_cost: 0,
|
|
39
|
+
total_cost: 0,
|
|
40
|
+
estimated: false,
|
|
41
|
+
source: "stub",
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export class StubAdapter extends BasePeerAdapter {
|
|
45
|
+
id;
|
|
46
|
+
provider;
|
|
47
|
+
model;
|
|
48
|
+
constructor(config, id, modelOverride) {
|
|
49
|
+
super(config);
|
|
50
|
+
this.id = id;
|
|
51
|
+
this.provider = PROVIDERS[id];
|
|
52
|
+
this.model = modelOverride ?? `stub-${id}`;
|
|
53
|
+
}
|
|
54
|
+
streamStubText(context, phase, text) {
|
|
55
|
+
if (!this.shouldStreamTokens(context))
|
|
56
|
+
return;
|
|
57
|
+
const tokenStream = this.createTokenEventBuffer(context, phase, "stub.chunk");
|
|
58
|
+
for (const delta of text.match(/.{1,32}/gs) ?? []) {
|
|
59
|
+
tokenStream.append(delta);
|
|
60
|
+
}
|
|
61
|
+
tokenStream.complete(text.length);
|
|
62
|
+
}
|
|
63
|
+
async probe() {
|
|
64
|
+
return {
|
|
65
|
+
peer: this.id,
|
|
66
|
+
provider: this.provider,
|
|
67
|
+
model: this.model,
|
|
68
|
+
available: true,
|
|
69
|
+
auth_present: true,
|
|
70
|
+
latency_ms: 0,
|
|
71
|
+
model_selection: this.config.model_selection[this.id],
|
|
72
|
+
message: "Stub enabled by CROSS_REVIEW_STUB=1.",
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
async call(prompt, context) {
|
|
76
|
+
context.emit({
|
|
77
|
+
type: "peer.call.started",
|
|
78
|
+
session_id: context.session_id,
|
|
79
|
+
round: context.round,
|
|
80
|
+
peer: this.id,
|
|
81
|
+
message: "stub review",
|
|
82
|
+
});
|
|
83
|
+
if (context.signal?.aborted) {
|
|
84
|
+
throw new Error("AbortError: stub call cancelled");
|
|
85
|
+
}
|
|
86
|
+
if (prompt.includes("FORCE_MODERATION_FAIL_UNRECOVERABLE")) {
|
|
87
|
+
throw new Error("Invalid prompt: prompt flagged by moderation policy.");
|
|
88
|
+
}
|
|
89
|
+
if (prompt.includes("FORCE_MODERATION_FAIL") &&
|
|
90
|
+
!prompt.includes("Compact Moderation-Safe Review")) {
|
|
91
|
+
throw new Error("Invalid prompt: prompt flagged by moderation policy.");
|
|
92
|
+
}
|
|
93
|
+
if (prompt.includes("FORCE_NETWORK_FAIL") && !this.model.includes("fallback")) {
|
|
94
|
+
throw new Error("network fetch failed");
|
|
95
|
+
}
|
|
96
|
+
const text = prompt.includes("Cross Review - Decision Retry")
|
|
97
|
+
? JSON.stringify({
|
|
98
|
+
status: "READY",
|
|
99
|
+
summary: "Stub completed a full decision retry after an empty response.",
|
|
100
|
+
confidence: "verified",
|
|
101
|
+
evidence_sources: [],
|
|
102
|
+
caller_requests: [],
|
|
103
|
+
follow_ups: [],
|
|
104
|
+
})
|
|
105
|
+
: prompt.includes("Cross Review - Format Recovery")
|
|
106
|
+
? prompt.includes("FORCE_RECOVERY_FAIL")
|
|
107
|
+
? "Still no machine-readable status."
|
|
108
|
+
: JSON.stringify({
|
|
109
|
+
status: "READY",
|
|
110
|
+
summary: "Stub recovered the previous unparseable response.",
|
|
111
|
+
confidence: "verified",
|
|
112
|
+
evidence_sources: [],
|
|
113
|
+
caller_requests: [],
|
|
114
|
+
follow_ups: [],
|
|
115
|
+
})
|
|
116
|
+
: prompt.includes("FORCE_BAD_FORMAT_UNRECOVERABLE")
|
|
117
|
+
? "I am READY, but this intentionally lacks JSON. FORCE_RECOVERY_FAIL"
|
|
118
|
+
: prompt.includes("FORCE_EMPTY_REVIEW")
|
|
119
|
+
? ""
|
|
120
|
+
: prompt.includes("FORCE_BAD_FORMAT")
|
|
121
|
+
? "I am READY, but this intentionally lacks the required machine-readable status object."
|
|
122
|
+
: prompt.includes("FORCE_NOT_READY") || prompt.includes("FORCE_NEEDS_EVIDENCE")
|
|
123
|
+
? JSON.stringify({
|
|
124
|
+
status: prompt.includes("FORCE_NEEDS_EVIDENCE")
|
|
125
|
+
? "NEEDS_EVIDENCE"
|
|
126
|
+
: "NOT_READY",
|
|
127
|
+
summary: "Stub detected a test marker.",
|
|
128
|
+
confidence: "verified",
|
|
129
|
+
evidence_sources: [],
|
|
130
|
+
caller_requests: ["Remove the test marker."],
|
|
131
|
+
follow_ups: [],
|
|
132
|
+
})
|
|
133
|
+
: prompt.includes("FORCE_CANCEL_SLOW")
|
|
134
|
+
? await new Promise((resolve, reject) => {
|
|
135
|
+
const timer = setTimeout(() => resolve(JSON.stringify({
|
|
136
|
+
status: "READY",
|
|
137
|
+
summary: "Stub completed after a cancellable delay.",
|
|
138
|
+
confidence: "verified",
|
|
139
|
+
evidence_sources: [],
|
|
140
|
+
caller_requests: [],
|
|
141
|
+
follow_ups: [],
|
|
142
|
+
})), 10_000);
|
|
143
|
+
context.signal?.addEventListener("abort", () => {
|
|
144
|
+
clearTimeout(timer);
|
|
145
|
+
reject(new Error("AbortError: stub call cancelled"));
|
|
146
|
+
}, { once: true });
|
|
147
|
+
})
|
|
148
|
+
: JSON.stringify({
|
|
149
|
+
status: "READY",
|
|
150
|
+
summary: "Stub approved the test round.",
|
|
151
|
+
confidence: "verified",
|
|
152
|
+
evidence_sources: [],
|
|
153
|
+
caller_requests: [],
|
|
154
|
+
follow_ups: [],
|
|
155
|
+
});
|
|
156
|
+
this.streamStubText(context, "review", text);
|
|
157
|
+
return {
|
|
158
|
+
...this.resultFromText({
|
|
159
|
+
text,
|
|
160
|
+
raw: { stub: true },
|
|
161
|
+
usage: {
|
|
162
|
+
input_tokens: prompt.length,
|
|
163
|
+
output_tokens: text.length,
|
|
164
|
+
total_tokens: prompt.length + text.length,
|
|
165
|
+
},
|
|
166
|
+
started: Date.now(),
|
|
167
|
+
attempts: 1,
|
|
168
|
+
modelReported: process.env.CROSS_REVIEW_STUB_REPORTED_MODEL,
|
|
169
|
+
}),
|
|
170
|
+
...(shouldForceRealStubCost() ? {} : { cost: stubZeroCost() }),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
async generate(prompt, context) {
|
|
174
|
+
context.emit({
|
|
175
|
+
type: "peer.generate.started",
|
|
176
|
+
session_id: context.session_id,
|
|
177
|
+
round: context.round,
|
|
178
|
+
peer: this.id,
|
|
179
|
+
message: "stub generation",
|
|
180
|
+
});
|
|
181
|
+
// v2.5.0: propagate FORCE_* test markers from the input prompt into
|
|
182
|
+
// the generated draft. Pre-v2.5.0 the stub took a 1200-char slice of
|
|
183
|
+
// the prompt; once cross-review grew per-round prompt headers
|
|
184
|
+
// (review focus, session-start contract directives, etc.) the
|
|
185
|
+
// FORCE_* markers buried in `## Previous Version` fell out of the
|
|
186
|
+
// 1200-char window, breaking smoke tests that rely on multi-round
|
|
187
|
+
// marker continuity (e.g. budget-exceeded test driving claude with
|
|
188
|
+
// FORCE_NOT_READY across 3 rounds). The slice still drives the
|
|
189
|
+
// synthetic body for inspection; the marker preamble guarantees
|
|
190
|
+
// semantic continuity.
|
|
191
|
+
const FORCE_MARKERS = [
|
|
192
|
+
"FORCE_BAD_FORMAT_UNRECOVERABLE",
|
|
193
|
+
"FORCE_MODERATION_FAIL_UNRECOVERABLE",
|
|
194
|
+
"FORCE_BAD_FORMAT",
|
|
195
|
+
"FORCE_MODERATION_FAIL",
|
|
196
|
+
"FORCE_NETWORK_FAIL",
|
|
197
|
+
"FORCE_NEEDS_EVIDENCE",
|
|
198
|
+
"FORCE_NOT_READY",
|
|
199
|
+
"FORCE_RECOVERY_FAIL",
|
|
200
|
+
"FORCE_EMPTY_REVIEW",
|
|
201
|
+
"FORCE_CANCEL_SLOW",
|
|
202
|
+
// v2.13.0: drift simulation. Three shapes covered (resolution
|
|
203
|
+
// path: keyword-prefix → JSON-prefix → markdown-fenced JSON,
|
|
204
|
+
// matching ship-review R1 → R2 → R-fix2 evolution):
|
|
205
|
+
// FORCE_DRIFT → keyword-prefix drift (`NEEDS_EVIDENCE\n...`)
|
|
206
|
+
// FORCE_DRIFT_JSON → raw JSON drift (`{"status":"NEEDS_EVIDENCE",...}`)
|
|
207
|
+
// FORCE_DRIFT_MD → markdown-wrapped JSON drift (` ```json\n{...}\n``` `)
|
|
208
|
+
// FORCE_DRIFT_MD takes precedence over FORCE_DRIFT_JSON, which
|
|
209
|
+
// takes precedence over FORCE_DRIFT.
|
|
210
|
+
"FORCE_DRIFT_MD",
|
|
211
|
+
"FORCE_DRIFT_JSON",
|
|
212
|
+
"FORCE_DRIFT",
|
|
213
|
+
];
|
|
214
|
+
const carriedMarkers = FORCE_MARKERS.filter((marker) => prompt.includes(marker));
|
|
215
|
+
let driftPrefix = [];
|
|
216
|
+
if (prompt.includes("FORCE_DRIFT_MD")) {
|
|
217
|
+
driftPrefix = [
|
|
218
|
+
"```json",
|
|
219
|
+
'{"status":"NEEDS_EVIDENCE","summary":"Stub-forced markdown-fenced JSON drift; orchestrator should detect this via PATTERN_STATUS_FIELD.","caller_requests":[]}',
|
|
220
|
+
"```",
|
|
221
|
+
"",
|
|
222
|
+
];
|
|
223
|
+
}
|
|
224
|
+
else if (prompt.includes("FORCE_DRIFT_JSON")) {
|
|
225
|
+
driftPrefix = [
|
|
226
|
+
'{"status":"NEEDS_EVIDENCE","summary":"Stub-forced JSON-shape meta-review drift; orchestrator should detect this via PATTERN_STATUS_FIELD.","caller_requests":[]}',
|
|
227
|
+
"",
|
|
228
|
+
];
|
|
229
|
+
}
|
|
230
|
+
else if (prompt.includes("FORCE_DRIFT")) {
|
|
231
|
+
driftPrefix = [
|
|
232
|
+
"NEEDS_EVIDENCE",
|
|
233
|
+
"",
|
|
234
|
+
"summary: Stub-forced meta-review drift; orchestrator should detect this and preserve prior draft.",
|
|
235
|
+
"",
|
|
236
|
+
];
|
|
237
|
+
}
|
|
238
|
+
const text = [
|
|
239
|
+
...driftPrefix,
|
|
240
|
+
...(driftPrefix.length ? [] : ["# Test Draft", ""]),
|
|
241
|
+
"This text was generated by the stub only because CROSS_REVIEW_STUB=1 is active.",
|
|
242
|
+
"",
|
|
243
|
+
...(carriedMarkers.length ? [carriedMarkers.join(" "), ""] : []),
|
|
244
|
+
prompt.slice(0, 1200),
|
|
245
|
+
].join("\n");
|
|
246
|
+
this.streamStubText(context, "generation", text);
|
|
247
|
+
return {
|
|
248
|
+
...this.generationFromText({
|
|
249
|
+
text,
|
|
250
|
+
raw: { stub: true },
|
|
251
|
+
usage: {
|
|
252
|
+
input_tokens: prompt.length,
|
|
253
|
+
output_tokens: text.length,
|
|
254
|
+
total_tokens: prompt.length + text.length,
|
|
255
|
+
},
|
|
256
|
+
started: Date.now(),
|
|
257
|
+
attempts: 1,
|
|
258
|
+
modelReported: process.env.CROSS_REVIEW_STUB_REPORTED_MODEL,
|
|
259
|
+
}),
|
|
260
|
+
...(shouldForceRealStubCost() ? {} : { cost: stubZeroCost() }),
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
// v2.9.0: deterministic judge response driven by FORCE_JUDGE_* markers
|
|
264
|
+
// in the draft (NOT the prompt; the prompt is built by BasePeerAdapter
|
|
265
|
+
// and includes the ask too). Markers:
|
|
266
|
+
// FORCE_JUDGE_SATISFIED → satisfied=true, confidence=verified
|
|
267
|
+
// FORCE_JUDGE_INFERRED → satisfied=true, confidence=inferred (NOT promoted by runtime)
|
|
268
|
+
// FORCE_JUDGE_UNKNOWN → satisfied=false, confidence=unknown
|
|
269
|
+
// FORCE_JUDGE_PARSE_FAIL → invalid JSON returned (parser_warnings populated)
|
|
270
|
+
// default → satisfied=false, confidence=verified
|
|
271
|
+
async judgeEvidenceAsk(ask, draft, context) {
|
|
272
|
+
void ask;
|
|
273
|
+
context.emit({
|
|
274
|
+
type: "peer.judge.started",
|
|
275
|
+
session_id: context.session_id,
|
|
276
|
+
round: context.round,
|
|
277
|
+
peer: this.id,
|
|
278
|
+
message: "stub judge",
|
|
279
|
+
});
|
|
280
|
+
const started = Date.now();
|
|
281
|
+
let payload;
|
|
282
|
+
if (draft.includes("FORCE_JUDGE_PARSE_FAIL")) {
|
|
283
|
+
// Bypass the JSON parser by emitting plain prose.
|
|
284
|
+
const generation = {
|
|
285
|
+
peer: this.id,
|
|
286
|
+
provider: this.provider,
|
|
287
|
+
model: this.model,
|
|
288
|
+
text: "stub: this response intentionally lacks a JSON object",
|
|
289
|
+
raw: { stub: true },
|
|
290
|
+
usage: { input_tokens: ask.length, output_tokens: 60, total_tokens: ask.length + 60 },
|
|
291
|
+
cost: shouldForceRealStubCost() ? undefined : stubZeroCost(),
|
|
292
|
+
latency_ms: Date.now() - started,
|
|
293
|
+
attempts: 1,
|
|
294
|
+
};
|
|
295
|
+
return this.parseJudgeResponse(generation, draft.length);
|
|
296
|
+
}
|
|
297
|
+
if (draft.includes("FORCE_JUDGE_SATISFIED")) {
|
|
298
|
+
payload = {
|
|
299
|
+
satisfied: true,
|
|
300
|
+
confidence: "verified",
|
|
301
|
+
rationale: "Stub judge: draft contains FORCE_JUDGE_SATISFIED marker.",
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
else if (draft.includes("FORCE_JUDGE_INFERRED")) {
|
|
305
|
+
payload = {
|
|
306
|
+
satisfied: true,
|
|
307
|
+
confidence: "inferred",
|
|
308
|
+
rationale: "Stub judge: draft hints at satisfaction but evidence is indirect.",
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
else if (draft.includes("FORCE_JUDGE_UNKNOWN")) {
|
|
312
|
+
payload = {
|
|
313
|
+
satisfied: false,
|
|
314
|
+
confidence: "unknown",
|
|
315
|
+
rationale: "Stub judge: cannot determine whether the draft satisfies the ask.",
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
payload = {
|
|
320
|
+
satisfied: false,
|
|
321
|
+
confidence: "verified",
|
|
322
|
+
rationale: "Stub judge default: no FORCE_JUDGE_* marker; treating as not satisfied.",
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
const text = JSON.stringify(payload);
|
|
326
|
+
const generation = {
|
|
327
|
+
peer: this.id,
|
|
328
|
+
provider: this.provider,
|
|
329
|
+
model: this.model,
|
|
330
|
+
text,
|
|
331
|
+
raw: { stub: true, payload },
|
|
332
|
+
usage: {
|
|
333
|
+
input_tokens: ask.length,
|
|
334
|
+
output_tokens: text.length,
|
|
335
|
+
total_tokens: ask.length + text.length,
|
|
336
|
+
},
|
|
337
|
+
cost: shouldForceRealStubCost() ? undefined : stubZeroCost(),
|
|
338
|
+
latency_ms: Date.now() - started,
|
|
339
|
+
attempts: 1,
|
|
340
|
+
};
|
|
341
|
+
return this.parseJudgeResponse(generation, draft.length);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
//# sourceMappingURL=stub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stub.js","sourceRoot":"","sources":["../../../src/peers/stub.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare function compactJson(value: unknown): string;
|
|
2
|
+
export interface AnthropicParseResult {
|
|
3
|
+
text: string;
|
|
4
|
+
parser_warning?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function parseAnthropicContent(content: Array<{
|
|
7
|
+
type: string;
|
|
8
|
+
text?: string;
|
|
9
|
+
}>): AnthropicParseResult;
|
|
10
|
+
export declare function textFromAnthropicContent(content: Array<{
|
|
11
|
+
type: string;
|
|
12
|
+
text?: string;
|
|
13
|
+
}>): string;
|
|
14
|
+
export declare function textFromOpenAIResponse(response: {
|
|
15
|
+
output_text?: string;
|
|
16
|
+
output?: unknown;
|
|
17
|
+
}): string;
|
|
18
|
+
export declare function userPrompt(reviewPrompt: string): string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export function compactJson(value) {
|
|
2
|
+
return JSON.stringify(value, null, 2);
|
|
3
|
+
}
|
|
4
|
+
const ANTHROPIC_THINKING_BLOCK_TYPES = new Set(["thinking", "redacted_thinking"]);
|
|
5
|
+
export function parseAnthropicContent(content) {
|
|
6
|
+
const textBlocks = content.filter((block) => block.type === "text" && typeof block.text === "string");
|
|
7
|
+
const text = textBlocks
|
|
8
|
+
.map((block) => block.text)
|
|
9
|
+
.filter(Boolean)
|
|
10
|
+
.join("\n")
|
|
11
|
+
.trim();
|
|
12
|
+
if (text === "" && content.length > 0) {
|
|
13
|
+
const hasThinking = content.some((block) => ANTHROPIC_THINKING_BLOCK_TYPES.has(block.type));
|
|
14
|
+
return {
|
|
15
|
+
text: "",
|
|
16
|
+
parser_warning: hasThinking
|
|
17
|
+
? "anthropic_thinking_only_no_text_block"
|
|
18
|
+
: "anthropic_empty_text_blocks",
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return { text };
|
|
22
|
+
}
|
|
23
|
+
// Thin backward-compatibility shim — discards the parser_warning. New code
|
|
24
|
+
// SHOULD call `parseAnthropicContent` directly so the warning can flow to
|
|
25
|
+
// `PeerResult.parser_warnings` / `GenerationResult.parser_warnings` and
|
|
26
|
+
// (for the relator-revision path) block promotion of an empty draft.
|
|
27
|
+
export function textFromAnthropicContent(content) {
|
|
28
|
+
return parseAnthropicContent(content).text;
|
|
29
|
+
}
|
|
30
|
+
export function textFromOpenAIResponse(response) {
|
|
31
|
+
if (typeof response.output_text === "string" && response.output_text.trim()) {
|
|
32
|
+
return response.output_text.trim();
|
|
33
|
+
}
|
|
34
|
+
return compactJson(response.output ?? response);
|
|
35
|
+
}
|
|
36
|
+
export function userPrompt(reviewPrompt) {
|
|
37
|
+
return reviewPrompt.trim();
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../../src/peers/text.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACxC,CAAC;AAkBD,MAAM,8BAA8B,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,mBAAmB,CAAC,CAAC,CAAC;AAElF,MAAM,UAAU,qBAAqB,CACnC,OAA+C;IAE/C,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAC/B,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CACnE,CAAC;IACF,MAAM,IAAI,GAAG,UAAU;SACpB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAc,CAAC;SACpC,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC;SACV,IAAI,EAAE,CAAC;IACV,IAAI,IAAI,KAAK,EAAE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,8BAA8B,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5F,OAAO;YACL,IAAI,EAAE,EAAE;YACR,cAAc,EAAE,WAAW;gBACzB,CAAC,CAAC,uCAAuC;gBACzC,CAAC,CAAC,6BAA6B;SAClC,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,CAAC;AAClB,CAAC;AAED,2EAA2E;AAC3E,0EAA0E;AAC1E,wEAAwE;AACxE,qEAAqE;AACrE,MAAM,UAAU,wBAAwB,CAAC,OAA+C;IACtF,OAAO,qBAAqB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,QAGtC;IACC,IAAI,OAAO,QAAQ,CAAC,WAAW,KAAK,QAAQ,IAAI,QAAQ,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5E,OAAO,QAAQ,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;IACrC,CAAC;IACD,OAAO,WAAW,CAAC,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,YAAoB;IAC7C,OAAO,YAAY,CAAC,IAAI,EAAE,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
const SECRET_PATTERNS = [
|
|
2
|
+
/sk-[A-Za-z0-9_-]{20,}/g,
|
|
3
|
+
/sk-ant-[A-Za-z0-9_-]{20,}/g,
|
|
4
|
+
/AIza[A-Za-z0-9_-]{20,}/g,
|
|
5
|
+
/cfut_[A-Za-z0-9_-]{30,}/g,
|
|
6
|
+
/gh[pousr]_[A-Za-z0-9]{30,}/g,
|
|
7
|
+
/github_pat_[A-Za-z0-9_]{20,}/g,
|
|
8
|
+
/npm_[A-Za-z0-9]{30,}/g,
|
|
9
|
+
/re_[A-Za-z0-9_]{30,}/g,
|
|
10
|
+
/xox[baprs]-[A-Za-z0-9-]{20,}/g,
|
|
11
|
+
// v2.18.4 / Codex audit 2026-05-07 P1.2: xAI API keys have prefix
|
|
12
|
+
// `xai-` and were not previously covered. Logs and session payloads
|
|
13
|
+
// can persist provider error messages or environment dumps that
|
|
14
|
+
// include the key, so adding this pattern closes a credential leak
|
|
15
|
+
// surface at parity with sk-/sk-ant-/AIza/etc.
|
|
16
|
+
/xai-[A-Za-z0-9_-]{20,}/g,
|
|
17
|
+
/AKIA[A-Z0-9]{16}/g,
|
|
18
|
+
/Bearer\s+[A-Za-z0-9._-]{20,}/gi,
|
|
19
|
+
/[A-Za-z0-9_-]{32,}\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}/g,
|
|
20
|
+
// v2.4.0 / audit closure: env-style assignments. Catches `PASSWORD=value`
|
|
21
|
+
// / `API_KEY="value"` / `SECRET: value` / `Authorization: token` shapes
|
|
22
|
+
// that providers, smoke fixtures or stack traces sometimes echo back.
|
|
23
|
+
// The replacement preserves the key name so audit consumers see WHICH
|
|
24
|
+
// var was redacted, only the value is replaced. Mirrors the pattern in
|
|
25
|
+
// v1's `REDACTION_PATTERNS`.
|
|
26
|
+
// v2.25.1 (2026-05-11): exclude `\` from value char class. Without the
|
|
27
|
+
// exclusion the {6,} quantifier would consume the JSON-escape backslash
|
|
28
|
+
// in `token: write\"` (a peer-response string that survived round-1
|
|
29
|
+
// serialization), replace `write\` → `[REDACTED]`, and leave a bare `"`
|
|
30
|
+
// that closes the outer JSON string prematurely → corrupt meta.json.
|
|
31
|
+
// Empirically observed in 3 sessions today (be47a5b0, 77c47284, 7edf63e3)
|
|
32
|
+
// when the scorecard hotfix peer responses quoted `id-token: write` in
|
|
33
|
+
// backtick-fenced YAML excerpts. Excluding `\` keeps the regex from
|
|
34
|
+
// crossing JSON-escape boundaries.
|
|
35
|
+
/\b((?:password|passwd|api[_-]?key|secret|token|access[_-]?key|auth(?:orization)?|bearer|private[_-]?key)\s*[:=]\s*["']?)([^\s"',}\\]{6,})/gi,
|
|
36
|
+
];
|
|
37
|
+
const PRIVATE_KEY_LABELS = [
|
|
38
|
+
"PRIVATE KEY",
|
|
39
|
+
"OPENSSH PRIVATE KEY",
|
|
40
|
+
"EC PRIVATE KEY",
|
|
41
|
+
"RSA PRIVATE KEY",
|
|
42
|
+
"DSA PRIVATE KEY",
|
|
43
|
+
];
|
|
44
|
+
const PRIVATE_KEY_BEGIN_MARKERS = PRIVATE_KEY_LABELS.map((label) => `-----BEGIN ${label}-----`);
|
|
45
|
+
const PRIVATE_KEY_END_MARKERS = PRIVATE_KEY_LABELS.map((label) => `-----END ${label}-----`);
|
|
46
|
+
function findNextMarker(value, markers, fromIndex) {
|
|
47
|
+
let found;
|
|
48
|
+
for (const marker of markers) {
|
|
49
|
+
const index = value.indexOf(marker, fromIndex);
|
|
50
|
+
if (index !== -1 && (!found || index < found.index)) {
|
|
51
|
+
found = { index, marker };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return found;
|
|
55
|
+
}
|
|
56
|
+
function findNextPrivateKeyMarker(value, fromIndex) {
|
|
57
|
+
const begin = findNextMarker(value, PRIVATE_KEY_BEGIN_MARKERS, fromIndex);
|
|
58
|
+
const end = findNextMarker(value, PRIVATE_KEY_END_MARKERS, fromIndex);
|
|
59
|
+
if (!begin)
|
|
60
|
+
return end ? { ...end, side: "END" } : undefined;
|
|
61
|
+
if (!end)
|
|
62
|
+
return { ...begin, side: "BEGIN" };
|
|
63
|
+
return begin.index <= end.index ? { ...begin, side: "BEGIN" } : { ...end, side: "END" };
|
|
64
|
+
}
|
|
65
|
+
function redactPrivateKeyBlocks(value) {
|
|
66
|
+
let cursor = 0;
|
|
67
|
+
let parts;
|
|
68
|
+
while (cursor < value.length) {
|
|
69
|
+
const begin = findNextMarker(value, PRIVATE_KEY_BEGIN_MARKERS, cursor);
|
|
70
|
+
if (!begin)
|
|
71
|
+
break;
|
|
72
|
+
let depth = 1;
|
|
73
|
+
let scan = begin.index + begin.marker.length;
|
|
74
|
+
let close;
|
|
75
|
+
while (scan < value.length) {
|
|
76
|
+
const marker = findNextPrivateKeyMarker(value, scan);
|
|
77
|
+
if (!marker)
|
|
78
|
+
break;
|
|
79
|
+
scan = marker.index + marker.marker.length;
|
|
80
|
+
if (marker.side === "BEGIN") {
|
|
81
|
+
depth += 1;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
depth -= 1;
|
|
85
|
+
if (depth === 0) {
|
|
86
|
+
close = marker;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (!close) {
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
parts ??= [];
|
|
94
|
+
parts.push(value.slice(cursor, begin.index), "[REDACTED]");
|
|
95
|
+
cursor = close.index + close.marker.length;
|
|
96
|
+
}
|
|
97
|
+
if (!parts)
|
|
98
|
+
return value;
|
|
99
|
+
parts.push(value.slice(cursor));
|
|
100
|
+
return parts.join("");
|
|
101
|
+
}
|
|
102
|
+
export function redact(value) {
|
|
103
|
+
let output = redactPrivateKeyBlocks(value);
|
|
104
|
+
for (const re of SECRET_PATTERNS) {
|
|
105
|
+
// The env-style assignment pattern uses two capture groups so that
|
|
106
|
+
// the key name is preserved; the standalone-token patterns do not
|
|
107
|
+
// capture and we replace the whole match. We dispatch on the regex
|
|
108
|
+
// shape (`re.source.includes("(")`) but the safer signal is the
|
|
109
|
+
// number of groups we declared — both env-style and JWT use groups,
|
|
110
|
+
// but only the env-style declares two ((key)(value)). For the JWT
|
|
111
|
+
// pattern we still replace the whole match because there is no key
|
|
112
|
+
// half to preserve.
|
|
113
|
+
output = output.replace(re, (...args) => {
|
|
114
|
+
const groups = args.slice(1, -2).filter((g) => typeof g === "string");
|
|
115
|
+
if (groups.length >= 2) {
|
|
116
|
+
return `${groups[0]}[REDACTED]`;
|
|
117
|
+
}
|
|
118
|
+
return "[REDACTED]";
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return output;
|
|
122
|
+
}
|
|
123
|
+
export function safeErrorMessage(error) {
|
|
124
|
+
if (error instanceof Error)
|
|
125
|
+
return redact(error.message);
|
|
126
|
+
return redact(String(error));
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=redact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../../../src/security/redact.ts"],"names":[],"mappings":"AAAA,MAAM,eAAe,GAAG;IACtB,wBAAwB;IACxB,4BAA4B;IAC5B,yBAAyB;IACzB,0BAA0B;IAC1B,6BAA6B;IAC7B,+BAA+B;IAC/B,uBAAuB;IACvB,uBAAuB;IACvB,+BAA+B;IAC/B,kEAAkE;IAClE,oEAAoE;IACpE,gEAAgE;IAChE,mEAAmE;IACnE,+CAA+C;IAC/C,yBAAyB;IACzB,mBAAmB;IACnB,gCAAgC;IAChC,6DAA6D;IAC7D,0EAA0E;IAC1E,wEAAwE;IACxE,sEAAsE;IACtE,sEAAsE;IACtE,uEAAuE;IACvE,6BAA6B;IAC7B,uEAAuE;IACvE,wEAAwE;IACxE,oEAAoE;IACpE,wEAAwE;IACxE,qEAAqE;IACrE,0EAA0E;IAC1E,uEAAuE;IACvE,oEAAoE;IACpE,mCAAmC;IACnC,6IAA6I;CAC9I,CAAC;AAEF,MAAM,kBAAkB,GAAG;IACzB,aAAa;IACb,qBAAqB;IACrB,gBAAgB;IAChB,iBAAiB;IACjB,iBAAiB;CAClB,CAAC;AAEF,MAAM,yBAAyB,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,KAAK,OAAO,CAAC,CAAC;AAChG,MAAM,uBAAuB,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,KAAK,OAAO,CAAC,CAAC;AAE5F,SAAS,cAAc,CACrB,KAAa,EACb,OAA0B,EAC1B,SAAiB;IAEjB,IAAI,KAAoD,CAAC;IACzD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAC/C,IAAI,KAAK,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YACpD,KAAK,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,wBAAwB,CAC/B,KAAa,EACb,SAAiB;IAEjB,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,yBAAyB,EAAE,SAAS,CAAC,CAAC;IAC1E,MAAM,GAAG,GAAG,cAAc,CAAC,KAAK,EAAE,uBAAuB,EAAE,SAAS,CAAC,CAAC;IACtE,IAAI,CAAC,KAAK;QAAE,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7D,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAC7C,OAAO,KAAK,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAC1F,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAa;IAC3C,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,KAA2B,CAAC;IAEhC,OAAO,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,yBAAyB,EAAE,MAAM,CAAC,CAAC;QACvE,IAAI,CAAC,KAAK;YAAE,MAAM;QAElB,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,IAAI,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;QAC7C,IAAI,KAAoD,CAAC;QAEzD,OAAO,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,wBAAwB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACrD,IAAI,CAAC,MAAM;gBAAE,MAAM;YAEnB,IAAI,GAAG,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;YAC3C,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC5B,KAAK,IAAI,CAAC,CAAC;gBACX,SAAS;YACX,CAAC;YAED,KAAK,IAAI,CAAC,CAAC;YACX,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBAChB,KAAK,GAAG,MAAM,CAAC;gBACf,MAAM;YACR,CAAC;QACH,CAAC;QAED,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM;QACR,CAAC;QAED,KAAK,KAAK,EAAE,CAAC;QACb,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,CAAC;QAC3D,MAAM,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;IAC7C,CAAC;IAED,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAChC,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,KAAa;IAClC,IAAI,MAAM,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC;IAC3C,KAAK,MAAM,EAAE,IAAI,eAAe,EAAE,CAAC;QACjC,mEAAmE;QACnE,kEAAkE;QAClE,mEAAmE;QACnE,gEAAgE;QAChE,oEAAoE;QACpE,kEAAkE;QAClE,mEAAmE;QACnE,oBAAoB;QACpB,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE;YACtC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;YACtE,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;gBACvB,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC;YAClC,CAAC;YACD,OAAO,YAAY,CAAC;QACtB,CAAC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,IAAI,KAAK,YAAY,KAAK;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACzD,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/B,CAAC"}
|
package/docs/api-keys.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# API Keys
|
|
2
|
+
|
|
3
|
+
All runtime credentials must come from Windows environment variables.
|
|
4
|
+
|
|
5
|
+
## Required Variables
|
|
6
|
+
|
|
7
|
+
```powershell
|
|
8
|
+
[Environment]::SetEnvironmentVariable("OPENAI_API_KEY", "<OPENAI_API_KEY>", "User")
|
|
9
|
+
[Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", "<ANTHROPIC_API_KEY>", "User")
|
|
10
|
+
[Environment]::SetEnvironmentVariable("GEMINI_API_KEY", "<GEMINI_API_KEY>", "User")
|
|
11
|
+
[Environment]::SetEnvironmentVariable("DEEPSEEK_API_KEY", "<DEEPSEEK_API_KEY>", "User")
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Restart any terminal, editor, app or MCP host after changing these variables.
|
|
15
|
+
|
|
16
|
+
## Optional Model Overrides
|
|
17
|
+
|
|
18
|
+
Use overrides only when you intentionally want to pin a model rather than use automatic best-model selection.
|
|
19
|
+
|
|
20
|
+
```powershell
|
|
21
|
+
[Environment]::SetEnvironmentVariable("CROSS_REVIEW_OPENAI_MODEL", "gpt-5.5", "User")
|
|
22
|
+
[Environment]::SetEnvironmentVariable("CROSS_REVIEW_OPENAI_REASONING_EFFORT", "xhigh", "User")
|
|
23
|
+
[Environment]::SetEnvironmentVariable("CROSS_REVIEW_ANTHROPIC_MODEL", "claude-opus-4-7", "User")
|
|
24
|
+
[Environment]::SetEnvironmentVariable("CROSS_REVIEW_ANTHROPIC_REASONING_EFFORT", "xhigh", "User")
|
|
25
|
+
[Environment]::SetEnvironmentVariable("CROSS_REVIEW_GEMINI_MODEL", "gemini-2.5-pro", "User")
|
|
26
|
+
[Environment]::SetEnvironmentVariable("CROSS_REVIEW_DEEPSEEK_MODEL", "deepseek-v4-pro", "User")
|
|
27
|
+
[Environment]::SetEnvironmentVariable("CROSS_REVIEW_DEEPSEEK_REASONING_EFFORT", "max", "User")
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Safety
|
|
31
|
+
|
|
32
|
+
- Do not create `.env` files containing real secrets.
|
|
33
|
+
- Do not paste keys into prompts, issues, logs, screenshots or README files.
|
|
34
|
+
- If a key is accidentally committed, revoke it immediately and rotate it at the provider.
|