opencode-ultra 0.6.4 → 0.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.
- package/dist/index.js +96 -31
- package/package.json +16 -1
package/dist/index.js
CHANGED
|
@@ -27570,6 +27570,7 @@ function sanitizeSpawnResult(result) {
|
|
|
27570
27570
|
` + text;
|
|
27571
27571
|
}
|
|
27572
27572
|
// src/safety/trust-score.ts
|
|
27573
|
+
var MAX_TRUST_SCORE = 108;
|
|
27573
27574
|
var KNOWN_SCOPES = [
|
|
27574
27575
|
"@opencode-ai/",
|
|
27575
27576
|
"opencode-",
|
|
@@ -27588,13 +27589,17 @@ var TYPOSQUAT_PATTERNS = [
|
|
|
27588
27589
|
/^opencode-.{1,3}$/i
|
|
27589
27590
|
];
|
|
27590
27591
|
function computeTrustScore(meta3) {
|
|
27591
|
-
const factors = [
|
|
27592
|
-
|
|
27593
|
-
|
|
27594
|
-
|
|
27595
|
-
|
|
27596
|
-
|
|
27597
|
-
|
|
27592
|
+
const factors = [
|
|
27593
|
+
scoreRecency(meta3),
|
|
27594
|
+
scorePopularity(meta3),
|
|
27595
|
+
scoreQuality(meta3),
|
|
27596
|
+
scoreRepository(meta3),
|
|
27597
|
+
scoreSafety(meta3),
|
|
27598
|
+
scoreProvenance(meta3),
|
|
27599
|
+
scoreDependencyRisk(meta3)
|
|
27600
|
+
];
|
|
27601
|
+
const raw = factors.reduce((sum, f) => sum + f.score, 0);
|
|
27602
|
+
const totalScore = clamp(raw, 0, MAX_TRUST_SCORE);
|
|
27598
27603
|
const level = classifyLevel(totalScore);
|
|
27599
27604
|
const summary = buildSummary(meta3.name, totalScore, level, factors);
|
|
27600
27605
|
log("Trust score computed", { package: meta3.name, score: totalScore, level });
|
|
@@ -27701,49 +27706,107 @@ function scoreRepository(meta3) {
|
|
|
27701
27706
|
}
|
|
27702
27707
|
function scoreSafety(meta3) {
|
|
27703
27708
|
const maxScore = 15;
|
|
27704
|
-
let score =
|
|
27709
|
+
let score = 13;
|
|
27705
27710
|
const details = [];
|
|
27706
27711
|
if (isTyposquatSuspect(meta3.name)) {
|
|
27707
|
-
score
|
|
27712
|
+
score = 0;
|
|
27708
27713
|
details.push("TYPOSQUAT SUSPECT");
|
|
27709
27714
|
} else {
|
|
27710
27715
|
details.push("Name OK");
|
|
27716
|
+
if (KNOWN_SCOPES.some((s) => meta3.name.startsWith(s))) {
|
|
27717
|
+
score = Math.min(maxScore, score + 2);
|
|
27718
|
+
details.push("Known scope");
|
|
27719
|
+
}
|
|
27711
27720
|
}
|
|
27712
|
-
|
|
27713
|
-
|
|
27714
|
-
|
|
27721
|
+
return { name: "safety", score: Math.max(0, score), maxScore, detail: details.join(", ") };
|
|
27722
|
+
}
|
|
27723
|
+
function scoreProvenance(meta3) {
|
|
27724
|
+
const maxScore = 8;
|
|
27725
|
+
if (meta3.hasProvenance) {
|
|
27726
|
+
return { name: "provenance", score: 8, maxScore, detail: "Has npm provenance/attestation" };
|
|
27715
27727
|
}
|
|
27716
|
-
|
|
27717
|
-
|
|
27718
|
-
|
|
27719
|
-
|
|
27720
|
-
|
|
27721
|
-
|
|
27722
|
-
|
|
27728
|
+
return { name: "provenance", score: 0, maxScore, detail: "No npm provenance" };
|
|
27729
|
+
}
|
|
27730
|
+
function scoreDependencyRisk(meta3) {
|
|
27731
|
+
const maxScore = 5;
|
|
27732
|
+
const deps = meta3.dependencyCount;
|
|
27733
|
+
if (deps === undefined) {
|
|
27734
|
+
return { name: "dependency_risk", score: 0, maxScore, detail: "No dependency info" };
|
|
27723
27735
|
}
|
|
27724
|
-
|
|
27736
|
+
if (deps > 20) {
|
|
27737
|
+
return { name: "dependency_risk", score: -5, maxScore, detail: `${deps} deps > 20 \u2014 supply-chain risk` };
|
|
27738
|
+
}
|
|
27739
|
+
return { name: "dependency_risk", score: 0, maxScore, detail: `${deps} deps` };
|
|
27725
27740
|
}
|
|
27726
27741
|
function isTyposquatSuspect(name) {
|
|
27727
|
-
|
|
27742
|
+
if (TYPOSQUAT_PATTERNS.some((p) => p.test(name)))
|
|
27743
|
+
return true;
|
|
27744
|
+
const base = unscopedName(name).toLowerCase();
|
|
27745
|
+
const target = "opencode-ultra";
|
|
27746
|
+
if (base && base !== target && levenshteinDistance(base, target) <= 2)
|
|
27747
|
+
return true;
|
|
27748
|
+
return false;
|
|
27749
|
+
}
|
|
27750
|
+
function isHighPrivilege(name) {
|
|
27751
|
+
return /\b(pty|exec|shell|sudo)\b/i.test(name);
|
|
27752
|
+
}
|
|
27753
|
+
function unscopedName(name) {
|
|
27754
|
+
if (!name)
|
|
27755
|
+
return "";
|
|
27756
|
+
if (name.startsWith("@")) {
|
|
27757
|
+
const parts = name.split("/");
|
|
27758
|
+
return parts[1] ?? name;
|
|
27759
|
+
}
|
|
27760
|
+
return name;
|
|
27761
|
+
}
|
|
27762
|
+
function levenshteinDistance(a, b) {
|
|
27763
|
+
if (a === b)
|
|
27764
|
+
return 0;
|
|
27765
|
+
if (a.length === 0)
|
|
27766
|
+
return b.length;
|
|
27767
|
+
if (b.length === 0)
|
|
27768
|
+
return a.length;
|
|
27769
|
+
const m = a.length;
|
|
27770
|
+
const n = b.length;
|
|
27771
|
+
const dp = new Array(n + 1);
|
|
27772
|
+
for (let j = 0;j <= n; j++)
|
|
27773
|
+
dp[j] = j;
|
|
27774
|
+
for (let i = 1;i <= m; i++) {
|
|
27775
|
+
let prev = dp[0];
|
|
27776
|
+
dp[0] = i;
|
|
27777
|
+
for (let j = 1;j <= n; j++) {
|
|
27778
|
+
const tmp = dp[j];
|
|
27779
|
+
const cost = a.charCodeAt(i - 1) === b.charCodeAt(j - 1) ? 0 : 1;
|
|
27780
|
+
dp[j] = Math.min(dp[j] + 1, dp[j - 1] + 1, prev + cost);
|
|
27781
|
+
prev = tmp;
|
|
27782
|
+
}
|
|
27783
|
+
}
|
|
27784
|
+
return dp[n];
|
|
27728
27785
|
}
|
|
27729
27786
|
function classifyLevel(score) {
|
|
27730
|
-
|
|
27787
|
+
const pct = score / MAX_TRUST_SCORE;
|
|
27788
|
+
if (pct >= 0.9)
|
|
27731
27789
|
return "high";
|
|
27732
|
-
if (
|
|
27790
|
+
if (pct >= 0.7)
|
|
27733
27791
|
return "medium";
|
|
27734
|
-
if (
|
|
27792
|
+
if (pct >= 0.4)
|
|
27735
27793
|
return "low";
|
|
27736
27794
|
return "risky";
|
|
27737
27795
|
}
|
|
27738
27796
|
function daysSince(isoDate) {
|
|
27739
27797
|
const then = new Date(isoDate).getTime();
|
|
27798
|
+
if (!Number.isFinite(then))
|
|
27799
|
+
return 9999;
|
|
27740
27800
|
const now = Date.now();
|
|
27741
|
-
return Math.floor((now - then) / (1000 * 60 * 60 * 24));
|
|
27801
|
+
return Math.max(0, Math.floor((now - then) / (1000 * 60 * 60 * 24)));
|
|
27802
|
+
}
|
|
27803
|
+
function clamp(n, min, max) {
|
|
27804
|
+
return Math.max(min, Math.min(max, n));
|
|
27742
27805
|
}
|
|
27743
27806
|
function buildSummary(name, score, level, factors) {
|
|
27744
27807
|
const icon = level === "high" ? "V" : level === "medium" ? "~" : level === "low" ? "!" : "X";
|
|
27745
27808
|
const weakest = [...factors].sort((a, b) => a.score / a.maxScore - b.score / b.maxScore)[0];
|
|
27746
|
-
return `[${icon}] ${name}: ${score}
|
|
27809
|
+
return `[${icon}] ${name}: ${score}/${MAX_TRUST_SCORE} (${level}) \u2014 weakest: ${weakest.name} (${weakest.score}/${weakest.maxScore}: ${weakest.detail})`;
|
|
27747
27810
|
}
|
|
27748
27811
|
// src/tools/spawn-agent.ts
|
|
27749
27812
|
var DEFAULT_MAX_TOTAL_SPAWNED = 15;
|
|
@@ -28444,17 +28507,19 @@ evolve_apply({
|
|
|
28444
28507
|
}
|
|
28445
28508
|
const meta3 = rec.metadata ?? { name: rec.name };
|
|
28446
28509
|
const trustResult = computeTrustScore(meta3);
|
|
28447
|
-
const
|
|
28448
|
-
|
|
28510
|
+
const effectiveMinScore = isHighPrivilege(rec.name) ? minScore + 20 : minScore;
|
|
28511
|
+
const highPrivTag = isHighPrivilege(rec.name) ? " [HIGH-PRIV +20]" : "";
|
|
28512
|
+
const scoreTag = `[${trustResult.score}/108 ${trustResult.level}]`;
|
|
28513
|
+
trustLines.push(` ${scoreTag} ${rec.name}${highPrivTag} \u2014 ${rec.reason}`);
|
|
28449
28514
|
for (const f of trustResult.factors) {
|
|
28450
28515
|
trustLines.push(` ${f.name}: ${f.score}/${f.maxScore} (${f.detail})`);
|
|
28451
28516
|
}
|
|
28452
|
-
if (trustResult.score <
|
|
28517
|
+
if (trustResult.score < effectiveMinScore) {
|
|
28453
28518
|
skipped.push({
|
|
28454
28519
|
name: rec.name,
|
|
28455
|
-
reason: `Trust score ${trustResult.score} < ${
|
|
28520
|
+
reason: `Trust score ${trustResult.score} < ${effectiveMinScore} (${trustResult.level})${highPrivTag}`
|
|
28456
28521
|
});
|
|
28457
|
-
trustLines.push(` -> REJECTED (below threshold ${
|
|
28522
|
+
trustLines.push(` -> REJECTED (below threshold ${effectiveMinScore})`);
|
|
28458
28523
|
continue;
|
|
28459
28524
|
}
|
|
28460
28525
|
added.push(rec.name);
|
package/package.json
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-ultra",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Lightweight OpenCode 1.2.x plugin — ultrawork mode, multi-agent orchestration, rules injection",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"opencode",
|
|
7
|
+
"plugin",
|
|
8
|
+
"orchestration",
|
|
9
|
+
"multi-agent",
|
|
10
|
+
"ultrawork"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://github.com/outxci/opencode-ultra#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/outxci/opencode-ultra/issues"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/outxci/opencode-ultra.git"
|
|
19
|
+
},
|
|
5
20
|
"main": "dist/index.js",
|
|
6
21
|
"types": "dist/index.d.ts",
|
|
7
22
|
"type": "module",
|