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.
Files changed (2) hide show
  1. package/dist/index.js +96 -31
  2. 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
- factors.push(scoreRecency(meta3));
27593
- factors.push(scorePopularity(meta3));
27594
- factors.push(scoreQuality(meta3));
27595
- factors.push(scoreRepository(meta3));
27596
- factors.push(scoreSafety(meta3));
27597
- const totalScore = Math.min(100, factors.reduce((sum, f) => sum + f.score, 0));
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 = 15;
27709
+ let score = 13;
27705
27710
  const details = [];
27706
27711
  if (isTyposquatSuspect(meta3.name)) {
27707
- score -= 15;
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
- if (KNOWN_SCOPES.some((s) => meta3.name.startsWith(s))) {
27713
- score = Math.min(maxScore, score + 3);
27714
- details.push("Known scope");
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
- const deps = meta3.dependencyCount ?? 0;
27717
- if (deps > 50) {
27718
- score = Math.max(0, score - 5);
27719
- details.push(`${deps} deps \u2014 heavy`);
27720
- } else if (deps > 20) {
27721
- score = Math.max(0, score - 2);
27722
- details.push(`${deps} deps`);
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
- return { name: "safety", score: Math.max(0, score), maxScore, detail: details.join(", ") };
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
- return TYPOSQUAT_PATTERNS.some((p) => p.test(name));
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
- if (score >= 90)
27787
+ const pct = score / MAX_TRUST_SCORE;
27788
+ if (pct >= 0.9)
27731
27789
  return "high";
27732
- if (score >= 70)
27790
+ if (pct >= 0.7)
27733
27791
  return "medium";
27734
- if (score >= 40)
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}/100 (${level}) \u2014 weakest: ${weakest.name} (${weakest.score}/${weakest.maxScore}: ${weakest.detail})`;
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 scoreTag = `[${trustResult.score}/100 ${trustResult.level}]`;
28448
- trustLines.push(` ${scoreTag} ${rec.name} \u2014 ${rec.reason}`);
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 < minScore) {
28517
+ if (trustResult.score < effectiveMinScore) {
28453
28518
  skipped.push({
28454
28519
  name: rec.name,
28455
- reason: `Trust score ${trustResult.score} < ${minScore} (${trustResult.level})`
28520
+ reason: `Trust score ${trustResult.score} < ${effectiveMinScore} (${trustResult.level})${highPrivTag}`
28456
28521
  });
28457
- trustLines.push(` -> REJECTED (below threshold ${minScore})`);
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.6.4",
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",