@lucasschirm/devinp 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # devinp
2
2
 
3
3
  Pretty pricing table for [Devin](https://devin.ai) models — reads live prices
4
- from `devin models list`, joins SWE-bench Verified scores, and renders a
4
+ from `devin models list`, joins BenchLM coding scores, and renders a
5
5
  sorted table in your terminal or a web page.
6
6
 
7
7
  Thinking-effort variants that share a price (`low`, `medium`, `high`, `xhigh`,
@@ -27,12 +27,12 @@ The package ships as a self-contained bundle — no dependencies are installed.
27
27
  ## Usage
28
28
 
29
29
  ```sh
30
- devinp # table sorted by best value (SWE % ÷ output price)
30
+ devinp # table sorted by best value (Bench % ÷ output price)
31
31
  devinp -o=input # cheapest input price first
32
32
  devinp -o=cached # cheapest cached-input price first
33
33
  devinp -o=output # cheapest output price first
34
- devinp -o=swe # highest SWE-bench Verified score first
35
- devinp -o=value # default: best SWE score per output dollar
34
+ devinp -o=bench # highest BenchLM coding score first
35
+ devinp -o=value # default: best Bench score per output dollar
36
36
 
37
37
  devinp -g=family # section the table by model family
38
38
  devinp -g=price # section by identical price tier
@@ -48,33 +48,35 @@ devinp --json # emit normalized rows as JSON
48
48
  ### Reading the table
49
49
 
50
50
  ```
51
- │ # │ Model │ Ctx │ Input │ Cached │ Output │ SWE % │ Value │ Sidekick i/c/o │
52
- │ 1 │ Gemini 3 Flash │ 1.05M │ $0.5 │ $0.05 │ $3 │ 75.8% │ 25.27 │ — │
51
+ │ # │ Model │ Ctx │ Input │ Cached │ Output │ Bench % │ Value │ Sidekick i/c/o │
52
+ │ 1 │ Gemini 3.8 Flash│ 1.05M │ $0.75 │ $0.08 │ $3.75 │ 64.1% │ 17.10 │ — │
53
53
  ```
54
54
 
55
55
  - Prices are USD per 1M tokens; columns are heat-colored green → red.
56
- - **Value** = `SWE % ÷ output $/1M` — the score you buy per output dollar.
57
- Free models show `∞`; models without a SWE score show `—` and sort last
58
- under `-o=swe` / `-o=value`.
56
+ - **Value** = `Bench % ÷ output $/1M` — the score you buy per output dollar.
57
+ Free models show `∞`; models without a Bench score show `—` and sort last
58
+ under `-o=bench` / `-o=value`.
59
59
  - Markers: `β` = beta, `●` = new, magenta name = free. `Sidekick` shows the
60
60
  partner-model pricing for Fusion rows.
61
61
  - Colors disable automatically when piping; `NO_COLOR` / `FORCE_COLOR` are
62
62
  respected.
63
63
 
64
- ## SWE-bench scores
64
+ ## BenchLM scores
65
65
 
66
- Scores live in `data/swe-scores.json` and ship with the package. To refresh
66
+ Scores live in `data/benchlm-scores.json` and ship with the package. To refresh
67
67
  them (maintainers, manual — not automated):
68
68
 
69
69
  ```sh
70
- npm run update-swe
70
+ npm run update-benchlm
71
71
  ```
72
72
 
73
- This scrapes the embedded leaderboard JSON on
74
- [swebench.com](https://www.swebench.com) — the **Verified** board's
75
- `mini-SWE-agent` ("Bash Only") entries — and writes `data/swe-scores.json`.
76
- Leaderboard names that don't map to a family slug are reported under
77
- `unmatched`; add entries to `MANUAL_MAP` in `scripts/update-swe.js` to fix them.
73
+ This fetches the [BenchLM](https://benchlm.ai/embed) leaderboard API
74
+ (`api/data/leaderboard?category=coding&limit=200` — the limit is raised from
75
+ the default 50 so the long tail of the board is included) and writes
76
+ `data/benchlm-scores.json`. Model names are
77
+ matched to Devin family slugs order-insensitively; names that still don't map
78
+ are reported under `unmatched` — add entries to `MANUAL_MAP` in
79
+ `scripts/update-benchlm.js` to fix them.
78
80
 
79
81
  ## Development
80
82
 
package/bin/command.js CHANGED
@@ -54630,10 +54630,10 @@ function formatContext(tokens) {
54630
54630
  function priceKey(cost) {
54631
54631
  return [cost.input, cost.cached, cost.output, cost.sidekick?.input, cost.sidekick?.cached, cost.sidekick?.output].map((n) => n == null ? "-" : n).join("/");
54632
54632
  }
54633
- function buildRows(data, sweScores = {}) {
54633
+ function buildRows(data, scores = {}) {
54634
54634
  const rows = /* @__PURE__ */ new Map();
54635
54635
  for (const family of data.families ?? []) {
54636
- const swe = sweScores.models?.[family.slug] ?? null;
54636
+ const bench = scores.models?.[family.slug] ?? null;
54637
54637
  for (const variant of family.variants ?? []) {
54638
54638
  const cost = parseCostSummary(variant.cost_summary);
54639
54639
  const label = normalizeLabel(variant.label, family.family_label);
@@ -54658,26 +54658,26 @@ function buildRows(data, sweScores = {}) {
54658
54658
  isBeta: Boolean(variant.is_beta),
54659
54659
  isNew: Boolean(variant.is_new),
54660
54660
  variantCount: 1,
54661
- swe: swe ? { resolved: swe.resolved, sweName: swe.sweName } : null,
54662
- value: computeValue(swe?.resolved, cost.output)
54661
+ bench: bench ? { score: bench.score, benchName: bench.benchName } : null,
54662
+ value: computeValue(bench?.score, cost.output)
54663
54663
  });
54664
54664
  }
54665
54665
  }
54666
54666
  return [...rows.values()];
54667
54667
  }
54668
- function computeValue(resolved, output) {
54669
- if (resolved == null) return null;
54668
+ function computeValue(score, output) {
54669
+ if (score == null) return null;
54670
54670
  if (output == null) return null;
54671
54671
  if (output === 0) return Number.POSITIVE_INFINITY;
54672
- return resolved / output;
54672
+ return score / output;
54673
54673
  }
54674
54674
  var priceAsc = (field) => (a2, b) => (a2[field] ?? Number.POSITIVE_INFINITY) - (b[field] ?? Number.POSITIVE_INFINITY) || (a2.output ?? Number.POSITIVE_INFINITY) - (b.output ?? Number.POSITIVE_INFINITY) || a2.label.localeCompare(b.label);
54675
54675
  var SORTS = {
54676
54676
  input: priceAsc("input"),
54677
54677
  cached: priceAsc("cached"),
54678
54678
  output: priceAsc("output"),
54679
- swe: (a2, b) => (b.swe?.resolved ?? -1) - (a2.swe?.resolved ?? -1) || (a2.output ?? Number.POSITIVE_INFINITY) - (b.output ?? Number.POSITIVE_INFINITY) || a2.label.localeCompare(b.label),
54680
- value: (a2, b) => (b.value ?? -1) - (a2.value ?? -1) || (b.swe?.resolved ?? -1) - (a2.swe?.resolved ?? -1) || a2.label.localeCompare(b.label)
54679
+ bench: (a2, b) => (b.bench?.score ?? -1) - (a2.bench?.score ?? -1) || (a2.output ?? Number.POSITIVE_INFINITY) - (b.output ?? Number.POSITIVE_INFINITY) || a2.label.localeCompare(b.label),
54680
+ value: (a2, b) => (b.value ?? -1) - (a2.value ?? -1) || (b.bench?.score ?? -1) - (a2.bench?.score ?? -1) || a2.label.localeCompare(b.label)
54681
54681
  };
54682
54682
  var SORT_IDS = Object.keys(SORTS);
54683
54683
  var GROUPS = {
@@ -54745,10 +54745,10 @@ function formatValue(c, row) {
54745
54745
  if (!Number.isFinite(row.value)) return c.magenta("\u221E");
54746
54746
  return c.bold.green(row.value.toFixed(2));
54747
54747
  }
54748
- function formatSwe(c, row) {
54749
- if (row.swe == null) return c.dim("\u2014");
54750
- const text = `${row.swe.resolved}%`;
54751
- return row.swe.resolved >= 70 ? c.cyan.bold(text) : c.cyan(text);
54748
+ function formatBench(c, row) {
54749
+ if (row.bench == null) return c.dim("\u2014");
54750
+ const text = `${row.bench.score}%`;
54751
+ return row.bench.score >= 70 ? c.cyan.bold(text) : c.cyan(text);
54752
54752
  }
54753
54753
  function formatLabel(c, row) {
54754
54754
  let text = row.free ? c.magenta(row.label) : c.bold(row.label);
@@ -54769,7 +54769,7 @@ function colorsEnabled(stream = process.stdout) {
54769
54769
  if (process.env.NO_COLOR) return false;
54770
54770
  return Boolean(stream.isTTY);
54771
54771
  }
54772
- function renderTable(sections, { sweMeta, colors = colorsEnabled() } = {}) {
54772
+ function renderTable(sections, { benchMeta, colors = colorsEnabled() } = {}) {
54773
54773
  const c = colors ? ansis_default : plain;
54774
54774
  const allRows = sections.flatMap((s) => s.rows);
54775
54775
  const hasSidekick = allRows.some((r) => r.sidekick);
@@ -54785,7 +54785,7 @@ function renderTable(sections, { sweMeta, colors = colorsEnabled() } = {}) {
54785
54785
  { title: "Input", align: "right" },
54786
54786
  { title: "Cached", align: "right" },
54787
54787
  { title: "Output", align: "right" },
54788
- { title: "SWE %", align: "right" },
54788
+ { title: "Bench %", align: "right" },
54789
54789
  { title: "Value", align: "right" }
54790
54790
  ];
54791
54791
  if (hasSidekick) columns.push({ title: "Sidekick i/c/o", align: "left" });
@@ -54803,7 +54803,7 @@ function renderTable(sections, { sweMeta, colors = colorsEnabled() } = {}) {
54803
54803
  formatPrice(c, row.input, ...ranges.input),
54804
54804
  formatPrice(c, row.cached, ...ranges.cached),
54805
54805
  formatPrice(c, row.output, ...ranges.output),
54806
- formatSwe(c, row),
54806
+ formatBench(c, row),
54807
54807
  formatValue(c, row),
54808
54808
  ...hasSidekick ? [formatSidekick(c, row)] : []
54809
54809
  ]
@@ -54830,13 +54830,29 @@ function renderTable(sections, { sweMeta, colors = colorsEnabled() } = {}) {
54830
54830
  out.push(line("\u2570", "\u2534", "\u256F"));
54831
54831
  const legend = [
54832
54832
  c.dim("prices per 1M tokens"),
54833
- c.dim("value = SWE % \xF7 output $/1M"),
54834
- sweMeta?.updated ? c.dim(`SWE-bench Verified (mini-SWE-agent) \xB7 updated ${sweMeta.updated}`) : c.dim("SWE scores: not available")
54833
+ c.dim("value = Bench % \xF7 output $/1M"),
54834
+ benchMeta?.updated ? c.dim(`BenchLM (coding) \xB7 updated ${benchMeta.updated}`) : c.dim("Bench scores: not available")
54835
54835
  ];
54836
54836
  return `${out.join("\n")}
54837
54837
  ${legend.join(c.dim(" \xB7 "))}`;
54838
54838
  }
54839
54839
 
54840
+ // src/lib/scores.js
54841
+ import { readFile } from "node:fs/promises";
54842
+ import { join } from "node:path";
54843
+ async function loadScores(root) {
54844
+ const path = join(root, "data", "benchlm-scores.json");
54845
+ try {
54846
+ const parsed = JSON.parse(await readFile(path, "utf8"));
54847
+ return {
54848
+ models: parsed.models ?? {},
54849
+ meta: { updated: parsed.updated, source: parsed.source, unmatched: parsed.unmatched ?? [] }
54850
+ };
54851
+ } catch {
54852
+ return { models: {}, meta: {} };
54853
+ }
54854
+ }
54855
+
54840
54856
  // src/lib/server.js
54841
54857
  var import_fastify = __toESM(require_fastify(), 1);
54842
54858
  import { execFile as execFile3 } from "node:child_process";
@@ -54871,7 +54887,7 @@ var PAGE = `<!doctype html>
54871
54887
  td.name, th.name { text-align: left; font-weight: 600; }
54872
54888
  td.dim { color: #64748b; }
54873
54889
  td.free { color: #e879f9; }
54874
- td.swe { color: #22d3ee; font-weight: 600; }
54890
+ td.bench { color: #22d3ee; font-weight: 600; }
54875
54891
  td.value { color: #4ade80; font-weight: 700; }
54876
54892
  tr.section td {
54877
54893
  color: #7dd3fc; font-weight: 700; text-align: left;
@@ -54882,12 +54898,12 @@ var PAGE = `<!doctype html>
54882
54898
  </head>
54883
54899
  <body>
54884
54900
  <h1>devinp</h1>
54885
- <div class="sub">Devin model prices \xB7 per 1M tokens \xB7 value = SWE % \xF7 output $/1M</div>
54901
+ <div class="sub">Devin model prices \xB7 per 1M tokens \xB7 value = Bench % \xF7 output $/1M</div>
54886
54902
  <div class="controls">
54887
54903
  <label>sort
54888
54904
  <select id="order">
54889
- <option value="value">best value (SWE \xF7 output)</option>
54890
- <option value="swe">SWE-bench score</option>
54905
+ <option value="value">best value (Bench \xF7 output)</option>
54906
+ <option value="bench">BenchLM score</option>
54891
54907
  <option value="input">input price</option>
54892
54908
  <option value="cached">cached price</option>
54893
54909
  <option value="output">output price</option>
@@ -54906,7 +54922,7 @@ var PAGE = `<!doctype html>
54906
54922
  <table>
54907
54923
  <thead><tr>
54908
54924
  <th>#</th><th class="name">Model</th><th>Ctx</th><th>Input</th>
54909
- <th>Cached</th><th>Output</th><th>SWE %</th><th>Value</th><th id="sk"></th>
54925
+ <th>Cached</th><th>Output</th><th>Bench %</th><th>Value</th><th id="sk"></th>
54910
54926
  </tr></thead>
54911
54927
  <tbody id="body"></tbody>
54912
54928
  </table>
@@ -54920,7 +54936,7 @@ const heat = (v, lo, hi) => v == null ? '<span class="dim">\u2014</span>'
54920
54936
 
54921
54937
  async function main() {
54922
54938
  const res = await fetch('/api/models');
54923
- const {rows, swe} = await res.json();
54939
+ const {rows, bench} = await res.json();
54924
54940
  const range = (f) => { const vs = rows.map(r => r[f]).filter(v => v != null); return [Math.min(...vs), Math.max(...vs)]; };
54925
54941
  const RI = range('input'), RC = range('cached'), RO = range('output');
54926
54942
  const hasSk = rows.some(r => r.sidekick);
@@ -54930,8 +54946,8 @@ async function main() {
54930
54946
  input: (a, b) => (a.input ?? 1e9) - (b.input ?? 1e9) || (a.output ?? 1e9) - (b.output ?? 1e9) || a.label.localeCompare(b.label),
54931
54947
  cached: (a, b) => (a.cached ?? 1e9) - (b.cached ?? 1e9) || (a.output ?? 1e9) - (b.output ?? 1e9) || a.label.localeCompare(b.label),
54932
54948
  output: (a, b) => (a.output ?? 1e9) - (b.output ?? 1e9) || a.label.localeCompare(b.label),
54933
- swe: (a, b) => (b.swe?.resolved ?? -1) - (a.swe?.resolved ?? -1) || (a.output ?? 1e9) - (b.output ?? 1e9) || a.label.localeCompare(b.label),
54934
- value: (a, b) => (b.value ?? -1) - (a.value ?? -1) || (b.swe?.resolved ?? -1) - (a.swe?.resolved ?? -1) || a.label.localeCompare(b.label),
54949
+ bench: (a, b) => (b.bench?.score ?? -1) - (a.bench?.score ?? -1) || (a.output ?? 1e9) - (b.output ?? 1e9) || a.label.localeCompare(b.label),
54950
+ value: (a, b) => (b.value ?? -1) - (a.value ?? -1) || (b.bench?.score ?? -1) - (a.bench?.score ?? -1) || a.label.localeCompare(b.label),
54935
54951
  };
54936
54952
  const GROUPS = {
54937
54953
  family: {key: r => r.familySlug, head: r => r.familyLabel},
@@ -54967,7 +54983,7 @@ async function main() {
54967
54983
  + '<td>' + heat(r.input, ...RI) + '</td>'
54968
54984
  + '<td>' + heat(r.cached, ...RC) + '</td>'
54969
54985
  + '<td>' + heat(r.output, ...RO) + '</td>'
54970
- + '<td class="swe">' + (r.swe ? r.swe.resolved + '%' : '<span class="dim">\u2014</span>') + '</td>'
54986
+ + '<td class="bench">' + (r.bench ? r.bench.score + '%' : '<span class="dim">\u2014</span>') + '</td>'
54971
54987
  + '<td class="value">' + (r.value == null ? '<span class="dim">\u2014</span>' : !isFinite(r.value) ? '\u221E' : r.value.toFixed(2)) + '</td>'
54972
54988
  + (hasSk ? '<td class="dim">' + (r.sidekick ? '$' + r.sidekick.input + '/$' + r.sidekick.cached + '/$' + r.sidekick.output : '\u2014') + '</td>' : '')
54973
54989
  + '</tr>';
@@ -54975,9 +54991,9 @@ async function main() {
54975
54991
  }
54976
54992
  document.getElementById('body').innerHTML = html;
54977
54993
  document.getElementById('count').textContent = n + ' rows';
54978
- document.getElementById('legend').textContent = swe.updated
54979
- ? 'SWE-bench Verified (mini-SWE-agent) \xB7 scores updated ' + swe.updated
54980
- : 'SWE scores not available';
54994
+ document.getElementById('legend').textContent = bench.updated
54995
+ ? 'BenchLM (coding) \xB7 scores updated ' + bench.updated
54996
+ : 'Bench scores not available';
54981
54997
  }
54982
54998
  document.getElementById('order').onchange = render;
54983
54999
  document.getElementById('group').onchange = render;
@@ -54987,12 +55003,12 @@ main();
54987
55003
  </script>
54988
55004
  </body>
54989
55005
  </html>`;
54990
- async function startServer({ rows, sweMeta, port, log }) {
55006
+ async function startServer({ rows, benchMeta, port, log }) {
54991
55007
  const app = (0, import_fastify.default)({ logger: false });
54992
55008
  app.get("/", async (_request, reply) => {
54993
55009
  reply.type("text/html").send(PAGE);
54994
55010
  });
54995
- app.get("/api/models", async () => ({ rows, swe: sweMeta ?? {} }));
55011
+ app.get("/api/models", async () => ({ rows, bench: benchMeta ?? {} }));
54996
55012
  const address = await app.listen({ port, host: "127.0.0.1" });
54997
55013
  log(`devinp web \u2014 ${address}`);
54998
55014
  const opener = process.platform === "darwin" ? "open" : "xdg-open";
@@ -55008,14 +55024,14 @@ async function startServer({ rows, sweMeta, port, log }) {
55008
55024
 
55009
55025
  // src/lib/source.js
55010
55026
  import { execFile as execFile4 } from "node:child_process";
55011
- import { readFile } from "node:fs/promises";
55027
+ import { readFile as readFile2 } from "node:fs/promises";
55012
55028
  import { promisify as promisify3 } from "node:util";
55013
55029
  var execFileAsync = promisify3(execFile4);
55014
55030
  async function loadModelData({ source } = {}) {
55015
55031
  if (source) {
55016
55032
  let raw;
55017
55033
  try {
55018
- raw = await readFile(source, "utf8");
55034
+ raw = await readFile2(source, "utf8");
55019
55035
  } catch (error) {
55020
55036
  throw new Error(`Unable to get model prices: cannot read source file "${source}" (${error.code ?? error.message})`);
55021
55037
  }
@@ -55045,35 +55061,19 @@ async function loadModelData({ source } = {}) {
55045
55061
  }
55046
55062
  }
55047
55063
 
55048
- // src/lib/swe.js
55049
- import { readFile as readFile2 } from "node:fs/promises";
55050
- import { join } from "node:path";
55051
- async function loadSweScores(root) {
55052
- const path = join(root, "data", "swe-scores.json");
55053
- try {
55054
- const parsed = JSON.parse(await readFile2(path, "utf8"));
55055
- return {
55056
- models: parsed.models ?? {},
55057
- meta: { updated: parsed.updated, source: parsed.source, unmatched: parsed.unmatched ?? [] }
55058
- };
55059
- } catch {
55060
- return { models: {}, meta: {} };
55061
- }
55062
- }
55063
-
55064
55064
  // src/command.js
55065
55065
  var Devinp = class _Devinp extends import_core.Command {
55066
55066
  static summary = "Show Devin model prices in a pretty table";
55067
55067
  static description = [
55068
55068
  "Reads prices from `devin models list --format json` (or a saved snapshot via",
55069
- "--source), joins SWE-bench Verified scores from data/swe-scores.json, and",
55069
+ "--source), joins BenchLM coding scores from data/benchlm-scores.json, and",
55070
55070
  "renders a sorted pricing table. Thinking-effort variants that share a price",
55071
55071
  "are collapsed into one row."
55072
55072
  ].join("\n");
55073
55073
  static examples = [
55074
55074
  "<%= config.bin %>",
55075
55075
  "<%= config.bin %> -o=input",
55076
- "<%= config.bin %> -o=swe -g=family",
55076
+ "<%= config.bin %> -o=bench -g=family",
55077
55077
  "<%= config.bin %> --web --port 8080",
55078
55078
  "<%= config.bin %> --source sample/models.json"
55079
55079
  ];
@@ -55082,7 +55082,7 @@ var Devinp = class _Devinp extends import_core.Command {
55082
55082
  char: "o",
55083
55083
  options: SORT_IDS,
55084
55084
  default: "value",
55085
- summary: "sort by input | cached | output price, swe score, or value (SWE \xF7 output)"
55085
+ summary: "sort by input | cached | output price, bench score, or value (Bench \xF7 output)"
55086
55086
  }),
55087
55087
  group: import_core.Flags.string({
55088
55088
  char: "g",
@@ -55115,18 +55115,18 @@ var Devinp = class _Devinp extends import_core.Command {
55115
55115
  } catch (error) {
55116
55116
  this.error(error instanceof Error ? error.message : String(error), { exit: 1 });
55117
55117
  }
55118
- const swe = await loadSweScores(this.config.root);
55119
- const rows = buildRows(data, swe);
55118
+ const scores = await loadScores(this.config.root);
55119
+ const rows = buildRows(data, scores);
55120
55120
  if (flags.json) {
55121
55121
  this.log(JSON.stringify(rows, null, 2));
55122
55122
  return;
55123
55123
  }
55124
55124
  if (flags.web) {
55125
- await startServer({ rows, sweMeta: swe.meta, port: flags.port, log: (m) => this.log(m) });
55125
+ await startServer({ rows, benchMeta: scores.meta, port: flags.port, log: (m) => this.log(m) });
55126
55126
  return;
55127
55127
  }
55128
55128
  const sections = arrangeRows(rows, { order: flags.order, group: flags.group });
55129
- this.log(renderTable(sections, { sweMeta: swe.meta }));
55129
+ this.log(renderTable(sections, { benchMeta: scores.meta }));
55130
55130
  }
55131
55131
  };
55132
55132
  export {
@@ -0,0 +1,293 @@
1
+ {
2
+ "updated": "2026-09-22",
3
+ "source": "https://benchlm.ai/api/data/leaderboard?category=coding&limit=200",
4
+ "models": {
5
+ "claude-fable-5": {
6
+ "score": 74.47,
7
+ "benchName": "Claude Fable 5",
8
+ "supported": true
9
+ },
10
+ "claude-fable-5.1": {
11
+ "score": 81.29,
12
+ "benchName": "Claude Fable 5.1",
13
+ "supported": true
14
+ },
15
+ "claude-haiku-4.5": {
16
+ "score": 19.77,
17
+ "benchName": "Claude Haiku 4.5",
18
+ "supported": true
19
+ },
20
+ "claude-opus-4.5": {
21
+ "score": 46.1,
22
+ "benchName": "Claude Opus 4.5",
23
+ "supported": false
24
+ },
25
+ "claude-opus-4.6": {
26
+ "score": 51.32,
27
+ "benchName": "Claude Opus 4.6",
28
+ "supported": true
29
+ },
30
+ "claude-opus-4.7": {
31
+ "score": 59.77,
32
+ "benchName": "Claude Opus 4.7",
33
+ "supported": true
34
+ },
35
+ "claude-opus-4.8": {
36
+ "score": 63.58,
37
+ "benchName": "Claude Opus 4.8",
38
+ "supported": true
39
+ },
40
+ "claude-opus-5": {
41
+ "score": 72.91,
42
+ "benchName": "Claude Opus 5",
43
+ "supported": true
44
+ },
45
+ "claude-opus-5.5": {
46
+ "score": 86.85,
47
+ "benchName": "Claude Opus 5.5",
48
+ "supported": true
49
+ },
50
+ "claude-sonnet-4.6": {
51
+ "score": 48.52,
52
+ "benchName": "Claude Sonnet 4.6",
53
+ "supported": true
54
+ },
55
+ "claude-sonnet-5": {
56
+ "score": 61.05,
57
+ "benchName": "Claude Sonnet 5",
58
+ "supported": true
59
+ },
60
+ "gemini-3-flash": {
61
+ "score": 36.84,
62
+ "benchName": "Gemini 3 Flash",
63
+ "supported": true
64
+ },
65
+ "gemini-3.1-pro": {
66
+ "score": 43.36,
67
+ "benchName": "Gemini 3.1 Pro",
68
+ "supported": true
69
+ },
70
+ "gemini-3.5-flash": {
71
+ "score": 53.7,
72
+ "benchName": "Gemini 3.5 Flash",
73
+ "supported": true
74
+ },
75
+ "gemini-3.6-flash": {
76
+ "score": 54.73,
77
+ "benchName": "Gemini 3.6 Flash",
78
+ "supported": true
79
+ },
80
+ "gemini-3.7-flash": {
81
+ "score": 59.79,
82
+ "benchName": "Gemini 3.7 Flash",
83
+ "supported": true
84
+ },
85
+ "gemini-3.8-flash": {
86
+ "score": 64.14,
87
+ "benchName": "Gemini 3.8 Flash",
88
+ "supported": true
89
+ },
90
+ "glm-5.2": {
91
+ "score": 57.32,
92
+ "benchName": "GLM-5.2",
93
+ "supported": true
94
+ },
95
+ "glm-5.3": {
96
+ "score": 58.15,
97
+ "benchName": "GLM-5.3",
98
+ "supported": true
99
+ },
100
+ "glm-5.3-flash": {
101
+ "score": 51.6,
102
+ "benchName": "GLM-5.3-Flash",
103
+ "supported": true
104
+ },
105
+ "gpt-5.1": {
106
+ "score": 39.77,
107
+ "benchName": "GPT-5.1",
108
+ "supported": true
109
+ },
110
+ "gpt-5.2": {
111
+ "score": 41.57,
112
+ "benchName": "GPT-5.2",
113
+ "supported": true
114
+ },
115
+ "gpt-5.3-codex": {
116
+ "score": 56.8,
117
+ "benchName": "GPT-5.3 Codex",
118
+ "supported": true
119
+ },
120
+ "gpt-5.4": {
121
+ "score": 50.93,
122
+ "benchName": "GPT-5.4",
123
+ "supported": true
124
+ },
125
+ "gpt-5.4-mini": {
126
+ "score": 38.61,
127
+ "benchName": "GPT-5.4 mini",
128
+ "supported": true
129
+ },
130
+ "gpt-5.5": {
131
+ "score": 64.47,
132
+ "benchName": "GPT-5.5",
133
+ "supported": true
134
+ },
135
+ "gpt-5.6-luna": {
136
+ "score": 64.72,
137
+ "benchName": "GPT-5.6 Luna",
138
+ "supported": true
139
+ },
140
+ "gpt-5.6-sol": {
141
+ "score": 71.77,
142
+ "benchName": "GPT-5.6 Sol",
143
+ "supported": true
144
+ },
145
+ "gpt-5.6-terra": {
146
+ "score": 65.05,
147
+ "benchName": "GPT-5.6 Terra",
148
+ "supported": true
149
+ },
150
+ "gpt-6-astra": {
151
+ "score": 74.43,
152
+ "benchName": "GPT-6 Astra",
153
+ "supported": true
154
+ },
155
+ "gpt-6-luna": {
156
+ "score": 59.93,
157
+ "benchName": "GPT-6 Luna",
158
+ "supported": true
159
+ },
160
+ "gpt-6-sol": {
161
+ "score": 65.48,
162
+ "benchName": "GPT-6 Sol",
163
+ "supported": true
164
+ },
165
+ "grok-4.5": {
166
+ "score": 58.55,
167
+ "benchName": "Grok 4.5",
168
+ "supported": true
169
+ },
170
+ "grok-4.6": {
171
+ "score": 62.55,
172
+ "benchName": "Grok 4.6",
173
+ "supported": true
174
+ },
175
+ "inkling": {
176
+ "score": 37.23,
177
+ "benchName": "Inkling",
178
+ "supported": true
179
+ },
180
+ "kimi-k2.6": {
181
+ "score": 47.36,
182
+ "benchName": "Kimi K2.6",
183
+ "supported": true
184
+ },
185
+ "kimi-k3": {
186
+ "score": 63.31,
187
+ "benchName": "Kimi K3",
188
+ "supported": true
189
+ },
190
+ "nemotron-3-ultra": {
191
+ "score": 23.53,
192
+ "benchName": "Nemotron 3 Ultra",
193
+ "supported": true
194
+ }
195
+ },
196
+ "unmatched": [
197
+ "Apodex 1.1",
198
+ "Claude 3 Opus",
199
+ "Command A+",
200
+ "DeepSeek V3",
201
+ "DeepSeek V3.2",
202
+ "DeepSeek V3.2 (Thinking)",
203
+ "DeepSeek V4 Pro 0813",
204
+ "GLM-4.6",
205
+ "GLM-4.7",
206
+ "GLM-5",
207
+ "GLM-5.1",
208
+ "GLM-5V-Turbo",
209
+ "GPT-4 Turbo",
210
+ "GPT-4.1 mini",
211
+ "GPT-4.1 nano",
212
+ "GPT-4o mini",
213
+ "GPT-5 (medium)",
214
+ "GPT-5 mini",
215
+ "GPT-5.1-Codex",
216
+ "GPT-5.2-Codex",
217
+ "GPT-5.4 nano",
218
+ "GPT-OSS 120B",
219
+ "GPT-OSS 20B",
220
+ "Gemini 1.5 Pro",
221
+ "Gemini 2.5 Pro",
222
+ "Gemini 3 Pro",
223
+ "Gemini 3.1 Flash-Lite",
224
+ "Gemini 3.5 Flash-Lite",
225
+ "Gemma 3 27B",
226
+ "Gemma 4 12B",
227
+ "Gemma 4 26B A4B",
228
+ "Gemma 4 31B",
229
+ "Gemma 4 E2B",
230
+ "Gemma 4 E4B",
231
+ "Granite 4.2 8B",
232
+ "Grok 4 Fast (Reasoning)",
233
+ "Grok 4.1 Fast (Reasoning)",
234
+ "Grok 4.20",
235
+ "Grok 4.3",
236
+ "Grok Build 0.1",
237
+ "Grok Code Fast 1",
238
+ "Hy3",
239
+ "Hy3 Preview",
240
+ "Hy4 preview",
241
+ "Inkling-Small",
242
+ "K-Exaone",
243
+ "Kimi K2.5",
244
+ "Kimi K2.7 Code",
245
+ "LFM2.5-2.6B",
246
+ "Laguna M.1",
247
+ "Laguna XS.2",
248
+ "Ling 2.6 Flash",
249
+ "Ling 3.0 Flash",
250
+ "Llama 4 Maverick",
251
+ "Llama 4 Scout",
252
+ "Mercury 2",
253
+ "Mercury 2.5",
254
+ "MiMo-V2-Flash",
255
+ "MiMo-V2-Pro",
256
+ "MiMo-V2.5",
257
+ "MiMo-V2.5-Pro",
258
+ "MiniMax M2.5",
259
+ "MiniMax M2.7",
260
+ "MiniMax M3",
261
+ "Ministral 3 14B",
262
+ "Ministral 3 3B",
263
+ "Ministral 3 8B",
264
+ "Mistral Large 3",
265
+ "Mistral Medium 3.5 128B",
266
+ "Mistral Small 4",
267
+ "Muse Glimmer 30B",
268
+ "Muse Spark",
269
+ "Muse Spark 1.1",
270
+ "Muse Spark 1.2",
271
+ "Nemotron 3 Nano Omni 30B A3B",
272
+ "Nemotron 3.5 Lightning 30B A3B NVFP4",
273
+ "Ornith-1.5-35B-A3B",
274
+ "Ornith-1.5-397B",
275
+ "Qwen 3.6 Max (preview)",
276
+ "Qwen3.5 Flash",
277
+ "Qwen3.5-122B-A10B",
278
+ "Qwen3.5-27B",
279
+ "Qwen3.5-35B-A3B",
280
+ "Qwen3.6 Plus",
281
+ "Qwen3.6-27B",
282
+ "Qwen3.6-35B-A3B",
283
+ "Qwen3.7 Max",
284
+ "Qwen3.7 Plus",
285
+ "Qwen3.8 Max",
286
+ "Qwen3.8-27B",
287
+ "Qwen3.8-Flash-Next",
288
+ "Step 3.7 Flash",
289
+ "Trinity-Large-Thinking",
290
+ "o1",
291
+ "o1-preview"
292
+ ]
293
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucasschirm/devinp",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Pretty pricing table for Devin models, powered by `devin models list`",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,7 +23,7 @@
23
23
  "devin",
24
24
  "pricing",
25
25
  "models",
26
- "swe-bench",
26
+ "benchlm",
27
27
  "cli"
28
28
  ],
29
29
  "engines": {
@@ -35,7 +35,7 @@
35
35
  "prepack": "npm run build",
36
36
  "prepare": "npm run build",
37
37
  "test": "node --test",
38
- "update-swe": "node scripts/update-swe.js"
38
+ "update-benchlm": "node scripts/update-benchlm.js"
39
39
  },
40
40
  "oclif": {
41
41
  "bin": "devinp",
@@ -1,73 +0,0 @@
1
- {
2
- "updated": "2026-09-21",
3
- "source": "https://www.swebench.com/index.html (Verified · mini-SWE-agent)",
4
- "models": {
5
- "gemini-3-flash": {
6
- "resolved": 75.8,
7
- "sweName": "Gemini 3 Flash (high)",
8
- "checked": false,
9
- "date": "2026-02-17"
10
- },
11
- "gpt-4.1": {
12
- "resolved": 39.58,
13
- "sweName": "GPT 4.1 (2025-04-14)",
14
- "checked": true,
15
- "date": "2025-07-26"
16
- },
17
- "gpt-5.1": {
18
- "resolved": 66,
19
- "sweName": "GPT 5.1 (2025-11-13) (medium)",
20
- "checked": false,
21
- "date": "2025-11-20"
22
- },
23
- "gpt-5.2": {
24
- "resolved": 72.8,
25
- "sweName": "GPT 5.2 (high)",
26
- "checked": false,
27
- "date": "2026-02-17"
28
- }
29
- },
30
- "unmatched": [
31
- "Claude 3.7 Sonnet (20250219)",
32
- "Claude 4 Opus (20250514)",
33
- "Claude 4 Sonnet (20250514)",
34
- "Claude 4.5 Haiku (high)",
35
- "Claude 4.5 Opus (20251101) (medium)",
36
- "Claude 4.5 Opus (high)",
37
- "Claude 4.5 Sonnet (20250929)",
38
- "Claude 4.5 Sonnet (high)",
39
- "Claude 4.6 Opus",
40
- "DeepSeek V3.2 (high)",
41
- "DeepSeek V3.2 Reasoner",
42
- "Devstral (2512)",
43
- "Devstral Small (2512)",
44
- "GLM 4.5 (2025-08-22)",
45
- "GLM 4.6 (T=1)",
46
- "GLM 5 (high)",
47
- "GPT 4.1 mini (2025-04-14)",
48
- "GPT 4o (2024-11-20)",
49
- "GPT 5 (2025-08-07) (medium)",
50
- "GPT 5 mini",
51
- "GPT 5 mini (2025-08-07) (medium)",
52
- "GPT 5 nano (2025-08-07) (medium)",
53
- "GPT 5.1 Codex (medium)",
54
- "GPT 5.2 Codex",
55
- "Gemini 2.0 Flash",
56
- "Gemini 2.5 Flash (2025-04-17)",
57
- "Gemini 2.5 Pro (2025-05-06)",
58
- "Gemini 3 Pro",
59
- "Gemini 3 Pro Preview (2025-11-18)",
60
- "Kimi K2 Instruct",
61
- "Kimi K2 Thinking",
62
- "Kimi K2.5 (high)",
63
- "Llama 4 Maverick Instruct",
64
- "Llama 4 Scout Instruct",
65
- "MiniMax M2",
66
- "MiniMax M2.5 (high)",
67
- "Qwen2.5-Coder 32B Instruct",
68
- "Qwen3-Coder 480B/A35B Instruct",
69
- "gpt-oss-120b",
70
- "o3 (2025-04-16)",
71
- "o4-mini (2025-04-16)"
72
- ]
73
- }