@almightygpt/core 0.4.0 → 0.5.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/adapters/claude.d.ts +1 -1
- package/dist/adapters/claude.d.ts.map +1 -1
- package/dist/adapters/claude.js.map +1 -1
- package/dist/adapters/gemini.d.ts +1 -1
- package/dist/adapters/gemini.d.ts.map +1 -1
- package/dist/adapters/gemini.js.map +1 -1
- package/dist/adapters/mock.d.ts +1 -0
- package/dist/adapters/mock.d.ts.map +1 -1
- package/dist/adapters/mock.js +1 -0
- package/dist/adapters/mock.js.map +1 -1
- package/dist/adapters/openai.d.ts +1 -1
- package/dist/adapters/openai.d.ts.map +1 -1
- package/dist/adapters/openai.js.map +1 -1
- package/dist/adapters/types.d.ts +8 -0
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/adapters/types.js.map +1 -1
- package/dist/git/status.d.ts.map +1 -1
- package/dist/git/status.js +18 -5
- package/dist/git/status.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/review/diff-filter.d.ts +37 -0
- package/dist/review/diff-filter.d.ts.map +1 -0
- package/dist/review/diff-filter.js +144 -0
- package/dist/review/diff-filter.js.map +1 -0
- package/dist/review/run-diff-review.d.ts.map +1 -1
- package/dist/review/run-diff-review.js +30 -8
- package/dist/review/run-diff-review.js.map +1 -1
- package/dist/review/run-worker-reviewer.d.ts.map +1 -1
- package/dist/review/run-worker-reviewer.js +31 -10
- package/dist/review/run-worker-reviewer.js.map +1 -1
- package/dist/review/write.d.ts +15 -0
- package/dist/review/write.d.ts.map +1 -1
- package/dist/review/write.js +29 -0
- package/dist/review/write.js.map +1 -1
- package/package.json +2 -1
- package/src/adapters/claude.ts +1 -1
- package/src/adapters/gemini.ts +1 -1
- package/src/adapters/mock.ts +1 -0
- package/src/adapters/openai.ts +1 -1
- package/src/adapters/types.ts +8 -0
- package/src/git/status.ts +21 -5
- package/src/index.ts +3 -1
- package/src/review/diff-filter.ts +190 -0
- package/src/review/run-diff-review.ts +40 -8
- package/src/review/run-worker-reviewer.ts +41 -10
- package/src/review/write.ts +42 -0
|
@@ -37,12 +37,16 @@ import {
|
|
|
37
37
|
} from "../runs/folder.js";
|
|
38
38
|
import type { RunMetadata } from "../runs/types.js";
|
|
39
39
|
import { collectGitDiff } from "./diff.js";
|
|
40
|
+
import { filterDiffByIgnoreLists } from "./diff-filter.js";
|
|
40
41
|
import { assembleMemory } from "./memory.js";
|
|
41
42
|
import {
|
|
42
43
|
buildReviewerSystemFraming,
|
|
43
44
|
buildReviewerUserMessage,
|
|
44
45
|
} from "./prompts.js";
|
|
45
|
-
import {
|
|
46
|
+
import {
|
|
47
|
+
preflightReviewFileCollision,
|
|
48
|
+
writeHumanReviewFile,
|
|
49
|
+
} from "./write.js";
|
|
46
50
|
import { BudgetTracker, BudgetExceededError } from "./budget.js";
|
|
47
51
|
|
|
48
52
|
export interface DiffReviewOptions {
|
|
@@ -111,6 +115,16 @@ export async function runDiffReview(
|
|
|
111
115
|
);
|
|
112
116
|
}
|
|
113
117
|
|
|
118
|
+
// Preflight the review-file collision BEFORE any paid adapter call.
|
|
119
|
+
// (Codex review v0.5: previously the check ran post-adapter, burning API
|
|
120
|
+
// money on duplicate-topic runs that were going to fail anyway.)
|
|
121
|
+
await preflightReviewFileCollision(
|
|
122
|
+
opts.repoRoot,
|
|
123
|
+
config.reviewsDir,
|
|
124
|
+
opts.topic,
|
|
125
|
+
opts.force ?? false,
|
|
126
|
+
);
|
|
127
|
+
|
|
114
128
|
// Create run folder up front so partial failures still leave an artifact.
|
|
115
129
|
const runFolder = await createRunFolder({
|
|
116
130
|
repoRoot: opts.repoRoot,
|
|
@@ -157,14 +171,29 @@ export async function runDiffReview(
|
|
|
157
171
|
);
|
|
158
172
|
}
|
|
159
173
|
|
|
174
|
+
// Codex review v0.5 P1 #2: filter ignored files BEFORE secret redaction
|
|
175
|
+
// and BEFORE the provider call. Honors .almightyignore + .gitignore +
|
|
176
|
+
// config.context.exclude. Redaction still runs on the survivors as
|
|
177
|
+
// defense-in-depth.
|
|
178
|
+
const filtered = await filterDiffByIgnoreLists({
|
|
179
|
+
repoRoot: opts.repoRoot,
|
|
180
|
+
diffText: diffResult.diff,
|
|
181
|
+
files: diffResult.files,
|
|
182
|
+
configExclude: config.context.exclude,
|
|
183
|
+
});
|
|
184
|
+
|
|
160
185
|
const redaction = config.security.redactSecrets
|
|
161
|
-
? redactSecrets(
|
|
162
|
-
: { text:
|
|
186
|
+
? redactSecrets(filtered.filteredDiff)
|
|
187
|
+
: { text: filtered.filteredDiff, redactions: [], totalCount: 0 };
|
|
163
188
|
|
|
164
189
|
const manifest = buildContextManifest({
|
|
165
190
|
inputSource: opts.range ? "diff-range" : "diff",
|
|
166
|
-
filesIncluded:
|
|
167
|
-
filesSkipped:
|
|
191
|
+
filesIncluded: filtered.filesIncluded.map((p) => ({ path: p, bytes: 0 })),
|
|
192
|
+
filesSkipped: filtered.filesSkipped.map((s) => ({
|
|
193
|
+
path: s.path,
|
|
194
|
+
bytes: 0,
|
|
195
|
+
skippedReason: s.reason,
|
|
196
|
+
})),
|
|
168
197
|
diffText: redaction.text,
|
|
169
198
|
redaction: {
|
|
170
199
|
enabled: config.security.redactSecrets,
|
|
@@ -184,15 +213,18 @@ export async function runDiffReview(
|
|
|
184
213
|
const userMessage = buildReviewerUserMessage({
|
|
185
214
|
topic: opts.topic,
|
|
186
215
|
diff: redaction.text,
|
|
187
|
-
files:
|
|
216
|
+
files: filtered.filesIncluded,
|
|
188
217
|
});
|
|
189
218
|
|
|
190
219
|
const budget = new BudgetTracker(config.budget);
|
|
191
220
|
const estimatedTokensIn = Math.ceil(
|
|
192
221
|
(systemPrompt.length + userMessage.length) / 4,
|
|
193
222
|
);
|
|
223
|
+
// Codex review v0.5 P2 #5: previously hardcoded "gpt-4o" here, which
|
|
224
|
+
// could block a cheap Gemini run on an OpenAI cost estimate. Use the
|
|
225
|
+
// actual adapter's default model so the preflight matches reality.
|
|
194
226
|
budget.preflightCheck({
|
|
195
|
-
model:
|
|
227
|
+
model: adapter.defaultModel,
|
|
196
228
|
estimatedTokensIn,
|
|
197
229
|
maxOutputTokens: 4096,
|
|
198
230
|
});
|
|
@@ -278,7 +310,7 @@ export async function runDiffReview(
|
|
|
278
310
|
costUsd: adapterOut.costUsd,
|
|
279
311
|
latencyMs: adapterOut.latencyMs,
|
|
280
312
|
diffEmpty: diffResult.empty,
|
|
281
|
-
filesReviewed:
|
|
313
|
+
filesReviewed: filtered.filesIncluded,
|
|
282
314
|
memorySources: memory.sources,
|
|
283
315
|
memoryMissing: memory.missing,
|
|
284
316
|
runId: runFolder.id,
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
} from "../runs/folder.js";
|
|
46
46
|
import type { AgentMetrics, RunMetadata } from "../runs/types.js";
|
|
47
47
|
import { collectGitDiff } from "./diff.js";
|
|
48
|
+
import { filterDiffByIgnoreLists } from "./diff-filter.js";
|
|
48
49
|
import { assembleMemory } from "./memory.js";
|
|
49
50
|
import {
|
|
50
51
|
buildReviewerSystemFraming,
|
|
@@ -52,7 +53,10 @@ import {
|
|
|
52
53
|
buildWorkerSystemFraming,
|
|
53
54
|
buildWorkerUserMessage,
|
|
54
55
|
} from "./prompts.js";
|
|
55
|
-
import {
|
|
56
|
+
import {
|
|
57
|
+
preflightReviewFileCollision,
|
|
58
|
+
writeHumanReviewFile,
|
|
59
|
+
} from "./write.js";
|
|
56
60
|
import { BudgetTracker, BudgetExceededError } from "./budget.js";
|
|
57
61
|
import type { ReviewEventHandler } from "./events.js";
|
|
58
62
|
|
|
@@ -153,6 +157,16 @@ export async function runWorkerReviewerReview(
|
|
|
153
157
|
? `Worker and Reviewer are both ${workerCfg.provider}. Cross-vendor pairing catches more issues.`
|
|
154
158
|
: undefined;
|
|
155
159
|
|
|
160
|
+
// Preflight the review-file collision BEFORE Worker or Reviewer fires.
|
|
161
|
+
// (Codex review v0.5: previously the check ran post-adapter, burning two
|
|
162
|
+
// adapter calls of API money on duplicate-topic runs.)
|
|
163
|
+
await preflightReviewFileCollision(
|
|
164
|
+
opts.repoRoot,
|
|
165
|
+
config.reviewsDir,
|
|
166
|
+
opts.topic,
|
|
167
|
+
opts.force ?? false,
|
|
168
|
+
);
|
|
169
|
+
|
|
156
170
|
const runFolder = await createRunFolder({
|
|
157
171
|
repoRoot: opts.repoRoot,
|
|
158
172
|
runsDir: config.runsDir,
|
|
@@ -207,9 +221,19 @@ export async function runWorkerReviewerReview(
|
|
|
207
221
|
);
|
|
208
222
|
}
|
|
209
223
|
|
|
224
|
+
// Codex review v0.5 P1 #2: filter ignored files BEFORE redaction and
|
|
225
|
+
// BEFORE either adapter call. Honors .almightyignore + .gitignore +
|
|
226
|
+
// config.context.exclude.
|
|
227
|
+
const filtered = await filterDiffByIgnoreLists({
|
|
228
|
+
repoRoot: opts.repoRoot,
|
|
229
|
+
diffText: diffResult.diff,
|
|
230
|
+
files: diffResult.files,
|
|
231
|
+
configExclude: config.context.exclude,
|
|
232
|
+
});
|
|
233
|
+
|
|
210
234
|
const redaction = config.security.redactSecrets
|
|
211
|
-
? redactSecrets(
|
|
212
|
-
: { text:
|
|
235
|
+
? redactSecrets(filtered.filteredDiff)
|
|
236
|
+
: { text: filtered.filteredDiff, redactions: [], totalCount: 0 };
|
|
213
237
|
emit({
|
|
214
238
|
type: "redaction_complete",
|
|
215
239
|
totalCount: redaction.totalCount,
|
|
@@ -218,8 +242,12 @@ export async function runWorkerReviewerReview(
|
|
|
218
242
|
|
|
219
243
|
const manifest = buildContextManifest({
|
|
220
244
|
inputSource: opts.range ? "diff-range" : "diff",
|
|
221
|
-
filesIncluded:
|
|
222
|
-
filesSkipped:
|
|
245
|
+
filesIncluded: filtered.filesIncluded.map((p) => ({ path: p, bytes: 0 })),
|
|
246
|
+
filesSkipped: filtered.filesSkipped.map((s) => ({
|
|
247
|
+
path: s.path,
|
|
248
|
+
bytes: 0,
|
|
249
|
+
skippedReason: s.reason,
|
|
250
|
+
})),
|
|
223
251
|
diffText: redaction.text,
|
|
224
252
|
redaction: {
|
|
225
253
|
enabled: config.security.redactSecrets,
|
|
@@ -245,11 +273,14 @@ export async function runWorkerReviewerReview(
|
|
|
245
273
|
const workerUser = buildWorkerUserMessage({
|
|
246
274
|
topic: opts.topic,
|
|
247
275
|
diff: redaction.text,
|
|
248
|
-
files:
|
|
276
|
+
files: filtered.filesIncluded,
|
|
249
277
|
});
|
|
250
278
|
|
|
279
|
+
// Codex review v0.5 P2 #5: use the actual adapter's default model
|
|
280
|
+
// for the preflight estimate so a cheap Gemini Worker isn't blocked
|
|
281
|
+
// by an OpenAI cost estimate.
|
|
251
282
|
budget.preflightCheck({
|
|
252
|
-
model:
|
|
283
|
+
model: workerAdapter.defaultModel,
|
|
253
284
|
estimatedTokensIn: Math.ceil(
|
|
254
285
|
(workerSystem.length + workerUser.length) / 4,
|
|
255
286
|
),
|
|
@@ -299,14 +330,14 @@ export async function runWorkerReviewerReview(
|
|
|
299
330
|
const reviewerUser = buildReviewerOfWorkerUserMessage({
|
|
300
331
|
topic: opts.topic,
|
|
301
332
|
diff: redaction.text,
|
|
302
|
-
files:
|
|
333
|
+
files: filtered.filesIncluded,
|
|
303
334
|
workerOutput: workerOut.content,
|
|
304
335
|
workerAgent: workerName,
|
|
305
336
|
workerProvider: workerAdapter.provider,
|
|
306
337
|
});
|
|
307
338
|
|
|
308
339
|
budget.preflightCheck({
|
|
309
|
-
model:
|
|
340
|
+
model: reviewerAdapter.defaultModel,
|
|
310
341
|
estimatedTokensIn: Math.ceil(
|
|
311
342
|
(reviewerSystem.length + reviewerUser.length) / 4,
|
|
312
343
|
),
|
|
@@ -454,7 +485,7 @@ export async function runWorkerReviewerReview(
|
|
|
454
485
|
},
|
|
455
486
|
metrics,
|
|
456
487
|
totals,
|
|
457
|
-
filesReviewed:
|
|
488
|
+
filesReviewed: filtered.filesIncluded,
|
|
458
489
|
redactionsTotal: redaction.totalCount,
|
|
459
490
|
memoryMissing: [
|
|
460
491
|
...new Set([...workerMemory.missing, ...reviewerMemory.missing]),
|
package/src/review/write.ts
CHANGED
|
@@ -86,6 +86,48 @@ export async function writeHumanReviewFile(
|
|
|
86
86
|
return { path: relPath, bytes: content.length };
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Compute the review file path for a topic without writing anything. Used
|
|
91
|
+
* by the review pipelines to **preflight** collisions *before* any paid
|
|
92
|
+
* adapter call. Same sanitization rules as writeHumanReviewFile.
|
|
93
|
+
*/
|
|
94
|
+
export function reviewFilePathFor(
|
|
95
|
+
reviewsDir: string,
|
|
96
|
+
topic: string,
|
|
97
|
+
): string {
|
|
98
|
+
return join(reviewsDir, `${sanitizeTopic(topic)}.md`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Preflight check: throws ReviewFileExistsError if the topic's review file
|
|
103
|
+
* already exists and `force` isn't set. Surfaces the error BEFORE any
|
|
104
|
+
* adapter is invoked so the user doesn't spend API money discovering an
|
|
105
|
+
* easily-avoidable collision.
|
|
106
|
+
*
|
|
107
|
+
* Returns the (relative) path so the caller doesn't have to recompute it.
|
|
108
|
+
*/
|
|
109
|
+
export async function preflightReviewFileCollision(
|
|
110
|
+
repoRoot: string,
|
|
111
|
+
reviewsDir: string,
|
|
112
|
+
topic: string,
|
|
113
|
+
force = false,
|
|
114
|
+
): Promise<string> {
|
|
115
|
+
const relPath = reviewFilePathFor(reviewsDir, topic);
|
|
116
|
+
const absPath = join(repoRoot, relPath);
|
|
117
|
+
if (existsSync(absPath) && !force) {
|
|
118
|
+
// Also run the git-status check to give a richer dirty-file message
|
|
119
|
+
// when applicable; falls through to the existence error below.
|
|
120
|
+
await assertSafeToWrite(repoRoot, relPath, false);
|
|
121
|
+
throw new ReviewFileExistsError(
|
|
122
|
+
`Refusing to overwrite ${relPath}. Pass --force to overwrite (the ` +
|
|
123
|
+
`previous version remains in git history). Alternatively pick a ` +
|
|
124
|
+
`different --topic to keep both reviews.`,
|
|
125
|
+
relPath,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
return relPath;
|
|
129
|
+
}
|
|
130
|
+
|
|
89
131
|
function sanitizeTopic(topic: string): string {
|
|
90
132
|
// Allow letters, digits, dot, dash, underscore. Replace everything else
|
|
91
133
|
// with a single dash. Trim leading/trailing dashes. Lowercase.
|