@rigour-labs/core 6.6.6 → 6.7.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.
Files changed (133) hide show
  1. package/README.md +16 -92
  2. package/dist/environment.test.js +0 -4
  3. package/dist/gates/agent-team.d.ts +0 -2
  4. package/dist/gates/agent-team.js +0 -8
  5. package/dist/gates/checkpoint.d.ts +0 -1
  6. package/dist/gates/checkpoint.js +0 -1
  7. package/dist/gates/context.d.ts +0 -4
  8. package/dist/gates/context.js +7 -17
  9. package/dist/gates/deep-analysis.d.ts +0 -1
  10. package/dist/gates/deep-runner.js +0 -1
  11. package/dist/gates/frontend-secret-exposure.test.js +2 -2
  12. package/dist/gates/hallucinated-imports/index.d.ts +0 -2
  13. package/dist/gates/hallucinated-imports/index.js +2 -2
  14. package/dist/gates/hallucinated-imports/js-resolver.js +1 -0
  15. package/dist/gates/hallucinated-imports.test.js +10 -0
  16. package/dist/gates/runner.js +3 -4
  17. package/dist/gates/test-quality-matchers.d.ts +0 -4
  18. package/dist/gates/test-quality-matchers.js +0 -7
  19. package/dist/gates/test-quality.d.ts +0 -2
  20. package/dist/gates/test-quality.js +1 -10
  21. package/dist/hooks/checker.js +1 -1
  22. package/dist/hooks/index.d.ts +1 -2
  23. package/dist/hooks/index.js +0 -1
  24. package/dist/hooks/types.d.ts +0 -14
  25. package/dist/hooks/types.js +1 -15
  26. package/dist/index.d.ts +6 -1
  27. package/dist/index.js +6 -1
  28. package/dist/inference/cloud-provider.d.ts +2 -0
  29. package/dist/inference/cloud-provider.js +16 -6
  30. package/dist/inference/cloud-provider.test.js +21 -0
  31. package/dist/pattern-index/embeddings.d.ts +0 -5
  32. package/dist/pattern-index/embeddings.js +11 -4
  33. package/dist/pattern-index/semantic-runtime.d.ts +10 -0
  34. package/dist/pattern-index/semantic-runtime.js +46 -0
  35. package/dist/pattern-index/semantic-runtime.test.d.ts +1 -0
  36. package/dist/pattern-index/semantic-runtime.test.js +31 -0
  37. package/dist/review/backtest-judges.d.ts +38 -0
  38. package/dist/review/backtest-judges.js +63 -0
  39. package/dist/review/backtest-judges.test.d.ts +1 -0
  40. package/dist/review/backtest-judges.test.js +32 -0
  41. package/dist/review/backtest.d.ts +9 -4
  42. package/dist/review/backtest.js +19 -9
  43. package/dist/review/backtest.test.js +2 -2
  44. package/dist/review/baseline.js +2 -1
  45. package/dist/review/dead-code.test.js +7 -0
  46. package/dist/review/fix-scope.d.ts +21 -0
  47. package/dist/review/fix-scope.js +94 -0
  48. package/dist/review/fix-scope.test.d.ts +1 -0
  49. package/dist/review/fix-scope.test.js +104 -0
  50. package/dist/review/lint-overlay.js +1 -1
  51. package/dist/review/orphan-files.js +3 -2
  52. package/dist/review/partial-wiring.js +5 -3
  53. package/dist/review/query-patterns.js +3 -2
  54. package/dist/review/review.js +2 -1
  55. package/dist/review/reviewer/adapters.d.ts +23 -7
  56. package/dist/review/reviewer/adapters.js +32 -7
  57. package/dist/review/reviewer/adapters.test.d.ts +1 -0
  58. package/dist/review/reviewer/adapters.test.js +23 -0
  59. package/dist/review/reviewer/background.d.ts +8 -1
  60. package/dist/review/reviewer/background.js +34 -9
  61. package/dist/review/reviewer/background.test.js +16 -2
  62. package/dist/review/reviewer/consensus.d.ts +36 -0
  63. package/dist/review/reviewer/consensus.js +144 -0
  64. package/dist/review/reviewer/context.d.ts +75 -0
  65. package/dist/review/reviewer/context.js +140 -0
  66. package/dist/review/reviewer/context.test.d.ts +1 -0
  67. package/dist/review/reviewer/context.test.js +18 -0
  68. package/dist/review/reviewer/exec.js +6 -2
  69. package/dist/review/reviewer/exec.test.d.ts +1 -0
  70. package/dist/review/reviewer/exec.test.js +23 -0
  71. package/dist/review/reviewer/inputs.d.ts +2 -0
  72. package/dist/review/reviewer/inputs.js +5 -1
  73. package/dist/review/reviewer/panel.d.ts +67 -0
  74. package/dist/review/reviewer/panel.js +101 -0
  75. package/dist/review/reviewer/panel.test.d.ts +1 -0
  76. package/dist/review/reviewer/panel.test.js +110 -0
  77. package/dist/review/reviewer/prompt.d.ts +11 -0
  78. package/dist/review/reviewer/prompt.js +26 -4
  79. package/dist/review/reviewer/settings.d.ts +58 -0
  80. package/dist/review/reviewer/settings.js +152 -0
  81. package/dist/review/reviewer/settings.test.d.ts +1 -0
  82. package/dist/review/reviewer/settings.test.js +57 -0
  83. package/dist/review/reviewer/store.d.ts +25 -2
  84. package/dist/review/reviewer/store.js +43 -1
  85. package/dist/review/reviewer/usage.d.ts +2 -0
  86. package/dist/review/reviewer/usage.js +28 -0
  87. package/dist/review/reviewer/usage.test.d.ts +1 -0
  88. package/dist/review/reviewer/usage.test.js +14 -0
  89. package/dist/review/reviewer/verdict.d.ts +15 -1
  90. package/dist/review/reviewer/verdict.js +17 -7
  91. package/dist/review/reviewer.d.ts +45 -2
  92. package/dist/review/reviewer.js +186 -25
  93. package/dist/review/reviewer.test.js +127 -12
  94. package/dist/review/test-files.d.ts +5 -1
  95. package/dist/review/test-files.js +6 -2
  96. package/dist/review/toolchain.js +10 -3
  97. package/dist/review/toolchain.test.js +6 -3
  98. package/dist/review/typed/program.d.ts +0 -1
  99. package/dist/review/typed/program.js +3 -3
  100. package/dist/review/typed/redundancy.js +43 -4
  101. package/dist/review/typed/redundancy.test.js +58 -0
  102. package/dist/review/typed/schema-nullability.d.ts +6 -0
  103. package/dist/review/typed/schema-nullability.js +218 -0
  104. package/dist/review/typed/schema-nullability.test.d.ts +1 -0
  105. package/dist/review/typed/schema-nullability.test.js +63 -0
  106. package/dist/review/unused-exports.js +5 -6
  107. package/dist/semantic/learn/types.d.ts +2 -2
  108. package/dist/services/adaptive-thresholds.d.ts +2 -52
  109. package/dist/services/adaptive-thresholds.js +2 -147
  110. package/dist/services/adaptive-thresholds.test.js +1 -81
  111. package/dist/settings.d.ts +14 -6
  112. package/dist/settings.js +0 -12
  113. package/dist/storage/team-diagnostics.js +1 -1
  114. package/dist/storage/team-schema.d.ts +1 -1
  115. package/dist/storage/team-schema.js +2 -0
  116. package/dist/storage/team-store.js +26 -3
  117. package/dist/storage/team-sync-scope.test.js +35 -2
  118. package/dist/telemetry/telemetry.d.ts +5 -0
  119. package/dist/telemetry/telemetry.js +11 -1
  120. package/dist/templates/paradigms.js +0 -8
  121. package/dist/templates/presets.d.ts +0 -1
  122. package/dist/templates/presets.js +0 -23
  123. package/dist/templates/universal-config.js +8 -45
  124. package/dist/types/index.d.ts +108 -566
  125. package/dist/types/index.js +41 -66
  126. package/dist/types/index.test.d.ts +1 -0
  127. package/dist/types/index.test.js +33 -0
  128. package/dist/utils/command-line.d.ts +8 -0
  129. package/dist/utils/command-line.js +8 -0
  130. package/dist/utils/command-line.test.d.ts +1 -0
  131. package/dist/utils/command-line.test.js +8 -0
  132. package/dist/utils/profile.js +1 -1
  133. package/package.json +6 -7
@@ -1,9 +1,10 @@
1
1
  import { z } from 'zod';
2
+ /** A model name handed to an agent CLI as an argument: one that starts with "-" would be read as a flag. */
3
+ const ModelName = z.string().regex(/^[\w.:/@][\w.:/@-]*$/, 'a model name (letters, digits and . : / @ -), not starting with -');
2
4
  export const GatesSchema = z.object({
3
5
  max_file_lines: z.number().optional().default(500),
4
6
  forbid_todos: z.boolean().optional().default(true),
5
7
  forbid_fixme: z.boolean().optional().default(true),
6
- forbid_paths: z.array(z.string()).optional().default([]),
7
8
  required_files: z.array(z.string()).optional().default([
8
9
  'docs/SPEC.md',
9
10
  'docs/ARCH.md',
@@ -14,10 +15,6 @@ export const GatesSchema = z.object({
14
15
  complexity: z.number().optional().default(10),
15
16
  max_methods: z.number().optional().default(10),
16
17
  max_params: z.number().optional().default(5),
17
- max_nesting: z.number().optional().default(4),
18
- max_inheritance_depth: z.number().optional().default(3),
19
- max_class_dependencies: z.number().optional().default(5),
20
- max_function_lines: z.number().optional().default(50),
21
18
  }).optional().default({}),
22
19
  staleness: z.object({
23
20
  enabled: z.boolean().optional().default(false),
@@ -35,7 +32,6 @@ export const GatesSchema = z.object({
35
32
  }).optional().default({}),
36
33
  dependencies: z.object({
37
34
  forbid: z.array(z.string()).optional().default([]),
38
- trusted_registry: z.string().optional(),
39
35
  detect_unused: z.boolean().optional().default(true),
40
36
  detect_heavy_alternatives: z.boolean().optional().default(true),
41
37
  detect_duplicate_purpose: z.boolean().optional().default(true),
@@ -56,12 +52,6 @@ export const GatesSchema = z.object({
56
52
  enabled: z.boolean().optional().default(true),
57
53
  sensitivity: z.number().min(0).max(1).optional().default(0.8), // 0.8 correlation threshold
58
54
  mining_depth: z.number().optional().default(100), // Number of files to sample
59
- ignored_patterns: z.array(z.string()).optional().default([]),
60
- // v2.14+ Extended Context for frontier models
61
- cross_file_patterns: z.boolean().optional().default(true),
62
- naming_consistency: z.boolean().optional().default(true),
63
- import_relationships: z.boolean().optional().default(true),
64
- max_cross_file_depth: z.number().optional().default(50),
65
55
  }).optional().default({}),
66
56
  environment: z.object({
67
57
  enabled: z.boolean().optional().default(true),
@@ -72,14 +62,11 @@ export const GatesSchema = z.object({
72
62
  retry_loop_breaker: z.object({
73
63
  enabled: z.boolean().optional().default(true),
74
64
  max_retries: z.number().optional().default(3), // Fail after 3 consecutive failures in same category
75
- auto_classify: z.boolean().optional().default(true), // Auto-detect failure category from error message
76
65
  doc_sources: z.record(z.string()).optional().default({}), // Custom doc URLs per category
77
66
  }).optional().default({}),
78
67
  agent_team: z.object({
79
68
  enabled: z.boolean().optional().default(false),
80
69
  max_concurrent_agents: z.number().optional().default(3),
81
- cross_agent_pattern_check: z.boolean().optional().default(true),
82
- handoff_verification: z.boolean().optional().default(true),
83
70
  task_ownership: z.enum(['strict', 'collaborative']).optional().default('strict'),
84
71
  }).optional().default({}),
85
72
  checkpoint: z.object({
@@ -87,7 +74,6 @@ export const GatesSchema = z.object({
87
74
  interval_minutes: z.number().optional().default(15),
88
75
  quality_threshold: z.number().optional().default(80),
89
76
  drift_detection: z.boolean().optional().default(true),
90
- auto_save_on_failure: z.boolean().optional().default(true),
91
77
  }).optional().default({}),
92
78
  security: z.object({
93
79
  enabled: z.boolean().optional().default(true),
@@ -135,13 +121,6 @@ export const GatesSchema = z.object({
135
121
  ]),
136
122
  allowlist_env_names: z.array(z.string()).optional().default([]),
137
123
  }).optional().default({}),
138
- adaptive: z.object({
139
- enabled: z.boolean().optional().default(false),
140
- base_coverage_threshold: z.number().optional().default(80),
141
- base_quality_threshold: z.number().optional().default(80),
142
- auto_detect_tier: z.boolean().optional().default(true),
143
- forced_tier: z.enum(['hobby', 'startup', 'enterprise']).optional(),
144
- }).optional().default({}),
145
124
  // v2.16+ AI-Native Drift Detection Gates
146
125
  duplication_drift: z.object({
147
126
  enabled: z.boolean().optional().default(true),
@@ -150,8 +129,6 @@ export const GatesSchema = z.object({
150
129
  }).optional().default({}),
151
130
  hallucinated_imports: z.object({
152
131
  enabled: z.boolean().optional().default(true),
153
- check_relative: z.boolean().optional().default(true),
154
- check_packages: z.boolean().optional().default(true),
155
132
  ignore_patterns: z.array(z.string()).optional().default([
156
133
  '\\.css$', '\\.scss$', '\\.less$', '\\.svg$', '\\.png$', '\\.jpg$',
157
134
  '\\.json$', '\\.wasm$', '\\.graphql$', '\\.gql$',
@@ -203,10 +180,8 @@ export const GatesSchema = z.object({
203
180
  check_empty_tests: z.boolean().optional().default(true),
204
181
  check_tautological: z.boolean().optional().default(true),
205
182
  check_mock_heavy: z.boolean().optional().default(true),
206
- check_snapshot_abuse: z.boolean().optional().default(true),
207
183
  check_assertion_free_async: z.boolean().optional().default(true),
208
184
  max_mocks_per_test: z.number().optional().default(5),
209
- ignore_patterns: z.array(z.string()).optional().default([]),
210
185
  }).optional().default({}),
211
186
  // v4.2+ Memory & Skills Governance
212
187
  governance: z.object({
@@ -259,15 +234,6 @@ export const GatesSchema = z.object({
259
234
  '.windsurf/hooks.json', // Rigour's own hook config
260
235
  ]),
261
236
  }).optional().default({}),
262
- // v4.2+ AI Agent DLP (Data Loss Prevention)
263
- input_validation: z.object({
264
- enabled: z.boolean().optional().default(true),
265
- block_on_detection: z.boolean().optional().default(true),
266
- min_secret_length: z.number().optional().default(8),
267
- custom_patterns: z.array(z.string()).optional().default([]),
268
- ignore_patterns: z.array(z.string()).optional().default([]),
269
- audit_log: z.boolean().optional().default(true),
270
- }).optional().default({}),
271
237
  // v4.3+ Side-Effect Safety Analysis
272
238
  // On by default: full scans of three real repositories reported no finding that was not a real defect.
273
239
  // A supabase-js read no index can serve, proved from the repository's own migrations (advisory, off by default).
@@ -295,10 +261,13 @@ export const GatesSchema = z.object({
295
261
  * range on the same column, a nullable row type the query filters non-null, an optional member every host supplies, a
296
262
  * property written and never read. Runs at push, in `rigour review` and in a backtest (the program takes seconds to build).
297
263
  * `wire_contracts`: files whose types another service reads, so their members are never write-only here.
264
+ * `schema_migrations`: folders of SQL migrations (relative, absolute, or `~/`; another repository's is fine, read only)
265
+ * replayed to learn which columns are NOT NULL, for the nullable-not-null-column note. Missing folders are skipped.
298
266
  */
299
267
  redundancy: z.object({
300
268
  enabled: z.boolean().optional().default(true),
301
269
  wire_contracts: z.array(z.string()).optional().default([]),
270
+ schema_migrations: z.array(z.string()).optional().default(['supabase/migrations']),
302
271
  }).optional().default({}),
303
272
  /** A parameter the change adds as optional that only tests omit (review/optional-params.ts). */
304
273
  optional_params: z.object({ enabled: z.boolean().optional().default(true) }).optional().default({}),
@@ -344,20 +313,11 @@ export const GatesSchema = z.object({
344
313
  track_branches: z.boolean().optional().default(false), // opt-in: counts change on purpose in most edits
345
314
  track_returns: z.boolean().optional().default(false), // opt-in: same
346
315
  }).optional().default({}),
347
- // v4.0+ Deep Analysis (LLM-powered)
316
+ // Model review. Whether it runs, the tier, the provider and its key come from flags and the person's settings, never from a committed file.
348
317
  deep: z.object({
349
- enabled: z.boolean().optional().default(false),
350
- pro: z.boolean().optional().default(false),
351
- max: z.boolean().optional().default(false), // local Qwen2.5-Coder-7B (4.7GB); needs ~8GB free memory
352
- provider: z.string().optional().default('local'), // 'local' for sidecar, or any cloud: 'claude', 'openai', 'gemini', 'groq', 'mistral', 'together', etc.
353
- api_key: z.string().optional(),
354
- api_base_url: z.string().optional(), // custom API base URL (for self-hosted, proxies, any OpenAI-compatible endpoint)
355
- model_name: z.string().optional(), // cloud model name override (e.g. 'gpt-4o', 'claude-sonnet-4-5-20250929', 'gemini-pro')
356
- model_path: z.string().optional(), // custom local GGUF model path override
357
- threads: z.number().optional().default(4),
358
318
  max_tokens: z.number().optional(), // default per provider: local 1024, cloud 4096
359
319
  temperature: z.number().optional().default(0.1),
360
- timeout_ms: z.number().optional(), // per inference call; default per provider: local 60s, cloud 120s
320
+ timeout_ms: z.number().optional(), // per model call; default: cloud 120s, local 60s, local --max 240s
361
321
  budget_ms: z.number().optional(), // whole deep run; files not started in time are reported as skipped
362
322
  agentic: z.boolean().optional(), // cloud tier: the model may read the repository while it reviews (default true)
363
323
  repo_rules: z.boolean().optional(), // show the reviewer the rules in AGENTS.md / CLAUDE.md / Cursor rules that name what the change touches (default false)
@@ -389,26 +349,10 @@ export const CommandsSchema = z.object({
389
349
  test: z.string().optional(),
390
350
  });
391
351
  export const HooksSchema = z.object({
392
- enabled: z.boolean().optional().default(false),
393
- tools: z.array(z.enum(['claude', 'cursor', 'cline', 'windsurf'])).optional().default([]),
394
- fast_gates: z.array(z.string()).optional().default([
395
- 'hallucinated-imports',
396
- 'phantom-apis',
397
- 'deprecated-apis',
398
- 'promise-safety',
399
- 'security-patterns',
400
- 'side-effect-analysis',
401
- 'file-size',
402
- ]),
403
- timeout_ms: z.number().optional().default(5000),
404
- block_on_failure: z.boolean().optional().default(false),
405
352
  /** Stop hook: hold "done" until the agent acknowledges each risky changed function (rigour_review_ack). */
406
353
  require_review_ack: z.boolean().optional().default(false),
407
- /** Enable DLP (Data Loss Prevention) pre-input hooks — default ON for security */
408
- dlp: z.boolean().optional().default(true),
409
354
  }).optional().default({});
410
355
  export const ConfigSchema = z.object({
411
- version: z.number().default(1),
412
356
  preset: z.string().optional(),
413
357
  paradigm: z.string().optional(),
414
358
  commands: CommandsSchema.optional().default({}),
@@ -439,13 +383,44 @@ export const ConfigSchema = z.object({
439
383
  /** single: the first installed reviewer. cross: prefer a vendor not on the commits' trailers. full: two vendors, verdicts merged. */
440
384
  mode: z.enum(['single', 'cross', 'full']).optional().default('single'),
441
385
  /** The model for the claude reviewer. */
442
- model: z.string().optional(),
386
+ model: ModelName.optional(),
443
387
  /** A model per reviewer name, e.g. { cursor: "auto" }. */
444
- models: z.record(z.string()).optional().default({}),
388
+ models: z.record(ModelName).optional().default({}),
445
389
  timeout_ms: z.number().optional().default(15 * 60_000),
390
+ /**
391
+ * With two vendors: match their findings, cross-examine only what one raised, and block only on what is
392
+ * confirmed (review/reviewer/panel.ts). `on` implies mode full. `required`: no user or run may turn it off,
393
+ * and a run without two vendors is unavailable instead of falling back to one.
394
+ */
395
+ panel: z.enum(['off', 'on', 'required']).optional().default('off'),
396
+ /** No user or run may review with fewer than the team's mode (a protected branch, CI). */
397
+ mode_required: z.boolean().optional().default(false),
398
+ /**
399
+ * Whether people may dismiss a reviewer finding as not a bug (`rigour dismiss <id>`, Studio). Off by default:
400
+ * a wrong finding is fixed by improving the reviewer, a right one by fixing the code. A team decision only.
401
+ */
402
+ dismissals: z.boolean().optional().default(false),
403
+ /** Findings cross-examined per review at most; the rest are shown as disputed. */
404
+ panel_max_items: z.number().int().positive().optional().default(20),
405
+ /**
406
+ * Spending caps per repository and local day, unset by default. Runs are checked before any judge starts
407
+ * (a cross-examination counts too); dollars are the ones the CLIs reported, so a cap stops new reviews once
408
+ * reached. Past a cap a review is skipped, or unavailable when the team requires the reviewer.
409
+ */
410
+ max_runs_per_day: z.number().int().positive().optional(),
411
+ max_usd_per_day: z.number().positive().optional(),
412
+ /** Judges in a full or panel review, each from a different vendor; capped by the vendors installed. */
413
+ judges: z.union([z.literal(2), z.literal(3)]).optional().default(2),
414
+ /**
415
+ * When a full or panel review adds judges. `always`: every review. `risk`: only when the change has a
416
+ * risky function (the router's score), a human review exists, or the run is the --full hard stop; any
417
+ * other change gets one judge. Measured against `always` by the backtest before you rely on it.
418
+ */
419
+ escalate: z.enum(['always', 'risk']).optional().default('always'),
420
+ /** A model per reviewer name for cross-examination (a narrow verification task), e.g. { claude: "haiku" }. */
421
+ cross_models: z.record(ModelName).optional().default({}),
446
422
  }).optional().default({}),
447
423
  }).optional().default({}),
448
- planned: z.array(z.string()).optional().default([]),
449
424
  ignore: z.array(z.string()).optional().default([]),
450
425
  });
451
426
  export const StatusSchema = z.enum(['PASS', 'FAIL', 'SKIP', 'ERROR']);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,33 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import yaml from 'yaml';
3
+ import { ConfigSchema } from './index.js';
4
+ describe('rigour.yml', () => {
5
+ it('still loads a file that sets the settings no check ever read, and keeps everything else', () => {
6
+ const old = yaml.parse(`
7
+ version: 1
8
+ planned: [Layer boundaries]
9
+ hooks: { enabled: true, tools: [claude], fast_gates: [file-size], timeout_ms: 5000, block_on_failure: true, dlp: false, require_review_ack: true }
10
+ gates:
11
+ max_file_lines: 300
12
+ forbid_paths: [secret/]
13
+ ast: { complexity: 7, max_nesting: 3, max_function_lines: 40 }
14
+ adaptive: { enabled: true, forced_tier: enterprise }
15
+ input_validation: { enabled: true, min_secret_length: 12 }
16
+ deep: { enabled: true, provider: claude, api_key: sk-test, model_name: x, threads: 8, temperature: 0.2 }
17
+ test_quality: { check_snapshot_abuse: false, ignore_patterns: [x], max_mocks_per_test: 3 }
18
+ `);
19
+ const config = ConfigSchema.parse(old);
20
+ expect(config.gates.max_file_lines).toBe(300);
21
+ expect(config.gates.ast.complexity).toBe(7);
22
+ expect(config.gates.deep.temperature).toBe(0.2);
23
+ expect(config.gates.test_quality.max_mocks_per_test).toBe(3);
24
+ expect(config.hooks.require_review_ack).toBe(true);
25
+ // What nothing read is dropped, so no code can start depending on it by accident.
26
+ expect(config).not.toHaveProperty('version');
27
+ expect(config).not.toHaveProperty('planned');
28
+ expect(config.gates).not.toHaveProperty('adaptive');
29
+ expect(config.gates).not.toHaveProperty('input_validation');
30
+ expect(config.gates.deep).not.toHaveProperty('api_key');
31
+ expect(config.hooks).not.toHaveProperty('block_on_failure');
32
+ });
33
+ });
@@ -0,0 +1,8 @@
1
+ /**
2
+ * A `commands:` entry from rigour.yml as a program and its arguments. Run without a shell, so pipes,
3
+ * `&&` and variable assignments are not interpreted: a team that needs them points at a script.
4
+ */
5
+ export declare function splitCommand(command: string): {
6
+ bin: string;
7
+ args: string[];
8
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * A `commands:` entry from rigour.yml as a program and its arguments. Run without a shell, so pipes,
3
+ * `&&` and variable assignments are not interpreted: a team that needs them points at a script.
4
+ */
5
+ export function splitCommand(command) {
6
+ const parts = command.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g) ?? [command];
7
+ return { bin: parts[0], args: parts.slice(1).map(arg => arg.replace(/^["']|["']$/g, '')) };
8
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { splitCommand } from './command-line.js';
3
+ describe('splitCommand', () => {
4
+ it('splits on spaces and keeps a quoted argument whole, without its quotes', () => {
5
+ expect(splitCommand('npm run lint')).toEqual({ bin: 'npm', args: ['run', 'lint'] });
6
+ expect(splitCommand(`vitest run "src/a b.test.ts" --reporter 'dot'`)).toEqual({ bin: 'vitest', args: ['run', 'src/a b.test.ts', '--reporter', 'dot'] });
7
+ });
8
+ });
@@ -16,7 +16,7 @@ import { spawnSync } from 'child_process';
16
16
  import fs from 'fs';
17
17
  import os from 'os';
18
18
  import path from 'path';
19
- const TEAM_ENV = ['RIGOUR_ORGANIZATION_ID', 'RIGOUR_TEAM_ID', 'RIGOUR_ACTOR_ID', 'RIGOUR_TEAM_REPOSITORIES', 'RIGOUR_TEAM_DATABASE_URL', 'RIGOUR_TEAM_DATABASE_URL_COMMAND', 'RIGOUR_TEAM_SEMANTIC'];
19
+ const TEAM_ENV = ['RIGOUR_ORGANIZATION_ID', 'RIGOUR_TEAM_ID', 'RIGOUR_ACTOR_ID', 'RIGOUR_TEAM_REPOSITORIES', 'RIGOUR_TEAM_DATABASE_URL', 'RIGOUR_TEAM_DATABASE_URL_COMMAND', 'RIGOUR_TEAM_SEMANTIC', 'RIGOUR_TEAM_SYNC_PERSONAL'];
20
20
  /** Where profiles are listed: always the person's real home, never a profile's. */
21
21
  export function profilesPath() {
22
22
  return process.env.RIGOUR_PROFILES || path.join(os.homedir(), '.rigour', 'profiles.json');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rigour-labs/core",
3
- "version": "6.6.6",
3
+ "version": "6.7.0",
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"
@@ -70,15 +70,14 @@
70
70
  },
71
71
  "optionalDependencies": {
72
72
  "@anthropic-ai/sdk": "^0.30.1",
73
- "@xenova/transformers": "^2.17.2",
74
73
  "pg": "^8.16.3",
75
74
  "sqlite3": "^5.1.7",
76
75
  "openai": "^4.104.0",
77
- "@rigour-labs/brain-darwin-x64": "6.6.6",
78
- "@rigour-labs/brain-darwin-arm64": "6.6.6",
79
- "@rigour-labs/brain-win-x64": "6.6.6",
80
- "@rigour-labs/brain-linux-x64": "6.6.6",
81
- "@rigour-labs/brain-linux-arm64": "6.6.6"
76
+ "@rigour-labs/brain-darwin-x64": "6.7.0",
77
+ "@rigour-labs/brain-linux-arm64": "6.7.0",
78
+ "@rigour-labs/brain-darwin-arm64": "6.7.0",
79
+ "@rigour-labs/brain-win-x64": "6.7.0",
80
+ "@rigour-labs/brain-linux-x64": "6.7.0"
82
81
  },
83
82
  "devDependencies": {
84
83
  "@types/fs-extra": "^11.0.4",