tribunal-kit 9.2.6 → 9.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent/ARCHITECTURE.md +2 -2
- package/.agent/history/architecture-intelligence.html +1487 -401
- package/.agent/history/architecture-model.json +9365 -5697
- package/.agent/history/architecture-verification.json +37 -9
- package/.agent/routing_index.json +2069 -3340
- package/.agent/rules/GEMINI.md +1 -1
- package/.agent/scripts/adaptive_execution.js +511 -0
- package/.agent/scripts/architecture_diff.js +303 -260
- package/.agent/scripts/architecture_extractor.js +792 -753
- package/.agent/scripts/architecture_health.js +293 -256
- package/.agent/scripts/architecture_intelligence.js +3100 -0
- package/.agent/scripts/architecture_verifier.js +303 -270
- package/.agent/scripts/architecture_visualizer.js +880 -873
- package/.agent/scripts/blast_radius_engine.js +274 -234
- package/.agent/scripts/capability_evolution.js +453 -0
- package/.agent/scripts/concept_extractor.js +240 -0
- package/.agent/scripts/consideration_engine.js +284 -0
- package/.agent/scripts/coverage_engine.js +102 -0
- package/.agent/scripts/cross_domain_engine.js +1883 -0
- package/.agent/scripts/engineering_memory.js +1313 -0
- package/.agent/scripts/integrity_manifest.js +1 -5
- package/.agent/scripts/judgment_engine.js +790 -0
- package/.agent/scripts/materiality_engine.js +251 -0
- package/.agent/scripts/outcome_engine.js +624 -0
- package/.agent/scripts/outcome_optimization_engine.js +1632 -0
- package/.agent/scripts/simulation_engine.js +1478 -0
- package/.agent/scripts/skill_intelligence.js +1371 -0
- package/.agent/scripts/validation_engine.js +236 -236
- package/.agent/scripts/verification_auditor.js +266 -0
- package/.agent/skill-intelligence/taxonomy/engineering-concepts.json +555 -0
- package/.agent/skill_topic_map.json +301 -341
- package/.agent/skills_inventory.json +4272 -6922
- package/.agent/workflows/arch.md +96 -80
- package/.agent/workflows/skill-intelligence.md +216 -0
- package/CONTRIBUTING.md +2 -2
- package/README.md +24 -24
- package/bin/adapter-install.js +1 -1
- package/package.json +8 -9
- package/plugins/core-plugin.json +1 -1
- package/plugins/gemini/extension.json +1 -1
- package/src/browser/index.js +2 -1
- package/src/browser/launcher.js +41 -1
- package/src/cli.js +3 -1
- package/src/commands/arch.js +261 -172
- package/src/commands/context.js +27 -8
- package/src/commands/learn.js +21 -6
- package/src/commands/memory.js +10 -1
- package/src/commands/native.js +12 -3
- package/src/commands/skill-intelligence.js +1165 -0
- package/src/commands/system1.js +105 -4
- package/src/context/ranker.js +337 -339
- package/src/evolution/engine.js +296 -295
- package/src/synthesis/claim_check_separator.js +294 -271
- package/src/system1/browser_intelligence.js +300 -0
- package/src/system1/constants.js +49 -0
- package/src/system1/decision_engine.js +498 -0
- package/src/system1/evidence_engine.js +602 -0
- package/src/system1/evolution_pipeline.js +581 -0
- package/src/system1/index.d.ts +114 -0
- package/src/system1/index.js +102 -0
- package/src/system1/reviewer_orchestrator.js +477 -0
- package/src/tui/banner.js +1 -1
- package/src/utils/fs.js +27 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* index.js — System-1 Capability Suite for Tribunal Kit
|
|
5
|
+
* =======================================================
|
|
6
|
+
* Unified export interface for all five System-1 capability layers:
|
|
7
|
+
*
|
|
8
|
+
* 1. Evidence Intelligence (`evidence_engine.js`)
|
|
9
|
+
* 2. Cross-Capability Decision Engine (`decision_engine.js`)
|
|
10
|
+
* 3. Adaptive Reviewer Orchestration (`reviewer_orchestrator.js`)
|
|
11
|
+
* 4. Self-Evolution Pipeline (`evolution_pipeline.js`)
|
|
12
|
+
* 5. Browser / Interaction Intelligence (`browser_intelligence.js`)
|
|
13
|
+
* + Laya Local ONNX Provider (`provider.js`)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const { System1Provider, getLayaDir, getConfigPath } = require('./provider');
|
|
17
|
+
const {
|
|
18
|
+
collectAndRankEvidence,
|
|
19
|
+
extractChangedSymbols,
|
|
20
|
+
extractBoundedSnippet,
|
|
21
|
+
redactSecrets,
|
|
22
|
+
TYPE_PRIORITY,
|
|
23
|
+
SECURITY_BOUNDARIES,
|
|
24
|
+
} = require('./evidence_engine');
|
|
25
|
+
const {
|
|
26
|
+
evaluateDecision,
|
|
27
|
+
resolveMonotonicImpactTier,
|
|
28
|
+
HIGH_RISK_PATTERNS,
|
|
29
|
+
HIGH_RISK_EXTENSIONS,
|
|
30
|
+
TIER_NAMES,
|
|
31
|
+
ROUTING_NAMES,
|
|
32
|
+
} = require('./decision_engine');
|
|
33
|
+
const {
|
|
34
|
+
orchestrateReviewers,
|
|
35
|
+
detectRequiredDomains,
|
|
36
|
+
REVIEWER_CATALOG,
|
|
37
|
+
} = require('./reviewer_orchestrator');
|
|
38
|
+
const {
|
|
39
|
+
createCandidateFromOutcome,
|
|
40
|
+
validateCandidateAgainstCorpus,
|
|
41
|
+
approveCandidate,
|
|
42
|
+
promoteCandidate,
|
|
43
|
+
rollbackCandidate,
|
|
44
|
+
saveCandidate,
|
|
45
|
+
loadCandidate,
|
|
46
|
+
loadAllCandidates,
|
|
47
|
+
getActiveEvolutionsPath,
|
|
48
|
+
acquireEvolutionLock,
|
|
49
|
+
releaseEvolutionLock,
|
|
50
|
+
writeFileSyncAtomic,
|
|
51
|
+
VALID_SOURCES,
|
|
52
|
+
CANDIDATE_STATES,
|
|
53
|
+
} = require('./evolution_pipeline');
|
|
54
|
+
const { evaluateBrowserRequirement, extractAffectedRoutes } = require('./browser_intelligence');
|
|
55
|
+
|
|
56
|
+
module.exports = {
|
|
57
|
+
// Provider
|
|
58
|
+
System1Provider,
|
|
59
|
+
getLayaDir,
|
|
60
|
+
getConfigPath,
|
|
61
|
+
|
|
62
|
+
// Capability 1: Evidence Intelligence
|
|
63
|
+
collectAndRankEvidence,
|
|
64
|
+
extractChangedSymbols,
|
|
65
|
+
extractBoundedSnippet,
|
|
66
|
+
redactSecrets,
|
|
67
|
+
TYPE_PRIORITY,
|
|
68
|
+
SECURITY_BOUNDARIES,
|
|
69
|
+
|
|
70
|
+
// Capability 2: Decision Engine
|
|
71
|
+
evaluateDecision,
|
|
72
|
+
resolveMonotonicImpactTier,
|
|
73
|
+
HIGH_RISK_PATTERNS,
|
|
74
|
+
HIGH_RISK_EXTENSIONS,
|
|
75
|
+
TIER_NAMES,
|
|
76
|
+
ROUTING_NAMES,
|
|
77
|
+
|
|
78
|
+
// Capability 3: Reviewer Orchestration
|
|
79
|
+
orchestrateReviewers,
|
|
80
|
+
detectRequiredDomains,
|
|
81
|
+
REVIEWER_CATALOG,
|
|
82
|
+
|
|
83
|
+
// Capability 4: Self-Evolution
|
|
84
|
+
createCandidateFromOutcome,
|
|
85
|
+
validateCandidateAgainstCorpus,
|
|
86
|
+
approveCandidate,
|
|
87
|
+
promoteCandidate,
|
|
88
|
+
rollbackCandidate,
|
|
89
|
+
saveCandidate,
|
|
90
|
+
loadCandidate,
|
|
91
|
+
loadAllCandidates,
|
|
92
|
+
getActiveEvolutionsPath,
|
|
93
|
+
acquireEvolutionLock,
|
|
94
|
+
releaseEvolutionLock,
|
|
95
|
+
writeFileSyncAtomic,
|
|
96
|
+
VALID_SOURCES,
|
|
97
|
+
CANDIDATE_STATES,
|
|
98
|
+
|
|
99
|
+
// Capability 5: Browser Intelligence
|
|
100
|
+
evaluateBrowserRequirement,
|
|
101
|
+
extractAffectedRoutes,
|
|
102
|
+
};
|
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* reviewer_orchestrator.js — System-1 Capability 3: Adaptive Reviewer Orchestration
|
|
5
|
+
* ==================================================================================
|
|
6
|
+
* Replaces purely static reviewer selection with evidence-driven reviewer selection.
|
|
7
|
+
*
|
|
8
|
+
* Selects the smallest reviewer set capable of covering identified risks:
|
|
9
|
+
* score = required_coverage + specialization + historical_usefulness - overlap_penalty
|
|
10
|
+
*
|
|
11
|
+
* Guarantees:
|
|
12
|
+
* - Maximum unique review coverage with minimum reviewer count
|
|
13
|
+
* - Never optimizes away a reviewer solely for token savings when its domain is independently required
|
|
14
|
+
* - Every selected reviewer has: reason, risk covered, evidence supplied, expected contribution
|
|
15
|
+
* - Every rejected reviewer has: reason not selected
|
|
16
|
+
* - Deterministic, stable ordering
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const path = require('path');
|
|
20
|
+
const { HIGH_RISK_PATTERNS } = require('./constants');
|
|
21
|
+
|
|
22
|
+
// Standard Reviewer Catalog with domains, priority, and overlap groups
|
|
23
|
+
const REVIEWER_CATALOG = [
|
|
24
|
+
{
|
|
25
|
+
name: 'logic-reviewer',
|
|
26
|
+
primary_domains: ['logic', 'all'],
|
|
27
|
+
secondary_domains: ['api'],
|
|
28
|
+
priority: 'critical',
|
|
29
|
+
overlap_group: 'logic',
|
|
30
|
+
expected_contribution:
|
|
31
|
+
'Verification of state machines, API contract adherence, control flow integrity, and hallucination prevention.',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'security-auditor',
|
|
35
|
+
primary_domains: ['security', 'auth'],
|
|
36
|
+
secondary_domains: ['backend', 'frontend'],
|
|
37
|
+
priority: 'critical',
|
|
38
|
+
overlap_group: 'security_general',
|
|
39
|
+
expected_contribution:
|
|
40
|
+
'OWASP vulnerability scanning: injection, broken access control, token forgery, SSRF, and sensitive data leakage.',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'sql-reviewer',
|
|
44
|
+
primary_domains: ['database', 'sql'],
|
|
45
|
+
secondary_domains: ['migration', 'performance'],
|
|
46
|
+
priority: 'critical',
|
|
47
|
+
overlap_group: 'database_sql',
|
|
48
|
+
expected_contribution:
|
|
49
|
+
'Validation of SQL query parameters, schema migrations, table locks, transactional consistency, and missing indexes.',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'schema-reviewer',
|
|
53
|
+
primary_domains: ['schema', 'validation'],
|
|
54
|
+
secondary_domains: ['backend', 'database'],
|
|
55
|
+
priority: 'high',
|
|
56
|
+
overlap_group: 'schema_validation',
|
|
57
|
+
expected_contribution:
|
|
58
|
+
'Verification of Zod/Pydantic runtime schemas, DTO boundaries, and request payload validation.',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'resilience-reviewer',
|
|
62
|
+
primary_domains: ['resilience', 'backend'],
|
|
63
|
+
secondary_domains: ['network'],
|
|
64
|
+
priority: 'high',
|
|
65
|
+
overlap_group: 'resilience_fault_tolerance',
|
|
66
|
+
expected_contribution:
|
|
67
|
+
'Audit of timeout configurations, circuit breakers, retry policies, and unhandled promise rejections.',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: 'dependency-reviewer',
|
|
71
|
+
primary_domains: ['dependency'],
|
|
72
|
+
secondary_domains: ['security', 'devops'],
|
|
73
|
+
priority: 'high',
|
|
74
|
+
overlap_group: 'dependency_management',
|
|
75
|
+
expected_contribution:
|
|
76
|
+
'Detection of phantom/ghost dependencies, outdated packages, CVE advisories, and lockfile tampering.',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'type-safety-reviewer',
|
|
80
|
+
primary_domains: ['type_safety', 'typescript'],
|
|
81
|
+
secondary_domains: ['frontend', 'backend'],
|
|
82
|
+
priority: 'high',
|
|
83
|
+
overlap_group: 'type_soundness',
|
|
84
|
+
expected_contribution:
|
|
85
|
+
'Enforcement of TypeScript strictness, elimination of unsafe "any" casts, and generic constraint correctness.',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'frontend-reviewer',
|
|
89
|
+
primary_domains: ['frontend', 'ui'],
|
|
90
|
+
secondary_domains: ['performance'],
|
|
91
|
+
priority: 'high',
|
|
92
|
+
overlap_group: 'frontend_architecture',
|
|
93
|
+
expected_contribution:
|
|
94
|
+
'React/UI lifecycle review: hook dependency completeness, memoization balance, and re-render efficiency.',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'accessibility-reviewer',
|
|
98
|
+
primary_domains: ['accessibility'],
|
|
99
|
+
secondary_domains: ['frontend', 'ui'],
|
|
100
|
+
priority: 'high',
|
|
101
|
+
overlap_group: 'accessibility_standards',
|
|
102
|
+
expected_contribution:
|
|
103
|
+
'WCAG 2.2 compliance: semantic HTML elements, ARIA role verification, keyboard accessibility, and contrast ratios.',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'pipeline-reviewer',
|
|
107
|
+
primary_domains: ['devops', 'ci_cd'],
|
|
108
|
+
secondary_domains: ['security'],
|
|
109
|
+
priority: 'high',
|
|
110
|
+
overlap_group: 'infrastructure_pipeline',
|
|
111
|
+
expected_contribution:
|
|
112
|
+
'CI/CD pipeline hardening: workflow permissions, step injection defense, secret exposure prevention, and Docker security.',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: 'performance-reviewer',
|
|
116
|
+
primary_domains: ['performance'],
|
|
117
|
+
secondary_domains: ['backend', 'frontend'],
|
|
118
|
+
priority: 'medium',
|
|
119
|
+
overlap_group: 'performance_profiling',
|
|
120
|
+
expected_contribution:
|
|
121
|
+
'Resource efficiency analysis: asymptotic complexity, memory footprint, N+1 query patterns, and bundle weight.',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: 'mobile-reviewer',
|
|
125
|
+
primary_domains: ['mobile'],
|
|
126
|
+
secondary_domains: ['frontend'],
|
|
127
|
+
priority: 'high',
|
|
128
|
+
overlap_group: 'mobile_native',
|
|
129
|
+
expected_contribution:
|
|
130
|
+
'Mobile runtime evaluation: native gesture handlers, memory leaks, offline state, and navigation bridges.',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: 'precedence-reviewer',
|
|
134
|
+
primary_domains: ['governance', 'rules'],
|
|
135
|
+
secondary_domains: ['all'],
|
|
136
|
+
priority: 'high',
|
|
137
|
+
overlap_group: 'governance_rules',
|
|
138
|
+
expected_contribution:
|
|
139
|
+
'Enforcement of architectural rule priorities, agent boundary containment, and compliance with master directives.',
|
|
140
|
+
},
|
|
141
|
+
];
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Detect required risk domains based on files, diff, task, and evidence
|
|
145
|
+
*/
|
|
146
|
+
function detectRequiredDomains({
|
|
147
|
+
files = [],
|
|
148
|
+
diff = '',
|
|
149
|
+
task = '',
|
|
150
|
+
evidence = [],
|
|
151
|
+
previousFindings = [],
|
|
152
|
+
}) {
|
|
153
|
+
const domains = new Set();
|
|
154
|
+
const fileList = (Array.isArray(files) ? files : typeof files === 'string' ? [files] : [])
|
|
155
|
+
.map(f =>
|
|
156
|
+
typeof f === 'string'
|
|
157
|
+
? f
|
|
158
|
+
.replace(/[\u200B-\u200D\uFEFF]/g, '')
|
|
159
|
+
.trim()
|
|
160
|
+
.replace(/\\/g, '/')
|
|
161
|
+
: '',
|
|
162
|
+
)
|
|
163
|
+
.filter(Boolean);
|
|
164
|
+
const combined = `${task}\n${diff}\n${fileList.join('\n')}`;
|
|
165
|
+
|
|
166
|
+
// 1. File extension heuristics
|
|
167
|
+
for (const f of fileList) {
|
|
168
|
+
const ext = path.extname(f).toLowerCase();
|
|
169
|
+
if (['.sql', '.prisma'].includes(ext)) {
|
|
170
|
+
domains.add('database');
|
|
171
|
+
domains.add('sql');
|
|
172
|
+
}
|
|
173
|
+
if (['.ts', '.tsx'].includes(ext)) {
|
|
174
|
+
domains.add('type_safety');
|
|
175
|
+
}
|
|
176
|
+
if (
|
|
177
|
+
['.jsx', '.tsx', '.vue', '.svelte', '.css', '.scss'].includes(ext) ||
|
|
178
|
+
f.includes('/components/')
|
|
179
|
+
) {
|
|
180
|
+
domains.add('frontend');
|
|
181
|
+
}
|
|
182
|
+
if (f.includes('.github/') || f.includes('Dockerfile') || f.includes('docker-compose')) {
|
|
183
|
+
domains.add('devops');
|
|
184
|
+
domains.add('ci_cd');
|
|
185
|
+
}
|
|
186
|
+
if (f.endsWith('package.json') || f.endsWith('package-lock.json') || f.endsWith('Cargo.toml')) {
|
|
187
|
+
domains.add('dependency');
|
|
188
|
+
}
|
|
189
|
+
if (f.includes('/api/') || f.includes('/server/') || f.includes('/controllers/')) {
|
|
190
|
+
domains.add('backend');
|
|
191
|
+
domains.add('api');
|
|
192
|
+
}
|
|
193
|
+
if (f.includes('mobile/') || f.includes('ios/') || f.includes('android/')) {
|
|
194
|
+
domains.add('mobile');
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// 2. Keyword & pattern heuristics
|
|
199
|
+
if (
|
|
200
|
+
HIGH_RISK_PATTERNS.test(combined) ||
|
|
201
|
+
combined.includes('token') ||
|
|
202
|
+
combined.includes('jwt') ||
|
|
203
|
+
combined.includes('auth')
|
|
204
|
+
) {
|
|
205
|
+
domains.add('security');
|
|
206
|
+
domains.add('auth');
|
|
207
|
+
}
|
|
208
|
+
if (/\b(schema|zod|pydantic|validate|dto)\b/i.test(combined)) {
|
|
209
|
+
domains.add('schema');
|
|
210
|
+
}
|
|
211
|
+
if (/\b(sql|database|query|migration|table|alter table|create table)\b/i.test(combined)) {
|
|
212
|
+
domains.add('database');
|
|
213
|
+
}
|
|
214
|
+
if (/\b(retry|circuit-breaker|fallback|timeout|graceful|catch|exception)\b/i.test(combined)) {
|
|
215
|
+
domains.add('resilience');
|
|
216
|
+
}
|
|
217
|
+
if (/\b(a11y|aria|accessibility|wcag|contrast|screen-reader)\b/i.test(combined)) {
|
|
218
|
+
domains.add('accessibility');
|
|
219
|
+
}
|
|
220
|
+
if (/\b(perf|performance|latency|slow|throughput|bundle)\b/i.test(combined)) {
|
|
221
|
+
domains.add('performance');
|
|
222
|
+
}
|
|
223
|
+
if (/\b(npm|yarn|pnpm|dependency|package|cve|vulnerability)\b/i.test(combined)) {
|
|
224
|
+
domains.add('dependency');
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// 3. Evidence signals
|
|
228
|
+
if (Array.isArray(evidence)) {
|
|
229
|
+
for (const e of evidence) {
|
|
230
|
+
if (e && typeof e === 'object') {
|
|
231
|
+
if (e.is_mandatory && e.type === 'security_boundary') {
|
|
232
|
+
domains.add('security');
|
|
233
|
+
}
|
|
234
|
+
if (
|
|
235
|
+
e.type === 'configuration' &&
|
|
236
|
+
typeof e.path === 'string' &&
|
|
237
|
+
e.path.includes('package')
|
|
238
|
+
) {
|
|
239
|
+
domains.add('dependency');
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// 4. Previous findings signals
|
|
246
|
+
if (Array.isArray(previousFindings)) {
|
|
247
|
+
for (const pf of previousFindings) {
|
|
248
|
+
if (pf && typeof pf === 'object' && typeof pf.category === 'string') {
|
|
249
|
+
domains.add(pf.category.toLowerCase());
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Default baseline: logic is always relevant when code changes
|
|
255
|
+
if (fileList.some(f => !/\.(md|txt)$/i.test(f))) {
|
|
256
|
+
domains.add('logic');
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return Array.from(domains);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Adaptive Reviewer Orchestrator
|
|
264
|
+
* @param {Object} options
|
|
265
|
+
* @param {number} [options.tier] - Impact tier (0 to 3)
|
|
266
|
+
* @param {string[]} [options.files] - Changed files
|
|
267
|
+
* @param {string} [options.diff] - Diff
|
|
268
|
+
* @param {string} [options.task] - Task description
|
|
269
|
+
* @param {Array} [options.evidence] - Evidence items
|
|
270
|
+
* @param {Array} [options.previousFindings] - Previous findings
|
|
271
|
+
* @param {string[]} [options.forcedReviewers] - Reviewers that must be included
|
|
272
|
+
* @returns {Object} Orchestration payload with selected and rejected reviewers
|
|
273
|
+
*/
|
|
274
|
+
function orchestrateReviewers(options = {}) {
|
|
275
|
+
const tier = typeof options.tier === 'number' ? options.tier : 1;
|
|
276
|
+
const files = options.files || [];
|
|
277
|
+
const diff = options.diff || '';
|
|
278
|
+
const task = options.task || '';
|
|
279
|
+
const evidence = Array.isArray(options.evidence) ? options.evidence : [];
|
|
280
|
+
const previousFindings = Array.isArray(options.previousFindings) ? options.previousFindings : [];
|
|
281
|
+
const forcedReviewers = new Set(options.forcedReviewers || []);
|
|
282
|
+
|
|
283
|
+
// Determine maximum reviewer capacity based on impact tier
|
|
284
|
+
// Tier 0 (Fast-Pass): 0 reviewers
|
|
285
|
+
// Tier 1 (Express Pass): 1 reviewer
|
|
286
|
+
// Tier 2 (Targeted Audit): 2-3 reviewers
|
|
287
|
+
// Tier 3 (Full Gauntlet): up to 8 reviewers
|
|
288
|
+
const capacityMap = { 0: 0, 1: 1, 2: 3, 3: 8 };
|
|
289
|
+
const maxCapacity = capacityMap[tier] ?? 1;
|
|
290
|
+
|
|
291
|
+
if (maxCapacity === 0) {
|
|
292
|
+
return {
|
|
293
|
+
selected: [],
|
|
294
|
+
rejected: REVIEWER_CATALOG.map(r => ({
|
|
295
|
+
reviewer: r.name,
|
|
296
|
+
reason: 'Fast-Pass (Tier 0) active: 0 reviewers required for low-risk change.',
|
|
297
|
+
})),
|
|
298
|
+
total_selected: 0,
|
|
299
|
+
coverage: {
|
|
300
|
+
domains_required: [],
|
|
301
|
+
domains_covered: [],
|
|
302
|
+
all_risks_covered: true,
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const requiredDomains = detectRequiredDomains({ files, diff, task, evidence, previousFindings });
|
|
308
|
+
const coveredDomains = new Set();
|
|
309
|
+
const selectedReviewers = [];
|
|
310
|
+
const rejectedReviewers = [];
|
|
311
|
+
const usedOverlapGroups = new Set();
|
|
312
|
+
|
|
313
|
+
// Score candidate reviewers
|
|
314
|
+
const candidateScores = REVIEWER_CATALOG.map(reviewer => {
|
|
315
|
+
let score = 0.0;
|
|
316
|
+
const matchedEvidence = [];
|
|
317
|
+
const matchedReasons = [];
|
|
318
|
+
|
|
319
|
+
// 1. Required Coverage Score
|
|
320
|
+
const primaryMatches = reviewer.primary_domains.filter(d => requiredDomains.includes(d));
|
|
321
|
+
const secondaryMatches = reviewer.secondary_domains.filter(d => requiredDomains.includes(d));
|
|
322
|
+
|
|
323
|
+
if (primaryMatches.length > 0) {
|
|
324
|
+
score += 0.45 * primaryMatches.length;
|
|
325
|
+
matchedReasons.push(`directly covers primary risk domains: ${primaryMatches.join(', ')}`);
|
|
326
|
+
}
|
|
327
|
+
if (secondaryMatches.length > 0) {
|
|
328
|
+
score += 0.2 * secondaryMatches.length;
|
|
329
|
+
matchedReasons.push(`covers secondary risk domains: ${secondaryMatches.join(', ')}`);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// 2. Specialization & Priority Score
|
|
333
|
+
const hasSpecificDomainMatch = primaryMatches.some(d => d !== 'logic' && d !== 'all');
|
|
334
|
+
if (hasSpecificDomainMatch) {
|
|
335
|
+
score += 0.3; // Domain specialist bonus over general logic reviewer
|
|
336
|
+
matchedReasons.push(
|
|
337
|
+
`domain specialist for ${primaryMatches.filter(d => d !== 'logic' && d !== 'all').join(', ')}`,
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (reviewer.priority === 'critical' && primaryMatches.length > 0) {
|
|
342
|
+
score += 0.25;
|
|
343
|
+
matchedReasons.push('critical priority specialist for active risk domain');
|
|
344
|
+
}
|
|
345
|
+
if (reviewer.priority === 'high' && primaryMatches.length > 0) {
|
|
346
|
+
score += 0.15;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// 3. Evidence Match
|
|
350
|
+
if (Array.isArray(evidence)) {
|
|
351
|
+
for (const e of evidence) {
|
|
352
|
+
if (e && typeof e === 'object' && typeof e.type === 'string') {
|
|
353
|
+
if (
|
|
354
|
+
primaryMatches.some(
|
|
355
|
+
d =>
|
|
356
|
+
e.type.includes(d) ||
|
|
357
|
+
(Array.isArray(e.reasons) &&
|
|
358
|
+
e.reasons.some(r => typeof r === 'string' && r.includes(d))),
|
|
359
|
+
)
|
|
360
|
+
) {
|
|
361
|
+
score += 0.1;
|
|
362
|
+
if (e.id) matchedEvidence.push(e.id);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// 4. Previous Findings Usefulness
|
|
369
|
+
const hasPriorIssues =
|
|
370
|
+
Array.isArray(previousFindings) &&
|
|
371
|
+
previousFindings.some(f => {
|
|
372
|
+
return (
|
|
373
|
+
f &&
|
|
374
|
+
typeof f === 'object' &&
|
|
375
|
+
typeof f.category === 'string' &&
|
|
376
|
+
primaryMatches.includes(f.category.toLowerCase())
|
|
377
|
+
);
|
|
378
|
+
});
|
|
379
|
+
if (hasPriorIssues) {
|
|
380
|
+
score += 0.15;
|
|
381
|
+
matchedReasons.push('prior audit findings detected in specialist domain');
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// 5. Mandatory / Forced Reviewers
|
|
385
|
+
if (forcedReviewers.has(reviewer.name)) {
|
|
386
|
+
score += 1.0;
|
|
387
|
+
matchedReasons.push('explicitly forced by caller / governance contract');
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return {
|
|
391
|
+
reviewer,
|
|
392
|
+
score: parseFloat(score.toFixed(2)),
|
|
393
|
+
primaryMatches,
|
|
394
|
+
matchedReasons,
|
|
395
|
+
matchedEvidence: Array.from(new Set(matchedEvidence)),
|
|
396
|
+
};
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
// Sort candidates by score DESC, then name ASC
|
|
400
|
+
candidateScores.sort((a, b) => {
|
|
401
|
+
if (Math.abs(b.score - a.score) > 0.001) return b.score - a.score;
|
|
402
|
+
return a.reviewer.name.localeCompare(b.reviewer.name);
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// Selection Loop with Overlap Penalty
|
|
406
|
+
for (const candidate of candidateScores) {
|
|
407
|
+
const { reviewer, score, primaryMatches, matchedReasons, matchedEvidence } = candidate;
|
|
408
|
+
|
|
409
|
+
// Check if reviewer has any relevance
|
|
410
|
+
if (score <= 0.1 && !forcedReviewers.has(reviewer.name)) {
|
|
411
|
+
rejectedReviewers.push({
|
|
412
|
+
reviewer: reviewer.name,
|
|
413
|
+
reason: 'Zero domain overlap with active change set.',
|
|
414
|
+
});
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Check capacity limit
|
|
419
|
+
if (selectedReviewers.length >= maxCapacity) {
|
|
420
|
+
rejectedReviewers.push({
|
|
421
|
+
reviewer: reviewer.name,
|
|
422
|
+
reason: `Tier ${tier} capacity limit (${maxCapacity} reviewers) reached. Lower priority than selected peers.`,
|
|
423
|
+
});
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Check Overlap Group: If an overlap group is already present, apply penalty or skip
|
|
428
|
+
// Exception: In Tier 3 or when unique uncovered domains exist, overlap is tolerated
|
|
429
|
+
const hasOverlap = usedOverlapGroups.has(reviewer.overlap_group);
|
|
430
|
+
const bringsNewDomain = primaryMatches.some(d => !coveredDomains.has(d));
|
|
431
|
+
|
|
432
|
+
if (hasOverlap && !bringsNewDomain && !forcedReviewers.has(reviewer.name)) {
|
|
433
|
+
rejectedReviewers.push({
|
|
434
|
+
reviewer: reviewer.name,
|
|
435
|
+
reason: `Substantial overlap with already selected peer in group "${reviewer.overlap_group}".`,
|
|
436
|
+
});
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Select this reviewer
|
|
441
|
+
selectedReviewers.push({
|
|
442
|
+
reviewer: reviewer.name,
|
|
443
|
+
reason: matchedReasons.join(' | ') || 'Specialist alignment with detected change scope',
|
|
444
|
+
risk_covered: primaryMatches.join(', ') || 'general',
|
|
445
|
+
evidence_supplied: matchedEvidence,
|
|
446
|
+
expected_contribution: reviewer.expected_contribution,
|
|
447
|
+
score,
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
primaryMatches.forEach(d => coveredDomains.add(d));
|
|
451
|
+
usedOverlapGroups.add(reviewer.overlap_group);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Safety Verification: Ensure critical domains are covered
|
|
455
|
+
const criticalUncovered = requiredDomains.filter(
|
|
456
|
+
d => ['security', 'database', 'auth'].includes(d) && !coveredDomains.has(d),
|
|
457
|
+
);
|
|
458
|
+
const allRisksCovered = criticalUncovered.length === 0;
|
|
459
|
+
|
|
460
|
+
return {
|
|
461
|
+
selected: selectedReviewers,
|
|
462
|
+
rejected: rejectedReviewers,
|
|
463
|
+
total_selected: selectedReviewers.length,
|
|
464
|
+
coverage: {
|
|
465
|
+
domains_required: requiredDomains,
|
|
466
|
+
domains_covered: Array.from(coveredDomains),
|
|
467
|
+
all_risks_covered: allRisksCovered,
|
|
468
|
+
uncovered_critical: criticalUncovered,
|
|
469
|
+
},
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
module.exports = {
|
|
474
|
+
orchestrateReviewers,
|
|
475
|
+
detectRequiredDomains,
|
|
476
|
+
REVIEWER_CATALOG,
|
|
477
|
+
};
|
package/src/tui/banner.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
const { isTTY, hasColor, hasTrueColor, RGB, GLYPHS, color, bold, getColumns } = require('./theme');
|
|
9
9
|
|
|
10
|
-
function renderBanner(version = '9.2.
|
|
10
|
+
function renderBanner(version = '9.2.7', quiet = false) {
|
|
11
11
|
if (quiet) return;
|
|
12
12
|
if (!isTTY && !hasColor) {
|
|
13
13
|
console.error(`TRIBUNAL-KIT v${version} — Anti-Hallucination Governance Layer`);
|
package/src/utils/fs.js
CHANGED
|
@@ -8,6 +8,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
8
8
|
exports.copyDir = copyDir;
|
|
9
9
|
exports.countDir = countDir;
|
|
10
10
|
exports.isSelfInstall = isSelfInstall;
|
|
11
|
+
exports.writeFileSyncAtomic = writeFileSyncAtomic;
|
|
11
12
|
const fs_1 = __importDefault(require('fs'));
|
|
12
13
|
const path_1 = __importDefault(require('path'));
|
|
13
14
|
const logger_1 = require('./logger');
|
|
@@ -101,3 +102,29 @@ function isSelfInstall(targetDir, pkgName, kitRoot) {
|
|
|
101
102
|
}
|
|
102
103
|
return false;
|
|
103
104
|
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Atomically writes data to a file by writing to a temporary file in the same directory
|
|
108
|
+
* and renaming it into place. Handles cross-platform and Windows locking cleanly.
|
|
109
|
+
*/
|
|
110
|
+
function writeFileSyncAtomic(filePath, data, encoding = 'utf8') {
|
|
111
|
+
const dir = path_1.default.dirname(filePath);
|
|
112
|
+
if (!fs_1.default.existsSync(dir)) fs_1.default.mkdirSync(dir, { recursive: true });
|
|
113
|
+
const tmpPath = path_1.default.join(
|
|
114
|
+
dir,
|
|
115
|
+
`.${path_1.default.basename(filePath)}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 6)}.tmp`,
|
|
116
|
+
);
|
|
117
|
+
fs_1.default.writeFileSync(tmpPath, data, encoding);
|
|
118
|
+
try {
|
|
119
|
+
fs_1.default.renameSync(tmpPath, filePath);
|
|
120
|
+
} catch (err) {
|
|
121
|
+
if (process.platform === 'win32' && (err.code === 'EEXIST' || err.code === 'EPERM')) {
|
|
122
|
+
try {
|
|
123
|
+
fs_1.default.unlinkSync(filePath);
|
|
124
|
+
} catch (_) {}
|
|
125
|
+
fs_1.default.renameSync(tmpPath, filePath);
|
|
126
|
+
} else {
|
|
127
|
+
throw err;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|