@plune-ai/cli 0.34.2 → 0.34.4
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 +4 -2
- package/dist/cli.cjs +46 -20
- package/dist/index.cjs +25 -1
- package/dist/index.js +25 -1
- package/dist/mcp-tools.cjs +1 -1
- package/dist/mcp-tools.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -70,8 +70,10 @@ evals:
|
|
|
70
70
|
value: "Paris"
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
Datasets are JSONL, one row per line, shaped `{ "vars": { ... }, "expected"?: "..." }`.
|
|
74
|
-
|
|
73
|
+
Datasets are JSONL, one row per line, shaped `{ "vars": { ... }, "expected"?: "..." }`. A line that
|
|
74
|
+
is not valid JSON or not a row (no `vars`, or `vars` that is not an object) stops the run before
|
|
75
|
+
any model call with `<file>:<line>` and what is wrong, exit code `2`, like any other configuration
|
|
76
|
+
error. The provider API key is read from the environment based on `provider.type`:
|
|
75
77
|
|
|
76
78
|
| Provider | `provider.type` | Environment variable |
|
|
77
79
|
| ---------- | --------------- | -------------------- |
|
package/dist/cli.cjs
CHANGED
|
@@ -2096,7 +2096,31 @@ function loadDataset(ref, baseDir) {
|
|
|
2096
2096
|
return ref.examples;
|
|
2097
2097
|
}
|
|
2098
2098
|
const content = fs4.readFileSync(path4.resolve(baseDir, ref), "utf8");
|
|
2099
|
-
|
|
2099
|
+
const rows = [];
|
|
2100
|
+
content.split(/\r?\n/).forEach((line, i) => {
|
|
2101
|
+
if (line.trim().length === 0) return;
|
|
2102
|
+
let row;
|
|
2103
|
+
try {
|
|
2104
|
+
row = JSON.parse(line.trim());
|
|
2105
|
+
} catch (err) {
|
|
2106
|
+
throw new RunConfigError(`${ref}:${i + 1}: not valid JSON (${err.message})`);
|
|
2107
|
+
}
|
|
2108
|
+
const vars = isObject(row) ? row["vars"] : void 0;
|
|
2109
|
+
if (!isObject(vars)) {
|
|
2110
|
+
const why = isObject(row) && "vars" in row ? `vars: Invalid input: expected record, received ${typeName(vars)}` : 'this row has no "vars"';
|
|
2111
|
+
throw new RunConfigError(
|
|
2112
|
+
`${ref}:${i + 1}: a dataset row must be { "vars": { ... } }; ${why}`
|
|
2113
|
+
);
|
|
2114
|
+
}
|
|
2115
|
+
rows.push(row);
|
|
2116
|
+
});
|
|
2117
|
+
return rows;
|
|
2118
|
+
}
|
|
2119
|
+
function isObject(value2) {
|
|
2120
|
+
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
2121
|
+
}
|
|
2122
|
+
function typeName(value2) {
|
|
2123
|
+
return value2 === null ? "null" : Array.isArray(value2) ? "array" : typeof value2;
|
|
2100
2124
|
}
|
|
2101
2125
|
var fs4, path4;
|
|
2102
2126
|
var init_dataset = __esm({
|
|
@@ -2105,6 +2129,7 @@ var init_dataset = __esm({
|
|
|
2105
2129
|
init_cjs_shims();
|
|
2106
2130
|
fs4 = __toESM(require("fs"), 1);
|
|
2107
2131
|
path4 = __toESM(require("path"), 1);
|
|
2132
|
+
init_run();
|
|
2108
2133
|
}
|
|
2109
2134
|
});
|
|
2110
2135
|
|
|
@@ -5662,21 +5687,21 @@ var init_playwright_json = __esm({
|
|
|
5662
5687
|
});
|
|
5663
5688
|
|
|
5664
5689
|
// src/importers/k6.ts
|
|
5665
|
-
function
|
|
5690
|
+
function isObject2(value2) {
|
|
5666
5691
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
5667
5692
|
}
|
|
5668
5693
|
function isK6Summary(parsed) {
|
|
5669
|
-
if (!
|
|
5670
|
-
if (
|
|
5671
|
-
return Object.values(parsed["metrics"]).some((m) =>
|
|
5694
|
+
if (!isObject2(parsed) || !isObject2(parsed["metrics"])) return false;
|
|
5695
|
+
if (isObject2(parsed["root_group"])) return true;
|
|
5696
|
+
return Object.values(parsed["metrics"]).some((m) => isObject2(m) && (typeof m["type"] === "string" || isObject2(m["thresholds"])));
|
|
5672
5697
|
}
|
|
5673
5698
|
function passedOf(verdict) {
|
|
5674
|
-
if (
|
|
5699
|
+
if (isObject2(verdict) && typeof verdict["ok"] === "boolean") return verdict["ok"];
|
|
5675
5700
|
if (typeof verdict === "boolean") return !verdict;
|
|
5676
5701
|
return void 0;
|
|
5677
5702
|
}
|
|
5678
5703
|
function measuredOf(metric) {
|
|
5679
|
-
const values =
|
|
5704
|
+
const values = isObject2(metric.values) ? metric.values : metric;
|
|
5680
5705
|
const unit = metric.contains === "time" ? " ms" : "";
|
|
5681
5706
|
return Object.entries(values).filter(([name, v]) => name !== "thresholds" && typeof v === "number").map(([name, v]) => `${name}=${Math.round(v * 100) / 100}${unit}`).join(", ");
|
|
5682
5707
|
}
|
|
@@ -5687,13 +5712,13 @@ function readK6(source, file) {
|
|
|
5687
5712
|
} catch (err) {
|
|
5688
5713
|
throw new JsonReportError(file, `not JSON \u2014 ${printable(err instanceof Error ? err.message : String(err))}`);
|
|
5689
5714
|
}
|
|
5690
|
-
if (!
|
|
5715
|
+
if (!isObject2(parsed) || !isObject2(parsed["metrics"])) {
|
|
5691
5716
|
throw new JsonReportError(file, 'no "metrics" object \u2014 is this a k6 summary (k6 run --summary-export, or the data handleSummary receives)?');
|
|
5692
5717
|
}
|
|
5693
5718
|
const specRef = path13.basename(file);
|
|
5694
5719
|
const out = [];
|
|
5695
5720
|
for (const [name, raw] of Object.entries(parsed["metrics"])) {
|
|
5696
|
-
if (!
|
|
5721
|
+
if (!isObject2(raw) || !isObject2(raw["thresholds"])) continue;
|
|
5697
5722
|
const metric = raw;
|
|
5698
5723
|
const measured = measuredOf(metric);
|
|
5699
5724
|
for (const [expression, verdict] of Object.entries(metric.thresholds)) {
|
|
@@ -5734,11 +5759,11 @@ var init_k6 = __esm({
|
|
|
5734
5759
|
});
|
|
5735
5760
|
|
|
5736
5761
|
// src/importers/lighthouse.ts
|
|
5737
|
-
function
|
|
5762
|
+
function isObject3(value2) {
|
|
5738
5763
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
5739
5764
|
}
|
|
5740
5765
|
function isLighthouseReport(parsed) {
|
|
5741
|
-
return
|
|
5766
|
+
return isObject3(parsed) && typeof parsed["lighthouseVersion"] === "string" && isObject3(parsed["categories"]);
|
|
5742
5767
|
}
|
|
5743
5768
|
function idOf(key, category) {
|
|
5744
5769
|
return typeof category.id === "string" && category.id !== "" ? category.id : key;
|
|
@@ -5747,7 +5772,7 @@ function executionOf2(report) {
|
|
|
5747
5772
|
const started = typeof report["fetchTime"] === "string" ? new Date(report["fetchTime"]) : void 0;
|
|
5748
5773
|
if (started === void 0 || Number.isNaN(started.getTime())) return void 0;
|
|
5749
5774
|
const timing = report["timing"];
|
|
5750
|
-
const total =
|
|
5775
|
+
const total = isObject3(timing) && typeof timing["total"] === "number" && timing["total"] >= 0 ? Math.round(timing["total"]) : 0;
|
|
5751
5776
|
return {
|
|
5752
5777
|
startedAt: started.toISOString(),
|
|
5753
5778
|
finishedAt: new Date(started.getTime() + total).toISOString(),
|
|
@@ -5757,7 +5782,7 @@ function executionOf2(report) {
|
|
|
5757
5782
|
}
|
|
5758
5783
|
function runtimeErrorOf(report) {
|
|
5759
5784
|
const err = report["runtimeError"];
|
|
5760
|
-
if (!
|
|
5785
|
+
if (!isObject3(err)) return void 0;
|
|
5761
5786
|
const code = typeof err["code"] === "string" ? err["code"] : void 0;
|
|
5762
5787
|
if (code === "NO_ERROR") return void 0;
|
|
5763
5788
|
const message = typeof err["message"] === "string" ? err["message"] : void 0;
|
|
@@ -5778,11 +5803,11 @@ function readLighthouse(source, file, minScores = {}) {
|
|
|
5778
5803
|
const categories = report["categories"];
|
|
5779
5804
|
const url = ["requestedUrl", "finalDisplayedUrl", "finalUrl"].map((k) => report[k]).find((u) => typeof u === "string" && u !== "");
|
|
5780
5805
|
const settings = report["configSettings"];
|
|
5781
|
-
const formFactor =
|
|
5806
|
+
const formFactor = isObject3(settings) && typeof settings["formFactor"] === "string" && settings["formFactor"] !== "" ? settings["formFactor"] : void 0;
|
|
5782
5807
|
const runtimeError = runtimeErrorOf(report);
|
|
5783
5808
|
const execution = executionOf2(report);
|
|
5784
5809
|
const specRef = path14.basename(file);
|
|
5785
|
-
const known = Object.entries(categories).filter(([, raw]) =>
|
|
5810
|
+
const known = Object.entries(categories).filter(([, raw]) => isObject3(raw)).map(([key, raw]) => idOf(key, raw));
|
|
5786
5811
|
if (known.length > 0) {
|
|
5787
5812
|
for (const [id2, score] of Object.entries(minScores)) {
|
|
5788
5813
|
if (!known.includes(id2)) {
|
|
@@ -5809,7 +5834,7 @@ function readLighthouse(source, file, minScores = {}) {
|
|
|
5809
5834
|
});
|
|
5810
5835
|
};
|
|
5811
5836
|
for (const [key, raw] of Object.entries(categories)) {
|
|
5812
|
-
if (!
|
|
5837
|
+
if (!isObject3(raw)) continue;
|
|
5813
5838
|
const category = raw;
|
|
5814
5839
|
const id2 = idOf(key, category);
|
|
5815
5840
|
const name = typeof category.title === "string" && category.title !== "" ? category.title : id2;
|
|
@@ -6235,15 +6260,16 @@ function evalStatus(e) {
|
|
|
6235
6260
|
const statuses = e.rows.map(rowStatus);
|
|
6236
6261
|
if (statuses.includes("failed")) return "failed";
|
|
6237
6262
|
if (statuses.includes("errored")) return "errored";
|
|
6238
|
-
return "passed";
|
|
6263
|
+
return statuses.includes("passed") ? "passed" : "unjudged";
|
|
6239
6264
|
}
|
|
6240
6265
|
function classify2(baseline, current) {
|
|
6241
6266
|
if (current === "errored") return "errored";
|
|
6267
|
+
if (current === "unjudged") return "unmeasured";
|
|
6242
6268
|
if (baseline === "absent") return current === "passed" ? "new-pass" : "new-fail";
|
|
6243
6269
|
if (current === "absent") return "removed";
|
|
6244
6270
|
if (baseline === "passed") return current === "passed" ? "stable-pass" : "regression";
|
|
6245
6271
|
if (current === "passed") return "improvement";
|
|
6246
|
-
return baseline === "
|
|
6272
|
+
return baseline === "failed" ? "pre-existing-fail" : "unmeasured";
|
|
6247
6273
|
}
|
|
6248
6274
|
function diffRuns(baseline, current) {
|
|
6249
6275
|
const baseMap = new Map(baseline.evals.map((e) => [e.id, evalStatus(e)]));
|
|
@@ -6402,7 +6428,7 @@ var init_diff3 = __esm({
|
|
|
6402
6428
|
"new-pass": "\u{1F7E2} new pass",
|
|
6403
6429
|
"stable-pass": "\u2705 stable",
|
|
6404
6430
|
errored: "\u26A0\uFE0F errored",
|
|
6405
|
-
unmeasured: "\u26A0\uFE0F not measured
|
|
6431
|
+
unmeasured: "\u26A0\uFE0F not measured",
|
|
6406
6432
|
removed: "\u2796 removed"
|
|
6407
6433
|
};
|
|
6408
6434
|
}
|
|
@@ -6983,7 +7009,7 @@ var init_contract = __esm({
|
|
|
6983
7009
|
define({
|
|
6984
7010
|
name: "plune_review_decide",
|
|
6985
7011
|
title: "Decide queue entries",
|
|
6986
|
-
description: "Approve or reject up to 100 review queue entries in one decision. The first call changes nothing and returns a preview with a confirm value; repeat the same call with confirm to apply it.",
|
|
7012
|
+
description: "Approve or reject up to 100 review queue entries in one decision. The first call changes nothing and returns a preview with a confirm value; repeat the same call with confirm to apply it. An entry skipped as policy_refused was refused by the review policy of the project (for example, the person who proposed it cannot approve it): do not retry it \u2014 it needs another reviewer; its detail says why.",
|
|
6987
7013
|
input: import_zod5.z.strictObject({
|
|
6988
7014
|
itemIds: import_zod5.z.array(import_zod5.z.string().min(1)).min(1).max(BATCH_MAX2).refine((a) => new Set(a).size === a.length, { message: "an id is named once" }),
|
|
6989
7015
|
verdict: import_zod5.z.enum(["approved", "rejected"]),
|
package/dist/index.cjs
CHANGED
|
@@ -1686,7 +1686,31 @@ function loadDataset(ref, baseDir) {
|
|
|
1686
1686
|
return ref.examples;
|
|
1687
1687
|
}
|
|
1688
1688
|
const content = fs4.readFileSync(path3.resolve(baseDir, ref), "utf8");
|
|
1689
|
-
|
|
1689
|
+
const rows = [];
|
|
1690
|
+
content.split(/\r?\n/).forEach((line, i) => {
|
|
1691
|
+
if (line.trim().length === 0) return;
|
|
1692
|
+
let row;
|
|
1693
|
+
try {
|
|
1694
|
+
row = JSON.parse(line.trim());
|
|
1695
|
+
} catch (err) {
|
|
1696
|
+
throw new RunConfigError(`${ref}:${i + 1}: not valid JSON (${err.message})`);
|
|
1697
|
+
}
|
|
1698
|
+
const vars = isObject(row) ? row["vars"] : void 0;
|
|
1699
|
+
if (!isObject(vars)) {
|
|
1700
|
+
const why = isObject(row) && "vars" in row ? `vars: Invalid input: expected record, received ${typeName(vars)}` : 'this row has no "vars"';
|
|
1701
|
+
throw new RunConfigError(
|
|
1702
|
+
`${ref}:${i + 1}: a dataset row must be { "vars": { ... } }; ${why}`
|
|
1703
|
+
);
|
|
1704
|
+
}
|
|
1705
|
+
rows.push(row);
|
|
1706
|
+
});
|
|
1707
|
+
return rows;
|
|
1708
|
+
}
|
|
1709
|
+
function isObject(value) {
|
|
1710
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1711
|
+
}
|
|
1712
|
+
function typeName(value) {
|
|
1713
|
+
return value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
1690
1714
|
}
|
|
1691
1715
|
|
|
1692
1716
|
// src/cli/commands/run.ts
|
package/dist/index.js
CHANGED
|
@@ -1626,7 +1626,31 @@ function loadDataset(ref, baseDir) {
|
|
|
1626
1626
|
return ref.examples;
|
|
1627
1627
|
}
|
|
1628
1628
|
const content = fs4.readFileSync(path3.resolve(baseDir, ref), "utf8");
|
|
1629
|
-
|
|
1629
|
+
const rows = [];
|
|
1630
|
+
content.split(/\r?\n/).forEach((line, i) => {
|
|
1631
|
+
if (line.trim().length === 0) return;
|
|
1632
|
+
let row;
|
|
1633
|
+
try {
|
|
1634
|
+
row = JSON.parse(line.trim());
|
|
1635
|
+
} catch (err) {
|
|
1636
|
+
throw new RunConfigError(`${ref}:${i + 1}: not valid JSON (${err.message})`);
|
|
1637
|
+
}
|
|
1638
|
+
const vars = isObject(row) ? row["vars"] : void 0;
|
|
1639
|
+
if (!isObject(vars)) {
|
|
1640
|
+
const why = isObject(row) && "vars" in row ? `vars: Invalid input: expected record, received ${typeName(vars)}` : 'this row has no "vars"';
|
|
1641
|
+
throw new RunConfigError(
|
|
1642
|
+
`${ref}:${i + 1}: a dataset row must be { "vars": { ... } }; ${why}`
|
|
1643
|
+
);
|
|
1644
|
+
}
|
|
1645
|
+
rows.push(row);
|
|
1646
|
+
});
|
|
1647
|
+
return rows;
|
|
1648
|
+
}
|
|
1649
|
+
function isObject(value) {
|
|
1650
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1651
|
+
}
|
|
1652
|
+
function typeName(value) {
|
|
1653
|
+
return value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
1630
1654
|
}
|
|
1631
1655
|
|
|
1632
1656
|
// src/cli/commands/run.ts
|
package/dist/mcp-tools.cjs
CHANGED
|
@@ -298,7 +298,7 @@ var PLUNE_TOOLS = [
|
|
|
298
298
|
define({
|
|
299
299
|
name: "plune_review_decide",
|
|
300
300
|
title: "Decide queue entries",
|
|
301
|
-
description: "Approve or reject up to 100 review queue entries in one decision. The first call changes nothing and returns a preview with a confirm value; repeat the same call with confirm to apply it.",
|
|
301
|
+
description: "Approve or reject up to 100 review queue entries in one decision. The first call changes nothing and returns a preview with a confirm value; repeat the same call with confirm to apply it. An entry skipped as policy_refused was refused by the review policy of the project (for example, the person who proposed it cannot approve it): do not retry it \u2014 it needs another reviewer; its detail says why.",
|
|
302
302
|
input: import_zod2.z.strictObject({
|
|
303
303
|
itemIds: import_zod2.z.array(import_zod2.z.string().min(1)).min(1).max(BATCH_MAX).refine((a) => new Set(a).size === a.length, { message: "an id is named once" }),
|
|
304
304
|
verdict: import_zod2.z.enum(["approved", "rejected"]),
|
package/dist/mcp-tools.js
CHANGED
|
@@ -262,7 +262,7 @@ var PLUNE_TOOLS = [
|
|
|
262
262
|
define({
|
|
263
263
|
name: "plune_review_decide",
|
|
264
264
|
title: "Decide queue entries",
|
|
265
|
-
description: "Approve or reject up to 100 review queue entries in one decision. The first call changes nothing and returns a preview with a confirm value; repeat the same call with confirm to apply it.",
|
|
265
|
+
description: "Approve or reject up to 100 review queue entries in one decision. The first call changes nothing and returns a preview with a confirm value; repeat the same call with confirm to apply it. An entry skipped as policy_refused was refused by the review policy of the project (for example, the person who proposed it cannot approve it): do not retry it \u2014 it needs another reviewer; its detail says why.",
|
|
266
266
|
input: z2.strictObject({
|
|
267
267
|
itemIds: z2.array(z2.string().min(1)).min(1).max(BATCH_MAX).refine((a) => new Set(a).size === a.length, { message: "an id is named once" }),
|
|
268
268
|
verdict: z2.enum(["approved", "rejected"]),
|
package/package.json
CHANGED