instar 1.3.190 → 1.3.192
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/core/crossModelReviewer.d.ts +310 -0
- package/dist/core/crossModelReviewer.d.ts.map +1 -0
- package/dist/core/crossModelReviewer.js +489 -0
- package/dist/core/crossModelReviewer.js.map +1 -0
- package/package.json +1 -1
- package/scripts/instar-dev-precommit.js +279 -1
- package/scripts/lib/classify-tier.mjs +191 -0
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.191.md +37 -0
- package/upgrades/1.3.192.md +37 -0
- package/upgrades/side-effects/codex-crossreview-stepB.md +83 -0
- package/upgrades/side-effects/tier-classifier-and-tier1-path.md +81 -0
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* crossModelReviewer — Step B of the tiered development process.
|
|
3
|
+
*
|
|
4
|
+
* Re-platforms the `/spec-converge` external "cross-model" reviewer onto the
|
|
5
|
+
* agent's own installed `codex` CLI. The external pass that the skill used to
|
|
6
|
+
* describe as running "via the /crossreview pattern" (a never-built
|
|
7
|
+
* placeholder) is now a grounded mechanism: detect whether a supported reviewer
|
|
8
|
+
* framework is installed + authed, assemble the cross-model reviewer prompt
|
|
9
|
+
* (spec + referenced context, bounded to a budget), and run it THROUGH the
|
|
10
|
+
* existing `CodexCliIntelligenceProvider` (the factory with
|
|
11
|
+
* `framework: 'codex-cli'`, model `capable` → GPT-tier).
|
|
12
|
+
*
|
|
13
|
+
* Design invariants (see docs/specs/codex-crossreview-stepB-spec.md):
|
|
14
|
+
* - Detection is a pure function with injectable inputs (no real spawns in
|
|
15
|
+
* unit tests). It is SIGNAL-ONLY — it never throws and never blocks.
|
|
16
|
+
* - Reviewer invocation reuses the provider (its scratch-dir clean-notepad,
|
|
17
|
+
* env allowlist, `--skip-git-repo-check`, and the account-global circuit
|
|
18
|
+
* breaker the factory wraps it in). The ONLY new spawn-adjacent code is
|
|
19
|
+
* prompt assembly + result parsing.
|
|
20
|
+
* - Every failure mode routes toward internal-only convergence or a captured
|
|
21
|
+
* raw finding — never a stall. `unavailable` (no framework) is distinct
|
|
22
|
+
* from `degraded` (framework present, this call failed) and
|
|
23
|
+
* `skipped-abbreviated` (author chose the fast path).
|
|
24
|
+
*
|
|
25
|
+
* codex is the FIRST supported framework; the registry
|
|
26
|
+
* (`SUPPORTED_REVIEWER_FRAMEWORKS`) is the single seam for gemini-cli and
|
|
27
|
+
* others to plug in later (Out of Scope here). Adding a framework is one
|
|
28
|
+
* registry entry + one `id`-union extension — no skill change.
|
|
29
|
+
*/
|
|
30
|
+
import fs from 'node:fs';
|
|
31
|
+
import os from 'node:os';
|
|
32
|
+
import path from 'node:path';
|
|
33
|
+
import { detectCodexPath } from './Config.js';
|
|
34
|
+
import { validateRule1 } from '../providers/adapters/openai-codex/credentials.js';
|
|
35
|
+
import { resolveCliModelFlag } from '../providers/adapters/openai-codex/models.js';
|
|
36
|
+
import { buildIntelligenceProvider, } from './intelligenceProviderFactory.js';
|
|
37
|
+
// ── Constants (tunable) ─────────────────────────────────────────────────
|
|
38
|
+
/**
|
|
39
|
+
* Per-call timeout for a cross-model spec review. A reasoning review of a
|
|
40
|
+
* full spec is far heavier than the provider's 30s judgment-call default, so
|
|
41
|
+
* Step B bumps it to 120s (spec §2).
|
|
42
|
+
*/
|
|
43
|
+
export const REVIEW_TIMEOUT_MS = 120_000;
|
|
44
|
+
/**
|
|
45
|
+
* Total context budget (spec + referenced docs) inlined into the reviewer
|
|
46
|
+
* prompt. codex runs in an empty read-only scratch dir with no repo access,
|
|
47
|
+
* so referenced context MUST be inlined; this bounds the prompt size (spec §2).
|
|
48
|
+
* The spec is always included in full; referenced context fills the remainder
|
|
49
|
+
* and is truncated (with a loud note) if it overflows.
|
|
50
|
+
*/
|
|
51
|
+
export const CONTEXT_BUDGET_BYTES = 60 * 1024;
|
|
52
|
+
/**
|
|
53
|
+
* Deterministic priority ordering for referenced context (spec §2, F4).
|
|
54
|
+
*
|
|
55
|
+
* When the 60KB budget can't hold every referenced doc, truncation MUST be
|
|
56
|
+
* deterministic — the same spec + same docs always drop the same docs — so a
|
|
57
|
+
* review is reproducible and the "what got dropped" note is stable. The
|
|
58
|
+
* constitutional / lessons docs are the highest-value context for a reviewer
|
|
59
|
+
* (they're what the lessons-aware internal reviewer reads), so they are kept
|
|
60
|
+
* FIRST; everything else keeps the spec-declared link order (the order the
|
|
61
|
+
* caller passed the docs in, which is the order they appear in the spec).
|
|
62
|
+
*
|
|
63
|
+
* A doc whose path contains one of these substrings sorts ahead of the rest,
|
|
64
|
+
* in THIS order. Ties (and all non-priority docs) preserve the caller's order
|
|
65
|
+
* via a stable sort.
|
|
66
|
+
*/
|
|
67
|
+
export const CONTEXT_PRIORITY_SUBSTRINGS = [
|
|
68
|
+
'signal-vs-authority',
|
|
69
|
+
'INSTAR-DESIGN-PRINCIPLES-AND-LESSONS',
|
|
70
|
+
'STANDARDS-REGISTRY',
|
|
71
|
+
'integrated-being',
|
|
72
|
+
];
|
|
73
|
+
/**
|
|
74
|
+
* Return a deterministic priority rank for a context doc path: a small index
|
|
75
|
+
* for a constitutional/lessons doc (earlier substring = smaller rank), or a
|
|
76
|
+
* large sentinel for everything else (so non-priority docs keep their relative
|
|
77
|
+
* order behind the priority ones under a stable sort).
|
|
78
|
+
*/
|
|
79
|
+
function contextPriorityRank(docPath) {
|
|
80
|
+
const lower = docPath.toLowerCase();
|
|
81
|
+
for (let i = 0; i < CONTEXT_PRIORITY_SUBSTRINGS.length; i++) {
|
|
82
|
+
if (lower.includes(CONTEXT_PRIORITY_SUBSTRINGS[i].toLowerCase()))
|
|
83
|
+
return i;
|
|
84
|
+
}
|
|
85
|
+
return CONTEXT_PRIORITY_SUBSTRINGS.length;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Order referenced context deterministically: constitutional/lessons docs
|
|
89
|
+
* first (per CONTEXT_PRIORITY_SUBSTRINGS), then the caller's spec-declared link
|
|
90
|
+
* order for the rest. A stable sort on the priority rank achieves both — equal
|
|
91
|
+
* ranks keep their input order. Pure; never mutates the input.
|
|
92
|
+
*/
|
|
93
|
+
export function orderContextDeterministically(context) {
|
|
94
|
+
return context
|
|
95
|
+
.map((doc, idx) => ({ doc, idx, rank: contextPriorityRank(doc.path) }))
|
|
96
|
+
.sort((a, b) => a.rank - b.rank || a.idx - b.idx)
|
|
97
|
+
.map((e) => e.doc);
|
|
98
|
+
}
|
|
99
|
+
/** The canonical model tier a heavyweight cross-model review requests. */
|
|
100
|
+
const REVIEW_MODEL_TIER = 'capable';
|
|
101
|
+
/** Resolve the default codex auth.json path (CODEX_HOME-aware). */
|
|
102
|
+
function defaultAuthJsonPath(env) {
|
|
103
|
+
const home = env['CODEX_HOME'] || path.join(os.homedir(), '.codex');
|
|
104
|
+
return path.join(home, 'auth.json');
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Is the codex auth.json an OAuth (`tokens.access_token`) shape? This is the
|
|
108
|
+
* subscription-OAuth shape D3 requires. A missing / unreadable / malformed
|
|
109
|
+
* file → false (not authed). Uses the same probe shape as the codex smoketest.
|
|
110
|
+
*/
|
|
111
|
+
function authHasOAuthAccessToken(authJsonPath) {
|
|
112
|
+
try {
|
|
113
|
+
const raw = fs.readFileSync(authJsonPath, 'utf-8');
|
|
114
|
+
const parsed = JSON.parse(raw);
|
|
115
|
+
return typeof parsed?.tokens?.access_token === 'string' && parsed.tokens.access_token.length > 0;
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// missing / unreadable / malformed → not authed.
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Detect a codex reviewer. Returns `{ available: true, framework, model }`
|
|
124
|
+
* iff ALL of: codex binary detected, OAuth `access_token` present, Rule-1
|
|
125
|
+
* clean (no raw API key in env or auth.json). Any miss → a specific reason.
|
|
126
|
+
*
|
|
127
|
+
* Pure-ish: all external inputs are injectable. With no inputs it probes the
|
|
128
|
+
* real host. It NEVER throws.
|
|
129
|
+
*/
|
|
130
|
+
export function detectCodexReviewer(inputs = {}) {
|
|
131
|
+
const env = inputs.env ?? process.env;
|
|
132
|
+
const now = inputs.now ?? new Date();
|
|
133
|
+
const codexPath = inputs.codexPathDetected !== undefined ? inputs.codexPathDetected : detectCodexPath();
|
|
134
|
+
const authJsonPath = inputs.authJsonPath ?? defaultAuthJsonPath(env);
|
|
135
|
+
// 1. Binary present?
|
|
136
|
+
if (!codexPath) {
|
|
137
|
+
return { available: false, reason: 'codex-not-installed' };
|
|
138
|
+
}
|
|
139
|
+
// 2. Rule-1 clean? (API-key forbidden — env OPENAI_API_KEY or auth.json
|
|
140
|
+
// API-key shape). Reuses existing policy rather than inventing one.
|
|
141
|
+
const rule1 = validateRule1(env, authJsonPath, now);
|
|
142
|
+
if (!rule1.ok) {
|
|
143
|
+
// The killswitch-expired / apikey-detected codes all collapse to the same
|
|
144
|
+
// policy outcome here: a forbidden credential shape → reviewer unavailable.
|
|
145
|
+
return { available: false, reason: 'codex-auth-apikey-forbidden' };
|
|
146
|
+
}
|
|
147
|
+
// 3. Authed via subscription OAuth?
|
|
148
|
+
if (!authHasOAuthAccessToken(authJsonPath)) {
|
|
149
|
+
return { available: false, reason: 'codex-not-authed' };
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
available: true,
|
|
153
|
+
framework: 'codex-cli',
|
|
154
|
+
model: resolveCliModelFlag(REVIEW_MODEL_TIER),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* The codex reviewer entry. Detection delegates to `detectCodexReviewer`;
|
|
159
|
+
* `review` routes through the factory-built `CodexCliIntelligenceProvider`.
|
|
160
|
+
*/
|
|
161
|
+
const codexReviewer = {
|
|
162
|
+
id: 'codex-cli',
|
|
163
|
+
detect: (inputs) => detectCodexReviewer(inputs),
|
|
164
|
+
review: async (args) => {
|
|
165
|
+
const detection = detectCodexReviewer();
|
|
166
|
+
const model = detection.model ?? resolveCliModelFlag(REVIEW_MODEL_TIER);
|
|
167
|
+
const tag = `cross-model:codex-cli:${model}`;
|
|
168
|
+
// Build (or accept an injected) provider. The factory wraps it in the
|
|
169
|
+
// account-global circuit breaker, so a rate-limited review degrades the
|
|
170
|
+
// same way every other instar LLM call does.
|
|
171
|
+
const provider = args.providerOverride ??
|
|
172
|
+
buildIntelligenceProvider({ framework: 'codex-cli' });
|
|
173
|
+
if (!provider) {
|
|
174
|
+
// Binary vanished between detect and review (or detection said
|
|
175
|
+
// unavailable and review was called anyway). Degraded, not a throw.
|
|
176
|
+
return {
|
|
177
|
+
status: 'degraded',
|
|
178
|
+
framework: 'codex-cli',
|
|
179
|
+
model,
|
|
180
|
+
reason: 'provider-unavailable',
|
|
181
|
+
flag: `cross-model-review: codex-cli:${model} (degraded: provider-unavailable)`,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
let raw;
|
|
185
|
+
try {
|
|
186
|
+
raw = await provider.evaluate(args.promptText, {
|
|
187
|
+
model: REVIEW_MODEL_TIER,
|
|
188
|
+
timeoutMs: args.timeoutMs,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
const reason = classifyReviewFailure(err);
|
|
193
|
+
return {
|
|
194
|
+
status: 'degraded',
|
|
195
|
+
framework: 'codex-cli',
|
|
196
|
+
model,
|
|
197
|
+
reason,
|
|
198
|
+
flag: `cross-model-review: codex-cli:${model} (degraded: ${reason})`,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
const parsed = parseReviewerReply(raw, tag);
|
|
202
|
+
return {
|
|
203
|
+
status: 'ok',
|
|
204
|
+
framework: 'codex-cli',
|
|
205
|
+
model,
|
|
206
|
+
verdict: parsed.verdict,
|
|
207
|
+
findings: [parsed],
|
|
208
|
+
flag: `cross-model-review: codex-cli:${model}`,
|
|
209
|
+
};
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
/**
|
|
213
|
+
* The supported-reviewer registry. codex first — the order IS the preference
|
|
214
|
+
* order. gemini-cli and others land here as later steps (Out of Scope).
|
|
215
|
+
*/
|
|
216
|
+
export const SUPPORTED_REVIEWER_FRAMEWORKS = [codexReviewer];
|
|
217
|
+
/**
|
|
218
|
+
* Walk the registry in preference order and return the FIRST available
|
|
219
|
+
* framework's detection result. If none is available, returns the codex
|
|
220
|
+
* reason when there's exactly one entry (so the report can be specific), else
|
|
221
|
+
* the generic `no-supported-framework`.
|
|
222
|
+
*
|
|
223
|
+
* SIGNAL-ONLY: never throws, never blocks. A `false` simply routes the skill
|
|
224
|
+
* to the internal-only fallback (spec §4).
|
|
225
|
+
*/
|
|
226
|
+
export function detectCrossModelReviewer(inputs = {}) {
|
|
227
|
+
for (const framework of SUPPORTED_REVIEWER_FRAMEWORKS) {
|
|
228
|
+
const result = framework.detect(inputs);
|
|
229
|
+
if (result.available)
|
|
230
|
+
return result;
|
|
231
|
+
}
|
|
232
|
+
// Nothing available. Surface the single framework's specific reason when
|
|
233
|
+
// there's only one entry (codex today); otherwise the generic reason.
|
|
234
|
+
if (SUPPORTED_REVIEWER_FRAMEWORKS.length === 1) {
|
|
235
|
+
return SUPPORTED_REVIEWER_FRAMEWORKS[0].detect(inputs);
|
|
236
|
+
}
|
|
237
|
+
return { available: false, reason: 'no-supported-framework' };
|
|
238
|
+
}
|
|
239
|
+
// ── Failure classification ──────────────────────────────────────────────
|
|
240
|
+
/**
|
|
241
|
+
* Map a provider rejection into a coarse `degraded` reason. The provider
|
|
242
|
+
* surfaces timeouts, non-zero exits, and (via the circuit breaker) rate
|
|
243
|
+
* limits as thrown Errors; we classify on the message text the same way the
|
|
244
|
+
* rate-limit classifier does.
|
|
245
|
+
*/
|
|
246
|
+
export function classifyReviewFailure(err) {
|
|
247
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
248
|
+
const lower = msg.toLowerCase();
|
|
249
|
+
if (/circuit breaker|rate.?limit|usage limit|quota|429|too many requests/.test(lower)) {
|
|
250
|
+
return 'rate-limited';
|
|
251
|
+
}
|
|
252
|
+
if (/timed out|timeout|etimedout|killed/.test(lower)) {
|
|
253
|
+
return 'timeout';
|
|
254
|
+
}
|
|
255
|
+
return 'error';
|
|
256
|
+
}
|
|
257
|
+
// ── Reviewer reply parsing ──────────────────────────────────────────────
|
|
258
|
+
/**
|
|
259
|
+
* Parse a reviewer reply into a structured finding. The prompt mandates a
|
|
260
|
+
* `Verdict: CLEAN | MINOR ISSUES | SERIOUS ISSUES` line + a findings list. If
|
|
261
|
+
* the verdict line is unparseable (or the reply is blank), the whole reply is
|
|
262
|
+
* captured as one raw "unstructured external review — read manually" finding
|
|
263
|
+
* (never dropped, never thrown, never zero).
|
|
264
|
+
*/
|
|
265
|
+
export function parseReviewerReply(raw, reviewerTag) {
|
|
266
|
+
const text = (raw ?? '').trim();
|
|
267
|
+
if (!text) {
|
|
268
|
+
return {
|
|
269
|
+
reviewer: reviewerTag,
|
|
270
|
+
verdict: 'UNKNOWN',
|
|
271
|
+
body: '(empty reviewer reply — codex returned no output; read manually)',
|
|
272
|
+
unstructured: true,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
const verdict = extractVerdict(text);
|
|
276
|
+
if (verdict === 'UNKNOWN') {
|
|
277
|
+
return {
|
|
278
|
+
reviewer: reviewerTag,
|
|
279
|
+
verdict: 'UNKNOWN',
|
|
280
|
+
body: `unstructured external review — read manually:\n${text}`,
|
|
281
|
+
unstructured: true,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
return {
|
|
285
|
+
reviewer: reviewerTag,
|
|
286
|
+
verdict,
|
|
287
|
+
body: text,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Extract the verdict from a reviewer reply. Looks for a `Verdict:` line and
|
|
292
|
+
* matches one of the three canonical values (case-insensitive, tolerant of
|
|
293
|
+
* surrounding markdown like `**Verdict: SERIOUS ISSUES**`). Returns 'UNKNOWN'
|
|
294
|
+
* when none is found.
|
|
295
|
+
*/
|
|
296
|
+
function extractVerdict(text) {
|
|
297
|
+
// Find a line mentioning "Verdict" and inspect its content.
|
|
298
|
+
const verdictLine = text
|
|
299
|
+
.split('\n')
|
|
300
|
+
.find((l) => /verdict/i.test(l));
|
|
301
|
+
const haystack = (verdictLine ?? text).toUpperCase();
|
|
302
|
+
// Order matters: check the most specific multi-word verdicts first.
|
|
303
|
+
if (haystack.includes('SERIOUS ISSUES'))
|
|
304
|
+
return 'SERIOUS ISSUES';
|
|
305
|
+
if (haystack.includes('MINOR ISSUES'))
|
|
306
|
+
return 'MINOR ISSUES';
|
|
307
|
+
if (haystack.includes('CLEAN'))
|
|
308
|
+
return 'CLEAN';
|
|
309
|
+
return 'UNKNOWN';
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Assemble the cross-model reviewer prompt: the reviewer template (with
|
|
313
|
+
* `{SPEC_PATH}` substituted) + the full spec + as much referenced context as
|
|
314
|
+
* fits the budget. codex runs with NO repo access, so context is inlined under
|
|
315
|
+
* `--- CONTEXT: <path> ---` headers. The spec is ALWAYS included in full; if
|
|
316
|
+
* referenced docs overflow the budget, they are truncated and a loud
|
|
317
|
+
* truncation note is added so the reviewer knows its view was partial (a
|
|
318
|
+
* silently-truncated review is a trap; a disclosed-partial one is still signal).
|
|
319
|
+
*
|
|
320
|
+
* Truncation is DETERMINISTIC (spec §2, F4): referenced docs are ordered by
|
|
321
|
+
* `orderContextDeterministically` (constitutional/lessons docs first, then the
|
|
322
|
+
* spec-declared link order) BEFORE the budget walk, so the same spec + docs
|
|
323
|
+
* always drop the same docs. When a doc is fully or partially dropped, the
|
|
324
|
+
* truncation note NAMES the affected docs (which were partial, which were fully
|
|
325
|
+
* omitted) — a reviewer must know exactly which context it could not see, not
|
|
326
|
+
* just that "something" was cut.
|
|
327
|
+
*/
|
|
328
|
+
export function assembleReviewerPrompt(inputs) {
|
|
329
|
+
const budget = inputs.budgetBytes ?? CONTEXT_BUDGET_BYTES;
|
|
330
|
+
const template = inputs.reviewerTemplate.replace(/\{SPEC_PATH\}/g, inputs.specPath);
|
|
331
|
+
const header = `${template}\n\n--- SPEC UNDER REVIEW: ${inputs.specPath} ---\n${inputs.specMarkdown}\n`;
|
|
332
|
+
const parts = [header];
|
|
333
|
+
let used = Buffer.byteLength(header, 'utf-8');
|
|
334
|
+
let truncated = false;
|
|
335
|
+
// Deterministic priority order: constitutional/lessons docs first, then the
|
|
336
|
+
// spec-declared link order. Same inputs always drop the same docs.
|
|
337
|
+
const context = orderContextDeterministically(inputs.context ?? []);
|
|
338
|
+
// Track exactly which docs were partially included vs fully dropped so the
|
|
339
|
+
// truncation note can NAME them (F4 — a named-partial review is signal; a
|
|
340
|
+
// "something was cut" review is a trap).
|
|
341
|
+
let partialDoc = null;
|
|
342
|
+
const droppedDocs = [];
|
|
343
|
+
for (let i = 0; i < context.length; i++) {
|
|
344
|
+
const doc = context[i];
|
|
345
|
+
const docHeader = `\n--- CONTEXT: ${doc.path} ---\n`;
|
|
346
|
+
const docBlock = `${docHeader}${doc.content}\n`;
|
|
347
|
+
const docBytes = Buffer.byteLength(docBlock, 'utf-8');
|
|
348
|
+
if (!truncated && used + docBytes <= budget) {
|
|
349
|
+
parts.push(docBlock);
|
|
350
|
+
used += docBytes;
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
// Budget exceeded at this doc. Include as much of THIS doc as the remaining
|
|
354
|
+
// budget allows (header always; body sliced), record it as PARTIAL, then
|
|
355
|
+
// mark every remaining doc as fully DROPPED. We do NOT break — we keep
|
|
356
|
+
// walking so the note can name all the dropped docs, not just the first.
|
|
357
|
+
if (!truncated) {
|
|
358
|
+
const remaining = budget - used - Buffer.byteLength(docHeader, 'utf-8');
|
|
359
|
+
if (remaining > 0) {
|
|
360
|
+
// Slice by bytes safely (avoid splitting a multibyte char by slicing
|
|
361
|
+
// the buffer then decoding with replacement tolerated).
|
|
362
|
+
const sliced = Buffer.from(doc.content, 'utf-8').subarray(0, remaining).toString('utf-8');
|
|
363
|
+
parts.push(`${docHeader}${sliced}`);
|
|
364
|
+
partialDoc = doc.path;
|
|
365
|
+
}
|
|
366
|
+
else {
|
|
367
|
+
// Not even the header fits — this doc is fully dropped too.
|
|
368
|
+
droppedDocs.push(doc.path);
|
|
369
|
+
}
|
|
370
|
+
truncated = true;
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
// Already truncated — every subsequent doc is fully omitted.
|
|
374
|
+
droppedDocs.push(doc.path);
|
|
375
|
+
}
|
|
376
|
+
if (truncated) {
|
|
377
|
+
const detail = [];
|
|
378
|
+
if (partialDoc)
|
|
379
|
+
detail.push(`PARTIAL (cut mid-document): ${partialDoc}`);
|
|
380
|
+
if (droppedDocs.length > 0)
|
|
381
|
+
detail.push(`FULLY OMITTED: ${droppedDocs.join(', ')}`);
|
|
382
|
+
const named = detail.length > 0 ? ` ${detail.join('. ')}.` : '';
|
|
383
|
+
parts.push('\n\n--- NOTE: referenced context was TRUNCATED to fit the review budget.' +
|
|
384
|
+
named +
|
|
385
|
+
' Your view of the supporting docs is PARTIAL — flag any finding that ' +
|
|
386
|
+
'depends on context you could not see. ---\n');
|
|
387
|
+
}
|
|
388
|
+
const promptText = parts.join('');
|
|
389
|
+
return {
|
|
390
|
+
promptText,
|
|
391
|
+
truncated,
|
|
392
|
+
bytes: Buffer.byteLength(promptText, 'utf-8'),
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Build the fallback flag for the unavailable / skipped / degraded-all-rounds
|
|
397
|
+
* states. (The available and per-round degraded flags come back on the
|
|
398
|
+
* ReviewerResult.) Centralizes the exact strings the frontmatter writer +
|
|
399
|
+
* report banner consume.
|
|
400
|
+
*
|
|
401
|
+
* `degraded-all-rounds` is the spec-level aggregate the skill writes when a
|
|
402
|
+
* framework was present but no round ever succeeded (see
|
|
403
|
+
* `aggregateRoundOutcomes`).
|
|
404
|
+
*/
|
|
405
|
+
export function buildCrossModelFlag(status, reason) {
|
|
406
|
+
if (status === 'unavailable') {
|
|
407
|
+
return { status, flag: 'cross-model-review: unavailable', reason };
|
|
408
|
+
}
|
|
409
|
+
if (status === 'degraded-all-rounds') {
|
|
410
|
+
return { status, flag: 'cross-model-review: degraded-all-rounds', reason };
|
|
411
|
+
}
|
|
412
|
+
return { status, flag: 'cross-model-review: skipped-abbreviated', reason };
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Aggregate per-round cross-model outcomes into the ONE final spec-level flag
|
|
416
|
+
* (spec §2/§4, F2). Convergence runs multiple rounds; each round yields a
|
|
417
|
+
* `ReviewerResult` (`ok` / `degraded` / `unavailable`). The skill collects the
|
|
418
|
+
* per-round statuses and calls this to decide what `write-convergence-tag.mjs`
|
|
419
|
+
* stamps:
|
|
420
|
+
*
|
|
421
|
+
* - `skipped-abbreviated` if the author opted out (passed explicitly) — wins
|
|
422
|
+
* over everything, since no external pass was attempted by choice.
|
|
423
|
+
* - `codex-cli:<model>` (the LAST successful round's flag) if ANY round got a
|
|
424
|
+
* real external pass — one genuine outside opinion is enough to say the spec
|
|
425
|
+
* received cross-model review.
|
|
426
|
+
* - `degraded-all-rounds` if a framework was present every round but ZERO
|
|
427
|
+
* rounds succeeded (all degraded) — as loud as `unavailable`.
|
|
428
|
+
* - `unavailable` if no framework was ever available (all rounds unavailable).
|
|
429
|
+
*
|
|
430
|
+
* Returns the `{ flag, reason }` the tag writer + report banner consume.
|
|
431
|
+
*/
|
|
432
|
+
export function aggregateRoundOutcomes(rounds, opts = {}) {
|
|
433
|
+
if (opts.skippedAbbreviated) {
|
|
434
|
+
return buildCrossModelFlag('skipped-abbreviated');
|
|
435
|
+
}
|
|
436
|
+
if (rounds.length === 0) {
|
|
437
|
+
// No rounds recorded at all — treat as no external reviewer available.
|
|
438
|
+
return buildCrossModelFlag('unavailable', 'no-rounds-recorded');
|
|
439
|
+
}
|
|
440
|
+
// Any successful round → the spec received a real external opinion. Use the
|
|
441
|
+
// LAST successful round's flag (the freshest pass on the most-converged spec).
|
|
442
|
+
const successful = rounds.filter((r) => r.status === 'ok');
|
|
443
|
+
if (successful.length > 0) {
|
|
444
|
+
const last = successful[successful.length - 1];
|
|
445
|
+
return { status: 'available', flag: last.flag, ...(last.reason ? { reason: last.reason } : {}) };
|
|
446
|
+
}
|
|
447
|
+
// No successes. Was a framework ever present? If ANY round degraded (vs
|
|
448
|
+
// unavailable), the framework was there but never delivered → all-rounds.
|
|
449
|
+
const anyDegraded = rounds.some((r) => r.status === 'degraded');
|
|
450
|
+
if (anyDegraded) {
|
|
451
|
+
// Surface the most recent degraded reason for the `-reason` field.
|
|
452
|
+
const lastDegraded = [...rounds].reverse().find((r) => r.status === 'degraded');
|
|
453
|
+
return buildCrossModelFlag('degraded-all-rounds', lastDegraded?.reason);
|
|
454
|
+
}
|
|
455
|
+
// Every round was unavailable (no framework, ever).
|
|
456
|
+
const lastUnavailable = [...rounds].reverse().find((r) => r.status === 'unavailable');
|
|
457
|
+
return buildCrossModelFlag('unavailable', lastUnavailable?.reason);
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* The high-level entry the skill driver calls: detect, and if available run
|
|
461
|
+
* the first available framework's reviewer with the assembled prompt;
|
|
462
|
+
* otherwise return the `unavailable` flag. NEVER throws, NEVER blocks.
|
|
463
|
+
*
|
|
464
|
+
* `assembled` is produced by `assembleReviewerPrompt`. `detectInputs` and
|
|
465
|
+
* `providerOverride` exist for tests; production omits them.
|
|
466
|
+
*/
|
|
467
|
+
export async function runCrossModelReview(args) {
|
|
468
|
+
const detection = detectCrossModelReviewer(args.detectInputs);
|
|
469
|
+
if (!detection.available) {
|
|
470
|
+
const flag = buildCrossModelFlag('unavailable', detection.reason);
|
|
471
|
+
return {
|
|
472
|
+
status: 'unavailable',
|
|
473
|
+
reason: detection.reason,
|
|
474
|
+
flag: flag.flag,
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
const framework = SUPPORTED_REVIEWER_FRAMEWORKS.find((f) => f.id === detection.framework);
|
|
478
|
+
if (!framework) {
|
|
479
|
+
// Defensive: detection named a framework with no registry entry.
|
|
480
|
+
const flag = buildCrossModelFlag('unavailable', 'no-supported-framework');
|
|
481
|
+
return { status: 'unavailable', reason: 'no-supported-framework', flag: flag.flag };
|
|
482
|
+
}
|
|
483
|
+
return framework.review({
|
|
484
|
+
promptText: args.assembled.promptText,
|
|
485
|
+
timeoutMs: args.timeoutMs ?? REVIEW_TIMEOUT_MS,
|
|
486
|
+
...(args.providerOverride ? { providerOverride: args.providerOverride } : {}),
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
//# sourceMappingURL=crossModelReviewer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crossModelReviewer.js","sourceRoot":"","sources":["../../src/core/crossModelReviewer.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED