@kaitranntt/ccs 7.64.0 → 7.65.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/api/services/profile-types.d.ts +17 -0
- package/dist/api/services/profile-types.d.ts.map +1 -1
- package/dist/ccs.js +61 -6
- package/dist/ccs.js.map +1 -1
- package/dist/cliproxy/executor/env-resolver.d.ts +27 -0
- package/dist/cliproxy/executor/env-resolver.d.ts.map +1 -1
- package/dist/cliproxy/executor/env-resolver.js +87 -3
- package/dist/cliproxy/executor/env-resolver.js.map +1 -1
- package/dist/cliproxy/executor/index.d.ts.map +1 -1
- package/dist/cliproxy/executor/index.js +30 -0
- package/dist/cliproxy/executor/index.js.map +1 -1
- package/dist/cliproxy/model-catalog.d.ts +6 -0
- package/dist/cliproxy/model-catalog.d.ts.map +1 -1
- package/dist/cliproxy/model-catalog.js +38 -1
- package/dist/cliproxy/model-catalog.js.map +1 -1
- package/dist/cliproxy/proxy-config-resolver.d.ts +2 -1
- package/dist/cliproxy/proxy-config-resolver.d.ts.map +1 -1
- package/dist/cliproxy/proxy-config-resolver.js +1 -0
- package/dist/cliproxy/proxy-config-resolver.js.map +1 -1
- package/dist/cliproxy/proxy-target-resolver.d.ts +2 -0
- package/dist/cliproxy/proxy-target-resolver.d.ts.map +1 -1
- package/dist/cliproxy/proxy-target-resolver.js +3 -0
- package/dist/cliproxy/proxy-target-resolver.js.map +1 -1
- package/dist/cliproxy/remote-auth-fetcher.d.ts.map +1 -1
- package/dist/cliproxy/remote-auth-fetcher.js +89 -8
- package/dist/cliproxy/remote-auth-fetcher.js.map +1 -1
- package/dist/cliproxy/services/variant-settings.d.ts.map +1 -1
- package/dist/cliproxy/services/variant-settings.js +19 -4
- package/dist/cliproxy/services/variant-settings.js.map +1 -1
- package/dist/cliproxy/types.d.ts +2 -0
- package/dist/cliproxy/types.d.ts.map +1 -1
- package/dist/commands/config-image-analysis-command.d.ts.map +1 -1
- package/dist/commands/config-image-analysis-command.js +87 -1
- package/dist/commands/config-image-analysis-command.js.map +1 -1
- package/dist/config/unified-config-loader.d.ts.map +1 -1
- package/dist/config/unified-config-loader.js +9 -4
- package/dist/config/unified-config-loader.js.map +1 -1
- package/dist/config/unified-config-types.d.ts +4 -0
- package/dist/config/unified-config-types.d.ts.map +1 -1
- package/dist/config/unified-config-types.js +4 -2
- package/dist/config/unified-config-types.js.map +1 -1
- package/dist/copilot/copilot-executor.d.ts +13 -0
- package/dist/copilot/copilot-executor.d.ts.map +1 -1
- package/dist/copilot/copilot-executor.js +52 -2
- package/dist/copilot/copilot-executor.js.map +1 -1
- package/dist/management/checks/image-analysis-check.js +1 -1
- package/dist/management/checks/image-analysis-check.js.map +1 -1
- package/dist/shared/compatible-cli-contracts.d.ts +4 -0
- package/dist/shared/compatible-cli-contracts.d.ts.map +1 -1
- package/dist/types/config.d.ts +5 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js.map +1 -1
- package/dist/ui/assets/{accounts-D0UZf0nz.js → accounts-BHEYnq6b.js} +1 -1
- package/dist/ui/assets/{alert-dialog-Da7R-FpD.js → alert-dialog-D0EFRcfB.js} +1 -1
- package/dist/ui/assets/api-DhM3BYXr.js +4 -0
- package/dist/ui/assets/{auth-section-CH2_H6xn.js → auth-section-DVp8FQGm.js} +1 -1
- package/dist/ui/assets/{backups-section-C0k3svHF.js → backups-section-CRo0NZkA.js} +1 -1
- package/dist/ui/assets/channels-uZ_9CBqO.js +1 -0
- package/dist/ui/assets/checkbox-32DNqW_Q.js +1 -0
- package/dist/ui/assets/{claude-extension-CSnMQC_L.js → claude-extension-BfXlz5gV.js} +1 -1
- package/dist/ui/assets/cliproxy-DjNY9H-U.js +3 -0
- package/dist/ui/assets/{cliproxy-ai-providers-DdQZEqoN.js → cliproxy-ai-providers-5SHLMHiy.js} +5 -5
- package/dist/ui/assets/{cliproxy-control-panel-3Glps_oU.js → cliproxy-control-panel-Zax_m1AC.js} +1 -1
- package/dist/ui/assets/codex-CRUSpjsu.js +27 -0
- package/dist/ui/assets/{confirm-dialog-tjayxZcM.js → confirm-dialog-DVf5ZmCZ.js} +1 -1
- package/dist/ui/assets/copilot-BZrihl_Z.js +3 -0
- package/dist/ui/assets/cursor-BP4nbEk_.js +1 -0
- package/dist/ui/assets/{droid-C4qduLWT.js → droid-BG92rdM2.js} +2 -2
- package/dist/ui/assets/globalenv-section-Cf6dKgSf.js +1 -0
- package/dist/ui/assets/{health-ocBJ9xoH.js → health-BTy1UZs3.js} +1 -1
- package/dist/ui/assets/icons-CeH5899d.js +1 -0
- package/dist/ui/assets/index-B6SrL1O-.css +1 -0
- package/dist/ui/assets/index-BVeN0dIB.js +1 -0
- package/dist/ui/assets/{index-B3D2Pi4S.js → index-Corv1lSo.js} +32 -32
- package/dist/ui/assets/{index-BkXZkwWB.js → index-DHrTq-0n.js} +1 -1
- package/dist/ui/assets/index-DuRYaONg.js +1 -0
- package/dist/ui/assets/index-N2ZSJurX.js +1 -0
- package/dist/ui/assets/index-wg7UtkFv.js +1 -0
- package/dist/ui/assets/{masked-input-XGpOJSYQ.js → masked-input-DX9bedLy.js} +1 -1
- package/dist/ui/assets/{proxy-status-widget-DwizqfDs.js → proxy-status-widget-DVDMuZK5.js} +1 -1
- package/dist/ui/assets/{radix-ui-Dt3edmE5.js → radix-ui-C98W0NRG.js} +1 -1
- package/dist/ui/assets/{raw-json-settings-editor-panel-DLf0iq8r.js → raw-json-settings-editor-panel-Dkt5E6Z_.js} +1 -1
- package/dist/ui/assets/{searchable-select-C2N5ZoC7.js → searchable-select-BP3Q1-Yn.js} +1 -1
- package/dist/ui/assets/separator-BLGGUlh9.js +1 -0
- package/dist/ui/assets/{shared-CbpV9mUS.js → shared-G0XRyLig.js} +1 -1
- package/dist/ui/assets/{table-CkgTbRUO.js → table-B4lRrWC-.js} +1 -1
- package/dist/ui/assets/{tanstack-CkjseTWE.js → tanstack-CfKik0yL.js} +1 -1
- package/dist/ui/assets/{updates-HsQEuJIR.js → updates--A2Sdo7N.js} +1 -1
- package/dist/ui/index.html +5 -5
- package/dist/utils/hooks/get-image-analysis-hook-env.d.ts +3 -2
- package/dist/utils/hooks/get-image-analysis-hook-env.d.ts.map +1 -1
- package/dist/utils/hooks/get-image-analysis-hook-env.js +15 -6
- package/dist/utils/hooks/get-image-analysis-hook-env.js.map +1 -1
- package/dist/utils/hooks/image-analysis-backend-resolver.d.ts +53 -0
- package/dist/utils/hooks/image-analysis-backend-resolver.d.ts.map +1 -0
- package/dist/utils/hooks/image-analysis-backend-resolver.js +376 -0
- package/dist/utils/hooks/image-analysis-backend-resolver.js.map +1 -0
- package/dist/utils/hooks/image-analysis-runtime-status.d.ts +17 -0
- package/dist/utils/hooks/image-analysis-runtime-status.d.ts.map +1 -0
- package/dist/utils/hooks/image-analysis-runtime-status.js +132 -0
- package/dist/utils/hooks/image-analysis-runtime-status.js.map +1 -0
- package/dist/utils/hooks/image-analyzer-profile-hook-injector.d.ts +6 -5
- package/dist/utils/hooks/image-analyzer-profile-hook-injector.d.ts.map +1 -1
- package/dist/utils/hooks/image-analyzer-profile-hook-injector.js +37 -17
- package/dist/utils/hooks/image-analyzer-profile-hook-injector.js.map +1 -1
- package/dist/utils/hooks/index.d.ts +2 -0
- package/dist/utils/hooks/index.d.ts.map +1 -1
- package/dist/utils/hooks/index.js +8 -1
- package/dist/utils/hooks/index.js.map +1 -1
- package/dist/web-server/index.d.ts.map +1 -1
- package/dist/web-server/index.js +6 -1
- package/dist/web-server/index.js.map +1 -1
- package/dist/web-server/routes/image-analysis-routes.d.ts +3 -0
- package/dist/web-server/routes/image-analysis-routes.d.ts.map +1 -0
- package/dist/web-server/routes/image-analysis-routes.js +362 -0
- package/dist/web-server/routes/image-analysis-routes.js.map +1 -0
- package/dist/web-server/routes/index.d.ts.map +1 -1
- package/dist/web-server/routes/index.js +2 -0
- package/dist/web-server/routes/index.js.map +1 -1
- package/dist/web-server/routes/settings-routes.d.ts.map +1 -1
- package/dist/web-server/routes/settings-routes.js +67 -5
- package/dist/web-server/routes/settings-routes.js.map +1 -1
- package/dist/web-server/services/codex-dashboard-service.d.ts.map +1 -1
- package/dist/web-server/services/codex-dashboard-service.js +14 -0
- package/dist/web-server/services/codex-dashboard-service.js.map +1 -1
- package/package.json +2 -2
- package/scripts/github/normalize-ai-review-output.mjs +305 -17
- package/scripts/github/prepare-ai-review-scope.mjs +338 -0
- package/dist/ui/assets/api-DpKfrsn2.js +0 -4
- package/dist/ui/assets/channels-Cpxagv1M.js +0 -1
- package/dist/ui/assets/checkbox-B_ZY6YZW.js +0 -1
- package/dist/ui/assets/cliproxy-D9B-TLY3.js +0 -3
- package/dist/ui/assets/codex-xj_XJVjB.js +0 -27
- package/dist/ui/assets/copilot-DQ5Dr5Ff.js +0 -3
- package/dist/ui/assets/cursor-DtFjK37Z.js +0 -1
- package/dist/ui/assets/globalenv-section-B2YBzWoz.js +0 -1
- package/dist/ui/assets/icons-Cn04FDSc.js +0 -1
- package/dist/ui/assets/index-1TKCj6WA.js +0 -1
- package/dist/ui/assets/index-9Qv0NQVB.js +0 -1
- package/dist/ui/assets/index-C9UUemEw.js +0 -1
- package/dist/ui/assets/index-DGQOg_8Q.css +0 -1
- package/dist/ui/assets/separator-CuY8SIhQ.js +0 -1
- package/dist/ui/assets/switch-Dz4ptkeA.js +0 -1
|
@@ -21,6 +21,12 @@ const STATUS_LABELS = {
|
|
|
21
21
|
na: 'N/A',
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
+
const REVIEW_MODE_DETAILS = {
|
|
25
|
+
fast: 'diff-focused bounded review',
|
|
26
|
+
triage: 'hotspot-based bounded review (non-exhaustive)',
|
|
27
|
+
deep: 'expanded surrounding-code review',
|
|
28
|
+
};
|
|
29
|
+
|
|
24
30
|
const RENDERER_OWNED_MARKUP_PATTERNS = [
|
|
25
31
|
{ pattern: /^#{1,6}\s/u, reason: 'markdown heading' },
|
|
26
32
|
{ pattern: /^\s*Verdict\s*:/iu, reason: 'verdict label' },
|
|
@@ -44,6 +50,171 @@ function renderCode(value) {
|
|
|
44
50
|
return `${fence}${text}${fence}`;
|
|
45
51
|
}
|
|
46
52
|
|
|
53
|
+
function parsePositiveInteger(value) {
|
|
54
|
+
if (value === null || value === undefined || value === '') {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const parsed = typeof value === 'number' ? value : Number.parseInt(cleanText(value), 10);
|
|
59
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function normalizeReviewMode(value) {
|
|
63
|
+
const mode = cleanText(value).toLowerCase();
|
|
64
|
+
return REVIEW_MODE_DETAILS[mode] ? mode : null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function normalizeRenderingMetadata(raw) {
|
|
68
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
69
|
+
return {};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const mode = normalizeReviewMode(raw.mode);
|
|
73
|
+
const maxTurns = parsePositiveInteger(raw.maxTurns);
|
|
74
|
+
const timeoutMinutes = parsePositiveInteger(raw.timeoutMinutes);
|
|
75
|
+
const timeoutSeconds = parsePositiveInteger(raw.timeoutSeconds);
|
|
76
|
+
const selectedFiles = parsePositiveInteger(raw.selectedFiles);
|
|
77
|
+
const reviewableFiles = parsePositiveInteger(raw.reviewableFiles);
|
|
78
|
+
const selectedChanges = parsePositiveInteger(raw.selectedChanges);
|
|
79
|
+
const reviewableChanges = parsePositiveInteger(raw.reviewableChanges);
|
|
80
|
+
const scopeLabel = cleanText(raw.scopeLabel).toLowerCase();
|
|
81
|
+
const metadata = {};
|
|
82
|
+
|
|
83
|
+
if (mode) metadata.mode = mode;
|
|
84
|
+
if (maxTurns) metadata.maxTurns = maxTurns;
|
|
85
|
+
if (timeoutMinutes) metadata.timeoutMinutes = timeoutMinutes;
|
|
86
|
+
if (timeoutSeconds) metadata.timeoutSeconds = timeoutSeconds;
|
|
87
|
+
if (selectedFiles) metadata.selectedFiles = selectedFiles;
|
|
88
|
+
if (reviewableFiles) metadata.reviewableFiles = reviewableFiles;
|
|
89
|
+
if (selectedChanges) metadata.selectedChanges = selectedChanges;
|
|
90
|
+
if (reviewableChanges) metadata.reviewableChanges = reviewableChanges;
|
|
91
|
+
if (scopeLabel === 'reviewable files' || scopeLabel === 'changed files') metadata.scopeLabel = scopeLabel;
|
|
92
|
+
|
|
93
|
+
return metadata;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function mergeRenderingMetadata(...sources) {
|
|
97
|
+
const merged = {};
|
|
98
|
+
for (const source of sources) {
|
|
99
|
+
Object.assign(merged, normalizeRenderingMetadata(source));
|
|
100
|
+
}
|
|
101
|
+
return merged;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function formatTurnBudget(rendering) {
|
|
105
|
+
return typeof rendering.maxTurns === 'number' ? `${rendering.maxTurns} turns` : null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function formatTimeBudget(rendering) {
|
|
109
|
+
if (typeof rendering.timeoutMinutes === 'number') {
|
|
110
|
+
return `${rendering.timeoutMinutes} minute${rendering.timeoutMinutes === 1 ? '' : 's'}`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (typeof rendering.timeoutSeconds === 'number') {
|
|
114
|
+
return `${rendering.timeoutSeconds} second${rendering.timeoutSeconds === 1 ? '' : 's'}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function formatCombinedBudget(rendering) {
|
|
121
|
+
const parts = [formatTurnBudget(rendering), formatTimeBudget(rendering)].filter(Boolean);
|
|
122
|
+
return parts.length > 0 ? parts.join(' / ') : null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function formatScopeSummary(rendering) {
|
|
126
|
+
if (
|
|
127
|
+
typeof rendering.selectedFiles !== 'number' ||
|
|
128
|
+
typeof rendering.reviewableFiles !== 'number'
|
|
129
|
+
) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const scopeLabel = rendering.scopeLabel || 'reviewable files';
|
|
134
|
+
const fileScope = `${rendering.selectedFiles}/${rendering.reviewableFiles} ${scopeLabel}`;
|
|
135
|
+
if (
|
|
136
|
+
typeof rendering.selectedChanges === 'number' &&
|
|
137
|
+
typeof rendering.reviewableChanges === 'number'
|
|
138
|
+
) {
|
|
139
|
+
const changeLabel = scopeLabel === 'reviewable files' ? 'reviewable changed lines' : 'changed lines';
|
|
140
|
+
return `${fileScope}; ${rendering.selectedChanges}/${rendering.reviewableChanges} ${changeLabel}`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return fileScope;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function formatReviewContext(rendering) {
|
|
147
|
+
const parts = [];
|
|
148
|
+
|
|
149
|
+
if (rendering.mode) {
|
|
150
|
+
parts.push(`mode ${renderCode(rendering.mode)}`);
|
|
151
|
+
parts.push(REVIEW_MODE_DETAILS[rendering.mode]);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const scopeSummary = formatScopeSummary(rendering);
|
|
155
|
+
if (scopeSummary) {
|
|
156
|
+
parts.push(`scope ${scopeSummary}`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const turnBudget = formatTurnBudget(rendering);
|
|
160
|
+
if (turnBudget) {
|
|
161
|
+
parts.push(`turn budget ${turnBudget}`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const timeBudget = formatTimeBudget(rendering);
|
|
165
|
+
if (timeBudget) {
|
|
166
|
+
parts.push(`workflow cap ${timeBudget}`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (parts.length === 0) {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return `> 🧭 Review context: ${parts.join('; ')}.`;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function classifyFallbackReason(reason) {
|
|
177
|
+
const normalized = cleanText(reason).toLowerCase();
|
|
178
|
+
if (!normalized || normalized === 'missing structured output') {
|
|
179
|
+
return 'missing';
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (normalized === 'structured output is not valid json') {
|
|
183
|
+
return 'invalid_json';
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return 'invalid_fields';
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function describeIncompleteOutcome({ reason, rendering, turnsUsed, status }) {
|
|
190
|
+
const reviewLabel = rendering.mode ? `${renderCode(rendering.mode)} review` : 'bounded review';
|
|
191
|
+
const turnBudget = formatTurnBudget(rendering);
|
|
192
|
+
const timeBudget = formatTimeBudget(rendering);
|
|
193
|
+
const combinedBudget = formatCombinedBudget(rendering);
|
|
194
|
+
const exhaustedTurnBudget =
|
|
195
|
+
typeof turnsUsed === 'number' &&
|
|
196
|
+
typeof rendering.maxTurns === 'number' &&
|
|
197
|
+
turnsUsed >= rendering.maxTurns;
|
|
198
|
+
|
|
199
|
+
if (status === 'cancelled' && timeBudget) {
|
|
200
|
+
return `The ${reviewLabel} hit the workflow runtime cap before it produced validated structured output. The run stayed bounded to ${timeBudget}.`;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (exhaustedTurnBudget) {
|
|
204
|
+
return `The ${reviewLabel} reached its ${rendering.maxTurns}-turn runtime budget before it produced validated structured output.`;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (combinedBudget && classifyFallbackReason(reason) === 'missing') {
|
|
208
|
+
return `The ${reviewLabel} ended before it could produce validated structured output within the available ${combinedBudget} runtime budget.`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (classifyFallbackReason(reason) === 'missing' || classifyFallbackReason(reason) === 'invalid_json') {
|
|
212
|
+
return `The ${reviewLabel} ended without validated structured output, so the normalizer published the safe fallback comment instead.`;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return `The ${reviewLabel} returned incomplete structured data, so the normalizer published the safe fallback comment instead.`;
|
|
216
|
+
}
|
|
217
|
+
|
|
47
218
|
function validatePlainTextField(fieldName, value) {
|
|
48
219
|
const text = cleanText(value);
|
|
49
220
|
if (!text) {
|
|
@@ -119,6 +290,66 @@ function readExecutionMetadata(executionFile) {
|
|
|
119
290
|
}
|
|
120
291
|
}
|
|
121
292
|
|
|
293
|
+
function readSelectedFiles(manifestFile) {
|
|
294
|
+
if (!manifestFile || !fs.existsSync(manifestFile)) {
|
|
295
|
+
return [];
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
try {
|
|
299
|
+
return fs
|
|
300
|
+
.readFileSync(manifestFile, 'utf8')
|
|
301
|
+
.split('\n')
|
|
302
|
+
.map((line) => cleanText(line))
|
|
303
|
+
.filter(Boolean);
|
|
304
|
+
} catch {
|
|
305
|
+
return [];
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function formatHotspotFiles(files) {
|
|
310
|
+
if (!files.length) {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const visible = files.slice(0, 4).map(renderCode).join(', ');
|
|
315
|
+
return files.length > 4 ? `${visible}, and ${files.length - 4} more` : visible;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function formatRemainingCoverage(rendering) {
|
|
319
|
+
if (
|
|
320
|
+
typeof rendering.selectedFiles !== 'number' ||
|
|
321
|
+
typeof rendering.reviewableFiles !== 'number'
|
|
322
|
+
) {
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const remainingFiles = Math.max(rendering.reviewableFiles - rendering.selectedFiles, 0);
|
|
327
|
+
const hasChangeCounts =
|
|
328
|
+
typeof rendering.selectedChanges === 'number' &&
|
|
329
|
+
typeof rendering.reviewableChanges === 'number';
|
|
330
|
+
const remainingChanges = hasChangeCounts
|
|
331
|
+
? Math.max(rendering.reviewableChanges - rendering.selectedChanges, 0)
|
|
332
|
+
: null;
|
|
333
|
+
|
|
334
|
+
if (remainingFiles === 0 && (!hasChangeCounts || remainingChanges === 0)) {
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (typeof remainingChanges === 'number') {
|
|
339
|
+
return `${remainingFiles} file${remainingFiles === 1 ? '' : 's'}; ${remainingChanges} changed lines`;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return `${remainingFiles} file${remainingFiles === 1 ? '' : 's'}`;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function formatFallbackFollowUp(rendering) {
|
|
346
|
+
if (rendering.mode === 'triage') {
|
|
347
|
+
return 'Focus manual review on the hotspot files above, and use `/review` for a deeper pass when release, auth, config, or workflow paths changed.';
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return 'Use `/review` when you need a deeper maintainer rerun with more surrounding context.';
|
|
351
|
+
}
|
|
352
|
+
|
|
122
353
|
export function normalizeStructuredOutput(raw) {
|
|
123
354
|
if (!raw) {
|
|
124
355
|
return { ok: false, reason: 'missing structured output' };
|
|
@@ -155,6 +386,8 @@ export function normalizeStructuredOutput(raw) {
|
|
|
155
386
|
const strengths = normalizeStringList('strengths', parsed.strengths);
|
|
156
387
|
if (!strengths.ok) return strengths;
|
|
157
388
|
|
|
389
|
+
const rendering = normalizeRenderingMetadata(parsed.rendering);
|
|
390
|
+
|
|
158
391
|
if (!ASSESSMENTS[overallAssessment] || findings === null) {
|
|
159
392
|
return { ok: false, reason: 'structured output is missing required review fields' };
|
|
160
393
|
}
|
|
@@ -203,19 +436,22 @@ export function normalizeStructuredOutput(raw) {
|
|
|
203
436
|
});
|
|
204
437
|
}
|
|
205
438
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
informational: informational.value,
|
|
216
|
-
strengths: strengths.value,
|
|
217
|
-
},
|
|
439
|
+
const value = {
|
|
440
|
+
summary: summary.value,
|
|
441
|
+
findings: normalizedFindings,
|
|
442
|
+
overallAssessment,
|
|
443
|
+
overallRationale: overallRationale.value,
|
|
444
|
+
securityChecklist: securityChecklist.value,
|
|
445
|
+
ccsCompliance: ccsCompliance.value,
|
|
446
|
+
informational: informational.value,
|
|
447
|
+
strengths: strengths.value,
|
|
218
448
|
};
|
|
449
|
+
|
|
450
|
+
if (Object.keys(rendering).length > 0) {
|
|
451
|
+
value.rendering = rendering;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
return { ok: true, value };
|
|
219
455
|
}
|
|
220
456
|
|
|
221
457
|
function renderChecklistTable(title, labelHeader, labelKey, rows) {
|
|
@@ -233,8 +469,14 @@ function renderBulletSection(title, items) {
|
|
|
233
469
|
return ['', title, ...items.map((item) => `- ${escapeMarkdownText(item)}`)];
|
|
234
470
|
}
|
|
235
471
|
|
|
236
|
-
export function renderStructuredReview(review, { model }) {
|
|
472
|
+
export function renderStructuredReview(review, { model, rendering: renderOptions } = {}) {
|
|
473
|
+
const rendering = mergeRenderingMetadata(review?.rendering, renderOptions);
|
|
237
474
|
const lines = ['### 📋 Summary', '', escapeMarkdownText(review.summary), '', '### 🔍 Findings'];
|
|
475
|
+
const reviewContext = formatReviewContext(rendering);
|
|
476
|
+
|
|
477
|
+
if (reviewContext) {
|
|
478
|
+
lines.splice(4, 0, reviewContext, '');
|
|
479
|
+
}
|
|
238
480
|
|
|
239
481
|
if (review.findings.length === 0) {
|
|
240
482
|
lines.push('No confirmed issues found after reviewing the diff and surrounding code.');
|
|
@@ -273,15 +515,45 @@ export function renderStructuredReview(review, { model }) {
|
|
|
273
515
|
return lines.join('\n');
|
|
274
516
|
}
|
|
275
517
|
|
|
276
|
-
export function renderIncompleteReview({
|
|
518
|
+
export function renderIncompleteReview({
|
|
519
|
+
model,
|
|
520
|
+
reason,
|
|
521
|
+
runUrl,
|
|
522
|
+
runtimeTools,
|
|
523
|
+
turnsUsed,
|
|
524
|
+
selectedFiles,
|
|
525
|
+
rendering: renderOptions,
|
|
526
|
+
status,
|
|
527
|
+
}) {
|
|
528
|
+
const rendering = mergeRenderingMetadata(renderOptions);
|
|
277
529
|
const lines = [
|
|
278
530
|
'### ⚠️ AI Review Incomplete',
|
|
279
531
|
'',
|
|
280
|
-
'Claude did not return validated structured review output, so this workflow
|
|
532
|
+
'Claude did not return validated structured review output, so this workflow published deterministic hotspot context instead of raw scratch text.',
|
|
281
533
|
'',
|
|
282
|
-
`-
|
|
534
|
+
`- Outcome: ${describeIncompleteOutcome({ reason, rendering, turnsUsed, status })}`,
|
|
283
535
|
];
|
|
284
536
|
|
|
537
|
+
if (rendering.mode) {
|
|
538
|
+
lines.push(`- Review mode: ${renderCode(rendering.mode)} (${escapeMarkdownText(REVIEW_MODE_DETAILS[rendering.mode])})`);
|
|
539
|
+
}
|
|
540
|
+
const scopeSummary = formatScopeSummary(rendering);
|
|
541
|
+
if (scopeSummary) {
|
|
542
|
+
lines.push(`- Review scope: ${escapeMarkdownText(scopeSummary)}`);
|
|
543
|
+
}
|
|
544
|
+
const runtimeBudget = formatCombinedBudget(rendering);
|
|
545
|
+
if (runtimeBudget) {
|
|
546
|
+
lines.push(`- Runtime budget: ${escapeMarkdownText(runtimeBudget)}`);
|
|
547
|
+
}
|
|
548
|
+
const hotspotFiles = formatHotspotFiles(selectedFiles || []);
|
|
549
|
+
if (hotspotFiles) {
|
|
550
|
+
lines.push(`- Hotspot files in this pass: ${hotspotFiles}`);
|
|
551
|
+
}
|
|
552
|
+
const remainingCoverage = formatRemainingCoverage(rendering);
|
|
553
|
+
if (remainingCoverage) {
|
|
554
|
+
lines.push(`- Remaining reviewable scope not fully covered: ${escapeMarkdownText(remainingCoverage)}`);
|
|
555
|
+
}
|
|
556
|
+
lines.push(`- Manual follow-up: ${escapeMarkdownText(formatFallbackFollowUp(rendering))}`);
|
|
285
557
|
if (runtimeTools?.length) {
|
|
286
558
|
lines.push(`- Runtime tools: ${runtimeTools.map(renderCode).join(', ')}`);
|
|
287
559
|
}
|
|
@@ -299,14 +571,30 @@ export function writeReviewFromEnv(env = process.env) {
|
|
|
299
571
|
const runUrl = env.AI_REVIEW_RUN_URL || '#';
|
|
300
572
|
const validation = normalizeStructuredOutput(env.AI_REVIEW_STRUCTURED_OUTPUT);
|
|
301
573
|
const metadata = readExecutionMetadata(env.AI_REVIEW_EXECUTION_FILE);
|
|
574
|
+
const selectedFiles = readSelectedFiles(env.AI_REVIEW_SCOPE_MANIFEST_FILE);
|
|
575
|
+
const status = cleanText(env.AI_REVIEW_STATUS).toLowerCase() || null;
|
|
576
|
+
const rendering = normalizeRenderingMetadata({
|
|
577
|
+
mode: env.AI_REVIEW_MODE,
|
|
578
|
+
selectedFiles: env.AI_REVIEW_SELECTED_FILES,
|
|
579
|
+
reviewableFiles: env.AI_REVIEW_REVIEWABLE_FILES,
|
|
580
|
+
selectedChanges: env.AI_REVIEW_SELECTED_CHANGES,
|
|
581
|
+
reviewableChanges: env.AI_REVIEW_REVIEWABLE_CHANGES,
|
|
582
|
+
scopeLabel: env.AI_REVIEW_SCOPE_LABEL,
|
|
583
|
+
maxTurns: env.AI_REVIEW_MAX_TURNS,
|
|
584
|
+
timeoutMinutes: env.AI_REVIEW_TIMEOUT_MINUTES ?? env.AI_REVIEW_TIMEOUT_MINUTES_BUDGET,
|
|
585
|
+
timeoutSeconds: env.AI_REVIEW_TIMEOUT_SECONDS ?? env.AI_REVIEW_TIMEOUT_SEC,
|
|
586
|
+
});
|
|
302
587
|
const content = validation.ok
|
|
303
|
-
? renderStructuredReview(validation.value, { model })
|
|
588
|
+
? renderStructuredReview(validation.value, { model, rendering })
|
|
304
589
|
: renderIncompleteReview({
|
|
305
590
|
model,
|
|
306
591
|
reason: validation.reason,
|
|
307
592
|
runUrl,
|
|
308
593
|
runtimeTools: metadata.runtimeTools,
|
|
309
594
|
turnsUsed: metadata.turnsUsed,
|
|
595
|
+
selectedFiles,
|
|
596
|
+
rendering,
|
|
597
|
+
status,
|
|
310
598
|
});
|
|
311
599
|
|
|
312
600
|
fs.mkdirSync(path.dirname(outputFile), { recursive: true });
|