@orangepro/orangepro-mcp 0.2.39 → 0.2.41
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/local/cli.js
CHANGED
|
@@ -692,6 +692,8 @@ async function main() {
|
|
|
692
692
|
printJson(res);
|
|
693
693
|
else {
|
|
694
694
|
out(`Test gaps (${res.gaps.length} of ${res.total_behaviors} behaviors):`);
|
|
695
|
+
for (const w of res.warnings ?? [])
|
|
696
|
+
out(` warning: ${w}`);
|
|
695
697
|
if (res.guidance)
|
|
696
698
|
out(` ${res.guidance}`);
|
|
697
699
|
for (const g of res.gaps) {
|
package/dist/local/operations.js
CHANGED
|
@@ -656,7 +656,9 @@ export function opAnalyze(root, opts = {}, deps = defaultDeps()) {
|
|
|
656
656
|
const coverageSuccess = runtimeCoveragePrepare?.generated
|
|
657
657
|
.filter((g) => g.ok && g.artifact_path)
|
|
658
658
|
.map((g) => `coverage artifact generated for ${g.language} module ${g.module_dir}: ${g.artifact_path}`) ?? [];
|
|
659
|
-
|
|
659
|
+
// Risk-config problems must surface on EVERY entry point that ranks, not just `start`.
|
|
660
|
+
const riskConfigWarnings = loadRiskConfig(scanRoot).warnings;
|
|
661
|
+
const warnings = [...coverageSuccess, ...coverageWarnings, ...(runtimeCoveragePrepare?.warnings ?? []), ...analyzeFragment.warnings, ...enrichFragments.flatMap((f) => f.warnings), ...riskConfigWarnings];
|
|
660
662
|
return {
|
|
661
663
|
graph_path: paths.graphPath,
|
|
662
664
|
sources_count: graph.sources.length,
|
|
@@ -876,8 +878,11 @@ export function opGaps(root, opts = {}) {
|
|
|
876
878
|
is_new_code: gap.is_new_code,
|
|
877
879
|
integration_signal: gap.integration_signal
|
|
878
880
|
}));
|
|
881
|
+
// Same root the ranking itself uses (the analyzed source), not the workspace cwd.
|
|
882
|
+
const riskConfigWarnings = loadRiskConfig(graph.workspace.root).warnings;
|
|
879
883
|
return {
|
|
880
884
|
...gaps,
|
|
885
|
+
...(riskConfigWarnings.length ? { warnings: riskConfigWarnings } : {}),
|
|
881
886
|
top_risk_gaps: topRiskGaps,
|
|
882
887
|
risk_model: {
|
|
883
888
|
formula: "OrangePro Risk Score = Probability(1-10) × Impact(1-10) × DetectionDifficulty(1|5|10); P = normalize(git_churn*0.35 + fan_out*0.30 + new_code*15 + complexity*0.20); I = normalize(fan_in*0.30 + route_weight*0.30 + flow_position*0.20 + data_sensitivity*0.20); D = {proven:1, associated:5, none:10}",
|
|
@@ -301,8 +301,6 @@ body{padding-bottom:48px}
|
|
|
301
301
|
.mode-btn.active{background:var(--orange);color:#1a0a02;box-shadow:0 1px 3px rgba(240,136,62,.25)}
|
|
302
302
|
body[data-mode="simple"] .expert-only{display:none!important}
|
|
303
303
|
body[data-mode="simple"] .kpis{grid-template-columns:repeat(3,1fr)}
|
|
304
|
-
body[data-mode="simple"] .gen-test .gen-test-body{display:block}
|
|
305
|
-
body[data-mode="simple"] .gen-test .gen-test-toggle{display:none}
|
|
306
304
|
body[data-mode="simple"] .risk-card{border-left:3px solid var(--orange)}
|
|
307
305
|
body[data-mode="simple"] .risk-ctx{color:var(--ink2);font-size:13px}
|
|
308
306
|
body[data-mode="simple"] .todo{font-size:12.5px;font-weight:600;color:var(--ink);background:var(--obg);border-color:var(--obd)}
|
|
@@ -990,7 +988,7 @@ function riskCardHtml(r){
|
|
|
990
988
|
const cBadge=t.concern?\`<span class="badge b-info" style="margin-left:6px;font-size:9px">\${esc(t.concern.replace('_',' '))}</span>\`:'';
|
|
991
989
|
const iBadge=t.runnable===false?\`<span class="badge b-cand" style="margin-left:6px;font-size:9px">Manual test</span>\`:'';
|
|
992
990
|
const bBadge=t.bucket?\`<span class="badge b-info" style="margin-left:6px;font-size:9px">\${esc(String(t.bucket).replace(/_/g,' '))}</span>\`:'';
|
|
993
|
-
testsHtml+=\`<div class="gen-test"><div class="gen-test-head"><span class="gen-test-name">\${esc(t.name)}\${cBadge}\${bBadge}\${iBadge}</span><span class="gen-test-assert">\${esc(t.assertion)}</span><button class="copy-btn" onclick="event.stopPropagation();navigator.clipboard.writeText(this.closest('.gen-test').querySelector('.gen-test-body').textContent).then(()=>{this.textContent='Copied!';this.classList.add('copied');setTimeout(()=>{this.textContent='Copy';this.classList.remove('copied')},1500)})">Copy</button><span class="gen-test-toggle">▼</span></div><div class="gen-test-body">\${esc(t.code)}</div></div>\`;
|
|
991
|
+
testsHtml+=\`<div class="gen-test"><div class="gen-test-head" role="button" tabindex="0" aria-expanded="false"><span class="gen-test-name">\${esc(t.name)}\${cBadge}\${bBadge}\${iBadge}</span><span class="gen-test-assert">\${esc(t.assertion)}</span><button class="copy-btn" onclick="event.stopPropagation();navigator.clipboard.writeText(this.closest('.gen-test').querySelector('.gen-test-body').textContent).then(()=>{this.textContent='Copied!';this.classList.add('copied');setTimeout(()=>{this.textContent='Copy';this.classList.remove('copied')},1500)})">Copy</button><span class="gen-test-toggle" aria-hidden="true">▼</span></div><div class="gen-test-body">\${esc(t.code)}</div></div>\`;
|
|
994
992
|
});
|
|
995
993
|
testsHtml+=\`</div>\`;
|
|
996
994
|
}
|
|
@@ -1067,10 +1065,24 @@ renderRisks();
|
|
|
1067
1065
|
</div>\`;
|
|
1068
1066
|
host.addEventListener("click",e=>{const r=e.target.closest("[data-path]");if(r&&topPaths.has(r.getAttribute("data-path")))scrollToRisk(r.getAttribute("data-path"));});
|
|
1069
1067
|
})();
|
|
1070
|
-
//
|
|
1068
|
+
// Generated-test drafts are collapsed by default in every view. Keep the
|
|
1069
|
+
// control operable by pointer and keyboard; Simple mode must not override it.
|
|
1070
|
+
function toggleGeneratedTest(h){
|
|
1071
|
+
const item=h.closest('.gen-test');
|
|
1072
|
+
if(!item)return;
|
|
1073
|
+
const open=item.classList.toggle('open');
|
|
1074
|
+
h.setAttribute('aria-expanded',String(open));
|
|
1075
|
+
}
|
|
1071
1076
|
document.addEventListener('click',e=>{
|
|
1072
1077
|
const h=e.target.closest('.gen-test-head');
|
|
1073
|
-
if(h)h
|
|
1078
|
+
if(h)toggleGeneratedTest(h);
|
|
1079
|
+
});
|
|
1080
|
+
document.addEventListener('keydown',e=>{
|
|
1081
|
+
const h=e.target.closest('.gen-test-head');
|
|
1082
|
+
if(h&&(e.key==='Enter'||e.key===' ')){
|
|
1083
|
+
e.preventDefault();
|
|
1084
|
+
toggleGeneratedTest(h);
|
|
1085
|
+
}
|
|
1074
1086
|
});
|
|
1075
1087
|
|
|
1076
1088
|
// tabs
|
package/dist/local/workspace.js
CHANGED
|
@@ -92,7 +92,16 @@ export function loadConfig(paths) {
|
|
|
92
92
|
privacy: defaultPrivacySettings()
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
|
-
|
|
95
|
+
const raw = readFileSync(paths.configPath, "utf8");
|
|
96
|
+
try {
|
|
97
|
+
return JSON.parse(raw);
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
// Fail loud AND clear: this file also carries the per-repo risk config, so a
|
|
101
|
+
// silent default here would be exactly the failure a verification layer must not have.
|
|
102
|
+
const hint = /\/\//.test(raw) ? " JSON does not allow // comments." : "";
|
|
103
|
+
throw new Error(`Unreadable ${paths.configPath}: ${err.message}.${hint} Fix the JSON, or delete the file to regenerate defaults.`);
|
|
104
|
+
}
|
|
96
105
|
}
|
|
97
106
|
export function saveConfig(paths, config) {
|
|
98
107
|
writeJson(paths.configPath, config);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orangepro/orangepro-mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.41",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "OrangePro (`opro`) — a local-first, BYOK CLI + MCP server that builds an evidence graph from a local checkout, ingests runtime coverage, and generates grounded tests. Metadata-only exports; no source upload; generated tests stay local.",
|
|
6
6
|
"license": "MIT",
|