@rigour-labs/core 6.2.3 → 6.2.5
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/deep/code-context.d.ts +28 -0
- package/dist/deep/code-context.js +93 -0
- package/dist/deep/code-context.test.d.ts +1 -0
- package/dist/deep/code-context.test.js +48 -0
- package/dist/deep/code-pass.d.ts +15 -0
- package/dist/deep/code-pass.js +44 -0
- package/dist/deep/code-review-prompt.d.ts +17 -0
- package/dist/deep/code-review-prompt.js +30 -0
- package/dist/deep/code-review-prompt.test.d.ts +1 -0
- package/dist/deep/code-review-prompt.test.js +20 -0
- package/dist/deep/code-verifier.d.ts +19 -0
- package/dist/deep/code-verifier.js +48 -0
- package/dist/deep/code-verifier.test.d.ts +1 -0
- package/dist/deep/code-verifier.test.js +46 -0
- package/dist/deep/fact-extractor.d.ts +7 -1
- package/dist/deep/fact-extractor.js +16 -8
- package/dist/deep/fact-extractor.test.js +34 -1
- package/dist/deep/facts-pass.d.ts +24 -0
- package/dist/deep/facts-pass.js +69 -0
- package/dist/deep/index.d.ts +6 -1
- package/dist/deep/index.js +5 -1
- package/dist/deep/parse-findings.d.ts +12 -0
- package/dist/deep/parse-findings.js +73 -0
- package/dist/deep/parse-findings.test.d.ts +1 -0
- package/dist/deep/parse-findings.test.js +25 -0
- package/dist/deep/prompts.d.ts +1 -1
- package/dist/deep/prompts.js +7 -8
- package/dist/deep/prompts.test.js +15 -0
- package/dist/gates/context.js +7 -0
- package/dist/gates/deep-analysis.d.ts +31 -8
- package/dist/gates/deep-analysis.js +165 -306
- package/dist/gates/deep-analysis.test.d.ts +1 -0
- package/dist/gates/deep-analysis.test.js +86 -0
- package/dist/gates/deep-runner.d.ts +15 -0
- package/dist/gates/deep-runner.js +65 -0
- package/dist/gates/dependency.js +4 -0
- package/dist/gates/hallucinated-imports/index.js +13 -9
- package/dist/gates/hallucinated-imports.test.js +10 -0
- package/dist/gates/js-style-context.d.ts +3 -0
- package/dist/gates/js-style-context.js +65 -0
- package/dist/gates/js-style-context.test.d.ts +1 -0
- package/dist/gates/js-style-context.test.js +35 -0
- package/dist/gates/logic-drift-git-base.d.ts +7 -0
- package/dist/gates/logic-drift-git-base.js +41 -0
- package/dist/gates/logic-drift.d.ts +3 -3
- package/dist/gates/logic-drift.js +39 -7
- package/dist/gates/logic-drift.test.d.ts +1 -0
- package/dist/gates/logic-drift.test.js +45 -0
- package/dist/gates/runner.js +5 -40
- package/dist/gates/runner.test.js +37 -25
- package/dist/gates/scoped-gates.test.d.ts +1 -0
- package/dist/gates/scoped-gates.test.js +52 -0
- package/dist/gates/security-command-execution.d.ts +5 -0
- package/dist/gates/security-command-execution.js +123 -0
- package/dist/gates/security-patterns-data.js +1 -17
- package/dist/gates/security-patterns.d.ts +0 -5
- package/dist/gates/security-patterns.js +11 -19
- package/dist/gates/security-patterns.test.js +37 -2
- package/dist/gates/style-drift.d.ts +4 -4
- package/dist/gates/style-drift.js +15 -16
- package/dist/gates/style-drift.test.d.ts +1 -0
- package/dist/gates/style-drift.test.js +26 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/dist/inference/http-download.d.ts +22 -0
- package/dist/inference/http-download.js +132 -0
- package/dist/inference/http-download.test.d.ts +1 -0
- package/dist/inference/http-download.test.js +109 -0
- package/dist/inference/index.d.ts +5 -1
- package/dist/inference/index.js +2 -1
- package/dist/inference/llama-engine.d.ts +27 -0
- package/dist/inference/llama-engine.js +152 -0
- package/dist/inference/llama-engine.test.d.ts +1 -0
- package/dist/inference/llama-engine.test.js +51 -0
- package/dist/inference/llama-process.d.ts +72 -0
- package/dist/inference/llama-process.js +126 -0
- package/dist/inference/llama-process.test.d.ts +1 -0
- package/dist/inference/llama-process.test.js +61 -0
- package/dist/inference/model-download.test.d.ts +1 -0
- package/dist/inference/model-download.test.js +73 -0
- package/dist/inference/model-manager.d.ts +14 -1
- package/dist/inference/model-manager.js +65 -80
- package/dist/inference/sidecar-provider.d.ts +19 -10
- package/dist/inference/sidecar-provider.js +115 -343
- package/dist/templates/universal-config.js +0 -2
- package/dist/types/index.d.ts +58 -14
- package/dist/types/index.js +9 -2
- package/dist/utils/deep-status.d.ts +7 -0
- package/dist/utils/deep-status.js +11 -0
- package/dist/utils/diff.d.ts +3 -0
- package/dist/utils/diff.js +52 -0
- package/dist/utils/diff.test.d.ts +1 -0
- package/dist/utils/diff.test.js +38 -0
- package/dist/utils/scanner.js +13 -2
- package/dist/utils/scanner.test.js +22 -8
- package/dist/utils/scope.d.ts +15 -0
- package/dist/utils/scope.js +51 -0
- package/dist/utils/scope.test.d.ts +1 -0
- package/dist/utils/scope.test.js +38 -0
- package/package.json +6 -6
package/dist/types/index.d.ts
CHANGED
|
@@ -573,9 +573,9 @@ export declare const GatesSchema: z.ZodObject<{
|
|
|
573
573
|
model_name: z.ZodOptional<z.ZodString>;
|
|
574
574
|
model_path: z.ZodOptional<z.ZodString>;
|
|
575
575
|
threads: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
576
|
-
max_tokens: z.
|
|
576
|
+
max_tokens: z.ZodOptional<z.ZodNumber>;
|
|
577
577
|
temperature: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
578
|
-
timeout_ms: z.
|
|
578
|
+
timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
579
579
|
checks: z.ZodDefault<z.ZodOptional<z.ZodObject<{
|
|
580
580
|
solid: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
581
581
|
dry: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
@@ -609,9 +609,7 @@ export declare const GatesSchema: z.ZodObject<{
|
|
|
609
609
|
pro: boolean;
|
|
610
610
|
provider: string;
|
|
611
611
|
threads: number;
|
|
612
|
-
max_tokens: number;
|
|
613
612
|
temperature: number;
|
|
614
|
-
timeout_ms: number;
|
|
615
613
|
checks: {
|
|
616
614
|
architecture: boolean;
|
|
617
615
|
test_quality: boolean;
|
|
@@ -626,6 +624,8 @@ export declare const GatesSchema: z.ZodObject<{
|
|
|
626
624
|
api_base_url?: string | undefined;
|
|
627
625
|
model_name?: string | undefined;
|
|
628
626
|
model_path?: string | undefined;
|
|
627
|
+
max_tokens?: number | undefined;
|
|
628
|
+
timeout_ms?: number | undefined;
|
|
629
629
|
}, {
|
|
630
630
|
enabled?: boolean | undefined;
|
|
631
631
|
pro?: boolean | undefined;
|
|
@@ -655,9 +655,7 @@ export declare const GatesSchema: z.ZodObject<{
|
|
|
655
655
|
pro: boolean;
|
|
656
656
|
provider: string;
|
|
657
657
|
threads: number;
|
|
658
|
-
max_tokens: number;
|
|
659
658
|
temperature: number;
|
|
660
|
-
timeout_ms: number;
|
|
661
659
|
checks: {
|
|
662
660
|
architecture: boolean;
|
|
663
661
|
test_quality: boolean;
|
|
@@ -672,6 +670,8 @@ export declare const GatesSchema: z.ZodObject<{
|
|
|
672
670
|
api_base_url?: string | undefined;
|
|
673
671
|
model_name?: string | undefined;
|
|
674
672
|
model_path?: string | undefined;
|
|
673
|
+
max_tokens?: number | undefined;
|
|
674
|
+
timeout_ms?: number | undefined;
|
|
675
675
|
};
|
|
676
676
|
max_file_lines: number;
|
|
677
677
|
forbid_todos: boolean;
|
|
@@ -1739,9 +1739,9 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
1739
1739
|
model_name: z.ZodOptional<z.ZodString>;
|
|
1740
1740
|
model_path: z.ZodOptional<z.ZodString>;
|
|
1741
1741
|
threads: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
1742
|
-
max_tokens: z.
|
|
1742
|
+
max_tokens: z.ZodOptional<z.ZodNumber>;
|
|
1743
1743
|
temperature: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
1744
|
-
timeout_ms: z.
|
|
1744
|
+
timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
1745
1745
|
checks: z.ZodDefault<z.ZodOptional<z.ZodObject<{
|
|
1746
1746
|
solid: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
1747
1747
|
dry: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
@@ -1775,9 +1775,7 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
1775
1775
|
pro: boolean;
|
|
1776
1776
|
provider: string;
|
|
1777
1777
|
threads: number;
|
|
1778
|
-
max_tokens: number;
|
|
1779
1778
|
temperature: number;
|
|
1780
|
-
timeout_ms: number;
|
|
1781
1779
|
checks: {
|
|
1782
1780
|
architecture: boolean;
|
|
1783
1781
|
test_quality: boolean;
|
|
@@ -1792,6 +1790,8 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
1792
1790
|
api_base_url?: string | undefined;
|
|
1793
1791
|
model_name?: string | undefined;
|
|
1794
1792
|
model_path?: string | undefined;
|
|
1793
|
+
max_tokens?: number | undefined;
|
|
1794
|
+
timeout_ms?: number | undefined;
|
|
1795
1795
|
}, {
|
|
1796
1796
|
enabled?: boolean | undefined;
|
|
1797
1797
|
pro?: boolean | undefined;
|
|
@@ -1821,9 +1821,7 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
1821
1821
|
pro: boolean;
|
|
1822
1822
|
provider: string;
|
|
1823
1823
|
threads: number;
|
|
1824
|
-
max_tokens: number;
|
|
1825
1824
|
temperature: number;
|
|
1826
|
-
timeout_ms: number;
|
|
1827
1825
|
checks: {
|
|
1828
1826
|
architecture: boolean;
|
|
1829
1827
|
test_quality: boolean;
|
|
@@ -1838,6 +1836,8 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
1838
1836
|
api_base_url?: string | undefined;
|
|
1839
1837
|
model_name?: string | undefined;
|
|
1840
1838
|
model_path?: string | undefined;
|
|
1839
|
+
max_tokens?: number | undefined;
|
|
1840
|
+
timeout_ms?: number | undefined;
|
|
1841
1841
|
};
|
|
1842
1842
|
max_file_lines: number;
|
|
1843
1843
|
forbid_todos: boolean;
|
|
@@ -2319,9 +2319,7 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
2319
2319
|
pro: boolean;
|
|
2320
2320
|
provider: string;
|
|
2321
2321
|
threads: number;
|
|
2322
|
-
max_tokens: number;
|
|
2323
2322
|
temperature: number;
|
|
2324
|
-
timeout_ms: number;
|
|
2325
2323
|
checks: {
|
|
2326
2324
|
architecture: boolean;
|
|
2327
2325
|
test_quality: boolean;
|
|
@@ -2336,6 +2334,8 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
2336
2334
|
api_base_url?: string | undefined;
|
|
2337
2335
|
model_name?: string | undefined;
|
|
2338
2336
|
model_path?: string | undefined;
|
|
2337
|
+
max_tokens?: number | undefined;
|
|
2338
|
+
timeout_ms?: number | undefined;
|
|
2339
2339
|
};
|
|
2340
2340
|
max_file_lines: number;
|
|
2341
2341
|
forbid_todos: boolean;
|
|
@@ -2944,26 +2944,45 @@ export declare const ReportSchema: z.ZodObject<{
|
|
|
2944
2944
|
}>>;
|
|
2945
2945
|
deep: z.ZodOptional<z.ZodObject<{
|
|
2946
2946
|
enabled: z.ZodBoolean;
|
|
2947
|
+
/** ok: every inference ran; partial: some failed; error: deep did not run. */
|
|
2948
|
+
status: z.ZodOptional<z.ZodEnum<["ok", "partial", "error"]>>;
|
|
2949
|
+
mode: z.ZodOptional<z.ZodEnum<["facts", "code"]>>;
|
|
2947
2950
|
tier: z.ZodOptional<z.ZodEnum<["deep", "lite", "legacy", "cloud"]>>;
|
|
2948
2951
|
model: z.ZodOptional<z.ZodString>;
|
|
2952
|
+
model_fallback: z.ZodOptional<z.ZodBoolean>;
|
|
2949
2953
|
total_ms: z.ZodOptional<z.ZodNumber>;
|
|
2950
2954
|
files_analyzed: z.ZodOptional<z.ZodNumber>;
|
|
2955
|
+
chunks_total: z.ZodOptional<z.ZodNumber>;
|
|
2956
|
+
chunks_failed: z.ZodOptional<z.ZodNumber>;
|
|
2957
|
+
error: z.ZodOptional<z.ZodString>;
|
|
2951
2958
|
findings_count: z.ZodOptional<z.ZodNumber>;
|
|
2952
2959
|
findings_verified: z.ZodOptional<z.ZodNumber>;
|
|
2953
2960
|
}, "strip", z.ZodTypeAny, {
|
|
2954
2961
|
enabled: boolean;
|
|
2962
|
+
status?: "ok" | "partial" | "error" | undefined;
|
|
2963
|
+
mode?: "code" | "facts" | undefined;
|
|
2964
|
+
error?: string | undefined;
|
|
2955
2965
|
tier?: "deep" | "lite" | "legacy" | "cloud" | undefined;
|
|
2956
2966
|
model?: string | undefined;
|
|
2967
|
+
model_fallback?: boolean | undefined;
|
|
2957
2968
|
total_ms?: number | undefined;
|
|
2958
2969
|
files_analyzed?: number | undefined;
|
|
2970
|
+
chunks_total?: number | undefined;
|
|
2971
|
+
chunks_failed?: number | undefined;
|
|
2959
2972
|
findings_count?: number | undefined;
|
|
2960
2973
|
findings_verified?: number | undefined;
|
|
2961
2974
|
}, {
|
|
2962
2975
|
enabled: boolean;
|
|
2976
|
+
status?: "ok" | "partial" | "error" | undefined;
|
|
2977
|
+
mode?: "code" | "facts" | undefined;
|
|
2978
|
+
error?: string | undefined;
|
|
2963
2979
|
tier?: "deep" | "lite" | "legacy" | "cloud" | undefined;
|
|
2964
2980
|
model?: string | undefined;
|
|
2981
|
+
model_fallback?: boolean | undefined;
|
|
2965
2982
|
total_ms?: number | undefined;
|
|
2966
2983
|
files_analyzed?: number | undefined;
|
|
2984
|
+
chunks_total?: number | undefined;
|
|
2985
|
+
chunks_failed?: number | undefined;
|
|
2967
2986
|
findings_count?: number | undefined;
|
|
2968
2987
|
findings_verified?: number | undefined;
|
|
2969
2988
|
}>>;
|
|
@@ -2971,10 +2990,16 @@ export declare const ReportSchema: z.ZodObject<{
|
|
|
2971
2990
|
duration_ms: number;
|
|
2972
2991
|
deep?: {
|
|
2973
2992
|
enabled: boolean;
|
|
2993
|
+
status?: "ok" | "partial" | "error" | undefined;
|
|
2994
|
+
mode?: "code" | "facts" | undefined;
|
|
2995
|
+
error?: string | undefined;
|
|
2974
2996
|
tier?: "deep" | "lite" | "legacy" | "cloud" | undefined;
|
|
2975
2997
|
model?: string | undefined;
|
|
2998
|
+
model_fallback?: boolean | undefined;
|
|
2976
2999
|
total_ms?: number | undefined;
|
|
2977
3000
|
files_analyzed?: number | undefined;
|
|
3001
|
+
chunks_total?: number | undefined;
|
|
3002
|
+
chunks_failed?: number | undefined;
|
|
2978
3003
|
findings_count?: number | undefined;
|
|
2979
3004
|
findings_verified?: number | undefined;
|
|
2980
3005
|
} | undefined;
|
|
@@ -2994,10 +3019,16 @@ export declare const ReportSchema: z.ZodObject<{
|
|
|
2994
3019
|
duration_ms: number;
|
|
2995
3020
|
deep?: {
|
|
2996
3021
|
enabled: boolean;
|
|
3022
|
+
status?: "ok" | "partial" | "error" | undefined;
|
|
3023
|
+
mode?: "code" | "facts" | undefined;
|
|
3024
|
+
error?: string | undefined;
|
|
2997
3025
|
tier?: "deep" | "lite" | "legacy" | "cloud" | undefined;
|
|
2998
3026
|
model?: string | undefined;
|
|
3027
|
+
model_fallback?: boolean | undefined;
|
|
2999
3028
|
total_ms?: number | undefined;
|
|
3000
3029
|
files_analyzed?: number | undefined;
|
|
3030
|
+
chunks_total?: number | undefined;
|
|
3031
|
+
chunks_failed?: number | undefined;
|
|
3001
3032
|
findings_count?: number | undefined;
|
|
3002
3033
|
findings_verified?: number | undefined;
|
|
3003
3034
|
} | undefined;
|
|
@@ -3019,10 +3050,16 @@ export declare const ReportSchema: z.ZodObject<{
|
|
|
3019
3050
|
duration_ms: number;
|
|
3020
3051
|
deep?: {
|
|
3021
3052
|
enabled: boolean;
|
|
3053
|
+
status?: "ok" | "partial" | "error" | undefined;
|
|
3054
|
+
mode?: "code" | "facts" | undefined;
|
|
3055
|
+
error?: string | undefined;
|
|
3022
3056
|
tier?: "deep" | "lite" | "legacy" | "cloud" | undefined;
|
|
3023
3057
|
model?: string | undefined;
|
|
3058
|
+
model_fallback?: boolean | undefined;
|
|
3024
3059
|
total_ms?: number | undefined;
|
|
3025
3060
|
files_analyzed?: number | undefined;
|
|
3061
|
+
chunks_total?: number | undefined;
|
|
3062
|
+
chunks_failed?: number | undefined;
|
|
3026
3063
|
findings_count?: number | undefined;
|
|
3027
3064
|
findings_verified?: number | undefined;
|
|
3028
3065
|
} | undefined;
|
|
@@ -3061,10 +3098,16 @@ export declare const ReportSchema: z.ZodObject<{
|
|
|
3061
3098
|
duration_ms: number;
|
|
3062
3099
|
deep?: {
|
|
3063
3100
|
enabled: boolean;
|
|
3101
|
+
status?: "ok" | "partial" | "error" | undefined;
|
|
3102
|
+
mode?: "code" | "facts" | undefined;
|
|
3103
|
+
error?: string | undefined;
|
|
3064
3104
|
tier?: "deep" | "lite" | "legacy" | "cloud" | undefined;
|
|
3065
3105
|
model?: string | undefined;
|
|
3106
|
+
model_fallback?: boolean | undefined;
|
|
3066
3107
|
total_ms?: number | undefined;
|
|
3067
3108
|
files_analyzed?: number | undefined;
|
|
3109
|
+
chunks_total?: number | undefined;
|
|
3110
|
+
chunks_failed?: number | undefined;
|
|
3068
3111
|
findings_count?: number | undefined;
|
|
3069
3112
|
findings_verified?: number | undefined;
|
|
3070
3113
|
} | undefined;
|
|
@@ -3110,4 +3153,5 @@ export interface DeepOptions {
|
|
|
3110
3153
|
modelName?: string;
|
|
3111
3154
|
agents?: number;
|
|
3112
3155
|
maxFiles?: number;
|
|
3156
|
+
focusLines?: Record<string, number[]>;
|
|
3113
3157
|
}
|
package/dist/types/index.js
CHANGED
|
@@ -303,9 +303,9 @@ export const GatesSchema = z.object({
|
|
|
303
303
|
model_name: z.string().optional(), // cloud model name override (e.g. 'gpt-4o', 'claude-sonnet-4-5-20250929', 'gemini-pro')
|
|
304
304
|
model_path: z.string().optional(), // custom local GGUF model path override
|
|
305
305
|
threads: z.number().optional().default(4),
|
|
306
|
-
max_tokens: z.number().optional()
|
|
306
|
+
max_tokens: z.number().optional(), // default per provider: local 1024, cloud 4096
|
|
307
307
|
temperature: z.number().optional().default(0.1),
|
|
308
|
-
timeout_ms: z.number().optional()
|
|
308
|
+
timeout_ms: z.number().optional(), // per inference call; default per provider: local 60s, cloud 120s
|
|
309
309
|
checks: z.object({
|
|
310
310
|
solid: z.boolean().optional().default(true),
|
|
311
311
|
dry: z.boolean().optional().default(true),
|
|
@@ -402,10 +402,17 @@ export const ReportSchema = z.object({
|
|
|
402
402
|
}).optional(),
|
|
403
403
|
deep: z.object({
|
|
404
404
|
enabled: z.boolean(),
|
|
405
|
+
/** ok: every inference ran; partial: some failed; error: deep did not run. */
|
|
406
|
+
status: z.enum(['ok', 'partial', 'error']).optional(),
|
|
407
|
+
mode: z.enum(['facts', 'code']).optional(),
|
|
405
408
|
tier: z.enum(['deep', 'lite', 'legacy', 'cloud']).optional(),
|
|
406
409
|
model: z.string().optional(),
|
|
410
|
+
model_fallback: z.boolean().optional(),
|
|
407
411
|
total_ms: z.number().optional(),
|
|
408
412
|
files_analyzed: z.number().optional(),
|
|
413
|
+
chunks_total: z.number().optional(),
|
|
414
|
+
chunks_failed: z.number().optional(),
|
|
415
|
+
error: z.string().optional(),
|
|
409
416
|
findings_count: z.number().optional(),
|
|
410
417
|
findings_verified: z.number().optional(),
|
|
411
418
|
}).optional(),
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Report } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Why deep analysis did not run, or undefined when it ran (fully or
|
|
4
|
+
* partially) or was not requested. Callers use this to fail loudly instead
|
|
5
|
+
* of presenting an empty deep result as a clean pass.
|
|
6
|
+
*/
|
|
7
|
+
export declare function deepAnalysisError(report: Pick<Report, 'stats'>): string | undefined;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Why deep analysis did not run, or undefined when it ran (fully or
|
|
3
|
+
* partially) or was not requested. Callers use this to fail loudly instead
|
|
4
|
+
* of presenting an empty deep result as a clean pass.
|
|
5
|
+
*/
|
|
6
|
+
export function deepAnalysisError(report) {
|
|
7
|
+
const deep = report.stats.deep;
|
|
8
|
+
if (deep?.status !== 'error')
|
|
9
|
+
return undefined;
|
|
10
|
+
return deep.error || 'unknown error';
|
|
11
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export function parseDiff(diff) {
|
|
2
|
+
const state = { mapping: {}, file: '', newLine: 0, oldLeft: 0, newLeft: 0 };
|
|
3
|
+
for (const line of diff.split('\n')) {
|
|
4
|
+
if (state.oldLeft > 0 || state.newLeft > 0)
|
|
5
|
+
readHunkLine(state, line);
|
|
6
|
+
else
|
|
7
|
+
readHeaderLine(state, line);
|
|
8
|
+
}
|
|
9
|
+
return state.mapping;
|
|
10
|
+
}
|
|
11
|
+
function readHunkLine(state, line) {
|
|
12
|
+
if (line.startsWith('\\'))
|
|
13
|
+
return; // ""
|
|
14
|
+
if (line.startsWith('-')) {
|
|
15
|
+
state.oldLeft--;
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (line.startsWith('+')) {
|
|
19
|
+
if (state.file)
|
|
20
|
+
state.mapping[state.file].add(state.newLine);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
state.oldLeft--;
|
|
24
|
+
}
|
|
25
|
+
state.newLine++;
|
|
26
|
+
state.newLeft--;
|
|
27
|
+
}
|
|
28
|
+
function readHeaderLine(state, line) {
|
|
29
|
+
if (line.startsWith('diff --git ')) {
|
|
30
|
+
state.file = '';
|
|
31
|
+
}
|
|
32
|
+
else if (line.startsWith('+++ ')) {
|
|
33
|
+
state.file = line.startsWith('+++ b/') ? line.slice(6).trim() : '';
|
|
34
|
+
if (state.file)
|
|
35
|
+
state.mapping[state.file] ??= new Set();
|
|
36
|
+
}
|
|
37
|
+
else if (line.startsWith('@@')) {
|
|
38
|
+
readHunkHeader(state, line);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function readHunkHeader(state, line) {
|
|
42
|
+
const hunk = line.match(/^@@ -\d+(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
|
|
43
|
+
if (!hunk)
|
|
44
|
+
return;
|
|
45
|
+
state.oldLeft = hunk[1] === undefined ? 1 : parseInt(hunk[1], 10);
|
|
46
|
+
state.newLine = parseInt(hunk[2], 10);
|
|
47
|
+
state.newLeft = hunk[3] === undefined ? 1 : parseInt(hunk[3], 10);
|
|
48
|
+
}
|
|
49
|
+
/** Changed lines as sorted arrays, the shape DeepOptions.focusLines takes. */
|
|
50
|
+
export function changedLinesByFile(mapping) {
|
|
51
|
+
return Object.fromEntries(Object.entries(mapping).map(([file, lines]) => [file, [...lines].sort((a, b) => a - b)]));
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { changedLinesByFile, parseDiff } from './diff.js';
|
|
3
|
+
const lines = (m) => changedLinesByFile(m);
|
|
4
|
+
describe('parseDiff', () => {
|
|
5
|
+
it('maps added lines to new-side line numbers', () => {
|
|
6
|
+
const diff = [
|
|
7
|
+
'diff --git a/src/a.ts b/src/a.ts',
|
|
8
|
+
'--- a/src/a.ts',
|
|
9
|
+
'+++ b/src/a.ts',
|
|
10
|
+
'@@ -1,3 +1,4 @@',
|
|
11
|
+
' const a = 1;',
|
|
12
|
+
'-const b = 2;',
|
|
13
|
+
'+const b = 3;',
|
|
14
|
+
'+const c = 4;',
|
|
15
|
+
' export { a };',
|
|
16
|
+
].join('\n');
|
|
17
|
+
expect(lines(parseDiff(diff))).toEqual({ 'src/a.ts': [2, 3] });
|
|
18
|
+
});
|
|
19
|
+
it('handles several files and hunks', () => {
|
|
20
|
+
const diff = [
|
|
21
|
+
'+++ b/a.ts', '@@ -10,2 +10,3 @@', ' x', '+y', ' z',
|
|
22
|
+
'+++ b/b.ts', '@@ -1 +1 @@', '-old', '+new',
|
|
23
|
+
].join('\n');
|
|
24
|
+
expect(lines(parseDiff(diff))).toEqual({ 'a.ts': [11], 'b.ts': [1] });
|
|
25
|
+
});
|
|
26
|
+
it('does not mistake content lines starting with +++ or --- for headers', () => {
|
|
27
|
+
const diff = ['+++ b/a.ts', '@@ -1,2 +1,3 @@', ' let i = 0;', '+++i;', '---j;', ' done();'].join('\n');
|
|
28
|
+
expect(lines(parseDiff(diff))).toEqual({ 'a.ts': [2] });
|
|
29
|
+
});
|
|
30
|
+
it('does not count "No newline at end of file" as a line', () => {
|
|
31
|
+
const diff = ['+++ b/a.ts', '@@ -1,1 +1,2 @@', ' a', '\', '+b'].join('\n');
|
|
32
|
+
expect(lines(parseDiff(diff))).toEqual({ 'a.ts': [2] });
|
|
33
|
+
});
|
|
34
|
+
it('ignores deleted files', () => {
|
|
35
|
+
const diff = ['diff --git a/gone.ts b/gone.ts', '--- a/gone.ts', '+++ /dev/null', '@@ -1,2 +0,0 @@', '-a', '-b'].join('\n');
|
|
36
|
+
expect(parseDiff(diff)).toEqual({});
|
|
37
|
+
});
|
|
38
|
+
});
|
package/dist/utils/scanner.js
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import { globby } from 'globby';
|
|
2
2
|
import fs from 'fs-extra';
|
|
3
3
|
import path from 'path';
|
|
4
|
+
/**
|
|
5
|
+
* Glob patterns use `/` as the separator and `\` as the escape character.
|
|
6
|
+
* Only on Windows can a backslash be a path separator, and even there one
|
|
7
|
+
* that escapes a glob character (`\[` in `app/\[key\]/route.ts`) must stay.
|
|
8
|
+
* Same rule as fast-glob's convertPathToPattern for Windows paths.
|
|
9
|
+
*/
|
|
10
|
+
function toGlobSeparators(pattern) {
|
|
11
|
+
if (process.platform !== 'win32')
|
|
12
|
+
return pattern;
|
|
13
|
+
return pattern.replace(/\\(?![!()+@[\]{}])/g, '/');
|
|
14
|
+
}
|
|
4
15
|
export class FileScanner {
|
|
5
16
|
static DEFAULT_PATTERNS = ['**/*.{ts,tsx,js,jsx,mjs,cjs,py,go,rs,rb,cs,java,kt,css,html,md,yaml,yml,toml,json}'];
|
|
6
17
|
static DEFAULT_IGNORE = [
|
|
@@ -18,9 +29,9 @@ export class FileScanner {
|
|
|
18
29
|
'rigour-report.json'
|
|
19
30
|
];
|
|
20
31
|
static async findFiles(options) {
|
|
21
|
-
const patterns = (options.patterns || this.DEFAULT_PATTERNS).map(
|
|
32
|
+
const patterns = (options.patterns || this.DEFAULT_PATTERNS).map(toGlobSeparators);
|
|
22
33
|
const userIgnore = options.ignore || [];
|
|
23
|
-
const ignore = [...new Set([...this.DEFAULT_IGNORE, ...userIgnore])].map(
|
|
34
|
+
const ignore = [...new Set([...this.DEFAULT_IGNORE, ...userIgnore])].map(toGlobSeparators);
|
|
24
35
|
const normalizedCwd = options.cwd.replace(/\\/g, '/');
|
|
25
36
|
return globby(patterns, {
|
|
26
37
|
cwd: normalizedCwd,
|
|
@@ -16,14 +16,28 @@ describe('FileScanner', () => {
|
|
|
16
16
|
expect(ignore).toContain('**/node_modules/**');
|
|
17
17
|
expect(ignore).toContain('custom-ignore');
|
|
18
18
|
});
|
|
19
|
-
it('should normalize paths to forward slashes', async () => {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
it('should normalize Windows paths to forward slashes', async () => {
|
|
20
|
+
const platform = Object.getOwnPropertyDescriptor(process, 'platform');
|
|
21
|
+
Object.defineProperty(process, 'platform', { value: 'win32' });
|
|
22
|
+
try {
|
|
23
|
+
await FileScanner.findFiles({ cwd: 'C:\\test\\path', patterns: ['**\\*.ts', 'app\\\\[key\\]\\route.ts'] });
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
Object.defineProperty(process, 'platform', platform);
|
|
27
|
+
}
|
|
28
|
+
const call = vi.mocked(globby).mock.calls.at(-1);
|
|
29
|
+
expect(call[0]).toEqual(['**/*.ts', 'app/\\[key\\]/route.ts']);
|
|
27
30
|
expect(call[1]?.cwd).toBe('C:/test/path');
|
|
28
31
|
});
|
|
32
|
+
it('should keep glob escapes on POSIX', async () => {
|
|
33
|
+
const platform = Object.getOwnPropertyDescriptor(process, 'platform');
|
|
34
|
+
Object.defineProperty(process, 'platform', { value: 'linux' });
|
|
35
|
+
try {
|
|
36
|
+
await FileScanner.findFiles({ cwd: '/repo', patterns: ['src/app/\\[key\\]/route.ts'] });
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
Object.defineProperty(process, 'platform', platform);
|
|
40
|
+
}
|
|
41
|
+
expect(vi.mocked(globby).mock.calls.at(-1)[0]).toEqual(['src/app/\\[key\\]/route.ts']);
|
|
42
|
+
});
|
|
29
43
|
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Convert CLI path arguments into cwd-relative, escaped glob patterns. */
|
|
2
|
+
export declare function normalizeScopePatterns(cwd: string, inputs: string[]): Promise<string[]>;
|
|
3
|
+
/** True when a gate context carries an explicit file scope. */
|
|
4
|
+
export declare function isScoped(patterns: string[] | undefined): patterns is string[];
|
|
5
|
+
/** True when any of `files` is in the scoped file set (paths compared cwd-relative). */
|
|
6
|
+
export declare function touchesScope(files: string[] | undefined, scopedFiles: Set<string>): boolean;
|
|
7
|
+
/** The concrete cwd-relative files matched by a scoped run's patterns. */
|
|
8
|
+
export declare function resolveScopedFiles(cwd: string, patterns: string[], ignore?: string[]): Promise<Set<string>>;
|
|
9
|
+
/** True when a scoped run does not include `file` (a manifest such as package.json). */
|
|
10
|
+
export declare function scopeExcludes(context: {
|
|
11
|
+
cwd: string;
|
|
12
|
+
patterns?: string[];
|
|
13
|
+
ignore?: string[];
|
|
14
|
+
}, file: string): Promise<boolean>;
|
|
15
|
+
export declare function toPosix(p: string): string;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File scope for `rigour check <paths...>` and `rigour review`.
|
|
3
|
+
*
|
|
4
|
+
* CLI inputs may be absolute, relative or directories. Gates glob with
|
|
5
|
+
* globby, so each input becomes a cwd-relative glob with glob-special
|
|
6
|
+
* characters escaped (Next.js routes such as `app/[key]/route.ts` would
|
|
7
|
+
* otherwise be read as a character class).
|
|
8
|
+
*/
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import fs from 'fs-extra';
|
|
11
|
+
import { convertPathToPattern } from 'globby';
|
|
12
|
+
import { FileScanner } from './scanner.js';
|
|
13
|
+
/** Convert CLI path arguments into cwd-relative, escaped glob patterns. */
|
|
14
|
+
export async function normalizeScopePatterns(cwd, inputs) {
|
|
15
|
+
const patterns = [];
|
|
16
|
+
for (const input of inputs) {
|
|
17
|
+
const absolute = path.resolve(cwd, input);
|
|
18
|
+
const relative = toPosix(path.relative(cwd, absolute)) || '.';
|
|
19
|
+
const isDirectory = await fs.stat(absolute).then(s => s.isDirectory()).catch(() => false);
|
|
20
|
+
if (!isDirectory && !(await fs.pathExists(absolute))) {
|
|
21
|
+
// Not a path on disk: keep it as the glob the user wrote.
|
|
22
|
+
patterns.push(toPosix(input));
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const escaped = relative === '.' ? '' : convertPathToPattern(relative);
|
|
26
|
+
patterns.push(isDirectory ? (escaped ? `${escaped}/**/*` : '**/*') : escaped);
|
|
27
|
+
}
|
|
28
|
+
return patterns;
|
|
29
|
+
}
|
|
30
|
+
/** True when a gate context carries an explicit file scope. */
|
|
31
|
+
export function isScoped(patterns) {
|
|
32
|
+
return Array.isArray(patterns) && patterns.length > 0;
|
|
33
|
+
}
|
|
34
|
+
/** True when any of `files` is in the scoped file set (paths compared cwd-relative). */
|
|
35
|
+
export function touchesScope(files, scopedFiles) {
|
|
36
|
+
return (files ?? []).some(f => scopedFiles.has(toPosix(f).replace(/^\.\//, '')));
|
|
37
|
+
}
|
|
38
|
+
/** The concrete cwd-relative files matched by a scoped run's patterns. */
|
|
39
|
+
export async function resolveScopedFiles(cwd, patterns, ignore) {
|
|
40
|
+
const files = await FileScanner.findFiles({ cwd, patterns, ignore });
|
|
41
|
+
return new Set(files.map(toPosix));
|
|
42
|
+
}
|
|
43
|
+
/** True when a scoped run does not include `file` (a manifest such as package.json). */
|
|
44
|
+
export async function scopeExcludes(context, file) {
|
|
45
|
+
if (!isScoped(context.patterns))
|
|
46
|
+
return false;
|
|
47
|
+
return !(await resolveScopedFiles(context.cwd, context.patterns, context.ignore)).has(file);
|
|
48
|
+
}
|
|
49
|
+
export function toPosix(p) {
|
|
50
|
+
return p.replace(/\\/g, '/');
|
|
51
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { isScoped, normalizeScopePatterns, resolveScopedFiles, touchesScope } from './scope.js';
|
|
6
|
+
describe('scope', () => {
|
|
7
|
+
let cwd;
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
cwd = await fs.mkdtemp(path.join(os.tmpdir(), 'rigour-scope-'));
|
|
10
|
+
await fs.outputFile(path.join(cwd, 'src/app/[key]/route.ts'), 'export {}');
|
|
11
|
+
await fs.outputFile(path.join(cwd, 'src/app/k/route.ts'), 'export {}');
|
|
12
|
+
await fs.outputFile(path.join(cwd, 'src/lib/a.ts'), 'export {}');
|
|
13
|
+
});
|
|
14
|
+
afterEach(async () => { await fs.remove(cwd); });
|
|
15
|
+
it('turns absolute, relative and directory inputs into cwd-relative patterns', async () => {
|
|
16
|
+
const patterns = await normalizeScopePatterns(cwd, [path.join(cwd, 'src/lib/a.ts'), './src/lib', 'src/lib/a.ts']);
|
|
17
|
+
expect(patterns).toEqual(['src/lib/a.ts', 'src/lib/**/*', 'src/lib/a.ts']);
|
|
18
|
+
});
|
|
19
|
+
it('escapes glob characters so a Next.js [key] route matches only itself', async () => {
|
|
20
|
+
const patterns = await normalizeScopePatterns(cwd, ['src/app/[key]/route.ts']);
|
|
21
|
+
expect([...await resolveScopedFiles(cwd, patterns)]).toEqual(['src/app/[key]/route.ts']);
|
|
22
|
+
});
|
|
23
|
+
it('keeps a non-existent input as the glob the user wrote', async () => {
|
|
24
|
+
expect(await normalizeScopePatterns(cwd, ['src/**/*.ts'])).toEqual(['src/**/*.ts']);
|
|
25
|
+
});
|
|
26
|
+
it('treats the repo root as everything', async () => {
|
|
27
|
+
expect(await normalizeScopePatterns(cwd, ['.'])).toEqual(['**/*']);
|
|
28
|
+
});
|
|
29
|
+
it('detects scoped runs and scope membership', () => {
|
|
30
|
+
expect(isScoped(undefined)).toBe(false);
|
|
31
|
+
expect(isScoped([])).toBe(false);
|
|
32
|
+
expect(isScoped(['a.ts'])).toBe(true);
|
|
33
|
+
const scoped = new Set(['src/lib/a.ts']);
|
|
34
|
+
expect(touchesScope(['./src/lib/a.ts', 'b.ts'], scoped)).toBe(true);
|
|
35
|
+
expect(touchesScope(['b.ts'], scoped)).toBe(false);
|
|
36
|
+
expect(touchesScope(undefined, scoped)).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rigour-labs/core",
|
|
3
|
-
"version": "6.2.
|
|
3
|
+
"version": "6.2.5",
|
|
4
4
|
"description": "AI-native quality gate engine with local Bayesian learning. AST analysis, drift detection, Fix Packet generation, and agent self-healing across TypeScript, JavaScript, Python, Go, Ruby, and C#.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://rigour.run",
|
|
@@ -67,11 +67,11 @@
|
|
|
67
67
|
"pg": "^8.16.3",
|
|
68
68
|
"sqlite3": "^5.1.7",
|
|
69
69
|
"openai": "^4.104.0",
|
|
70
|
-
"@rigour-labs/brain-darwin-
|
|
71
|
-
"@rigour-labs/brain-darwin-
|
|
72
|
-
"@rigour-labs/brain-linux-arm64": "6.2.
|
|
73
|
-
"@rigour-labs/brain-win-x64": "6.2.
|
|
74
|
-
"@rigour-labs/brain-linux-x64": "6.2.
|
|
70
|
+
"@rigour-labs/brain-darwin-arm64": "6.2.5",
|
|
71
|
+
"@rigour-labs/brain-darwin-x64": "6.2.5",
|
|
72
|
+
"@rigour-labs/brain-linux-arm64": "6.2.5",
|
|
73
|
+
"@rigour-labs/brain-win-x64": "6.2.5",
|
|
74
|
+
"@rigour-labs/brain-linux-x64": "6.2.5"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
77
|
"@types/fs-extra": "^11.0.4",
|