@humanbased/crosscheck 0.14.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/AGENT.md +207 -0
- package/ISSUE.md +234 -0
- package/LICENSE +21 -0
- package/README.md +234 -0
- package/README.zh.md +169 -0
- package/assets/logo.png +0 -0
- package/assets/screenshot-watch-timing.png +0 -0
- package/assets/screenshot-watch-timing.svg +1 -0
- package/assets/screenshot-watch.png +0 -0
- package/crosscheck.config.example.yml +214 -0
- package/dist/__tests__/annotation.test.d.ts +2 -0
- package/dist/__tests__/annotation.test.d.ts.map +1 -0
- package/dist/__tests__/annotation.test.js +134 -0
- package/dist/__tests__/annotation.test.js.map +1 -0
- package/dist/__tests__/backtrace.test.d.ts +2 -0
- package/dist/__tests__/backtrace.test.d.ts.map +1 -0
- package/dist/__tests__/backtrace.test.js +280 -0
- package/dist/__tests__/backtrace.test.js.map +1 -0
- package/dist/__tests__/board.test.d.ts +2 -0
- package/dist/__tests__/board.test.d.ts.map +1 -0
- package/dist/__tests__/board.test.js +149 -0
- package/dist/__tests__/board.test.js.map +1 -0
- package/dist/__tests__/codex.test.d.ts +2 -0
- package/dist/__tests__/codex.test.d.ts.map +1 -0
- package/dist/__tests__/codex.test.js +92 -0
- package/dist/__tests__/codex.test.js.map +1 -0
- package/dist/__tests__/comment-bodies.test.d.ts +2 -0
- package/dist/__tests__/comment-bodies.test.d.ts.map +1 -0
- package/dist/__tests__/comment-bodies.test.js +75 -0
- package/dist/__tests__/comment-bodies.test.js.map +1 -0
- package/dist/__tests__/conflict-resolve.test.d.ts +2 -0
- package/dist/__tests__/conflict-resolve.test.d.ts.map +1 -0
- package/dist/__tests__/conflict-resolve.test.js +123 -0
- package/dist/__tests__/conflict-resolve.test.js.map +1 -0
- package/dist/__tests__/crosscheck-commit.test.d.ts +2 -0
- package/dist/__tests__/crosscheck-commit.test.d.ts.map +1 -0
- package/dist/__tests__/crosscheck-commit.test.js +13 -0
- package/dist/__tests__/crosscheck-commit.test.js.map +1 -0
- package/dist/__tests__/detector.test.d.ts +2 -0
- package/dist/__tests__/detector.test.d.ts.map +1 -0
- package/dist/__tests__/detector.test.js +112 -0
- package/dist/__tests__/detector.test.js.map +1 -0
- package/dist/__tests__/diagnose.test.d.ts +2 -0
- package/dist/__tests__/diagnose.test.d.ts.map +1 -0
- package/dist/__tests__/diagnose.test.js +164 -0
- package/dist/__tests__/diagnose.test.js.map +1 -0
- package/dist/__tests__/diff-hash.test.d.ts +2 -0
- package/dist/__tests__/diff-hash.test.d.ts.map +1 -0
- package/dist/__tests__/diff-hash.test.js +126 -0
- package/dist/__tests__/diff-hash.test.js.map +1 -0
- package/dist/__tests__/durations.test.d.ts +2 -0
- package/dist/__tests__/durations.test.d.ts.map +1 -0
- package/dist/__tests__/durations.test.js +26 -0
- package/dist/__tests__/durations.test.js.map +1 -0
- package/dist/__tests__/event-fields.test.d.ts +2 -0
- package/dist/__tests__/event-fields.test.d.ts.map +1 -0
- package/dist/__tests__/event-fields.test.js +50 -0
- package/dist/__tests__/event-fields.test.js.map +1 -0
- package/dist/__tests__/filter.test.d.ts +2 -0
- package/dist/__tests__/filter.test.d.ts.map +1 -0
- package/dist/__tests__/filter.test.js +21 -0
- package/dist/__tests__/filter.test.js.map +1 -0
- package/dist/__tests__/fix.test.d.ts +2 -0
- package/dist/__tests__/fix.test.d.ts.map +1 -0
- package/dist/__tests__/fix.test.js +124 -0
- package/dist/__tests__/fix.test.js.map +1 -0
- package/dist/__tests__/github-client.test.d.ts +2 -0
- package/dist/__tests__/github-client.test.d.ts.map +1 -0
- package/dist/__tests__/github-client.test.js +22 -0
- package/dist/__tests__/github-client.test.js.map +1 -0
- package/dist/__tests__/github-scan-client.test.d.ts +2 -0
- package/dist/__tests__/github-scan-client.test.d.ts.map +1 -0
- package/dist/__tests__/github-scan-client.test.js +100 -0
- package/dist/__tests__/github-scan-client.test.js.map +1 -0
- package/dist/__tests__/is-fresh-review-comment.test.d.ts +2 -0
- package/dist/__tests__/is-fresh-review-comment.test.d.ts.map +1 -0
- package/dist/__tests__/is-fresh-review-comment.test.js +86 -0
- package/dist/__tests__/is-fresh-review-comment.test.js.map +1 -0
- package/dist/__tests__/issue.test.d.ts +2 -0
- package/dist/__tests__/issue.test.d.ts.map +1 -0
- package/dist/__tests__/issue.test.js +259 -0
- package/dist/__tests__/issue.test.js.map +1 -0
- package/dist/__tests__/kickass.test.d.ts +2 -0
- package/dist/__tests__/kickass.test.d.ts.map +1 -0
- package/dist/__tests__/kickass.test.js +268 -0
- package/dist/__tests__/kickass.test.js.map +1 -0
- package/dist/__tests__/loader.test.d.ts +2 -0
- package/dist/__tests__/loader.test.d.ts.map +1 -0
- package/dist/__tests__/loader.test.js +180 -0
- package/dist/__tests__/loader.test.js.map +1 -0
- package/dist/__tests__/onboard-preservation.test.d.ts +2 -0
- package/dist/__tests__/onboard-preservation.test.d.ts.map +1 -0
- package/dist/__tests__/onboard-preservation.test.js +506 -0
- package/dist/__tests__/onboard-preservation.test.js.map +1 -0
- package/dist/__tests__/optimize.test.d.ts +2 -0
- package/dist/__tests__/optimize.test.d.ts.map +1 -0
- package/dist/__tests__/optimize.test.js +101 -0
- package/dist/__tests__/optimize.test.js.map +1 -0
- package/dist/__tests__/post-review-comment.test.d.ts +2 -0
- package/dist/__tests__/post-review-comment.test.d.ts.map +1 -0
- package/dist/__tests__/post-review-comment.test.js +44 -0
- package/dist/__tests__/post-review-comment.test.js.map +1 -0
- package/dist/__tests__/pr-lock.test.d.ts +2 -0
- package/dist/__tests__/pr-lock.test.d.ts.map +1 -0
- package/dist/__tests__/pr-lock.test.js +115 -0
- package/dist/__tests__/pr-lock.test.js.map +1 -0
- package/dist/__tests__/pr-picker.test.d.ts +2 -0
- package/dist/__tests__/pr-picker.test.d.ts.map +1 -0
- package/dist/__tests__/pr-picker.test.js +57 -0
- package/dist/__tests__/pr-picker.test.js.map +1 -0
- package/dist/__tests__/pr-status-scan.test.d.ts +2 -0
- package/dist/__tests__/pr-status-scan.test.d.ts.map +1 -0
- package/dist/__tests__/pr-status-scan.test.js +92 -0
- package/dist/__tests__/pr-status-scan.test.js.map +1 -0
- package/dist/__tests__/pr-status.test.d.ts +2 -0
- package/dist/__tests__/pr-status.test.d.ts.map +1 -0
- package/dist/__tests__/pr-status.test.js +346 -0
- package/dist/__tests__/pr-status.test.js.map +1 -0
- package/dist/__tests__/repo-picker.test.d.ts +2 -0
- package/dist/__tests__/repo-picker.test.d.ts.map +1 -0
- package/dist/__tests__/repo-picker.test.js +115 -0
- package/dist/__tests__/repo-picker.test.js.map +1 -0
- package/dist/__tests__/review-comment-body.test.d.ts +2 -0
- package/dist/__tests__/review-comment-body.test.d.ts.map +1 -0
- package/dist/__tests__/review-comment-body.test.js +54 -0
- package/dist/__tests__/review-comment-body.test.js.map +1 -0
- package/dist/__tests__/review-models.test.d.ts +2 -0
- package/dist/__tests__/review-models.test.d.ts.map +1 -0
- package/dist/__tests__/review-models.test.js +39 -0
- package/dist/__tests__/review-models.test.js.map +1 -0
- package/dist/__tests__/review-status.test.d.ts +2 -0
- package/dist/__tests__/review-status.test.d.ts.map +1 -0
- package/dist/__tests__/review-status.test.js +95 -0
- package/dist/__tests__/review-status.test.js.map +1 -0
- package/dist/__tests__/runner.test.d.ts +2 -0
- package/dist/__tests__/runner.test.d.ts.map +1 -0
- package/dist/__tests__/runner.test.js +204 -0
- package/dist/__tests__/runner.test.js.map +1 -0
- package/dist/__tests__/scan-cache.test.d.ts +2 -0
- package/dist/__tests__/scan-cache.test.d.ts.map +1 -0
- package/dist/__tests__/scan-cache.test.js +59 -0
- package/dist/__tests__/scan-cache.test.js.map +1 -0
- package/dist/__tests__/scan-client.test.d.ts +2 -0
- package/dist/__tests__/scan-client.test.d.ts.map +1 -0
- package/dist/__tests__/scan-client.test.js +30 -0
- package/dist/__tests__/scan-client.test.js.map +1 -0
- package/dist/__tests__/scan.test.d.ts +2 -0
- package/dist/__tests__/scan.test.d.ts.map +1 -0
- package/dist/__tests__/scan.test.js +115 -0
- package/dist/__tests__/scan.test.js.map +1 -0
- package/dist/__tests__/scopes.test.d.ts +2 -0
- package/dist/__tests__/scopes.test.d.ts.map +1 -0
- package/dist/__tests__/scopes.test.js +101 -0
- package/dist/__tests__/scopes.test.js.map +1 -0
- package/dist/__tests__/sha-cache.test.d.ts +2 -0
- package/dist/__tests__/sha-cache.test.d.ts.map +1 -0
- package/dist/__tests__/sha-cache.test.js +40 -0
- package/dist/__tests__/sha-cache.test.js.map +1 -0
- package/dist/__tests__/smart-switch.test.d.ts +2 -0
- package/dist/__tests__/smart-switch.test.d.ts.map +1 -0
- package/dist/__tests__/smart-switch.test.js +145 -0
- package/dist/__tests__/smart-switch.test.js.map +1 -0
- package/dist/ck.d.ts +3 -0
- package/dist/ck.d.ts.map +1 -0
- package/dist/ck.js +8 -0
- package/dist/ck.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +132 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/diagnose.d.ts +54 -0
- package/dist/commands/diagnose.d.ts.map +1 -0
- package/dist/commands/diagnose.js +294 -0
- package/dist/commands/diagnose.js.map +1 -0
- package/dist/commands/impact.d.ts +38 -0
- package/dist/commands/impact.d.ts.map +1 -0
- package/dist/commands/impact.js +210 -0
- package/dist/commands/impact.js.map +1 -0
- package/dist/commands/init.d.ts +12 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +183 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/issue.d.ts +25 -0
- package/dist/commands/issue.d.ts.map +1 -0
- package/dist/commands/issue.js +445 -0
- package/dist/commands/issue.js.map +1 -0
- package/dist/commands/kickass.d.ts +59 -0
- package/dist/commands/kickass.d.ts.map +1 -0
- package/dist/commands/kickass.js +288 -0
- package/dist/commands/kickass.js.map +1 -0
- package/dist/commands/onboard.d.ts +70 -0
- package/dist/commands/onboard.d.ts.map +1 -0
- package/dist/commands/onboard.js +883 -0
- package/dist/commands/onboard.js.map +1 -0
- package/dist/commands/optimize.d.ts +16 -0
- package/dist/commands/optimize.d.ts.map +1 -0
- package/dist/commands/optimize.js +244 -0
- package/dist/commands/optimize.js.map +1 -0
- package/dist/commands/review.d.ts +2 -0
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/commands/review.js +118 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/run.d.ts +13 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +243 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/scan.d.ts +94 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +276 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/serve.d.ts +9 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +402 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +89 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/watch.d.ts +9 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +902 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/config/loader.d.ts +47 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +334 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +814 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +152 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/github/client.d.ts +139 -0
- package/dist/github/client.d.ts.map +1 -0
- package/dist/github/client.js +711 -0
- package/dist/github/client.js.map +1 -0
- package/dist/github/detector.d.ts +12 -0
- package/dist/github/detector.d.ts.map +1 -0
- package/dist/github/detector.js +120 -0
- package/dist/github/detector.js.map +1 -0
- package/dist/github/merge.d.ts +9 -0
- package/dist/github/merge.d.ts.map +1 -0
- package/dist/github/merge.js +33 -0
- package/dist/github/merge.js.map +1 -0
- package/dist/github/review-status.d.ts +6 -0
- package/dist/github/review-status.d.ts.map +1 -0
- package/dist/github/review-status.js +51 -0
- package/dist/github/review-status.js.map +1 -0
- package/dist/github/webhook.d.ts +41 -0
- package/dist/github/webhook.d.ts.map +1 -0
- package/dist/github/webhook.js +50 -0
- package/dist/github/webhook.js.map +1 -0
- package/dist/lib/annotation.d.ts +23 -0
- package/dist/lib/annotation.d.ts.map +1 -0
- package/dist/lib/annotation.js +103 -0
- package/dist/lib/annotation.js.map +1 -0
- package/dist/lib/backtrace.d.ts +40 -0
- package/dist/lib/backtrace.d.ts.map +1 -0
- package/dist/lib/backtrace.js +169 -0
- package/dist/lib/backtrace.js.map +1 -0
- package/dist/lib/board.d.ts +74 -0
- package/dist/lib/board.d.ts.map +1 -0
- package/dist/lib/board.js +640 -0
- package/dist/lib/board.js.map +1 -0
- package/dist/lib/clone.d.ts +12 -0
- package/dist/lib/clone.d.ts.map +1 -0
- package/dist/lib/clone.js +30 -0
- package/dist/lib/clone.js.map +1 -0
- package/dist/lib/comment-bodies.d.ts +17 -0
- package/dist/lib/comment-bodies.d.ts.map +1 -0
- package/dist/lib/comment-bodies.js +51 -0
- package/dist/lib/comment-bodies.js.map +1 -0
- package/dist/lib/crosscheck-commit.d.ts +2 -0
- package/dist/lib/crosscheck-commit.d.ts.map +1 -0
- package/dist/lib/crosscheck-commit.js +4 -0
- package/dist/lib/crosscheck-commit.js.map +1 -0
- package/dist/lib/diff-hash.d.ts +16 -0
- package/dist/lib/diff-hash.d.ts.map +1 -0
- package/dist/lib/diff-hash.js +71 -0
- package/dist/lib/diff-hash.js.map +1 -0
- package/dist/lib/durations.d.ts +5 -0
- package/dist/lib/durations.d.ts.map +1 -0
- package/dist/lib/durations.js +39 -0
- package/dist/lib/durations.js.map +1 -0
- package/dist/lib/event-fields.d.ts +6 -0
- package/dist/lib/event-fields.d.ts.map +1 -0
- package/dist/lib/event-fields.js +20 -0
- package/dist/lib/event-fields.js.map +1 -0
- package/dist/lib/filter.d.ts +2 -0
- package/dist/lib/filter.d.ts.map +1 -0
- package/dist/lib/filter.js +4 -0
- package/dist/lib/filter.js.map +1 -0
- package/dist/lib/fortune.d.ts +2 -0
- package/dist/lib/fortune.d.ts.map +1 -0
- package/dist/lib/fortune.js +26 -0
- package/dist/lib/fortune.js.map +1 -0
- package/dist/lib/languages.d.ts +3 -0
- package/dist/lib/languages.d.ts.map +1 -0
- package/dist/lib/languages.js +26 -0
- package/dist/lib/languages.js.map +1 -0
- package/dist/lib/log-analysis.d.ts +17 -0
- package/dist/lib/log-analysis.d.ts.map +1 -0
- package/dist/lib/log-analysis.js +72 -0
- package/dist/lib/log-analysis.js.map +1 -0
- package/dist/lib/logger.d.ts +14 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +84 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/port.d.ts +2 -0
- package/dist/lib/port.d.ts.map +1 -0
- package/dist/lib/port.js +21 -0
- package/dist/lib/port.js.map +1 -0
- package/dist/lib/pr-lock.d.ts +4 -0
- package/dist/lib/pr-lock.d.ts.map +1 -0
- package/dist/lib/pr-lock.js +91 -0
- package/dist/lib/pr-lock.js.map +1 -0
- package/dist/lib/pr-picker.d.ts +10 -0
- package/dist/lib/pr-picker.d.ts.map +1 -0
- package/dist/lib/pr-picker.js +80 -0
- package/dist/lib/pr-picker.js.map +1 -0
- package/dist/lib/pr-status.d.ts +206 -0
- package/dist/lib/pr-status.d.ts.map +1 -0
- package/dist/lib/pr-status.js +613 -0
- package/dist/lib/pr-status.js.map +1 -0
- package/dist/lib/repo-picker.d.ts +23 -0
- package/dist/lib/repo-picker.d.ts.map +1 -0
- package/dist/lib/repo-picker.js +411 -0
- package/dist/lib/repo-picker.js.map +1 -0
- package/dist/lib/review-models.d.ts +7 -0
- package/dist/lib/review-models.d.ts.map +1 -0
- package/dist/lib/review-models.js +32 -0
- package/dist/lib/review-models.js.map +1 -0
- package/dist/lib/runner.d.ts +65 -0
- package/dist/lib/runner.d.ts.map +1 -0
- package/dist/lib/runner.js +710 -0
- package/dist/lib/runner.js.map +1 -0
- package/dist/lib/scan-cache.d.ts +31 -0
- package/dist/lib/scan-cache.d.ts.map +1 -0
- package/dist/lib/scan-cache.js +112 -0
- package/dist/lib/scan-cache.js.map +1 -0
- package/dist/lib/scopes.d.ts +16 -0
- package/dist/lib/scopes.d.ts.map +1 -0
- package/dist/lib/scopes.js +37 -0
- package/dist/lib/scopes.js.map +1 -0
- package/dist/lib/sha-cache.d.ts +7 -0
- package/dist/lib/sha-cache.d.ts.map +1 -0
- package/dist/lib/sha-cache.js +44 -0
- package/dist/lib/sha-cache.js.map +1 -0
- package/dist/lib/smart-switch.d.ts +44 -0
- package/dist/lib/smart-switch.d.ts.map +1 -0
- package/dist/lib/smart-switch.js +145 -0
- package/dist/lib/smart-switch.js.map +1 -0
- package/dist/lib/verdict.d.ts +9 -0
- package/dist/lib/verdict.d.ts.map +1 -0
- package/dist/lib/verdict.js +52 -0
- package/dist/lib/verdict.js.map +1 -0
- package/dist/lib/workflow.d.ts +85 -0
- package/dist/lib/workflow.d.ts.map +1 -0
- package/dist/lib/workflow.js +116 -0
- package/dist/lib/workflow.js.map +1 -0
- package/dist/reviewers/address.d.ts +5 -0
- package/dist/reviewers/address.d.ts.map +1 -0
- package/dist/reviewers/address.js +87 -0
- package/dist/reviewers/address.js.map +1 -0
- package/dist/reviewers/claude.d.ts +12 -0
- package/dist/reviewers/claude.d.ts.map +1 -0
- package/dist/reviewers/claude.js +78 -0
- package/dist/reviewers/claude.js.map +1 -0
- package/dist/reviewers/codex.d.ts +9 -0
- package/dist/reviewers/codex.d.ts.map +1 -0
- package/dist/reviewers/codex.js +121 -0
- package/dist/reviewers/codex.js.map +1 -0
- package/dist/reviewers/conflict-resolve.d.ts +15 -0
- package/dist/reviewers/conflict-resolve.d.ts.map +1 -0
- package/dist/reviewers/conflict-resolve.js +219 -0
- package/dist/reviewers/conflict-resolve.js.map +1 -0
- package/dist/reviewers/fix.d.ts +7 -0
- package/dist/reviewers/fix.d.ts.map +1 -0
- package/dist/reviewers/fix.js +197 -0
- package/dist/reviewers/fix.js.map +1 -0
- package/get-started.md +1271 -0
- package/get-started.zh.md +1208 -0
- package/package.json +75 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { execSync } from 'child_process';
|
|
3
|
+
import { mkdtempSync, rmSync, writeFileSync, readFileSync, existsSync } from 'fs';
|
|
4
|
+
import { tmpdir } from 'os';
|
|
5
|
+
import { join } from 'path';
|
|
6
|
+
import { computeDiffHash, PersistentDiffHashMap } from '../lib/diff-hash.js';
|
|
7
|
+
function git(args, cwd) {
|
|
8
|
+
return execSync(`git ${args}`, { cwd, stdio: ['ignore', 'pipe', 'pipe'], encoding: 'utf8' });
|
|
9
|
+
}
|
|
10
|
+
function setupRepo() {
|
|
11
|
+
const dir = mkdtempSync(join(tmpdir(), 'crosscheck-diff-test-'));
|
|
12
|
+
git('init --quiet -b main', dir);
|
|
13
|
+
git('config user.email test@test.local', dir);
|
|
14
|
+
git('config user.name Test', dir);
|
|
15
|
+
writeFileSync(join(dir, 'file.txt'), 'base content\n');
|
|
16
|
+
git('add .', dir);
|
|
17
|
+
git('commit --quiet -m base', dir);
|
|
18
|
+
// Create the "origin/main" remote-tracking ref that computeDiffHash expects
|
|
19
|
+
git('update-ref refs/remotes/origin/main HEAD', dir);
|
|
20
|
+
return { dir, baseRef: 'main' };
|
|
21
|
+
}
|
|
22
|
+
describe('computeDiffHash', () => {
|
|
23
|
+
let dir;
|
|
24
|
+
let baseRef;
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
;
|
|
27
|
+
({ dir, baseRef } = setupRepo());
|
|
28
|
+
});
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
rmSync(dir, { recursive: true, force: true });
|
|
31
|
+
});
|
|
32
|
+
it('returns a stable hex digest for a given patch', () => {
|
|
33
|
+
writeFileSync(join(dir, 'file.txt'), 'modified content\n');
|
|
34
|
+
git('commit --quiet -am edit', dir);
|
|
35
|
+
const h1 = computeDiffHash(dir, baseRef);
|
|
36
|
+
const h2 = computeDiffHash(dir, baseRef);
|
|
37
|
+
expect(h1).toBe(h2);
|
|
38
|
+
expect(h1).toMatch(/^[0-9a-f]{64}$/);
|
|
39
|
+
});
|
|
40
|
+
it('returns identical hash when an amend produces the same patch under a new SHA', () => {
|
|
41
|
+
writeFileSync(join(dir, 'file.txt'), 'modified content\n');
|
|
42
|
+
git('commit --quiet -am edit', dir);
|
|
43
|
+
const shaBefore = git('rev-parse HEAD', dir).trim();
|
|
44
|
+
const hashBefore = computeDiffHash(dir, baseRef);
|
|
45
|
+
// Amend the commit message only — same tree, new SHA
|
|
46
|
+
git('commit --quiet --amend -m "edit (reworded)"', dir);
|
|
47
|
+
const shaAfter = git('rev-parse HEAD', dir).trim();
|
|
48
|
+
const hashAfter = computeDiffHash(dir, baseRef);
|
|
49
|
+
expect(shaAfter).not.toBe(shaBefore);
|
|
50
|
+
expect(hashAfter).toBe(hashBefore);
|
|
51
|
+
});
|
|
52
|
+
it('returns different hash when the diff content changes', () => {
|
|
53
|
+
writeFileSync(join(dir, 'file.txt'), 'first change\n');
|
|
54
|
+
git('commit --quiet -am one', dir);
|
|
55
|
+
const h1 = computeDiffHash(dir, baseRef);
|
|
56
|
+
writeFileSync(join(dir, 'file.txt'), 'second change\n');
|
|
57
|
+
git('commit --quiet -am two', dir);
|
|
58
|
+
const h2 = computeDiffHash(dir, baseRef);
|
|
59
|
+
expect(h1).not.toBe(h2);
|
|
60
|
+
});
|
|
61
|
+
it('returns the empty-diff hash when HEAD equals base', () => {
|
|
62
|
+
const h = computeDiffHash(dir, baseRef);
|
|
63
|
+
expect(h).toMatch(/^[0-9a-f]{64}$/);
|
|
64
|
+
// Hash of empty string sha256 — stable sentinel
|
|
65
|
+
expect(h).toBe('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855');
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
describe('PersistentDiffHashMap', () => {
|
|
69
|
+
let cacheFile;
|
|
70
|
+
beforeEach(() => {
|
|
71
|
+
cacheFile = join(mkdtempSync(join(tmpdir(), 'crosscheck-dhm-')), 'diff-hashes.json');
|
|
72
|
+
});
|
|
73
|
+
afterEach(() => {
|
|
74
|
+
if (existsSync(cacheFile))
|
|
75
|
+
rmSync(cacheFile);
|
|
76
|
+
});
|
|
77
|
+
it('upserts and reads back an entry', () => {
|
|
78
|
+
const m = new PersistentDiffHashMap(cacheFile);
|
|
79
|
+
m.upsert('owner/repo#1', { sha: 'abc123', hash: 'h1' });
|
|
80
|
+
expect(m.get('owner/repo#1')).toEqual({ sha: 'abc123', hash: 'h1' });
|
|
81
|
+
});
|
|
82
|
+
it('overwrites an existing entry for the same key', () => {
|
|
83
|
+
const m = new PersistentDiffHashMap(cacheFile);
|
|
84
|
+
m.upsert('owner/repo#1', { sha: 'abc', hash: 'h1' });
|
|
85
|
+
m.upsert('owner/repo#1', { sha: 'def', hash: 'h2' });
|
|
86
|
+
expect(m.get('owner/repo#1')).toEqual({ sha: 'def', hash: 'h2' });
|
|
87
|
+
});
|
|
88
|
+
it('persists across instances backed by the same file', () => {
|
|
89
|
+
const a = new PersistentDiffHashMap(cacheFile);
|
|
90
|
+
a.upsert('owner/repo#42', { sha: 'aaa', hash: 'hash-x' });
|
|
91
|
+
const b = new PersistentDiffHashMap(cacheFile);
|
|
92
|
+
expect(b.get('owner/repo#42')).toEqual({ sha: 'aaa', hash: 'hash-x' });
|
|
93
|
+
});
|
|
94
|
+
it('returns undefined for missing keys', () => {
|
|
95
|
+
const m = new PersistentDiffHashMap(cacheFile);
|
|
96
|
+
expect(m.get('nope')).toBeUndefined();
|
|
97
|
+
});
|
|
98
|
+
it('evicts oldest entries when exceeding the cap (FIFO)', () => {
|
|
99
|
+
const m = new PersistentDiffHashMap(cacheFile, /*maxEntries*/ 3);
|
|
100
|
+
m.upsert('a', { sha: '1', hash: 'h1' });
|
|
101
|
+
m.upsert('b', { sha: '2', hash: 'h2' });
|
|
102
|
+
m.upsert('c', { sha: '3', hash: 'h3' });
|
|
103
|
+
m.upsert('d', { sha: '4', hash: 'h4' }); // evicts 'a'
|
|
104
|
+
expect(m.get('a')).toBeUndefined();
|
|
105
|
+
expect(m.get('b')).toEqual({ sha: '2', hash: 'h2' });
|
|
106
|
+
expect(m.get('d')).toEqual({ sha: '4', hash: 'h4' });
|
|
107
|
+
});
|
|
108
|
+
it('upsert that overwrites does not count toward the cap', () => {
|
|
109
|
+
const m = new PersistentDiffHashMap(cacheFile, 2);
|
|
110
|
+
m.upsert('a', { sha: '1', hash: 'h1' });
|
|
111
|
+
m.upsert('b', { sha: '2', hash: 'h2' });
|
|
112
|
+
m.upsert('a', { sha: '1b', hash: 'h1b' }); // overwrite, not insert
|
|
113
|
+
expect(m.get('a')).toEqual({ sha: '1b', hash: 'h1b' });
|
|
114
|
+
expect(m.get('b')).toEqual({ sha: '2', hash: 'h2' });
|
|
115
|
+
});
|
|
116
|
+
it('tolerates a missing or malformed cache file', () => {
|
|
117
|
+
writeFileSync(cacheFile, 'not json');
|
|
118
|
+
const m = new PersistentDiffHashMap(cacheFile);
|
|
119
|
+
expect(m.get('any')).toBeUndefined();
|
|
120
|
+
m.upsert('x', { sha: '9', hash: 'h9' });
|
|
121
|
+
// Should have rewritten the file to valid JSON
|
|
122
|
+
const parsed = JSON.parse(readFileSync(cacheFile, 'utf8'));
|
|
123
|
+
expect(parsed['x']).toEqual({ sha: '9', hash: 'h9' });
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
//# sourceMappingURL=diff-hash.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-hash.test.js","sourceRoot":"","sources":["../../src/__tests__/diff-hash.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"durations.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/durations.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { formatDuration, parseDuration } from '../lib/durations.js';
|
|
3
|
+
describe('parseDuration', () => {
|
|
4
|
+
it('parses minutes, hours, and days', () => {
|
|
5
|
+
expect(parseDuration('30m')).toBe(30 * 60 * 1000);
|
|
6
|
+
expect(parseDuration('2h')).toBe(2 * 60 * 60 * 1000);
|
|
7
|
+
expect(parseDuration('1d')).toBe(24 * 60 * 60 * 1000);
|
|
8
|
+
});
|
|
9
|
+
it('accepts surrounding whitespace', () => {
|
|
10
|
+
expect(parseDuration(' 4h ')).toBe(4 * 60 * 60 * 1000);
|
|
11
|
+
});
|
|
12
|
+
it('rejects invalid durations', () => {
|
|
13
|
+
expect(() => parseDuration('')).toThrow('Invalid duration');
|
|
14
|
+
expect(() => parseDuration('10')).toThrow('Invalid duration');
|
|
15
|
+
expect(() => parseDuration('1w')).toThrow('Invalid duration');
|
|
16
|
+
expect(() => parseDuration('0m')).toThrow('Invalid duration');
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
describe('formatDuration', () => {
|
|
20
|
+
it('formats common whole units', () => {
|
|
21
|
+
expect(formatDuration(30 * 60 * 1000)).toBe('30m');
|
|
22
|
+
expect(formatDuration(2 * 60 * 60 * 1000)).toBe('2h');
|
|
23
|
+
expect(formatDuration(24 * 60 * 60 * 1000)).toBe('1d');
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=durations.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"durations.test.js","sourceRoot":"","sources":["../../src/__tests__/durations.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEnE,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;QACjD,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;QACpD,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;IACvD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;IAC1D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;QAC3D,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;QAC7D,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;QAC7D,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;IAC/D,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAClD,MAAM,CAAC,cAAc,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACrD,MAAM,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACxD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-fields.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/event-fields.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { buildStepIdentityFields } from '../lib/event-fields.js';
|
|
3
|
+
describe('buildStepIdentityFields', () => {
|
|
4
|
+
// Effective type 'review' means this call is actually a fresh review,
|
|
5
|
+
// regardless of what the workflow step is named. The default workflow
|
|
6
|
+
// calls the initial step "review" but a user could rename it.
|
|
7
|
+
it('returns step_type=review when effectiveType is review', () => {
|
|
8
|
+
expect(buildStepIdentityFields('review', 'review')).toEqual({
|
|
9
|
+
step_type: 'review',
|
|
10
|
+
step_name: 'review',
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
it('preserves a custom step_name unchanged', () => {
|
|
14
|
+
expect(buildStepIdentityFields('review', 'initial-codex-pass')).toEqual({
|
|
15
|
+
step_type: 'review',
|
|
16
|
+
step_name: 'initial-codex-pass',
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
// Effective type 'recheck' is the case the field exists to disambiguate:
|
|
20
|
+
// today this is logged identically to a fresh review.
|
|
21
|
+
it('returns step_type=recheck when effectiveType is recheck', () => {
|
|
22
|
+
expect(buildStepIdentityFields('recheck', 'recheck')).toEqual({
|
|
23
|
+
step_type: 'recheck',
|
|
24
|
+
step_name: 'recheck',
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
// Coerced rechecks: runner.ts's getEffectiveStepType maps the workflow
|
|
28
|
+
// step typed 'review' to effectiveType 'recheck' when ctx.isRecheckRun.
|
|
29
|
+
// The step_name still reflects what's in workflow.yml (so analytics can
|
|
30
|
+
// group by workflow step), but step_type reflects what actually ran.
|
|
31
|
+
it('returns step_type=recheck even when the underlying workflow step is named "review"', () => {
|
|
32
|
+
expect(buildStepIdentityFields('recheck', 'review')).toEqual({
|
|
33
|
+
step_type: 'recheck',
|
|
34
|
+
step_name: 'review',
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
// Defensive: any other effectiveType value (shouldn't happen for the
|
|
38
|
+
// review_complete emit site, but the helper must not produce undefined).
|
|
39
|
+
it('falls back to step_type=review for any non-recheck effectiveType', () => {
|
|
40
|
+
expect(buildStepIdentityFields('fix', 'whatever')).toEqual({
|
|
41
|
+
step_type: 'review',
|
|
42
|
+
step_name: 'whatever',
|
|
43
|
+
});
|
|
44
|
+
expect(buildStepIdentityFields('', 'whatever')).toEqual({
|
|
45
|
+
step_type: 'review',
|
|
46
|
+
step_name: 'whatever',
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
//# sourceMappingURL=event-fields.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-fields.test.js","sourceRoot":"","sources":["../../src/__tests__/event-fields.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAEhE,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,sEAAsE;IACtE,sEAAsE;IACtE,8DAA8D;IAC9D,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,CAAC,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;YAC1D,SAAS,EAAE,QAAQ;YACnB,SAAS,EAAE,QAAQ;SACpB,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,CAAC,uBAAuB,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC,CAAC,OAAO,CAAC;YACtE,SAAS,EAAE,QAAQ;YACnB,SAAS,EAAE,oBAAoB;SAChC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,yEAAyE;IACzE,sDAAsD;IACtD,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,CAAC,uBAAuB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;YAC5D,SAAS,EAAE,SAAS;YACpB,SAAS,EAAE,SAAS;SACrB,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,uEAAuE;IACvE,wEAAwE;IACxE,wEAAwE;IACxE,qEAAqE;IACrE,EAAE,CAAC,oFAAoF,EAAE,GAAG,EAAE;QAC5F,MAAM,CAAC,uBAAuB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;YAC3D,SAAS,EAAE,SAAS;YACpB,SAAS,EAAE,QAAQ;SACpB,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,qEAAqE;IACrE,yEAAyE;IACzE,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,CAAC,uBAAuB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC;YACzD,SAAS,EAAE,QAAQ;YACnB,SAAS,EAAE,UAAU;SACtB,CAAC,CAAA;QACF,MAAM,CAAC,uBAAuB,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC;YACtD,SAAS,EAAE,QAAQ;YACnB,SAAS,EAAE,UAAU;SACtB,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/filter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { isAuthorAllowed } from '../lib/filter.js';
|
|
3
|
+
describe('isAuthorAllowed', () => {
|
|
4
|
+
it('allows any author when list is empty', () => {
|
|
5
|
+
expect(isAuthorAllowed([], 'alice')).toBe(true);
|
|
6
|
+
expect(isAuthorAllowed([], 'anyone')).toBe(true);
|
|
7
|
+
});
|
|
8
|
+
it('allows a listed author', () => {
|
|
9
|
+
expect(isAuthorAllowed(['alice', 'bob'], 'alice')).toBe(true);
|
|
10
|
+
expect(isAuthorAllowed(['alice', 'bob'], 'bob')).toBe(true);
|
|
11
|
+
});
|
|
12
|
+
it('blocks an unlisted author', () => {
|
|
13
|
+
expect(isAuthorAllowed(['alice'], 'bob')).toBe(false);
|
|
14
|
+
expect(isAuthorAllowed(['alice', 'bob'], 'carol')).toBe(false);
|
|
15
|
+
});
|
|
16
|
+
it('is case-sensitive', () => {
|
|
17
|
+
expect(isAuthorAllowed(['Alice'], 'alice')).toBe(false);
|
|
18
|
+
expect(isAuthorAllowed(['alice'], 'Alice')).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=filter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.test.js","sourceRoot":"","sources":["../../src/__tests__/filter.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAElD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,eAAe,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC/C,MAAM,CAAC,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAClD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC7D,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC7D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACrD,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAChE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAC3B,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACvD,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fix.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fix.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { mkdirSync, mkdtempSync, writeFileSync, readFileSync, rmSync } from 'fs';
|
|
3
|
+
import { tmpdir } from 'os';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { applyEdit } from '../reviewers/fix.js';
|
|
6
|
+
describe('applyEdit', () => {
|
|
7
|
+
it('replaces exact match at start of file', () => {
|
|
8
|
+
const content = 'function foo() {\n return 1\n}\n';
|
|
9
|
+
const result = applyEdit(content, 'return 1', 'return 2');
|
|
10
|
+
expect(result).toBe('function foo() {\n return 2\n}\n');
|
|
11
|
+
});
|
|
12
|
+
it('returns null when old text is not found', () => {
|
|
13
|
+
const content = 'function foo() {\n return 1\n}\n';
|
|
14
|
+
expect(applyEdit(content, 'return 99', 'return 2')).toBeNull();
|
|
15
|
+
});
|
|
16
|
+
it('returns null when old text is ambiguous (appears more than once)', () => {
|
|
17
|
+
const content = 'a\na\na\n';
|
|
18
|
+
expect(applyEdit(content, 'a', 'b')).toBeNull();
|
|
19
|
+
});
|
|
20
|
+
it('handles multi-line old text', () => {
|
|
21
|
+
const content = 'line1\nline2\nline3\nline4\n';
|
|
22
|
+
const result = applyEdit(content, 'line2\nline3', 'replaced');
|
|
23
|
+
expect(result).toBe('line1\nreplaced\nline4\n');
|
|
24
|
+
});
|
|
25
|
+
it('can replace with empty string (deletion)', () => {
|
|
26
|
+
const content = 'before\ndelete me\nafter\n';
|
|
27
|
+
const result = applyEdit(content, 'delete me\n', '');
|
|
28
|
+
expect(result).toBe('before\nafter\n');
|
|
29
|
+
});
|
|
30
|
+
it('returns null on empty old text (ambiguous — matches everywhere)', () => {
|
|
31
|
+
// '' satisfies indexOf !== lastIndexOf, so the ambiguity guard rejects it.
|
|
32
|
+
// Callers handle new-file creation separately before invoking applyEdit.
|
|
33
|
+
expect(applyEdit('content', '', 'new')).toBeNull();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe('fix step <edit> block parsing', () => {
|
|
37
|
+
let tmpDir;
|
|
38
|
+
beforeEach(() => {
|
|
39
|
+
tmpDir = mkdtempSync(join(tmpdir(), 'crosscheck-fix-test-'));
|
|
40
|
+
});
|
|
41
|
+
afterEach(() => {
|
|
42
|
+
rmSync(tmpDir, { force: true, recursive: true });
|
|
43
|
+
});
|
|
44
|
+
it('size guard: rejects <file> block when new content < 60% of original', async () => {
|
|
45
|
+
// Write a "large" original file (10 lines)
|
|
46
|
+
const filePath = join(tmpDir, 'src', 'large.ts');
|
|
47
|
+
const { mkdirSync } = await import('fs');
|
|
48
|
+
mkdirSync(join(tmpDir, 'src'), { recursive: true });
|
|
49
|
+
const original = Array.from({ length: 10 }, (_, i) => `line${i + 1}`).join('\n') + '\n';
|
|
50
|
+
writeFileSync(filePath, original);
|
|
51
|
+
// Simulate Claude outputting only 3 lines for a 10-line file (30% — below 60% threshold)
|
|
52
|
+
const truncated = 'line1\nline2\nline3\n';
|
|
53
|
+
// Directly test the guard logic: if newLines / origLines < 0.6, skip
|
|
54
|
+
const origLines = original.split('\n').length;
|
|
55
|
+
const newLines = truncated.split('\n').length;
|
|
56
|
+
expect(newLines / origLines).toBeLessThan(0.6);
|
|
57
|
+
// Confirm original is unchanged (guard would have skipped the write)
|
|
58
|
+
expect(readFileSync(filePath, 'utf8')).toBe(original);
|
|
59
|
+
});
|
|
60
|
+
it('size guard: accepts <file> block when new content >= 60% of original', () => {
|
|
61
|
+
const original = Array.from({ length: 10 }, (_, i) => `line${i + 1}`).join('\n') + '\n';
|
|
62
|
+
const replacement = Array.from({ length: 7 }, (_, i) => `replaced${i + 1}`).join('\n') + '\n';
|
|
63
|
+
const origLines = original.split('\n').length;
|
|
64
|
+
const newLines = replacement.split('\n').length;
|
|
65
|
+
expect(newLines / origLines).toBeGreaterThanOrEqual(0.6);
|
|
66
|
+
});
|
|
67
|
+
it('applyEdit composes correctly for multiple edits to same file', () => {
|
|
68
|
+
const content = 'a: 1\nb: 2\nc: 3\n';
|
|
69
|
+
const after1 = applyEdit(content, 'a: 1', 'a: 10');
|
|
70
|
+
expect(after1).not.toBeNull();
|
|
71
|
+
const after2 = applyEdit(after1, 'b: 2', 'b: 20');
|
|
72
|
+
expect(after2).not.toBeNull();
|
|
73
|
+
expect(after2).toBe('a: 10\nb: 20\nc: 3\n');
|
|
74
|
+
});
|
|
75
|
+
it('failed <old> match does not count as applied or write the unchanged file', () => {
|
|
76
|
+
// Regression for: file added to fileEdits during read step, then applyEdit returns null,
|
|
77
|
+
// but write loop still writes it and increments appliedCount.
|
|
78
|
+
const filePath = join(tmpDir, 'src.ts');
|
|
79
|
+
const original = 'export function foo() {\n return 1\n}\n';
|
|
80
|
+
writeFileSync(filePath, original);
|
|
81
|
+
// applyEdit with a non-matching old text returns null — file must not be touched
|
|
82
|
+
const result = applyEdit(original, 'does not exist in file', 'anything');
|
|
83
|
+
expect(result).toBeNull();
|
|
84
|
+
// File must be untouched on disk
|
|
85
|
+
expect(readFileSync(filePath, 'utf8')).toBe(original);
|
|
86
|
+
});
|
|
87
|
+
it('applyEdit: empty old text returns null (ambiguity guard catches it)', () => {
|
|
88
|
+
// Empty string satisfies indexOf('') !== lastIndexOf(''), so applyEdit rejects it.
|
|
89
|
+
// runFixStep handles new-file creation (empty <old> on missing file) before calling applyEdit.
|
|
90
|
+
expect(applyEdit('existing content', '', 'prepended ')).toBeNull();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
describe('fix step new-file and empty-old guard', () => {
|
|
94
|
+
let tmpDir;
|
|
95
|
+
beforeEach(() => {
|
|
96
|
+
tmpDir = mkdtempSync(join(tmpdir(), 'crosscheck-fix-test-'));
|
|
97
|
+
});
|
|
98
|
+
afterEach(() => {
|
|
99
|
+
rmSync(tmpDir, { force: true, recursive: true });
|
|
100
|
+
});
|
|
101
|
+
it('empty <old> on existing file is rejected — does not prepend new text', () => {
|
|
102
|
+
mkdirSync(join(tmpDir, 'src'), { recursive: true });
|
|
103
|
+
const filePath = join(tmpDir, 'src', 'util.ts');
|
|
104
|
+
const original = 'export const x = 1\n';
|
|
105
|
+
writeFileSync(filePath, original);
|
|
106
|
+
// applyEdit('export const x = 1\n', '', 'prepended\n') would prepend if not guarded.
|
|
107
|
+
// The guard in runFixStep must block this — original must be unchanged.
|
|
108
|
+
// We verify the guard logic directly: empty oldText on existing file => skip.
|
|
109
|
+
const oldText = '';
|
|
110
|
+
const fileExists = true; // file was readable
|
|
111
|
+
const wouldBeGuarded = fileExists && oldText === '';
|
|
112
|
+
expect(wouldBeGuarded).toBe(true);
|
|
113
|
+
expect(readFileSync(filePath, 'utf8')).toBe(original);
|
|
114
|
+
});
|
|
115
|
+
it('empty <old> on non-existent file writes <new> as new file content', () => {
|
|
116
|
+
mkdirSync(join(tmpDir, 'src'), { recursive: true });
|
|
117
|
+
const newFilePath = join(tmpDir, 'src', 'new-module.ts');
|
|
118
|
+
// File does not exist — simulate the new-file path: write newText directly
|
|
119
|
+
const newContent = 'export const added = true\n';
|
|
120
|
+
writeFileSync(newFilePath, newContent); // as runFixStep would do for empty <old>
|
|
121
|
+
expect(readFileSync(newFilePath, 'utf8')).toBe(newContent);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
//# sourceMappingURL=fix.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fix.test.js","sourceRoot":"","sources":["../../src/__tests__/fix.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-client.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/github-client.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { listOpenPRs, listOrgRepos } from '../github/client.js';
|
|
3
|
+
afterEach(() => {
|
|
4
|
+
vi.unstubAllGlobals();
|
|
5
|
+
});
|
|
6
|
+
describe('github client listing failures', () => {
|
|
7
|
+
it('throws when listOpenPRs receives a non-OK response', async () => {
|
|
8
|
+
vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(JSON.stringify({ message: 'server error' }), {
|
|
9
|
+
status: 500,
|
|
10
|
+
statusText: 'Internal Server Error',
|
|
11
|
+
})));
|
|
12
|
+
await expect(listOpenPRs('acme', 'api', 'token')).rejects.toThrow('Failed to list open PRs for acme/api page 1 [500]: server error');
|
|
13
|
+
});
|
|
14
|
+
it('throws when listOrgRepos receives a non-OK response', async () => {
|
|
15
|
+
vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(JSON.stringify({ message: 'rate limited' }), {
|
|
16
|
+
status: 403,
|
|
17
|
+
statusText: 'Forbidden',
|
|
18
|
+
})));
|
|
19
|
+
await expect(listOrgRepos('acme', 'token')).rejects.toThrow('Failed to list org repos [403]: Forbidden');
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
//# sourceMappingURL=github-client.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-client.test.js","sourceRoot":"","sources":["../../src/__tests__/github-client.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC5D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAE/D,SAAS,CAAC,GAAG,EAAE;IACb,EAAE,CAAC,gBAAgB,EAAE,CAAA;AACvB,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAC9C,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,EAAE;YACxD,MAAM,EAAE,GAAG;YACX,UAAU,EAAE,uBAAuB;SACpC,CAAC,CACH,CAAC,CAAA;QAEF,MAAM,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC/D,iEAAiE,CAClE,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAC9C,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,EAAE;YACxD,MAAM,EAAE,GAAG;YACX,UAAU,EAAE,WAAW;SACxB,CAAC,CACH,CAAC,CAAA;QAEF,MAAM,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CACzD,2CAA2C,CAC5C,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-scan-client.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/github-scan-client.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { getLastCrossCheckReviewComment, listCheckRuns, listCommitStatuses, listIssueComments, listOpenPRs, listOrgRepos, listTimelineEvents, listUserRepos } from '../github/client.js';
|
|
3
|
+
afterEach(() => {
|
|
4
|
+
vi.restoreAllMocks();
|
|
5
|
+
});
|
|
6
|
+
function jsonResponse(body, status = 200) {
|
|
7
|
+
return new Response(JSON.stringify(body), {
|
|
8
|
+
status,
|
|
9
|
+
headers: { 'content-type': 'application/json' },
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
describe('scan GitHub client helpers', () => {
|
|
13
|
+
it('paginates check runs for a commit ref', async () => {
|
|
14
|
+
const firstPage = Array.from({ length: 100 }, (_, index) => ({
|
|
15
|
+
name: `check-${index}`,
|
|
16
|
+
status: 'completed',
|
|
17
|
+
conclusion: 'success',
|
|
18
|
+
completed_at: '2026-05-29T00:00:00.000Z',
|
|
19
|
+
started_at: null,
|
|
20
|
+
}));
|
|
21
|
+
const fetchSpy = vi.spyOn(globalThis, 'fetch')
|
|
22
|
+
.mockResolvedValueOnce(jsonResponse({ check_runs: firstPage }))
|
|
23
|
+
.mockResolvedValueOnce(jsonResponse({
|
|
24
|
+
check_runs: [{
|
|
25
|
+
name: 'check-100',
|
|
26
|
+
status: 'completed',
|
|
27
|
+
conclusion: 'success',
|
|
28
|
+
completed_at: '2026-05-29T00:01:00.000Z',
|
|
29
|
+
started_at: null,
|
|
30
|
+
}],
|
|
31
|
+
}));
|
|
32
|
+
const runs = await listCheckRuns('acme', 'web', 'abc123', 'token');
|
|
33
|
+
expect(runs).toHaveLength(101);
|
|
34
|
+
expect(fetchSpy).toHaveBeenCalledTimes(2);
|
|
35
|
+
expect(String(fetchSpy.mock.calls[1][0])).toContain('page=2');
|
|
36
|
+
});
|
|
37
|
+
it('paginates commit statuses for a commit ref', async () => {
|
|
38
|
+
const firstPage = Array.from({ length: 100 }, (_, index) => ({
|
|
39
|
+
context: `ci-${index}`,
|
|
40
|
+
state: 'success',
|
|
41
|
+
updated_at: '2026-05-29T00:00:00.000Z',
|
|
42
|
+
}));
|
|
43
|
+
const fetchSpy = vi.spyOn(globalThis, 'fetch')
|
|
44
|
+
.mockResolvedValueOnce(jsonResponse(firstPage))
|
|
45
|
+
.mockResolvedValueOnce(jsonResponse([{
|
|
46
|
+
context: 'ci-100',
|
|
47
|
+
state: 'pending',
|
|
48
|
+
updated_at: '2026-05-29T00:01:00.000Z',
|
|
49
|
+
}]));
|
|
50
|
+
const statuses = await listCommitStatuses('acme', 'web', 'abc123', 'token');
|
|
51
|
+
expect(statuses).toHaveLength(101);
|
|
52
|
+
expect(fetchSpy).toHaveBeenCalledTimes(2);
|
|
53
|
+
expect(String(fetchSpy.mock.calls[0][0])).toContain('/statuses?per_page=100&page=1');
|
|
54
|
+
});
|
|
55
|
+
it('throws for non-404 issue comment failures', async () => {
|
|
56
|
+
vi.spyOn(globalThis, 'fetch').mockResolvedValueOnce(jsonResponse({ message: 'rate limited' }, 429));
|
|
57
|
+
await expect(listIssueComments('acme', 'web', 7, 'token'))
|
|
58
|
+
.rejects.toThrow('GitHub API request failed');
|
|
59
|
+
});
|
|
60
|
+
it('treats missing issue comments as empty activity', async () => {
|
|
61
|
+
vi.spyOn(globalThis, 'fetch').mockResolvedValueOnce(jsonResponse({ message: 'not found' }, 404));
|
|
62
|
+
await expect(listIssueComments('acme', 'web', 7, 'token')).resolves.toEqual([]);
|
|
63
|
+
});
|
|
64
|
+
it('throws for non-404 open PR list failures', async () => {
|
|
65
|
+
vi.spyOn(globalThis, 'fetch').mockResolvedValueOnce(jsonResponse({ message: 'rate limited' }, 429));
|
|
66
|
+
await expect(listOpenPRs('acme', 'web', 'token'))
|
|
67
|
+
.rejects.toThrow('Failed to list open PRs for acme/web page 1 [429]: rate limited');
|
|
68
|
+
});
|
|
69
|
+
it('throws for non-404 repo scope list failures', async () => {
|
|
70
|
+
vi.spyOn(globalThis, 'fetch')
|
|
71
|
+
.mockResolvedValueOnce(jsonResponse({ message: 'forbidden' }, 403))
|
|
72
|
+
.mockResolvedValueOnce(jsonResponse({ message: 'forbidden' }, 403));
|
|
73
|
+
await expect(listOrgRepos('acme', 'token')).rejects.toThrow('GitHub API request failed');
|
|
74
|
+
await expect(listUserRepos('alice', 'token')).rejects.toThrow('GitHub API request failed');
|
|
75
|
+
});
|
|
76
|
+
it('treats missing open PR lists as empty scope', async () => {
|
|
77
|
+
vi.spyOn(globalThis, 'fetch').mockResolvedValueOnce(jsonResponse({ message: 'not found' }, 404));
|
|
78
|
+
await expect(listOpenPRs('acme', 'web', 'token')).resolves.toEqual([]);
|
|
79
|
+
});
|
|
80
|
+
it('uses the standard GitHub JSON media type for timeline events', async () => {
|
|
81
|
+
const fetchSpy = vi.spyOn(globalThis, 'fetch')
|
|
82
|
+
.mockResolvedValueOnce(jsonResponse([{ event: 'ready_for_review', created_at: '2026-05-29T00:00:00.000Z' }]));
|
|
83
|
+
await listTimelineEvents('acme', 'web', 7, 'token');
|
|
84
|
+
expect(fetchSpy.mock.calls[0]?.[1]).toEqual(expect.objectContaining({
|
|
85
|
+
headers: expect.objectContaining({ Accept: 'application/vnd.github+json' }),
|
|
86
|
+
}));
|
|
87
|
+
});
|
|
88
|
+
it('returns the latest fresh crosscheck review comment body and id', async () => {
|
|
89
|
+
vi.spyOn(globalThis, 'fetch').mockResolvedValueOnce(jsonResponse([
|
|
90
|
+
{ id: 1, body: '<!-- crosscheck: origin=claude reviewer=codex verdict=BLOCK type=review -->' },
|
|
91
|
+
{ id: 2, body: '<!-- crosscheck: fix_applied -->' },
|
|
92
|
+
{ id: 3, body: '<!-- crosscheck: origin=claude reviewer=codex verdict=NEEDS_WORK type=review -->' },
|
|
93
|
+
]));
|
|
94
|
+
await expect(getLastCrossCheckReviewComment('acme', 'web', 7, 'token')).resolves.toEqual({
|
|
95
|
+
id: 3,
|
|
96
|
+
body: '<!-- crosscheck: origin=claude reviewer=codex verdict=NEEDS_WORK type=review -->',
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
//# sourceMappingURL=github-scan-client.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-scan-client.test.js","sourceRoot":"","sources":["../../src/__tests__/github-scan-client.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-fresh-review-comment.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/is-fresh-review-comment.test.ts"],"names":[],"mappings":""}
|