@lucasschirm/devinp 0.1.4 → 0.1.6

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
@@ -24,6 +24,19 @@ The package ships as a self-contained bundle — no dependencies are installed.
24
24
  not authenticated, `devinp` exits with an error (use `--source` for a saved
25
25
  snapshot).
26
26
 
27
+ ### When `devin` fails or truncates
28
+
29
+ - Prices are captured through a temp file in `os.tmpdir()` — `devin`'s
30
+ interactive CLI can truncate a pipe stream mid-write, so `devinp` points
31
+ `devin`'s stdout at a real file instead. The temp file is always removed
32
+ after the run.
33
+ - If `devin`'s output is cut off mid-stream, `devinp` repairs the document,
34
+ prints a warning, and renders the partial table.
35
+ - If the output cannot be recovered, `devinp` reports a diagnostic with the
36
+ size and tail of what `devin` wrote, and suggests re-running or saving the
37
+ output manually: `devin models list --format json > models.json`, then
38
+ `devinp --source models.json`.
39
+
27
40
  ## Usage
28
41
 
29
42
  ```sh
package/bin/command.js CHANGED
@@ -2887,9 +2887,9 @@ var require_ejs = __commonJS({
2887
2887
  createRegex: function() {
2888
2888
  var str = _REGEX_STRING;
2889
2889
  var delim = utils_js_1.default.escapeRegExpChars(this.opts.delimiter);
2890
- var open = utils_js_1.default.escapeRegExpChars(this.opts.openDelimiter);
2890
+ var open2 = utils_js_1.default.escapeRegExpChars(this.opts.openDelimiter);
2891
2891
  var close = utils_js_1.default.escapeRegExpChars(this.opts.closeDelimiter);
2892
- str = str.replace(/%/g, delim).replace(/</g, open).replace(/>/g, close);
2892
+ str = str.replace(/%/g, delim).replace(/</g, open2).replace(/>/g, close);
2893
2893
  return new RegExp(str);
2894
2894
  },
2895
2895
  compile: function() {
@@ -6393,8 +6393,8 @@ var require_async = __commonJS({
6393
6393
  "node_modules/get-package-type/async.cjs"(exports, module) {
6394
6394
  "use strict";
6395
6395
  var path = __require("path");
6396
- var { promisify: promisify4 } = __require("util");
6397
- var readFile3 = promisify4(__require("fs").readFile);
6396
+ var { promisify: promisify3 } = __require("util");
6397
+ var readFile3 = promisify3(__require("fs").readFile);
6398
6398
  var isNodeModules = require_is_node_modules();
6399
6399
  var resultsCache = require_cache2();
6400
6400
  var promiseCache = /* @__PURE__ */ new Map();
@@ -12628,10 +12628,10 @@ var require_commonjs3 = __commonJS({
12628
12628
  }
12629
12629
  return filtered.join("/");
12630
12630
  }).join("|");
12631
- const [open, close] = set.length > 1 ? ["(?:", ")"] : ["", ""];
12632
- re = "^" + open + re + close + "$";
12631
+ const [open2, close] = set.length > 1 ? ["(?:", ")"] : ["", ""];
12632
+ re = "^" + open2 + re + close + "$";
12633
12633
  if (this.partial) {
12634
- re = "^(?:\\/|" + open + re.slice(1, -1) + close + ")$";
12634
+ re = "^(?:\\/|" + open2 + re.slice(1, -1) + close + ")$";
12635
12635
  }
12636
12636
  if (this.negate)
12637
12637
  re = "^(?!" + re + ").+$";
@@ -13719,16 +13719,16 @@ var require_parse2 = __commonJS({
13719
13719
  const analysis = analyzeRepeatedExtglob(body, opts);
13720
13720
  if ((token.type === "plus" || token.type === "star") && analysis.risky) {
13721
13721
  const safeOutput = analysis.safeOutput ? (token.output ? "" : ONE_CHAR) + (opts.capture ? `(${analysis.safeOutput})` : analysis.safeOutput) : void 0;
13722
- const open = tokens[token.tokensIndex];
13723
- open.type = "text";
13724
- open.value = literal;
13725
- open.output = safeOutput || utils.escapeRegex(literal);
13722
+ const open2 = tokens[token.tokensIndex];
13723
+ open2.type = "text";
13724
+ open2.value = literal;
13725
+ open2.output = safeOutput || utils.escapeRegex(literal);
13726
13726
  for (let i = token.tokensIndex + 1; i < tokens.length; i++) {
13727
13727
  tokens[i].value = "";
13728
13728
  tokens[i].output = "";
13729
13729
  delete tokens[i].suffix;
13730
13730
  }
13731
- state.output = token.output + open.output;
13731
+ state.output = token.output + open2.output;
13732
13732
  state.backtrack = true;
13733
13733
  push({ type: "paren", extglob: true, value, output: "" });
13734
13734
  decrement("parens");
@@ -13948,15 +13948,15 @@ var require_parse2 = __commonJS({
13948
13948
  }
13949
13949
  if (value === "{" && opts.nobrace !== true) {
13950
13950
  increment("braces");
13951
- const open = {
13951
+ const open2 = {
13952
13952
  type: "brace",
13953
13953
  value,
13954
13954
  output: "(",
13955
13955
  outputIndex: state.output.length,
13956
13956
  tokensIndex: state.tokens.length
13957
13957
  };
13958
- braces.push(open);
13959
- push(open);
13958
+ braces.push(open2);
13959
+ push(open2);
13960
13960
  continue;
13961
13961
  }
13962
13962
  if (value === "}") {
@@ -27622,7 +27622,7 @@ var require_thread_stream = __commonJS({
27622
27622
  var { version } = require_package2();
27623
27623
  var { EventEmitter } = __require("events");
27624
27624
  var { Worker } = __require("worker_threads");
27625
- var { join: join2 } = __require("path");
27625
+ var { join: join3 } = __require("path");
27626
27626
  var { pathToFileURL } = __require("url");
27627
27627
  var { wait } = require_wait();
27628
27628
  var {
@@ -27673,7 +27673,7 @@ var require_thread_stream = __commonJS({
27673
27673
  function createWorker(stream, opts) {
27674
27674
  const { filename, workerData } = opts;
27675
27675
  const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
27676
- const toExecute = bundlerOverrides["thread-stream-worker"] || join2(__dirname, "lib", "worker.js");
27676
+ const toExecute = bundlerOverrides["thread-stream-worker"] || join3(__dirname, "lib", "worker.js");
27677
27677
  const worker = new Worker(toExecute, {
27678
27678
  ...opts.workerOpts,
27679
27679
  name: opts.workerOpts?.name || "thread-stream",
@@ -28141,7 +28141,7 @@ var require_transport = __commonJS({
28141
28141
  var { createRequire } = __require("module");
28142
28142
  var { existsSync } = __require("node:fs");
28143
28143
  var getCallers = require_caller();
28144
- var { join: join2, isAbsolute, sep } = __require("node:path");
28144
+ var { join: join3, isAbsolute, sep } = __require("node:path");
28145
28145
  var { fileURLToPath } = __require("node:url");
28146
28146
  var sleep = require_atomic_sleep();
28147
28147
  var onExit = require_on_exit_leak_free();
@@ -28294,7 +28294,7 @@ var require_transport = __commonJS({
28294
28294
  throw new Error("only one of target or targets can be specified");
28295
28295
  }
28296
28296
  if (targets) {
28297
- target = bundlerOverrides["pino-worker"] || join2(__dirname, "worker.js");
28297
+ target = bundlerOverrides["pino-worker"] || join3(__dirname, "worker.js");
28298
28298
  options.targets = targets.filter((dest) => dest.target).map((dest) => {
28299
28299
  return {
28300
28300
  ...dest,
@@ -28312,7 +28312,7 @@ var require_transport = __commonJS({
28312
28312
  });
28313
28313
  });
28314
28314
  } else if (pipeline) {
28315
- target = bundlerOverrides["pino-worker"] || join2(__dirname, "worker.js");
28315
+ target = bundlerOverrides["pino-worker"] || join3(__dirname, "worker.js");
28316
28316
  options.pipelines = [pipeline.map((dest) => {
28317
28317
  return {
28318
28318
  ...dest,
@@ -28335,7 +28335,7 @@ var require_transport = __commonJS({
28335
28335
  return origin;
28336
28336
  }
28337
28337
  if (origin === "pino/file") {
28338
- return join2(__dirname, "..", "file.js");
28338
+ return join3(__dirname, "..", "file.js");
28339
28339
  }
28340
28340
  let fixTarget2;
28341
28341
  for (const filePath of callers) {
@@ -29315,7 +29315,7 @@ var require_safe_stable_stringify = __commonJS({
29315
29315
  return circularValue;
29316
29316
  }
29317
29317
  let res = "";
29318
- let join2 = ",";
29318
+ let join3 = ",";
29319
29319
  const originalIndentation = indentation;
29320
29320
  if (Array.isArray(value)) {
29321
29321
  if (value.length === 0) {
@@ -29329,7 +29329,7 @@ var require_safe_stable_stringify = __commonJS({
29329
29329
  indentation += spacer;
29330
29330
  res += `
29331
29331
  ${indentation}`;
29332
- join2 = `,
29332
+ join3 = `,
29333
29333
  ${indentation}`;
29334
29334
  }
29335
29335
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -29337,13 +29337,13 @@ ${indentation}`;
29337
29337
  for (; i < maximumValuesToStringify - 1; i++) {
29338
29338
  const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
29339
29339
  res += tmp2 !== void 0 ? tmp2 : "null";
29340
- res += join2;
29340
+ res += join3;
29341
29341
  }
29342
29342
  const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
29343
29343
  res += tmp !== void 0 ? tmp : "null";
29344
29344
  if (value.length - 1 > maximumBreadth) {
29345
29345
  const removedKeys = value.length - maximumBreadth - 1;
29346
- res += `${join2}"... ${getItemCount(removedKeys)} not stringified"`;
29346
+ res += `${join3}"... ${getItemCount(removedKeys)} not stringified"`;
29347
29347
  }
29348
29348
  if (spacer !== "") {
29349
29349
  res += `
@@ -29364,7 +29364,7 @@ ${originalIndentation}`;
29364
29364
  let separator = "";
29365
29365
  if (spacer !== "") {
29366
29366
  indentation += spacer;
29367
- join2 = `,
29367
+ join3 = `,
29368
29368
  ${indentation}`;
29369
29369
  whitespace = " ";
29370
29370
  }
@@ -29378,13 +29378,13 @@ ${indentation}`;
29378
29378
  const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
29379
29379
  if (tmp !== void 0) {
29380
29380
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
29381
- separator = join2;
29381
+ separator = join3;
29382
29382
  }
29383
29383
  }
29384
29384
  if (keyLength > maximumBreadth) {
29385
29385
  const removedKeys = keyLength - maximumBreadth;
29386
29386
  res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
29387
- separator = join2;
29387
+ separator = join3;
29388
29388
  }
29389
29389
  if (spacer !== "" && separator.length > 1) {
29390
29390
  res = `
@@ -29425,7 +29425,7 @@ ${originalIndentation}`;
29425
29425
  }
29426
29426
  const originalIndentation = indentation;
29427
29427
  let res = "";
29428
- let join2 = ",";
29428
+ let join3 = ",";
29429
29429
  if (Array.isArray(value)) {
29430
29430
  if (value.length === 0) {
29431
29431
  return "[]";
@@ -29438,7 +29438,7 @@ ${originalIndentation}`;
29438
29438
  indentation += spacer;
29439
29439
  res += `
29440
29440
  ${indentation}`;
29441
- join2 = `,
29441
+ join3 = `,
29442
29442
  ${indentation}`;
29443
29443
  }
29444
29444
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -29446,13 +29446,13 @@ ${indentation}`;
29446
29446
  for (; i < maximumValuesToStringify - 1; i++) {
29447
29447
  const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
29448
29448
  res += tmp2 !== void 0 ? tmp2 : "null";
29449
- res += join2;
29449
+ res += join3;
29450
29450
  }
29451
29451
  const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
29452
29452
  res += tmp !== void 0 ? tmp : "null";
29453
29453
  if (value.length - 1 > maximumBreadth) {
29454
29454
  const removedKeys = value.length - maximumBreadth - 1;
29455
- res += `${join2}"... ${getItemCount(removedKeys)} not stringified"`;
29455
+ res += `${join3}"... ${getItemCount(removedKeys)} not stringified"`;
29456
29456
  }
29457
29457
  if (spacer !== "") {
29458
29458
  res += `
@@ -29465,7 +29465,7 @@ ${originalIndentation}`;
29465
29465
  let whitespace = "";
29466
29466
  if (spacer !== "") {
29467
29467
  indentation += spacer;
29468
- join2 = `,
29468
+ join3 = `,
29469
29469
  ${indentation}`;
29470
29470
  whitespace = " ";
29471
29471
  }
@@ -29474,7 +29474,7 @@ ${indentation}`;
29474
29474
  const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
29475
29475
  if (tmp !== void 0) {
29476
29476
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
29477
- separator = join2;
29477
+ separator = join3;
29478
29478
  }
29479
29479
  }
29480
29480
  if (spacer !== "" && separator.length > 1) {
@@ -29532,20 +29532,20 @@ ${originalIndentation}`;
29532
29532
  indentation += spacer;
29533
29533
  let res2 = `
29534
29534
  ${indentation}`;
29535
- const join3 = `,
29535
+ const join4 = `,
29536
29536
  ${indentation}`;
29537
29537
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
29538
29538
  let i = 0;
29539
29539
  for (; i < maximumValuesToStringify - 1; i++) {
29540
29540
  const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
29541
29541
  res2 += tmp2 !== void 0 ? tmp2 : "null";
29542
- res2 += join3;
29542
+ res2 += join4;
29543
29543
  }
29544
29544
  const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
29545
29545
  res2 += tmp !== void 0 ? tmp : "null";
29546
29546
  if (value.length - 1 > maximumBreadth) {
29547
29547
  const removedKeys = value.length - maximumBreadth - 1;
29548
- res2 += `${join3}"... ${getItemCount(removedKeys)} not stringified"`;
29548
+ res2 += `${join4}"... ${getItemCount(removedKeys)} not stringified"`;
29549
29549
  }
29550
29550
  res2 += `
29551
29551
  ${originalIndentation}`;
@@ -29561,16 +29561,16 @@ ${originalIndentation}`;
29561
29561
  return '"[Object]"';
29562
29562
  }
29563
29563
  indentation += spacer;
29564
- const join2 = `,
29564
+ const join3 = `,
29565
29565
  ${indentation}`;
29566
29566
  let res = "";
29567
29567
  let separator = "";
29568
29568
  let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
29569
29569
  if (isTypedArrayWithEntries(value)) {
29570
- res += stringifyTypedArray(value, join2, maximumBreadth);
29570
+ res += stringifyTypedArray(value, join3, maximumBreadth);
29571
29571
  keys = keys.slice(value.length);
29572
29572
  maximumPropertiesToStringify -= value.length;
29573
- separator = join2;
29573
+ separator = join3;
29574
29574
  }
29575
29575
  if (deterministic) {
29576
29576
  keys = sort(keys, comparator);
@@ -29581,13 +29581,13 @@ ${indentation}`;
29581
29581
  const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
29582
29582
  if (tmp !== void 0) {
29583
29583
  res += `${separator}${strEscape(key2)}: ${tmp}`;
29584
- separator = join2;
29584
+ separator = join3;
29585
29585
  }
29586
29586
  }
29587
29587
  if (keyLength > maximumBreadth) {
29588
29588
  const removedKeys = keyLength - maximumBreadth;
29589
29589
  res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
29590
- separator = join2;
29590
+ separator = join3;
29591
29591
  }
29592
29592
  if (separator !== "") {
29593
29593
  res = `
@@ -55023,41 +55023,155 @@ async function startServer({ rows, benchMeta, port, log }) {
55023
55023
  }
55024
55024
 
55025
55025
  // src/lib/source.js
55026
- import { execFile as execFile4 } from "node:child_process";
55027
- import { readFile as readFile2 } from "node:fs/promises";
55028
- import { promisify as promisify3 } from "node:util";
55029
- var execFileAsync = promisify3(execFile4);
55030
- async function loadModelData({ source } = {}) {
55026
+ import { spawn } from "node:child_process";
55027
+ import { open, readFile as readFile2, unlink } from "node:fs/promises";
55028
+ import { tmpdir } from "node:os";
55029
+ import { join as join2 } from "node:path";
55030
+
55031
+ // src/lib/repair-json.js
55032
+ var CLOSER = { "{": "}", "[": "]" };
55033
+ function recoverTruncatedJson(raw) {
55034
+ if (typeof raw !== "string") return null;
55035
+ try {
55036
+ return JSON.parse(raw);
55037
+ } catch {
55038
+ }
55039
+ const scan = scanJson(raw, raw.length);
55040
+ const cuts = [raw.length];
55041
+ if (scan.inString) cuts.push(scan.stringStart);
55042
+ if (scan.lastComma != null) cuts.push(scan.lastComma + 1);
55043
+ if (scan.lastCloser != null) cuts.push(scan.lastCloser + 1);
55044
+ const seen = /* @__PURE__ */ new Set();
55045
+ for (const cut of cuts) {
55046
+ if (seen.has(cut)) continue;
55047
+ seen.add(cut);
55048
+ let candidate = raw.slice(0, cut).replace(/[\s,]+$/g, "");
55049
+ if (candidate === "") continue;
55050
+ const s = scanJson(candidate, candidate.length);
55051
+ const repaired = candidate + s.stack.map((token) => CLOSER[token]).reverse().join("");
55052
+ try {
55053
+ return JSON.parse(repaired);
55054
+ } catch {
55055
+ }
55056
+ }
55057
+ return null;
55058
+ }
55059
+ function scanJson(s, end) {
55060
+ let inString = false;
55061
+ let escape2 = false;
55062
+ let stringStart = 0;
55063
+ const stack = [];
55064
+ let lastComma = null;
55065
+ let lastCloser = null;
55066
+ for (let i = 0; i < end; i++) {
55067
+ const ch = s[i];
55068
+ if (inString) {
55069
+ if (escape2) escape2 = false;
55070
+ else if (ch === "\\") escape2 = true;
55071
+ else if (ch === '"') inString = false;
55072
+ continue;
55073
+ }
55074
+ if (ch === '"') {
55075
+ inString = true;
55076
+ stringStart = i;
55077
+ } else if (ch === ",") {
55078
+ lastComma = i;
55079
+ } else if (ch === "{" || ch === "[") {
55080
+ stack.push(ch);
55081
+ } else if (ch === "}" || ch === "]") {
55082
+ stack.pop();
55083
+ lastCloser = i;
55084
+ }
55085
+ }
55086
+ return { inString, stringStart, stack, lastComma, lastCloser };
55087
+ }
55088
+
55089
+ // src/lib/source.js
55090
+ var DEVIN_TIMEOUT_MS = 3e4;
55091
+ async function runDevinJson({ command = "devin", timeoutMs = DEVIN_TIMEOUT_MS } = {}) {
55092
+ const file = join2(tmpdir(), `devinp-models-${process.pid}-${Date.now()}.json`);
55093
+ const handle = await open(file, "w");
55094
+ try {
55095
+ const { code, stderr, timedOut } = await new Promise((resolve, reject) => {
55096
+ const child = spawn(command, ["models", "list", "--format", "json"], {
55097
+ stdio: ["ignore", handle.fd, "pipe"]
55098
+ });
55099
+ let stderr2 = "";
55100
+ let timedOut2 = false;
55101
+ const timer = setTimeout(() => {
55102
+ timedOut2 = true;
55103
+ child.kill("SIGKILL");
55104
+ }, timeoutMs);
55105
+ child.stderr.on("data", (chunk) => {
55106
+ stderr2 += chunk;
55107
+ });
55108
+ child.on("error", (error) => {
55109
+ clearTimeout(timer);
55110
+ reject(error);
55111
+ });
55112
+ child.on("close", (childCode) => {
55113
+ clearTimeout(timer);
55114
+ resolve({ code: childCode, stderr: stderr2, timedOut: timedOut2 });
55115
+ });
55116
+ });
55117
+ if (timedOut) {
55118
+ throw new Error(`\`devin models list\` timed out after ${timeoutMs / 1e3}s`);
55119
+ }
55120
+ if (code !== 0) {
55121
+ throw new Error(`\`devin models list\` failed \u2014 ${stderr.trim() || `exited with code ${code}`}`);
55122
+ }
55123
+ return await readFile2(file, "utf8");
55124
+ } finally {
55125
+ await handle.close();
55126
+ await unlink(file).catch(() => {
55127
+ });
55128
+ }
55129
+ }
55130
+ function assertFamilies(data, sourceName) {
55131
+ if (data == null || typeof data !== "object" || !Array.isArray(data.families)) {
55132
+ throw new Error(`Unable to get model prices: ${sourceName} has no "families" array (expected \`devin models list --format json\` output)`);
55133
+ }
55134
+ if (data.families.length === 0) {
55135
+ throw new Error(`Unable to get model prices: ${sourceName} contains no model families`);
55136
+ }
55137
+ return data;
55138
+ }
55139
+ async function loadModelData({ source, command = "devin", timeoutMs = DEVIN_TIMEOUT_MS } = {}) {
55031
55140
  if (source) {
55032
- let raw;
55141
+ let raw2;
55033
55142
  try {
55034
- raw = await readFile2(source, "utf8");
55143
+ raw2 = await readFile2(source, "utf8");
55035
55144
  } catch (error) {
55036
55145
  throw new Error(`Unable to get model prices: cannot read source file "${source}" (${error.code ?? error.message})`);
55037
55146
  }
55038
55147
  try {
55039
- return JSON.parse(raw);
55040
- } catch {
55148
+ return { data: assertFamilies(JSON.parse(raw2), source) };
55149
+ } catch (error) {
55150
+ if (error.message.startsWith("Unable to get model prices")) throw error;
55041
55151
  throw new Error(`Unable to get model prices: "${source}" is not valid JSON (expected \`devin models list --format json\` output)`);
55042
55152
  }
55043
55153
  }
55044
- let stdout;
55154
+ let raw;
55045
55155
  try {
55046
- ;
55047
- ({ stdout } = await execFileAsync("devin", ["models", "list", "--format", "json"], {
55048
- maxBuffer: 64 * 1024 * 1024
55049
- }));
55156
+ raw = await runDevinJson({ command, timeoutMs });
55050
55157
  } catch (error) {
55051
55158
  if (error.code === "ENOENT") {
55052
55159
  throw new Error("Unable to get model prices: `devin` CLI not found in PATH. Install it or pass --source <file>.");
55053
55160
  }
55054
- const detail = error.stderr?.trim() || error.message;
55055
- throw new Error(`Unable to get model prices: \`devin models list\` failed \u2014 ${detail}`);
55161
+ throw new Error(`Unable to get model prices: ${error.message}`);
55056
55162
  }
55057
55163
  try {
55058
- return JSON.parse(stdout);
55059
- } catch {
55060
- throw new Error("Unable to get model prices: `devin models list --format json` returned invalid JSON");
55164
+ return { data: assertFamilies(JSON.parse(raw), "devin models list") };
55165
+ } catch (error) {
55166
+ if (error.message.startsWith("Unable to get model prices")) throw error;
55167
+ const recovered = recoverTruncatedJson(raw);
55168
+ if (recovered != null) {
55169
+ return { data: assertFamilies(recovered, "devin models list (recovered)"), truncated: true };
55170
+ }
55171
+ const tail = raw.trimEnd().slice(-200);
55172
+ throw new Error(
55173
+ `Unable to get model prices: \`devin models list --format json\` returned invalid JSON (${error.message} \u2014 ${raw.length} bytes, output ends with ${JSON.stringify(tail)}). The output may have been truncated mid-stream: re-run, or save the output with \`devin models list --format json > models.json\` and pass \`--source models.json\`.`
55174
+ );
55061
55175
  }
55062
55176
  }
55063
55177
 
@@ -55111,7 +55225,11 @@ var Devinp = class _Devinp extends import_core.Command {
55111
55225
  const { flags } = await this.parse(_Devinp);
55112
55226
  let data;
55113
55227
  try {
55114
- data = await loadModelData({ source: flags.source });
55228
+ const loaded = await loadModelData({ source: flags.source });
55229
+ if (loaded.truncated) {
55230
+ this.warn("devin output was truncated mid-stream \u2014 showing partial data, re-run for the full list");
55231
+ }
55232
+ data = loaded.data;
55115
55233
  } catch (error) {
55116
55234
  this.error(error instanceof Error ? error.message : String(error), { exit: 1 });
55117
55235
  }
@@ -1,154 +1,154 @@
1
1
  {
2
- "updated": "2026-09-29",
2
+ "updated": "2026-10-01",
3
3
  "source": "https://benchlm.ai/api/data/leaderboard?category=coding&limit=200",
4
4
  "models": {
5
5
  "claude-fable-5": {
6
- "score": 73.1,
6
+ "score": 72.98,
7
7
  "benchName": "Claude Fable 5",
8
8
  "supported": true
9
9
  },
10
10
  "claude-fable-5.1": {
11
- "score": 79.99,
11
+ "score": 79.75,
12
12
  "benchName": "Claude Fable 5.1",
13
13
  "supported": true
14
14
  },
15
15
  "claude-haiku-4.5": {
16
- "score": 19.61,
16
+ "score": 19.58,
17
17
  "benchName": "Claude Haiku 4.5",
18
18
  "supported": true
19
19
  },
20
20
  "claude-opus-4.5": {
21
- "score": 42.56,
21
+ "score": 42.64,
22
22
  "benchName": "Claude Opus 4.5",
23
23
  "supported": false
24
24
  },
25
25
  "claude-opus-4.6": {
26
- "score": 49.68,
26
+ "score": 49.58,
27
27
  "benchName": "Claude Opus 4.6",
28
28
  "supported": true
29
29
  },
30
30
  "claude-opus-4.7": {
31
- "score": 58.1,
31
+ "score": 57.97,
32
32
  "benchName": "Claude Opus 4.7",
33
33
  "supported": true
34
34
  },
35
35
  "claude-opus-4.8": {
36
- "score": 62.37,
36
+ "score": 62.28,
37
37
  "benchName": "Claude Opus 4.8",
38
38
  "supported": true
39
39
  },
40
40
  "claude-opus-5": {
41
- "score": 72.18,
41
+ "score": 72.05,
42
42
  "benchName": "Claude Opus 5",
43
43
  "supported": true
44
44
  },
45
45
  "claude-opus-5.5": {
46
- "score": 83.6,
46
+ "score": 83.32,
47
47
  "benchName": "Claude Opus 5.5",
48
48
  "supported": true
49
49
  },
50
50
  "claude-sonnet-4.6": {
51
- "score": 47.04,
51
+ "score": 47.14,
52
52
  "benchName": "Claude Sonnet 4.6",
53
53
  "supported": true
54
54
  },
55
55
  "claude-sonnet-5": {
56
- "score": 59.96,
56
+ "score": 59.84,
57
57
  "benchName": "Claude Sonnet 5",
58
58
  "supported": true
59
59
  },
60
60
  "claude-sonnet-5.5": {
61
- "score": 85.12,
61
+ "score": 85.56,
62
62
  "benchName": "Claude Sonnet 5.5",
63
63
  "supported": true
64
64
  },
65
65
  "deepseek-v4-pro": {
66
- "score": 49.36,
66
+ "score": 49.26,
67
67
  "benchName": "DeepSeek V4 Pro 0813",
68
68
  "supported": true
69
69
  },
70
70
  "deepseek-v4.1-flash": {
71
- "score": 49.63,
71
+ "score": 58.89,
72
72
  "benchName": "DeepSeek V4.1 Flash",
73
73
  "supported": false
74
74
  },
75
75
  "gemini-3-flash": {
76
- "score": 36.38,
76
+ "score": 36.32,
77
77
  "benchName": "Gemini 3 Flash",
78
78
  "supported": true
79
79
  },
80
80
  "gemini-3.1-pro": {
81
- "score": 42.44,
81
+ "score": 42.32,
82
82
  "benchName": "Gemini 3.1 Pro",
83
83
  "supported": true
84
84
  },
85
85
  "gemini-3.5-flash": {
86
- "score": 52.43,
86
+ "score": 52.36,
87
87
  "benchName": "Gemini 3.5 Flash",
88
88
  "supported": true
89
89
  },
90
90
  "gemini-3.6-flash": {
91
- "score": 53.78,
91
+ "score": 53.68,
92
92
  "benchName": "Gemini 3.6 Flash",
93
93
  "supported": true
94
94
  },
95
95
  "gemini-3.7-flash": {
96
- "score": 59.48,
96
+ "score": 59.32,
97
97
  "benchName": "Gemini 3.7 Flash",
98
98
  "supported": true
99
99
  },
100
100
  "gemini-3.8-flash": {
101
- "score": 64.16,
101
+ "score": 63.66,
102
102
  "benchName": "Gemini 3.8 Flash",
103
103
  "supported": true
104
104
  },
105
105
  "glm-5.2": {
106
- "score": 56.29,
106
+ "score": 56.27,
107
107
  "benchName": "GLM-5.2",
108
108
  "supported": true
109
109
  },
110
110
  "glm-5.3": {
111
- "score": 56.84,
111
+ "score": 56.65,
112
112
  "benchName": "GLM-5.3",
113
113
  "supported": true
114
114
  },
115
115
  "glm-5.3-flash": {
116
- "score": 52.54,
116
+ "score": 52.23,
117
117
  "benchName": "GLM-5.3-Flash",
118
118
  "supported": true
119
119
  },
120
120
  "gpt-5.1": {
121
- "score": 38.86,
121
+ "score": 38.92,
122
122
  "benchName": "GPT-5.1",
123
123
  "supported": true
124
124
  },
125
125
  "gpt-5.2": {
126
- "score": 39.7,
126
+ "score": 39.68,
127
127
  "benchName": "GPT-5.2",
128
128
  "supported": true
129
129
  },
130
130
  "gpt-5.3-codex": {
131
- "score": 55.5,
131
+ "score": 56.08,
132
132
  "benchName": "GPT-5.3 Codex",
133
133
  "supported": true
134
134
  },
135
135
  "gpt-5.4": {
136
- "score": 49.83,
136
+ "score": 49.67,
137
137
  "benchName": "GPT-5.4",
138
138
  "supported": true
139
139
  },
140
140
  "gpt-5.4-mini": {
141
- "score": 36.92,
141
+ "score": 36.95,
142
142
  "benchName": "GPT-5.4 mini",
143
143
  "supported": true
144
144
  },
145
145
  "gpt-5.5": {
146
- "score": 62.83,
146
+ "score": 62.79,
147
147
  "benchName": "GPT-5.5",
148
148
  "supported": true
149
149
  },
150
150
  "gpt-5.6-luna": {
151
- "score": 63.3,
151
+ "score": 63.38,
152
152
  "benchName": "GPT-5.6 Luna",
153
153
  "supported": true
154
154
  },
@@ -158,62 +158,62 @@
158
158
  "supported": true
159
159
  },
160
160
  "gpt-5.6-terra": {
161
- "score": 64.41,
161
+ "score": 64.33,
162
162
  "benchName": "GPT-5.6 Terra",
163
163
  "supported": true
164
164
  },
165
165
  "gpt-6-astra": {
166
- "score": 74.18,
166
+ "score": 74.03,
167
167
  "benchName": "GPT-6 Astra",
168
168
  "supported": true
169
169
  },
170
170
  "gpt-6-luna": {
171
- "score": 51.37,
171
+ "score": 50.18,
172
172
  "benchName": "GPT-6 Luna",
173
173
  "supported": true
174
174
  },
175
175
  "gpt-6-sol": {
176
- "score": 62.99,
176
+ "score": 61.88,
177
177
  "benchName": "GPT-6 Sol",
178
178
  "supported": true
179
179
  },
180
180
  "gpt-6.1-sol": {
181
- "score": 66.97,
181
+ "score": 59.06,
182
182
  "benchName": "GPT-6.1 Sol",
183
183
  "supported": true
184
184
  },
185
185
  "grok-4.5": {
186
- "score": 58.07,
186
+ "score": 58.11,
187
187
  "benchName": "Grok 4.5",
188
188
  "supported": true
189
189
  },
190
190
  "grok-4.6": {
191
- "score": 61.62,
191
+ "score": 61.42,
192
192
  "benchName": "Grok 4.6",
193
193
  "supported": true
194
194
  },
195
195
  "inkling": {
196
- "score": 36.56,
196
+ "score": 36.41,
197
197
  "benchName": "Inkling",
198
198
  "supported": true
199
199
  },
200
200
  "kimi-k2.6": {
201
- "score": 46.36,
201
+ "score": 46.09,
202
202
  "benchName": "Kimi K2.6",
203
203
  "supported": true
204
204
  },
205
205
  "kimi-k2.7": {
206
- "score": 44.45,
206
+ "score": 44.55,
207
207
  "benchName": "Kimi K2.7 Code",
208
208
  "supported": true
209
209
  },
210
210
  "kimi-k3": {
211
- "score": 61.59,
211
+ "score": 61.39,
212
212
  "benchName": "Kimi K3",
213
213
  "supported": true
214
214
  },
215
215
  "nemotron-3-ultra": {
216
- "score": 22.78,
216
+ "score": 23.14,
217
217
  "benchName": "Nemotron 3 Ultra",
218
218
  "supported": true
219
219
  }
@@ -247,6 +247,7 @@
247
247
  "Gemini 3 Pro",
248
248
  "Gemini 3.1 Flash-Lite",
249
249
  "Gemini 3.5 Flash-Lite",
250
+ "Gemini 4 Argon",
250
251
  "Gemma 3 27B",
251
252
  "Gemma 4 12B",
252
253
  "Gemma 4 26B A4B",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucasschirm/devinp",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Pretty pricing table for Devin models, powered by `devin models list`",
5
5
  "type": "module",
6
6
  "bin": {