@rigour-labs/core 6.7.10 → 6.8.1-rc.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/brief/briefing.d.ts +59 -0
- package/dist/brief/briefing.js +126 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/inference/cloud-provider.js +12 -2
- package/dist/review/backtest-init.d.ts +8 -5
- package/dist/review/backtest-init.js +27 -9
- package/dist/review/backtest-last.js +3 -1
- package/dist/review/reviewer/adapters.d.ts +4 -0
- package/dist/review/reviewer/adapters.js +23 -0
- package/dist/review/reviewer/inputs.d.ts +4 -1
- package/dist/review/reviewer/inputs.js +36 -2
- package/dist/review/reviewer/record.d.ts +5 -0
- package/dist/review/reviewer/record.js +3 -3
- package/dist/review/reviewer/verdict.d.ts +14 -0
- package/dist/review/reviewer/verdict.js +46 -6
- package/dist/review/reviewer.d.ts +2 -0
- package/dist/review/reviewer.js +24 -5
- package/dist/review-learning/repo-rules.d.ts +14 -2
- package/dist/review-learning/repo-rules.js +59 -9
- package/dist/task/thread.d.ts +47 -0
- package/dist/task/thread.js +234 -0
- package/dist/templates/universal-config.js +4 -0
- package/dist/types/index.d.ts +21 -0
- package/dist/types/index.js +7 -0
- package/package.json +11 -8
- package/dist/context/automatic-index-cache.test.d.ts +0 -1
- package/dist/context/automatic-index-cache.test.js +0 -30
- package/dist/context/automatic-index.test.d.ts +0 -1
- package/dist/context/automatic-index.test.js +0 -45
- package/dist/context/cache-engine.test.d.ts +0 -1
- package/dist/context/cache-engine.test.js +0 -99
- package/dist/context/dependency-graph.test.d.ts +0 -1
- package/dist/context/dependency-graph.test.js +0 -13
- package/dist/context/index-status.test.d.ts +0 -1
- package/dist/context/index-status.test.js +0 -26
- package/dist/context.test.d.ts +0 -1
- package/dist/context.test.js +0 -228
- package/dist/deep/agent-review.test.d.ts +0 -1
- package/dist/deep/agent-review.test.js +0 -53
- package/dist/deep/code-context.test.d.ts +0 -1
- package/dist/deep/code-context.test.js +0 -48
- package/dist/deep/code-pass.test.d.ts +0 -1
- package/dist/deep/code-pass.test.js +0 -112
- package/dist/deep/code-review-prompt.test.d.ts +0 -1
- package/dist/deep/code-review-prompt.test.js +0 -20
- package/dist/deep/code-verifier.test.d.ts +0 -1
- package/dist/deep/code-verifier.test.js +0 -54
- package/dist/deep/diff-tests/calls.test.d.ts +0 -1
- package/dist/deep/diff-tests/calls.test.js +0 -33
- package/dist/deep/diff-tests/run.test.d.ts +0 -1
- package/dist/deep/diff-tests/run.test.js +0 -58
- package/dist/deep/fact-extractor.test.d.ts +0 -1
- package/dist/deep/fact-extractor.test.js +0 -581
- package/dist/deep/parse-findings.test.d.ts +0 -1
- package/dist/deep/parse-findings.test.js +0 -25
- package/dist/deep/pr-review.test.d.ts +0 -1
- package/dist/deep/pr-review.test.js +0 -80
- package/dist/deep/prompts.test.d.ts +0 -1
- package/dist/deep/prompts.test.js +0 -235
- package/dist/deep/reference-pack.test.d.ts +0 -1
- package/dist/deep/reference-pack.test.js +0 -46
- package/dist/deep/related-changes.test.d.ts +0 -1
- package/dist/deep/related-changes.test.js +0 -33
- package/dist/deep/review-context-export.test.d.ts +0 -1
- package/dist/deep/review-context-export.test.js +0 -32
- package/dist/deep/review-tools.test.d.ts +0 -1
- package/dist/deep/review-tools.test.js +0 -39
- package/dist/deep/risk.test.d.ts +0 -1
- package/dist/deep/risk.test.js +0 -101
- package/dist/deep/verifier.test.d.ts +0 -1
- package/dist/deep/verifier.test.js +0 -635
- package/dist/discovery.test.d.ts +0 -1
- package/dist/discovery.test.js +0 -93
- package/dist/environment.test.d.ts +0 -1
- package/dist/environment.test.js +0 -94
- package/dist/firewall/firewall.test.d.ts +0 -1
- package/dist/firewall/firewall.test.js +0 -117
- package/dist/firewall/trust-boundaries.test.d.ts +0 -1
- package/dist/firewall/trust-boundaries.test.js +0 -64
- package/dist/firewall/trusted-control.test.d.ts +0 -1
- package/dist/firewall/trusted-control.test.js +0 -188
- package/dist/gates/agent-team.test.d.ts +0 -1
- package/dist/gates/agent-team.test.js +0 -113
- package/dist/gates/ast.test.d.ts +0 -1
- package/dist/gates/ast.test.js +0 -112
- package/dist/gates/checkpoint.test.d.ts +0 -1
- package/dist/gates/checkpoint.test.js +0 -105
- package/dist/gates/content.test.d.ts +0 -1
- package/dist/gates/content.test.js +0 -73
- package/dist/gates/coverage.test.d.ts +0 -1
- package/dist/gates/coverage.test.js +0 -53
- package/dist/gates/dedupe-failures.test.d.ts +0 -1
- package/dist/gates/dedupe-failures.test.js +0 -12
- package/dist/gates/deep-analysis.test.d.ts +0 -1
- package/dist/gates/deep-analysis.test.js +0 -86
- package/dist/gates/deep-intent.test.d.ts +0 -1
- package/dist/gates/deep-intent.test.js +0 -51
- package/dist/gates/deep-timeout.test.d.ts +0 -1
- package/dist/gates/deep-timeout.test.js +0 -10
- package/dist/gates/deprecated-apis.test.d.ts +0 -1
- package/dist/gates/deprecated-apis.test.js +0 -318
- package/dist/gates/deprecated-dependencies.test.d.ts +0 -1
- package/dist/gates/deprecated-dependencies.test.js +0 -55
- package/dist/gates/frontend-secret-exposure.test.d.ts +0 -1
- package/dist/gates/frontend-secret-exposure.test.js +0 -148
- package/dist/gates/hallucinated-imports/framework-modules-nuxt.test.d.ts +0 -1
- package/dist/gates/hallucinated-imports/framework-modules-nuxt.test.js +0 -27
- package/dist/gates/hallucinated-imports/js-resolver-types.test.d.ts +0 -1
- package/dist/gates/hallucinated-imports/js-resolver-types.test.js +0 -14
- package/dist/gates/hallucinated-imports-sveltekit.test.d.ts +0 -1
- package/dist/gates/hallucinated-imports-sveltekit.test.js +0 -132
- package/dist/gates/hallucinated-imports.test.d.ts +0 -1
- package/dist/gates/hallucinated-imports.test.js +0 -1206
- package/dist/gates/js-style-context.test.d.ts +0 -1
- package/dist/gates/js-style-context.test.js +0 -35
- package/dist/gates/logic-drift.test.d.ts +0 -1
- package/dist/gates/logic-drift.test.js +0 -52
- package/dist/gates/phantom-apis.test.d.ts +0 -1
- package/dist/gates/phantom-apis.test.js +0 -396
- package/dist/gates/promise-safety.test.d.ts +0 -1
- package/dist/gates/promise-safety.test.js +0 -34
- package/dist/gates/runner.test.d.ts +0 -1
- package/dist/gates/runner.test.js +0 -77
- package/dist/gates/scoped-gates.test.d.ts +0 -1
- package/dist/gates/scoped-gates.test.js +0 -52
- package/dist/gates/security-patterns-owasp.test.d.ts +0 -1
- package/dist/gates/security-patterns-owasp.test.js +0 -186
- package/dist/gates/security-patterns.test.d.ts +0 -1
- package/dist/gates/security-patterns.test.js +0 -194
- package/dist/gates/semantic-bugs.test.d.ts +0 -1
- package/dist/gates/semantic-bugs.test.js +0 -76
- package/dist/gates/side-effect-analysis.test.d.ts +0 -1
- package/dist/gates/side-effect-analysis.test.js +0 -162
- package/dist/gates/style-drift.test.d.ts +0 -1
- package/dist/gates/style-drift.test.js +0 -26
- package/dist/gates/test-quality.test.d.ts +0 -1
- package/dist/gates/test-quality.test.js +0 -325
- package/dist/gates/trusted-reviews.test.d.ts +0 -1
- package/dist/gates/trusted-reviews.test.js +0 -16
- package/dist/gates/unindexed-reads/queries.test.d.ts +0 -1
- package/dist/gates/unindexed-reads/queries.test.js +0 -54
- package/dist/gates/unindexed-reads/schema.test.d.ts +0 -1
- package/dist/gates/unindexed-reads/schema.test.js +0 -81
- package/dist/gates/unindexed-reads/unindexed-reads.test.d.ts +0 -1
- package/dist/gates/unindexed-reads/unindexed-reads.test.js +0 -90
- package/dist/hooks/checker.test.d.ts +0 -1
- package/dist/hooks/checker.test.js +0 -159
- package/dist/hooks/dlp-confidence.test.d.ts +0 -1
- package/dist/hooks/dlp-confidence.test.js +0 -51
- package/dist/hooks/dlp-feedback.test.d.ts +0 -1
- package/dist/hooks/dlp-feedback.test.js +0 -131
- package/dist/hooks/input-validator.test.d.ts +0 -1
- package/dist/hooks/input-validator.test.js +0 -329
- package/dist/hooks/templates.test.d.ts +0 -1
- package/dist/hooks/templates.test.js +0 -27
- package/dist/inference/brain-placeholder.test.d.ts +0 -1
- package/dist/inference/brain-placeholder.test.js +0 -28
- package/dist/inference/cloud-provider.test.d.ts +0 -1
- package/dist/inference/cloud-provider.test.js +0 -139
- package/dist/inference/executable.test.d.ts +0 -1
- package/dist/inference/executable.test.js +0 -41
- package/dist/inference/http-download.test.d.ts +0 -1
- package/dist/inference/http-download.test.js +0 -109
- package/dist/inference/llama-engine-checksum.test.d.ts +0 -1
- package/dist/inference/llama-engine-checksum.test.js +0 -27
- package/dist/inference/llama-engine.test.d.ts +0 -1
- package/dist/inference/llama-engine.test.js +0 -51
- package/dist/inference/llama-process.test.d.ts +0 -1
- package/dist/inference/llama-process.test.js +0 -61
- package/dist/inference/local-model.test.d.ts +0 -1
- package/dist/inference/local-model.test.js +0 -23
- package/dist/inference/model-download.test.d.ts +0 -1
- package/dist/inference/model-download.test.js +0 -125
- package/dist/inference/model-manager.test.d.ts +0 -1
- package/dist/inference/model-manager.test.js +0 -24
- package/dist/inference/types.test.d.ts +0 -1
- package/dist/inference/types.test.js +0 -19
- package/dist/memory/recall.test.d.ts +0 -1
- package/dist/memory/recall.test.js +0 -36
- package/dist/pattern-index/indexer.test.d.ts +0 -6
- package/dist/pattern-index/indexer.test.js +0 -197
- package/dist/pattern-index/matcher.test.d.ts +0 -6
- package/dist/pattern-index/matcher.test.js +0 -238
- package/dist/pattern-index/pattern-reuse.test.d.ts +0 -1
- package/dist/pattern-index/pattern-reuse.test.js +0 -76
- package/dist/pattern-index/semantic-runtime.test.d.ts +0 -1
- package/dist/pattern-index/semantic-runtime.test.js +0 -31
- package/dist/pattern-index/staleness.test.d.ts +0 -6
- package/dist/pattern-index/staleness.test.js +0 -211
- package/dist/review/agent-fixes.test.d.ts +0 -1
- package/dist/review/agent-fixes.test.js +0 -32
- package/dist/review/backtest-init.test.d.ts +0 -1
- package/dist/review/backtest-init.test.js +0 -98
- package/dist/review/backtest-judges.test.d.ts +0 -1
- package/dist/review/backtest-judges.test.js +0 -32
- package/dist/review/backtest-last.test.d.ts +0 -1
- package/dist/review/backtest-last.test.js +0 -109
- package/dist/review/backtest.test.d.ts +0 -1
- package/dist/review/backtest.test.js +0 -183
- package/dist/review/baseline.test.d.ts +0 -1
- package/dist/review/baseline.test.js +0 -22
- package/dist/review/branch-checks.test.d.ts +0 -1
- package/dist/review/branch-checks.test.js +0 -48
- package/dist/review/check-outcomes.test.d.ts +0 -1
- package/dist/review/check-outcomes.test.js +0 -56
- package/dist/review/code-patterns.test.d.ts +0 -1
- package/dist/review/code-patterns.test.js +0 -142
- package/dist/review/dead-code.test.d.ts +0 -1
- package/dist/review/dead-code.test.js +0 -154
- package/dist/review/deep-runs.test.d.ts +0 -1
- package/dist/review/deep-runs.test.js +0 -23
- package/dist/review/effectiveness.test.d.ts +0 -1
- package/dist/review/effectiveness.test.js +0 -42
- package/dist/review/fix-scope.test.d.ts +0 -1
- package/dist/review/fix-scope.test.js +0 -104
- package/dist/review/generated-files.test.d.ts +0 -1
- package/dist/review/generated-files.test.js +0 -25
- package/dist/review/migration-order.test.d.ts +0 -1
- package/dist/review/migration-order.test.js +0 -62
- package/dist/review/quiet.test.d.ts +0 -1
- package/dist/review/quiet.test.js +0 -38
- package/dist/review/receipt.test.d.ts +0 -1
- package/dist/review/receipt.test.js +0 -60
- package/dist/review/review-task.test.d.ts +0 -1
- package/dist/review/review-task.test.js +0 -89
- package/dist/review/review.test.d.ts +0 -1
- package/dist/review/review.test.js +0 -203
- package/dist/review/reviewer/adapters.test.d.ts +0 -1
- package/dist/review/reviewer/adapters.test.js +0 -60
- package/dist/review/reviewer/api-judge.test.d.ts +0 -1
- package/dist/review/reviewer/api-judge.test.js +0 -108
- package/dist/review/reviewer/background.test.d.ts +0 -1
- package/dist/review/reviewer/background.test.js +0 -118
- package/dist/review/reviewer/context.test.d.ts +0 -1
- package/dist/review/reviewer/context.test.js +0 -45
- package/dist/review/reviewer/exec.test.d.ts +0 -1
- package/dist/review/reviewer/exec.test.js +0 -59
- package/dist/review/reviewer/inputs.test.d.ts +0 -1
- package/dist/review/reviewer/inputs.test.js +0 -26
- package/dist/review/reviewer/panel.test.d.ts +0 -1
- package/dist/review/reviewer/panel.test.js +0 -110
- package/dist/review/reviewer/record.test.d.ts +0 -1
- package/dist/review/reviewer/record.test.js +0 -32
- package/dist/review/reviewer/rule-writer.test.d.ts +0 -1
- package/dist/review/reviewer/rule-writer.test.js +0 -52
- package/dist/review/reviewer/settings.test.d.ts +0 -1
- package/dist/review/reviewer/settings.test.js +0 -57
- package/dist/review/reviewer/usage.test.d.ts +0 -1
- package/dist/review/reviewer/usage.test.js +0 -14
- package/dist/review/reviewer.test.d.ts +0 -1
- package/dist/review/reviewer.test.js +0 -705
- package/dist/review/stories.test.d.ts +0 -1
- package/dist/review/stories.test.js +0 -58
- package/dist/review/toolchain.test.d.ts +0 -1
- package/dist/review/toolchain.test.js +0 -108
- package/dist/review/typed/redundancy.test.d.ts +0 -1
- package/dist/review/typed/redundancy.test.js +0 -315
- package/dist/review/typed/schema-nullability.test.d.ts +0 -1
- package/dist/review/typed/schema-nullability.test.js +0 -63
- package/dist/review-learning/human-edits.test.d.ts +0 -1
- package/dist/review-learning/human-edits.test.js +0 -47
- package/dist/review-learning/repo-rules.test.d.ts +0 -1
- package/dist/review-learning/repo-rules.test.js +0 -55
- package/dist/review-learning/review-learning.test.d.ts +0 -1
- package/dist/review-learning/review-learning.test.js +0 -249
- package/dist/safety.test.d.ts +0 -1
- package/dist/safety.test.js +0 -42
- package/dist/semantic/benchmark.test.d.ts +0 -1
- package/dist/semantic/benchmark.test.js +0 -22
- package/dist/semantic/intent/intent.test.d.ts +0 -1
- package/dist/semantic/intent/intent.test.js +0 -46
- package/dist/semantic/learn/learn.test.d.ts +0 -1
- package/dist/semantic/learn/learn.test.js +0 -67
- package/dist/semantic/origins.test.d.ts +0 -1
- package/dist/semantic/origins.test.js +0 -77
- package/dist/semantic/project-facts.test.d.ts +0 -1
- package/dist/semantic/project-facts.test.js +0 -45
- package/dist/semantic/sites/call-sites.test.d.ts +0 -1
- package/dist/semantic/sites/call-sites.test.js +0 -46
- package/dist/services/adaptive-thresholds.test.d.ts +0 -1
- package/dist/services/adaptive-thresholds.test.js +0 -53
- package/dist/services/agent-history.test.d.ts +0 -1
- package/dist/services/agent-history.test.js +0 -69
- package/dist/services/context-scope-summary.test.d.ts +0 -1
- package/dist/services/context-scope-summary.test.js +0 -17
- package/dist/services/context-telemetry-service.test.d.ts +0 -1
- package/dist/services/context-telemetry-service.test.js +0 -182
- package/dist/services/cursor-usage-sync.test.d.ts +0 -1
- package/dist/services/cursor-usage-sync.test.js +0 -173
- package/dist/services/engineering-knowledge-graph.test.d.ts +0 -1
- package/dist/services/engineering-knowledge-graph.test.js +0 -76
- package/dist/services/model-pricing.test.d.ts +0 -1
- package/dist/services/model-pricing.test.js +0 -44
- package/dist/services/observed-savings.test.d.ts +0 -1
- package/dist/services/observed-savings.test.js +0 -37
- package/dist/services/score-history.test.d.ts +0 -1
- package/dist/services/score-history.test.js +0 -61
- package/dist/smoke.test.d.ts +0 -1
- package/dist/smoke.test.js +0 -17
- package/dist/storage/cache-cleanup.test.d.ts +0 -1
- package/dist/storage/cache-cleanup.test.js +0 -54
- package/dist/storage/context-telemetry.test.d.ts +0 -1
- package/dist/storage/context-telemetry.test.js +0 -80
- package/dist/storage/db.test.d.ts +0 -1
- package/dist/storage/db.test.js +0 -46
- package/dist/storage/fix-lessons.test.d.ts +0 -1
- package/dist/storage/fix-lessons.test.js +0 -61
- package/dist/storage/lessons.test.d.ts +0 -1
- package/dist/storage/lessons.test.js +0 -81
- package/dist/storage/local-encryption.test.d.ts +0 -1
- package/dist/storage/local-encryption.test.js +0 -34
- package/dist/storage/local-memory.test.d.ts +0 -1
- package/dist/storage/local-memory.test.js +0 -55
- package/dist/storage/share-memory.test.d.ts +0 -1
- package/dist/storage/share-memory.test.js +0 -34
- package/dist/storage/team-diagnostics.test.d.ts +0 -1
- package/dist/storage/team-diagnostics.test.js +0 -51
- package/dist/storage/team-scope.test.d.ts +0 -1
- package/dist/storage/team-scope.test.js +0 -22
- package/dist/storage/team-store.test.d.ts +0 -1
- package/dist/storage/team-store.test.js +0 -11
- package/dist/storage/team-sync-scope.test.d.ts +0 -1
- package/dist/storage/team-sync-scope.test.js +0 -100
- package/dist/storage/team-vector-store.test.d.ts +0 -1
- package/dist/storage/team-vector-store.test.js +0 -56
- package/dist/storage/telemetry-scope.test.d.ts +0 -1
- package/dist/storage/telemetry-scope.test.js +0 -38
- package/dist/telemetry/telemetry.test.d.ts +0 -1
- package/dist/telemetry/telemetry.test.js +0 -64
- package/dist/types/index.test.d.ts +0 -1
- package/dist/types/index.test.js +0 -33
- package/dist/utils/command-line.test.d.ts +0 -1
- package/dist/utils/command-line.test.js +0 -8
- package/dist/utils/diff-removed.test.d.ts +0 -1
- package/dist/utils/diff-removed.test.js +0 -29
- package/dist/utils/diff.test.d.ts +0 -1
- package/dist/utils/diff.test.js +0 -38
- package/dist/utils/glob-paths.test.d.ts +0 -1
- package/dist/utils/glob-paths.test.js +0 -40
- package/dist/utils/profile.test.d.ts +0 -1
- package/dist/utils/profile.test.js +0 -68
- package/dist/utils/scanner.test.d.ts +0 -1
- package/dist/utils/scanner.test.js +0 -48
- package/dist/utils/scope.test.d.ts +0 -1
- package/dist/utils/scope.test.js +0 -38
package/dist/types/index.d.ts
CHANGED
|
@@ -2399,6 +2399,19 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
2399
2399
|
}, {
|
|
2400
2400
|
report_path?: string | undefined;
|
|
2401
2401
|
}>>>;
|
|
2402
|
+
/** The briefing an agent gets before it writes (rigour brief, the prompt hook, rigour_brief). */
|
|
2403
|
+
brief: z.ZodDefault<z.ZodOptional<z.ZodObject<{
|
|
2404
|
+
/** The kill switch: false stops every briefing, including an installed hook. The hook itself is installed only with `rigour hooks init --brief`. */
|
|
2405
|
+
enabled: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
2406
|
+
/** At most this many items, never more than 10. */
|
|
2407
|
+
max_items: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
2408
|
+
}, "strip", z.ZodTypeAny, {
|
|
2409
|
+
enabled: boolean;
|
|
2410
|
+
max_items: number;
|
|
2411
|
+
}, {
|
|
2412
|
+
enabled?: boolean | undefined;
|
|
2413
|
+
max_items?: number | undefined;
|
|
2414
|
+
}>>>;
|
|
2402
2415
|
/** rigour review / rigour_review / the PR bot / the stop hook. */
|
|
2403
2416
|
review: z.ZodDefault<z.ZodOptional<z.ZodObject<{
|
|
2404
2417
|
/** Let heuristic gates decide the verdict too; by default only findings that prove a defect do (quiet.ts). */
|
|
@@ -2873,6 +2886,10 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
2873
2886
|
output: {
|
|
2874
2887
|
report_path: string;
|
|
2875
2888
|
};
|
|
2889
|
+
brief: {
|
|
2890
|
+
enabled: boolean;
|
|
2891
|
+
max_items: number;
|
|
2892
|
+
};
|
|
2876
2893
|
review: {
|
|
2877
2894
|
include_heuristics: boolean;
|
|
2878
2895
|
show_preexisting: boolean;
|
|
@@ -3165,6 +3182,10 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
3165
3182
|
output?: {
|
|
3166
3183
|
report_path?: string | undefined;
|
|
3167
3184
|
} | undefined;
|
|
3185
|
+
brief?: {
|
|
3186
|
+
enabled?: boolean | undefined;
|
|
3187
|
+
max_items?: number | undefined;
|
|
3188
|
+
} | undefined;
|
|
3168
3189
|
review?: {
|
|
3169
3190
|
include_heuristics?: boolean | undefined;
|
|
3170
3191
|
show_preexisting?: boolean | undefined;
|
package/dist/types/index.js
CHANGED
|
@@ -365,6 +365,13 @@ export const ConfigSchema = z.object({
|
|
|
365
365
|
output: z.object({
|
|
366
366
|
report_path: z.string().default('rigour-report.json'),
|
|
367
367
|
}).optional().default({}),
|
|
368
|
+
/** The briefing an agent gets before it writes (rigour brief, the prompt hook, rigour_brief). */
|
|
369
|
+
brief: z.object({
|
|
370
|
+
/** The kill switch: false stops every briefing, including an installed hook. The hook itself is installed only with `rigour hooks init --brief`. */
|
|
371
|
+
enabled: z.boolean().optional().default(true),
|
|
372
|
+
/** At most this many items, never more than 10. */
|
|
373
|
+
max_items: z.number().int().min(1).max(10).optional().default(10),
|
|
374
|
+
}).optional().default({}),
|
|
368
375
|
/** rigour review / rigour_review / the PR bot / the stop hook. */
|
|
369
376
|
review: z.object({
|
|
370
377
|
/** Let heuristic gates decide the verdict too; by default only findings that prove a defect do (quiet.ts). */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rigour-labs/core",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.8.1-rc.1",
|
|
4
4
|
"description": "Rigour's review engine: deterministic gates on changed lines, rules and lessons learned from your team's fixes, and per-check precision from what you fix versus dismiss, across TypeScript, JavaScript, Python, Go, Ruby and C#.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.13"
|
|
@@ -30,7 +30,10 @@
|
|
|
30
30
|
"type": "module",
|
|
31
31
|
"files": [
|
|
32
32
|
"dist",
|
|
33
|
-
"README.md"
|
|
33
|
+
"README.md",
|
|
34
|
+
"!dist/**/*.test.js",
|
|
35
|
+
"!dist/**/*.test.d.ts",
|
|
36
|
+
"!dist/**/*.test.js.map"
|
|
34
37
|
],
|
|
35
38
|
"main": "dist/index.js",
|
|
36
39
|
"types": "dist/index.d.ts",
|
|
@@ -69,14 +72,14 @@
|
|
|
69
72
|
"zod": "^3.22.4"
|
|
70
73
|
},
|
|
71
74
|
"optionalDependencies": {
|
|
72
|
-
"@anthropic-ai/sdk": "^0.
|
|
75
|
+
"@anthropic-ai/sdk": "^0.132.1",
|
|
73
76
|
"pg": "^8.16.3",
|
|
74
77
|
"openai": "^5.23.2",
|
|
75
|
-
"@rigour-labs/brain-darwin-arm64": "6.
|
|
76
|
-
"@rigour-labs/brain-darwin-x64": "6.
|
|
77
|
-
"@rigour-labs/brain-linux-
|
|
78
|
-
"@rigour-labs/brain-
|
|
79
|
-
"@rigour-labs/brain-
|
|
78
|
+
"@rigour-labs/brain-darwin-arm64": "6.8.1-rc.1",
|
|
79
|
+
"@rigour-labs/brain-darwin-x64": "6.8.1-rc.1",
|
|
80
|
+
"@rigour-labs/brain-linux-arm64": "6.8.1-rc.1",
|
|
81
|
+
"@rigour-labs/brain-linux-x64": "6.8.1-rc.1",
|
|
82
|
+
"@rigour-labs/brain-win-x64": "6.8.1-rc.1"
|
|
80
83
|
},
|
|
81
84
|
"devDependencies": {
|
|
82
85
|
"@types/fs-extra": "^11.0.4",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import os from 'os';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
-
const writes = vi.hoisted(() => ({ count: 0 }));
|
|
6
|
-
vi.mock('../storage/context-telemetry.js', async (importOriginal) => ({
|
|
7
|
-
...(await importOriginal()),
|
|
8
|
-
setContextCacheRecord: async () => { writes.count++; },
|
|
9
|
-
}));
|
|
10
|
-
const { ensureAutomaticIndex, updateAutomaticIndexForFiles } = await import('./automatic-index.js');
|
|
11
|
-
let cwd;
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
writes.count = 0;
|
|
14
|
-
cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'auto-index-'));
|
|
15
|
-
fs.mkdirSync(path.join(cwd, 'src'));
|
|
16
|
-
fs.writeFileSync(path.join(cwd, 'src/a.ts'), 'export function alpha() { return 1; }\n');
|
|
17
|
-
fs.writeFileSync(path.join(cwd, 'src/b.ts'), 'export function beta() { return 2; }\n');
|
|
18
|
-
});
|
|
19
|
-
afterEach(() => fs.rmSync(cwd, { recursive: true, force: true }));
|
|
20
|
-
describe('automatic indexing', () => {
|
|
21
|
-
it('writes nothing to the context cache, however many edits it sees', async () => {
|
|
22
|
-
await ensureAutomaticIndex(cwd, { backgroundSemantic: false });
|
|
23
|
-
for (let edit = 0; edit < 5; edit++) {
|
|
24
|
-
fs.writeFileSync(path.join(cwd, 'src/a.ts'), `export function alpha() { return ${edit}; }\n`);
|
|
25
|
-
await updateAutomaticIndexForFiles(cwd, ['src/a.ts']);
|
|
26
|
-
}
|
|
27
|
-
expect(writes.count).toBe(0);
|
|
28
|
-
expect(fs.existsSync(path.join(cwd, '.rigour', 'patterns.json'))).toBe(true);
|
|
29
|
-
});
|
|
30
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import fs from 'fs-extra';
|
|
2
|
-
import os from 'os';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
-
import { ensureAutomaticIndex, mergeSemanticEmbeddings, updateAutomaticIndexForFiles } from './automatic-index.js';
|
|
6
|
-
describe('automatic incremental index', () => {
|
|
7
|
-
const cwd = path.join(os.tmpdir(), `rigour-auto-index-${process.pid}`);
|
|
8
|
-
afterEach(() => fs.remove(cwd));
|
|
9
|
-
it('builds once and refreshes only changed files and their dependents', async () => {
|
|
10
|
-
await fs.outputFile(path.join(cwd, 'src/value.ts'), 'export const value = 1;');
|
|
11
|
-
await fs.outputFile(path.join(cwd, 'src/consumer.ts'), "import { value } from './value';\nexport const doubled = value * 2;");
|
|
12
|
-
const baseline = await ensureAutomaticIndex(cwd, { backgroundSemantic: false });
|
|
13
|
-
const untouched = baseline.files.find(file => file.path === 'src/consumer.ts')?.indexedAt;
|
|
14
|
-
await fs.writeFile(path.join(cwd, 'src/value.ts'), 'export const value = 2;');
|
|
15
|
-
const result = await updateAutomaticIndexForFiles(cwd, ['src/value.ts']);
|
|
16
|
-
expect(result.affectedFiles.sort()).toEqual(['src/consumer.ts', 'src/value.ts']);
|
|
17
|
-
expect(result.index.files.find(file => file.path === 'src/consumer.ts')?.indexedAt).not.toBe(untouched);
|
|
18
|
-
});
|
|
19
|
-
it('ignores changed-file paths outside the repository', async () => {
|
|
20
|
-
await fs.outputFile(path.join(cwd, 'src/value.ts'), 'export const value = 1;');
|
|
21
|
-
const baseline = await ensureAutomaticIndex(cwd, { backgroundSemantic: false });
|
|
22
|
-
const result = await updateAutomaticIndexForFiles(cwd, [path.join(cwd, '..', 'outside.ts')]);
|
|
23
|
-
expect(result.affectedFiles).toEqual([]);
|
|
24
|
-
expect(result.index.patterns).toEqual(baseline.patterns);
|
|
25
|
-
});
|
|
26
|
-
it('merges background embeddings onto the latest structural snapshot', () => {
|
|
27
|
-
const pattern = (id, file, embedding) => ({
|
|
28
|
-
id, file, embedding, type: 'function', name: id, line: 1, endLine: 1,
|
|
29
|
-
signature: '', description: '', keywords: [], hash: id, exported: true,
|
|
30
|
-
usageCount: 0, indexedAt: '2026-09-10T00:00:00.000Z',
|
|
31
|
-
});
|
|
32
|
-
const makeIndex = (patterns) => ({
|
|
33
|
-
version: '1.0.0', lastUpdated: '2026-09-10T00:00:00.000Z', rootDir: cwd,
|
|
34
|
-
patterns,
|
|
35
|
-
files: patterns.map(entry => ({ path: entry.file, hash: entry.hash, patternCount: 1, indexedAt: entry.indexedAt })),
|
|
36
|
-
stats: { totalPatterns: patterns.length, totalFiles: patterns.length, byType: { function: patterns.length }, indexDurationMs: 1 },
|
|
37
|
-
});
|
|
38
|
-
const latest = makeIndex([pattern('changed', 'src/changed.ts'), pattern('new', 'src/new.ts')]);
|
|
39
|
-
const enriched = makeIndex([pattern('changed', 'src/old.ts', [0.1, 0.2]), pattern('deleted', 'src/deleted.ts', [0.3])]);
|
|
40
|
-
const merged = mergeSemanticEmbeddings(latest, enriched);
|
|
41
|
-
expect(merged.patterns.map(entry => entry.id)).toEqual(['changed', 'new']);
|
|
42
|
-
expect(merged.patterns[0].file).toBe('src/changed.ts');
|
|
43
|
-
expect(merged.patterns[0].embedding).toEqual([0.1, 0.2]);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import os from 'os';
|
|
4
|
-
import fs from 'fs-extra';
|
|
5
|
-
vi.mock('./db.js', () => ({
|
|
6
|
-
isSQLiteAvailable: () => false,
|
|
7
|
-
openDatabase: async () => null,
|
|
8
|
-
DB_PATH: '/tmp/rigour-test.db',
|
|
9
|
-
RIGOUR_DIR: '/tmp/.rigour',
|
|
10
|
-
}));
|
|
11
|
-
import { getSemanticQueryCache, setSemanticQueryCache, findRelatedSemanticQueryCache, queryTokenOverlap, distinctiveTokenAgreement, filterExistingEditScope, getTaskCheckpointCache, setTaskCheckpointCache, hashContent, normalizeQuery } from './cache-engine.js';
|
|
12
|
-
describe('Context cache engine', () => {
|
|
13
|
-
const testCwd = path.join(os.tmpdir(), `rigour-cache-test-${Date.now()}`);
|
|
14
|
-
beforeEach(async () => {
|
|
15
|
-
await fs.ensureDir(testCwd);
|
|
16
|
-
});
|
|
17
|
-
it('should calculate consistent SHA-256 hashes', () => {
|
|
18
|
-
const hash1 = hashContent('const x = 1;');
|
|
19
|
-
const hash2 = hashContent('const x = 1;');
|
|
20
|
-
const hash3 = hashContent('const x = 2;');
|
|
21
|
-
expect(hash1).toBe(hash2);
|
|
22
|
-
expect(hash1).not.toBe(hash3);
|
|
23
|
-
expect(hash1.length).toBe(16);
|
|
24
|
-
});
|
|
25
|
-
it('should normalize intent queries correctly', () => {
|
|
26
|
-
expect(normalizeQuery(' Add priority to task!! ')).toBe('add priority to task');
|
|
27
|
-
expect(normalizeQuery('Task SHOULD Support Priority.')).toBe('task should support priority');
|
|
28
|
-
});
|
|
29
|
-
it('Layer 3: should store and retrieve semantic query scope', async () => {
|
|
30
|
-
const entry = {
|
|
31
|
-
query: 'task priority persistence',
|
|
32
|
-
resolvedOwner: 'task-team',
|
|
33
|
-
editScope: ['services/task.ts'],
|
|
34
|
-
validationScope: ['npm test'],
|
|
35
|
-
evidence: ['AST match'],
|
|
36
|
-
commitSha: 'commit-99',
|
|
37
|
-
confidence: 0.95
|
|
38
|
-
};
|
|
39
|
-
await setSemanticQueryCache('add priority to task', 'commit-99', entry, testCwd);
|
|
40
|
-
const retrieved = await getSemanticQueryCache('add priority to task', 'commit-99', testCwd);
|
|
41
|
-
expect(retrieved).not.toBeNull();
|
|
42
|
-
expect(retrieved?.resolvedOwner).toBe('task-team');
|
|
43
|
-
expect(retrieved?.editScope).toContain('services/task.ts');
|
|
44
|
-
});
|
|
45
|
-
it('Layer 4: should store and retrieve subagent task checkpoint packet', async () => {
|
|
46
|
-
const packet = {
|
|
47
|
-
taskId: 'CTP-142',
|
|
48
|
-
agentId: 'CTP-142-task',
|
|
49
|
-
phase: 'implementation',
|
|
50
|
-
component: 'services/task',
|
|
51
|
-
changedFiles: ['services/task.ts'],
|
|
52
|
-
decisions: ['Added priority field'],
|
|
53
|
-
validation: ['npm test passed'],
|
|
54
|
-
remainingWork: ['Add integration test'],
|
|
55
|
-
risks: ['Migration needed']
|
|
56
|
-
};
|
|
57
|
-
await setTaskCheckpointCache(packet, 126000, testCwd);
|
|
58
|
-
const retrieved = await getTaskCheckpointCache('CTP-142', 'CTP-142-task', 'implementation', testCwd);
|
|
59
|
-
expect(retrieved).not.toBeNull();
|
|
60
|
-
expect(retrieved?.taskId).toBe('CTP-142');
|
|
61
|
-
expect(retrieved?.decisions).toContain('Added priority field');
|
|
62
|
-
});
|
|
63
|
-
it('Layer 3: finds related semantic queries at same commit for partial reuse', async () => {
|
|
64
|
-
expect(queryTokenOverlap('task priority persistence service', 'task priority persistence service layer')).toBeGreaterThan(0.7);
|
|
65
|
-
expect(distinctiveTokenAgreement('task service', 'payment service')).toBeLessThan(0.67);
|
|
66
|
-
await setSemanticQueryCache('task priority persistence service', 'commit-rel', {
|
|
67
|
-
query: 'task priority persistence service',
|
|
68
|
-
resolvedOwner: 'task-team',
|
|
69
|
-
editScope: ['services/task.ts'],
|
|
70
|
-
validationScope: ['npm test'],
|
|
71
|
-
evidence: ['related'],
|
|
72
|
-
commitSha: 'commit-rel',
|
|
73
|
-
confidence: 0.9,
|
|
74
|
-
}, testCwd);
|
|
75
|
-
const related = await findRelatedSemanticQueryCache('task priority persistence service layer', 'commit-rel', testCwd);
|
|
76
|
-
expect(related).not.toBeNull();
|
|
77
|
-
expect(related?.entry.editScope).toContain('services/task.ts');
|
|
78
|
-
// Same generic stem, different distinctive noun → reject
|
|
79
|
-
await setSemanticQueryCache('payment service billing', 'commit-rel', {
|
|
80
|
-
query: 'payment service billing',
|
|
81
|
-
resolvedOwner: 'pay',
|
|
82
|
-
editScope: ['services/pay.ts'],
|
|
83
|
-
validationScope: [],
|
|
84
|
-
evidence: [],
|
|
85
|
-
commitSha: 'commit-rel',
|
|
86
|
-
confidence: 0.9,
|
|
87
|
-
}, testCwd);
|
|
88
|
-
const crossDomain = await findRelatedSemanticQueryCache('task service billing', 'commit-rel', testCwd);
|
|
89
|
-
expect(crossDomain).toBeNull();
|
|
90
|
-
const otherCommit = await findRelatedSemanticQueryCache('task priority persistence service layer', 'commit-other', testCwd);
|
|
91
|
-
expect(otherCommit).toBeNull();
|
|
92
|
-
});
|
|
93
|
-
it('filters missing edit-scope files for quality', async () => {
|
|
94
|
-
await fs.writeFile(path.join(testCwd, 'alive.ts'), 'export const ok = 1;\n');
|
|
95
|
-
const result = await filterExistingEditScope(['alive.ts', 'gone.ts'], testCwd);
|
|
96
|
-
expect(result.valid).toEqual(['alive.ts']);
|
|
97
|
-
expect(result.missing).toEqual(['gone.ts']);
|
|
98
|
-
});
|
|
99
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { affectedDependents } from './dependency-graph.js';
|
|
3
|
-
describe('affectedDependents', () => {
|
|
4
|
-
it('includes direct and transitive consumers', () => {
|
|
5
|
-
const affected = affectedDependents({
|
|
6
|
-
version: 1,
|
|
7
|
-
generatedAt: '2026-09-10T00:00:00Z',
|
|
8
|
-
nodes: ['a.ts', 'b.ts', 'c.ts'],
|
|
9
|
-
edges: [{ from: 'b.ts', to: 'a.ts' }, { from: 'c.ts', to: 'b.ts' }],
|
|
10
|
-
}, ['a.ts']);
|
|
11
|
-
expect(new Set(affected)).toEqual(new Set(['a.ts', 'b.ts', 'c.ts']));
|
|
12
|
-
});
|
|
13
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import os from 'os';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
5
|
-
import { getAutomaticIndexStatus, recordIndexChoice } from './automatic-index.js';
|
|
6
|
-
let cwd;
|
|
7
|
-
beforeEach(() => { cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'index-status-')); });
|
|
8
|
-
afterEach(() => fs.rmSync(cwd, { recursive: true, force: true }));
|
|
9
|
-
const index = (embedded) => ({
|
|
10
|
-
version: '1.0.0', lastUpdated: '', rootDir: cwd, files: [],
|
|
11
|
-
patterns: [{ id: 'a', type: 'function', name: 'a', file: 'a.ts', line: 1, endLine: 1, signature: '', description: '', keywords: [], hash: 'a', exported: true, usageCount: 0, indexedAt: '', ...(embedded ? { embedding: [0.1] } : {}) }],
|
|
12
|
-
stats: { totalPatterns: 1, totalFiles: 1, byType: {}, indexDurationMs: 0 },
|
|
13
|
-
});
|
|
14
|
-
describe('semantic index status', () => {
|
|
15
|
-
it('treats no status yet as warming, not as an opt-out', async () => {
|
|
16
|
-
expect((await getAutomaticIndexStatus(cwd)).semantic).toBe('warming');
|
|
17
|
-
});
|
|
18
|
-
it('records what an explicit index chose, so automatic indexing and Studio agree', async () => {
|
|
19
|
-
await recordIndexChoice(cwd, index(false), false);
|
|
20
|
-
expect((await getAutomaticIndexStatus(cwd)).semantic).toBe('disabled');
|
|
21
|
-
await recordIndexChoice(cwd, index(true), true);
|
|
22
|
-
expect((await getAutomaticIndexStatus(cwd)).semantic).toBe('ready');
|
|
23
|
-
await recordIndexChoice(cwd, index(false), true);
|
|
24
|
-
expect((await getAutomaticIndexStatus(cwd)).semantic).toBe('degraded');
|
|
25
|
-
});
|
|
26
|
-
});
|
package/dist/context.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/context.test.js
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
2
|
-
import { GateRunner } from '../src/gates/runner.js';
|
|
3
|
-
import fs from 'fs-extra';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import os from 'os';
|
|
6
|
-
const TEST_CWD = path.join(os.tmpdir(), 'rigour-temp-test-context-' + process.pid);
|
|
7
|
-
describe('Context Awareness Engine', () => {
|
|
8
|
-
beforeAll(async () => {
|
|
9
|
-
await fs.ensureDir(TEST_CWD);
|
|
10
|
-
});
|
|
11
|
-
afterAll(async () => {
|
|
12
|
-
await fs.remove(TEST_CWD);
|
|
13
|
-
});
|
|
14
|
-
it('should detect context drift for redundant env suffixes (Golden Example)', async () => {
|
|
15
|
-
// Setup: Define standard GCP_PROJECT_ID
|
|
16
|
-
await fs.writeFile(path.join(TEST_CWD, '.env.example'), 'GCP_PROJECT_ID=my-project\n');
|
|
17
|
-
// Setup: Use drifted GCP_PROJECT_ID_PRODUCTION
|
|
18
|
-
await fs.writeFile(path.join(TEST_CWD, 'feature.js'), `
|
|
19
|
-
const id = process.env.GCP_PROJECT_ID_PRODUCTION;
|
|
20
|
-
console.log(id);
|
|
21
|
-
`);
|
|
22
|
-
const config = {
|
|
23
|
-
version: 1,
|
|
24
|
-
commands: {},
|
|
25
|
-
gates: {
|
|
26
|
-
context: {
|
|
27
|
-
enabled: true,
|
|
28
|
-
sensitivity: 0.8,
|
|
29
|
-
mining_depth: 10,
|
|
30
|
-
ignored_patterns: [],
|
|
31
|
-
cross_file_patterns: true,
|
|
32
|
-
naming_consistency: true,
|
|
33
|
-
import_relationships: true,
|
|
34
|
-
max_cross_file_depth: 50,
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
output: { report_path: 'rigour-report.json' }
|
|
38
|
-
};
|
|
39
|
-
const runner = new GateRunner(config);
|
|
40
|
-
const report = await runner.run(TEST_CWD);
|
|
41
|
-
const driftFailures = report.failures.filter(f => f.id === 'context-drift');
|
|
42
|
-
expect(driftFailures.length).toBeGreaterThan(0);
|
|
43
|
-
expect(driftFailures[0].details).toContain('GCP_PROJECT_ID_PRODUCTION');
|
|
44
|
-
expect(driftFailures[0].hint).toContain('GCP_PROJECT_ID');
|
|
45
|
-
});
|
|
46
|
-
it('should not flag valid environment variables', async () => {
|
|
47
|
-
await fs.writeFile(path.join(TEST_CWD, 'valid.js'), `
|
|
48
|
-
const id = process.env.GCP_PROJECT_ID;
|
|
49
|
-
`);
|
|
50
|
-
const config = {
|
|
51
|
-
version: 1,
|
|
52
|
-
commands: {},
|
|
53
|
-
gates: {
|
|
54
|
-
context: {
|
|
55
|
-
enabled: true,
|
|
56
|
-
sensitivity: 0.8,
|
|
57
|
-
mining_depth: 100,
|
|
58
|
-
ignored_patterns: [],
|
|
59
|
-
cross_file_patterns: true,
|
|
60
|
-
naming_consistency: true,
|
|
61
|
-
import_relationships: true,
|
|
62
|
-
max_cross_file_depth: 50,
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
output: { report_path: 'rigour-report.json' }
|
|
66
|
-
};
|
|
67
|
-
const runner = new GateRunner(config);
|
|
68
|
-
const report = await runner.run(TEST_CWD);
|
|
69
|
-
const driftFailures = report.failures.filter(f => f.id === 'context-drift');
|
|
70
|
-
// Filter out failures from other files if they still exist in TEST_CWD
|
|
71
|
-
const specificFailures = driftFailures.filter(f => f.files?.includes('valid.js'));
|
|
72
|
-
expect(specificFailures.length).toBe(0);
|
|
73
|
-
});
|
|
74
|
-
it('should classify arrow function exports as camelCase, not unknown', async () => {
|
|
75
|
-
// Create files with arrow function patterns that previously returned 'unknown'
|
|
76
|
-
await fs.writeFile(path.join(TEST_CWD, 'api.ts'), `
|
|
77
|
-
export const fetchData = async () => { return []; };
|
|
78
|
-
export const getUserProfile = async (id: string) => { return {}; };
|
|
79
|
-
export const use = () => {};
|
|
80
|
-
export const get = async () => {};
|
|
81
|
-
const handleClick = (e: Event) => {};
|
|
82
|
-
let processItem = async (item: any) => {};
|
|
83
|
-
`);
|
|
84
|
-
// Create a second file with consistent arrow function naming
|
|
85
|
-
await fs.writeFile(path.join(TEST_CWD, 'service.ts'), `
|
|
86
|
-
export const createUser = async (data: any) => {};
|
|
87
|
-
export const deleteUser = async (id: string) => {};
|
|
88
|
-
export const updateUser = async (id: string, data: any) => {};
|
|
89
|
-
`);
|
|
90
|
-
const config = {
|
|
91
|
-
version: 1,
|
|
92
|
-
commands: {},
|
|
93
|
-
gates: {
|
|
94
|
-
context: {
|
|
95
|
-
enabled: true,
|
|
96
|
-
sensitivity: 0.8,
|
|
97
|
-
mining_depth: 10,
|
|
98
|
-
ignored_patterns: [],
|
|
99
|
-
cross_file_patterns: true,
|
|
100
|
-
naming_consistency: true,
|
|
101
|
-
import_relationships: true,
|
|
102
|
-
max_cross_file_depth: 50,
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
output: { report_path: 'rigour-report.json' }
|
|
106
|
-
};
|
|
107
|
-
const runner = new GateRunner(config);
|
|
108
|
-
const report = await runner.run(TEST_CWD);
|
|
109
|
-
// Should NOT have any "unknown" naming convention failures
|
|
110
|
-
const namingFailures = report.failures.filter(f => f.id === 'context-drift' && f.details?.includes('unknown'));
|
|
111
|
-
expect(namingFailures.length).toBe(0);
|
|
112
|
-
});
|
|
113
|
-
it('should not classify plain variable declarations as function patterns', async () => {
|
|
114
|
-
// Create file with non-function const declarations
|
|
115
|
-
await fs.writeFile(path.join(TEST_CWD, 'constants.ts'), `
|
|
116
|
-
export const API_URL = 'https://api.example.com';
|
|
117
|
-
export const MAX_RETRIES = 3;
|
|
118
|
-
const config = { timeout: 5000 };
|
|
119
|
-
let count = 0;
|
|
120
|
-
`);
|
|
121
|
-
// Create file with actual functions for a dominant pattern
|
|
122
|
-
await fs.writeFile(path.join(TEST_CWD, 'utils.ts'), `
|
|
123
|
-
function getData() { return []; }
|
|
124
|
-
function setData(d: any) { return d; }
|
|
125
|
-
function processRequest(req: any) { return req; }
|
|
126
|
-
`);
|
|
127
|
-
const config = {
|
|
128
|
-
version: 1,
|
|
129
|
-
commands: {},
|
|
130
|
-
gates: {
|
|
131
|
-
context: {
|
|
132
|
-
enabled: true,
|
|
133
|
-
sensitivity: 0.8,
|
|
134
|
-
mining_depth: 10,
|
|
135
|
-
ignored_patterns: [],
|
|
136
|
-
cross_file_patterns: true,
|
|
137
|
-
naming_consistency: true,
|
|
138
|
-
import_relationships: true,
|
|
139
|
-
max_cross_file_depth: 50,
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
output: { report_path: 'rigour-report.json' }
|
|
143
|
-
};
|
|
144
|
-
const runner = new GateRunner(config);
|
|
145
|
-
const report = await runner.run(TEST_CWD);
|
|
146
|
-
// SCREAMING_SNAKE constants should NOT create naming drift failures
|
|
147
|
-
// because they should not be in the 'function' pattern bucket at all
|
|
148
|
-
const namingFailures = report.failures.filter(f => f.id === 'context-drift' && f.details?.includes('SCREAMING_SNAKE'));
|
|
149
|
-
expect(namingFailures.length).toBe(0);
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
|
-
/**
|
|
153
|
-
* Direct unit tests for detectCasing logic
|
|
154
|
-
*/
|
|
155
|
-
describe('detectCasing classification', () => {
|
|
156
|
-
// We test the regex rules directly since detectCasing is private
|
|
157
|
-
function detectCasing(name) {
|
|
158
|
-
if (/^[A-Z][a-z]/.test(name) && /[a-z][A-Z]/.test(name))
|
|
159
|
-
return 'PascalCase';
|
|
160
|
-
if (/^[a-z]/.test(name) && /[a-z][A-Z]/.test(name))
|
|
161
|
-
return 'camelCase';
|
|
162
|
-
if (/^[a-z][a-zA-Z0-9]*$/.test(name))
|
|
163
|
-
return 'camelCase'; // single-word lowercase
|
|
164
|
-
if (/^[a-z]+(_[a-z]+)+$/.test(name))
|
|
165
|
-
return 'snake_case';
|
|
166
|
-
if (/^[A-Z]+(_[A-Z]+)*$/.test(name))
|
|
167
|
-
return 'SCREAMING_SNAKE';
|
|
168
|
-
if (/^[A-Z][a-zA-Z]*$/.test(name))
|
|
169
|
-
return 'PascalCase';
|
|
170
|
-
return 'unknown';
|
|
171
|
-
}
|
|
172
|
-
// Multi-word camelCase
|
|
173
|
-
it('classifies multi-word camelCase', () => {
|
|
174
|
-
expect(detectCasing('fetchData')).toBe('camelCase');
|
|
175
|
-
expect(detectCasing('getUserProfile')).toBe('camelCase');
|
|
176
|
-
expect(detectCasing('handleClick')).toBe('camelCase');
|
|
177
|
-
expect(detectCasing('processItem')).toBe('camelCase');
|
|
178
|
-
expect(detectCasing('createNewUser')).toBe('camelCase');
|
|
179
|
-
});
|
|
180
|
-
// Single-word lowercase (the bug fix)
|
|
181
|
-
it('classifies single-word lowercase as camelCase', () => {
|
|
182
|
-
expect(detectCasing('fetch')).toBe('camelCase');
|
|
183
|
-
expect(detectCasing('use')).toBe('camelCase');
|
|
184
|
-
expect(detectCasing('get')).toBe('camelCase');
|
|
185
|
-
expect(detectCasing('set')).toBe('camelCase');
|
|
186
|
-
expect(detectCasing('run')).toBe('camelCase');
|
|
187
|
-
expect(detectCasing('a')).toBe('camelCase');
|
|
188
|
-
expect(detectCasing('x')).toBe('camelCase');
|
|
189
|
-
expect(detectCasing('id')).toBe('camelCase');
|
|
190
|
-
});
|
|
191
|
-
// Single-word lowercase with digits
|
|
192
|
-
it('classifies lowercase with digits as camelCase', () => {
|
|
193
|
-
expect(detectCasing('handler2')).toBe('camelCase');
|
|
194
|
-
expect(detectCasing('config3')).toBe('camelCase');
|
|
195
|
-
expect(detectCasing('v2')).toBe('camelCase');
|
|
196
|
-
});
|
|
197
|
-
// PascalCase
|
|
198
|
-
it('classifies PascalCase', () => {
|
|
199
|
-
expect(detectCasing('MyComponent')).toBe('PascalCase');
|
|
200
|
-
expect(detectCasing('UserService')).toBe('PascalCase');
|
|
201
|
-
expect(detectCasing('App')).toBe('PascalCase');
|
|
202
|
-
expect(detectCasing('A')).toBe('SCREAMING_SNAKE'); // single uppercase letter
|
|
203
|
-
});
|
|
204
|
-
// snake_case
|
|
205
|
-
it('classifies snake_case', () => {
|
|
206
|
-
expect(detectCasing('my_func')).toBe('snake_case');
|
|
207
|
-
expect(detectCasing('get_data')).toBe('snake_case');
|
|
208
|
-
expect(detectCasing('process_all_items')).toBe('snake_case');
|
|
209
|
-
});
|
|
210
|
-
// SCREAMING_SNAKE
|
|
211
|
-
it('classifies SCREAMING_SNAKE_CASE', () => {
|
|
212
|
-
expect(detectCasing('API_URL')).toBe('SCREAMING_SNAKE');
|
|
213
|
-
expect(detectCasing('MAX_RETRIES')).toBe('SCREAMING_SNAKE');
|
|
214
|
-
expect(detectCasing('A')).toBe('SCREAMING_SNAKE');
|
|
215
|
-
expect(detectCasing('DB')).toBe('SCREAMING_SNAKE');
|
|
216
|
-
});
|
|
217
|
-
// Edge cases that should NOT be unknown
|
|
218
|
-
it('does not return unknown for valid identifiers', () => {
|
|
219
|
-
const validIdentifiers = [
|
|
220
|
-
'fetch', 'getData', 'MyClass', 'my_func', 'API_KEY',
|
|
221
|
-
'use', 'run', 'a', 'x', 'id', 'App', 'handler2',
|
|
222
|
-
'processItem', 'UserProfile', 'get_all_data', 'MAX_SIZE',
|
|
223
|
-
];
|
|
224
|
-
for (const name of validIdentifiers) {
|
|
225
|
-
expect(detectCasing(name)).not.toBe('unknown');
|
|
226
|
-
}
|
|
227
|
-
});
|
|
228
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import os from 'os';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
5
|
-
import { reviewWithTools } from './agent-review.js';
|
|
6
|
-
import { verifyCodeFindings } from './code-verifier.js';
|
|
7
|
-
let repo;
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
repo = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-review-'));
|
|
10
|
-
fs.writeFileSync(path.join(repo, 'limits.ts'), 'export const MAX_ROWS = 0;\n');
|
|
11
|
-
fs.writeFileSync(path.join(repo, 'page.ts'), Array.from({ length: 60 }, (_, i) => `// line ${i + 1}`).join('\n'));
|
|
12
|
-
});
|
|
13
|
-
afterEach(() => { fs.rmSync(repo, { recursive: true, force: true }); });
|
|
14
|
-
const context = { file: 'page.ts', language: 'typescript', text: '1| export function page() {}', ranges: [[1, 5]], source: 'export function page() {}' };
|
|
15
|
-
function scripted(replies) {
|
|
16
|
-
const seen = [];
|
|
17
|
-
const provider = {
|
|
18
|
-
name: 'fake', isAvailable: async () => true, setup: async () => { }, dispose: () => { }, analyze: async () => '',
|
|
19
|
-
chat: async (messages, tools, options) => {
|
|
20
|
-
seen.push({ messages: [...messages], tools: tools.length, toolChoice: options?.toolChoice });
|
|
21
|
-
return replies.shift() ?? { text: '{"findings": []}', toolCalls: [] };
|
|
22
|
-
},
|
|
23
|
-
};
|
|
24
|
-
return { provider, seen };
|
|
25
|
-
}
|
|
26
|
-
const findingJson = (line, description) => JSON.stringify({ findings: [{ category: 'correctness', severity: 'high', file: 'page.ts', line, description, suggestion: 's', confidence: 0.9 }] });
|
|
27
|
-
describe('reviewWithTools', () => {
|
|
28
|
-
it('runs the tools the model asks for, then grounds its finding in what it read', async () => {
|
|
29
|
-
const { provider, seen } = scripted([
|
|
30
|
-
{ text: '', toolCalls: [{ id: 't1', name: 'read_file', arguments: { path: 'limits.ts' } }, { id: 't2', name: 'read_file', arguments: { path: 'page.ts', start_line: 40, end_line: 45 } }] },
|
|
31
|
-
{ text: findingJson(42, '`MAX_ROWS` is 0, so the page loop never runs.'), toolCalls: [] },
|
|
32
|
-
]);
|
|
33
|
-
const result = await reviewWithTools(provider, context, '', repo, {});
|
|
34
|
-
expect(result.toolCalls).toBe(2);
|
|
35
|
-
const toolResults = seen[1].messages.filter(m => m.role === 'tool').map(m => m.content);
|
|
36
|
-
expect(toolResults[0]).toContain('export const MAX_ROWS = 0;');
|
|
37
|
-
// Line 42 was outside the sent source, but the model read it, and it read MAX_ROWS.
|
|
38
|
-
expect(verifyCodeFindings(result.findings, [result.context])).toHaveLength(1);
|
|
39
|
-
expect(verifyCodeFindings(result.findings, [context])).toHaveLength(0);
|
|
40
|
-
});
|
|
41
|
-
it('forbids tool calls after the budget, keeping the tools defined for the history, and asks for the answer', async () => {
|
|
42
|
-
const greedy = Array.from({ length: 20 }, (_, i) => ({ text: '', toolCalls: [{ id: `t${i}`, name: 'grep', arguments: { pattern: 'line' } }] }));
|
|
43
|
-
const { provider, seen } = scripted(greedy);
|
|
44
|
-
const result = await reviewWithTools(provider, context, '', repo, {});
|
|
45
|
-
expect(result.toolCalls).toBeLessThanOrEqual(12);
|
|
46
|
-
expect(seen.at(-1)).toMatchObject({ tools: 2, toolChoice: 'none' });
|
|
47
|
-
expect(result.findings).toEqual([]);
|
|
48
|
-
});
|
|
49
|
-
it('refuses a provider that cannot call tools', async () => {
|
|
50
|
-
const provider = { name: 'local', isAvailable: async () => true, setup: async () => { }, dispose: () => { }, analyze: async () => '' };
|
|
51
|
-
await expect(reviewWithTools(provider, context, '', repo, {})).rejects.toThrow('cannot call tools');
|
|
52
|
-
});
|
|
53
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|